Skip to content

Commit 0400403

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 028b289 commit 0400403

File tree

2 files changed

+97
-47
lines changed

2 files changed

+97
-47
lines changed

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,
@@ -44,8 +44,8 @@ import { ParseKeys } from "i18next";
4444
import { LuChevronDown, LuChevronLeft, LuChevronRight, LuChevronUp } from "react-icons/lu";
4545
import { AsyncThunk } from "@reduxjs/toolkit";
4646
import { useLocation } from "react-router";
47-
48-
const containerPageSize = React.createRef<HTMLDivElement>();
47+
import Select, { components } from "react-select";
48+
import { pageSizeStyles } from "../../utils/componentStyles";
4949

5050
export type TemplateMap = {
5151
[key: string]: ({ row }: { row: any }) => JSX.Element | JSX.Element[]
@@ -397,26 +397,14 @@ const PageSize = ({ forceDeselectAll }: { forceDeselectAll: () => unknown }) =>
397397
const dispatch = useAppDispatch();
398398
const pagination = useAppSelector(state => getTablePagination(state));
399399

400-
const sizeOptions = [10, 20, 50, 100, 1000]; // Size options for pagination
401-
const [showPageSizes, setShowPageSizes] = useState(false);
402-
403-
useEffect(() => {
404-
// Function for handling clicks outside of an open dropdown menu
405-
const handleClickOutside = (e: MouseEvent) => {
406-
if (
407-
e && containerPageSize.current && !containerPageSize.current.contains(e.target as Node)
408-
) {
409-
setShowPageSizes(false);
410-
}
411-
};
412-
413-
// Event listener for handle a click outside of dropdown menu
414-
window.addEventListener("mousedown", handleClickOutside);
415-
416-
return () => {
417-
window.removeEventListener("mousedown", handleClickOutside);
418-
};
419-
});
400+
const sizeOptions = React.useMemo(
401+
() =>
402+
[10, 20, 50, 100, 1000].map(size => ({
403+
value: size,
404+
label: size.toString(),
405+
})),
406+
[],
407+
);
420408

421409
const changePageSize = (size: number) => {
422410
forceDeselectAll();
@@ -425,31 +413,28 @@ const PageSize = ({ forceDeselectAll }: { forceDeselectAll: () => unknown }) =>
425413
dispatch(updatePages());
426414
};
427415

416+
const DropdownIndicator = (props: any) => {
417+
return (
418+
<components.DropdownIndicator {...props}>
419+
<LuChevronDown />
420+
</components.DropdownIndicator>
421+
);
422+
};
423+
428424
return (
429-
<div
430-
className="drop-down-container small flipped"
431-
onClick={() => setShowPageSizes(!showPageSizes)}
432-
ref={containerPageSize}
433-
role="button"
434-
tabIndex={0}
435-
>
436-
<span>{pagination.limit}</span>
437-
<LuChevronDown className="chevron-down"/>
438-
{/* Drop down menu for selection of page size */}
439-
{showPageSizes && (
440-
<ul className="dropdown-ul">
441-
{sizeOptions.map((size, key) => (
442-
<li key={key}>
443-
<ButtonLikeAnchor
444-
onClick={() => changePageSize(size)}
445-
>
446-
{size}
447-
</ButtonLikeAnchor>
448-
</li>
449-
))}
450-
</ul>
451-
)}
452-
</div>
425+
<Select
426+
options={sizeOptions}
427+
value={sizeOptions.find(opt => opt.value === pagination.limit)}
428+
onChange={(option: {value: number, label: string}) => {
429+
if (option) {
430+
changePageSize(option.value);
431+
}
432+
}}
433+
isSearchable={false}
434+
components={{ DropdownIndicator }}
435+
styles={pageSizeStyles}
436+
menuPlacement="top"
437+
/>
453438
);
454439
};
455440

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)