Skip to content

Commit 1d61e25

Browse files
committed
refactor: extract hook from component
1 parent 9c9b216 commit 1d61e25

File tree

2 files changed

+72
-58
lines changed

2 files changed

+72
-58
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import classNames from "classnames";
2-
import { createElement, useMemo } from "react";
3-
import { useSelect, UseSelectPropGetters } from "downshift";
4-
import { useFloating, autoUpdate } from "@floating-ui/react-dom";
2+
import { createElement } from "react";
3+
import { useSelect } from "./useSelect";
54

65
interface Option {
76
value: string;
@@ -17,7 +16,7 @@ interface FilterSelectorProps {
1716

1817
export function FilterSelector(props: FilterSelectorProps): React.ReactElement {
1918
const { open, buttonProps, listboxProps, getItemProps, selectedItem, highlightedIndex, floatingStyles } =
20-
useController(props);
19+
useSelect(props);
2120

2221
return (
2322
<div className="filter-selector">
@@ -52,57 +51,3 @@ export function FilterSelector(props: FilterSelectorProps): React.ReactElement {
5251
</div>
5352
);
5453
}
55-
56-
interface ViewProps {
57-
open: boolean;
58-
buttonProps: JSX.IntrinsicElements["button"];
59-
listboxProps: JSX.IntrinsicElements["ul"];
60-
getItemProps: UseSelectPropGetters<Option>["getItemProps"];
61-
selectedItem: Option | null;
62-
highlightedIndex: number;
63-
floatingStyles: React.CSSProperties;
64-
}
65-
66-
function useController(props: FilterSelectorProps): ViewProps {
67-
const selectedItem = useMemo(
68-
() => props.options.find(item => item.value === props.value) ?? null,
69-
[props.options, props.value]
70-
);
71-
72-
const { isOpen, highlightedIndex, getToggleButtonProps, getMenuProps, getItemProps } = useSelect({
73-
items: props.options,
74-
selectedItem,
75-
itemToString,
76-
onSelectedItemChange: ({ selectedItem }) => props.onChange(selectedItem.value)
77-
});
78-
79-
const { refs, floatingStyles } = useFloating({
80-
open: isOpen,
81-
placement: "bottom-start",
82-
strategy: "fixed",
83-
whileElementsMounted: autoUpdate
84-
});
85-
86-
const listboxLabel = props.ariaLabel || "Select filter type";
87-
const buttonLabel = selectedItem?.label || listboxLabel;
88-
const buttonProps = getToggleButtonProps({
89-
"aria-label": buttonLabel,
90-
ref: refs.setReference
91-
});
92-
const listboxProps = getMenuProps({
93-
"aria-label": listboxLabel,
94-
ref: refs.setFloating
95-
});
96-
97-
return {
98-
open: isOpen,
99-
buttonProps,
100-
listboxProps,
101-
getItemProps,
102-
selectedItem,
103-
highlightedIndex,
104-
floatingStyles
105-
};
106-
}
107-
108-
const itemToString = (item: Option | null): string => (item ? item.label : "");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { UseSelectPropGetters, useSelect as useDownshiftSelect } from "downshift";
2+
import { useFloating, autoUpdate } from "@floating-ui/react-dom";
3+
import { useMemo } from "react";
4+
5+
interface Option {
6+
value: string;
7+
label: string;
8+
}
9+
10+
interface useSelectProps {
11+
ariaLabel?: string;
12+
value: string;
13+
onChange: (value: string) => void;
14+
options: Option[];
15+
}
16+
17+
interface ViewProps {
18+
open: boolean;
19+
buttonProps: JSX.IntrinsicElements["button"];
20+
listboxProps: JSX.IntrinsicElements["ul"];
21+
getItemProps: UseSelectPropGetters<Option>["getItemProps"];
22+
selectedItem: Option | null;
23+
highlightedIndex: number;
24+
floatingStyles: React.CSSProperties;
25+
}
26+
27+
export function useSelect(props: useSelectProps): ViewProps {
28+
const selectedItem = useMemo(
29+
() => props.options.find(item => item.value === props.value) ?? null,
30+
[props.options, props.value]
31+
);
32+
33+
const { isOpen, highlightedIndex, getToggleButtonProps, getMenuProps, getItemProps } = useDownshiftSelect({
34+
items: props.options,
35+
selectedItem,
36+
itemToString,
37+
onSelectedItemChange: ({ selectedItem }) => props.onChange(selectedItem.value)
38+
});
39+
40+
const { refs, floatingStyles } = useFloating({
41+
open: isOpen,
42+
placement: "bottom-start",
43+
strategy: "fixed",
44+
whileElementsMounted: autoUpdate
45+
});
46+
47+
const listboxLabel = props.ariaLabel || "Select filter type";
48+
const buttonLabel = selectedItem?.label || listboxLabel;
49+
const buttonProps = getToggleButtonProps({
50+
"aria-label": buttonLabel,
51+
ref: refs.setReference
52+
});
53+
const listboxProps = getMenuProps({
54+
"aria-label": listboxLabel,
55+
ref: refs.setFloating
56+
});
57+
58+
return {
59+
open: isOpen,
60+
buttonProps,
61+
listboxProps,
62+
getItemProps,
63+
selectedItem,
64+
highlightedIndex,
65+
floatingStyles
66+
};
67+
}
68+
69+
const itemToString = (item: Option | null): string => (item ? item.label : "");

0 commit comments

Comments
 (0)