Skip to content

Commit c66450d

Browse files
committed
Use react-select for page size dropdown
We are currently using our own custom styled dropdown thingy for the page size selector. This patch instead uses "Select" from react-select for the page size selector. The goal is to get the accessibility features of using a proper select component "for free", instead of having to painstakingly code our own. Apart from that, the page size selector should work as before.
1 parent 47bf603 commit c66450d

2 files changed

Lines changed: 97 additions & 47 deletions

File tree

src/components/shared/Table.tsx

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { JSX, useEffect, useRef, useState } from "react";
1+
import React, { JSX, useEffect, useRef } from "react";
22
import { useTranslation } from "react-i18next";
33
import {
44
getMultiSelect,
@@ -41,8 +41,8 @@ import ButtonLikeAnchor from "./ButtonLikeAnchor";
4141
import { ModalHandle } from "./modals/Modal";
4242
import { ParseKeys } from "i18next";
4343
import { LuChevronDown, LuChevronLeft, LuChevronRight, LuChevronUp } from "react-icons/lu";
44-
45-
const containerPageSize = React.createRef<HTMLDivElement>();
44+
import Select, { components } from "react-select";
45+
import { pageSizeStyles } from "../../utils/componentStyles";
4646

4747
export type TemplateMap = {
4848
[key: string]: ({ row }: { row: any }) => JSX.Element | JSX.Element[]
@@ -358,26 +358,14 @@ const PageSize = ({ forceDeselectAll }: { forceDeselectAll: () => unknown }) =>
358358
const dispatch = useAppDispatch();
359359
const pagination = useAppSelector(state => getTablePagination(state));
360360

361-
const sizeOptions = [10, 20, 50, 100, 1000]; // Size options for pagination
362-
const [showPageSizes, setShowPageSizes] = useState(false);
363-
364-
useEffect(() => {
365-
// Function for handling clicks outside of an open dropdown menu
366-
const handleClickOutside = (e: MouseEvent) => {
367-
if (
368-
e && containerPageSize.current && !containerPageSize.current.contains(e.target as Node)
369-
) {
370-
setShowPageSizes(false);
371-
}
372-
};
373-
374-
// Event listener for handle a click outside of dropdown menu
375-
window.addEventListener("mousedown", handleClickOutside);
376-
377-
return () => {
378-
window.removeEventListener("mousedown", handleClickOutside);
379-
};
380-
});
361+
const sizeOptions = React.useMemo(
362+
() =>
363+
[10, 20, 50, 100, 1000].map(size => ({
364+
value: size,
365+
label: size.toString(),
366+
})),
367+
[],
368+
);
381369

382370
const changePageSize = (size: number) => {
383371
forceDeselectAll();
@@ -386,31 +374,28 @@ const PageSize = ({ forceDeselectAll }: { forceDeselectAll: () => unknown }) =>
386374
dispatch(updatePages());
387375
};
388376

377+
const DropdownIndicator = (props: any) => {
378+
return (
379+
<components.DropdownIndicator {...props}>
380+
<LuChevronDown />
381+
</components.DropdownIndicator>
382+
);
383+
};
384+
389385
return (
390-
<div
391-
className="drop-down-container small flipped"
392-
onClick={() => setShowPageSizes(!showPageSizes)}
393-
ref={containerPageSize}
394-
role="button"
395-
tabIndex={0}
396-
>
397-
<span>{pagination.limit}</span>
398-
<LuChevronDown className="chevron-down"/>
399-
{/* Drop down menu for selection of page size */}
400-
{showPageSizes && (
401-
<ul className="dropdown-ul">
402-
{sizeOptions.map((size, key) => (
403-
<li key={key}>
404-
<ButtonLikeAnchor
405-
onClick={() => changePageSize(size)}
406-
>
407-
{size}
408-
</ButtonLikeAnchor>
409-
</li>
410-
))}
411-
</ul>
412-
)}
413-
</div>
386+
<Select
387+
options={sizeOptions}
388+
value={sizeOptions.find(opt => opt.value === pagination.limit)}
389+
onChange={(option: {value: number, label: string}) => {
390+
if (option) {
391+
changePageSize(option.value);
392+
}
393+
}}
394+
isSearchable={false}
395+
components={{ DropdownIndicator }}
396+
styles={pageSizeStyles}
397+
menuPlacement="top"
398+
/>
414399
);
415400
};
416401

src/utils/componentStyles.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,68 @@ export const dropDownSpacingTheme = (theme: Theme) => ({
147147
baseUnit: 2,
148148
},
149149
});
150+
151+
/**
152+
* Style specific to the page size component
153+
*/
154+
export const pageSizeStyles: StylesConfig<any, false> = {
155+
container: (base, _state) => ({
156+
...base,
157+
position: "absolute",
158+
right: "20px",
159+
}),
160+
control: base => ({
161+
...base,
162+
minHeight: 28,
163+
height: 28,
164+
width: 75,
165+
borderRadius: 4,
166+
paddingLeft: 10,
167+
168+
cursor: "pointer",
169+
fontSize: 12,
170+
fontWeight: 600,
171+
}),
172+
valueContainer: base => ({
173+
...base,
174+
padding: 0,
175+
}),
176+
singleValue: base => ({
177+
...base,
178+
color: "#666",
179+
}),
180+
indicatorSeparator: () => ({
181+
display: "none",
182+
}),
183+
184+
dropdownIndicator: (base, state) => ({
185+
...base,
186+
padding: "0 8px",
187+
color: "#666",
188+
transition: "transform 0.2s",
189+
transform: state.selectProps.menuIsOpen
190+
? "rotate(180deg)"
191+
: "rotate(0deg)",
192+
}),
193+
menu: base => ({
194+
...base,
195+
width: "75px",
196+
marginBottom: 2,
197+
borderRadius: 6,
198+
overflow: "hidden",
199+
zIndex: 9999,
200+
}),
201+
menuList: base => ({
202+
...base,
203+
padding: 0,
204+
}),
205+
option: (base, state) => ({
206+
...base,
207+
fontSize: 12,
208+
fontWeight: 600,
209+
cursor: "pointer",
210+
211+
backgroundColor: state.isFocused ? "#4da1f7" : "white",
212+
color: state.isFocused ? "white" : "#069",
213+
}),
214+
};

0 commit comments

Comments
 (0)