Skip to content

Commit 540e9c4

Browse files
jnumainvillegzh2003mofojed
authored
feat: DH-19683: Multi-select combobox component (#2685)
Add multi-select combobox component. Tested with (and required for) deephaven/deephaven-plugins#1349 --------- Co-authored-by: gzh2003 <germainzhanghoule@gmail.com> Co-authored-by: Mike Bender <mikebender@deephaven.io>
1 parent 211519a commit 540e9c4

41 files changed

Lines changed: 4607 additions & 6 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/code-studio/src/styleguide/Pickers.tsx

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
Icon,
88
Item,
99
type ItemKey,
10+
type ItemSelection,
11+
MultiSelect,
1012
PICKER_ITEM_HEIGHTS,
1113
PICKER_TOP_OFFSET,
1214
Picker,
@@ -96,6 +98,28 @@ export function Pickers(): JSX.Element {
9698
setSelectedKey(key);
9799
}, []);
98100

101+
const [multiSelectedKeys, setMultiSelectedKeys] = useState<
102+
'all' | Iterable<ItemKey>
103+
>([String(items[0].key), String(items[1].key), String(items[2].key)]);
104+
105+
const onMultiSelectChange = useCallback((keys: ItemSelection): void => {
106+
setMultiSelectedKeys(keys);
107+
}, []);
108+
109+
const [filteredMultiItems, setFilteredMultiItems] = useState(itemsWithIcons);
110+
111+
const onMultiSearch = useCallback(
112+
(searchText: string) =>
113+
setFilteredMultiItems(
114+
searchText === ''
115+
? itemsWithIcons
116+
: itemsWithIcons.filter(
117+
({ item }) => item?.textValue?.includes(searchText)
118+
)
119+
),
120+
[]
121+
);
122+
99123
return (
100124
// eslint-disable-next-line react/jsx-props-no-spreading
101125
<SampleSection name="pickers">
@@ -164,11 +188,63 @@ export function Pickers(): JSX.Element {
164188
);
165189
})}
166190

191+
<Flex direction="row" gap={14}>
192+
<MultiSelect
193+
label="MultiSelect (Single Child)"
194+
tooltip={{ placement: 'bottom-end' }}
195+
>
196+
<Item textValue="Aaa">Aaa</Item>
197+
</MultiSelect>
198+
<MultiSelect
199+
label="MultiSelect (Mixed Children Types)"
200+
defaultSelectedKeys={['999']}
201+
tooltip
202+
>
203+
{mixedItemsWithIconsNoDescriptions}
204+
</MultiSelect>
205+
<MultiSelect label="MultiSelect (Sections)" tooltip>
206+
{'String 1'}
207+
{'String 2'}
208+
{'String 3'}
209+
<Section title="Section">
210+
<Item textValue="Item Aaa">Item Aaa</Item>
211+
<Item textValue="Item Bbb">Item Bbb</Item>
212+
<Item textValue="Complex Ccc">
213+
<PersonIcon />
214+
<Text>Complex Ccc</Text>
215+
</Item>
216+
</Section>
217+
<Section key="Key B">
218+
<Item textValue="Item Ddd">Item Ddd</Item>
219+
<Item textValue="Item Eee">Item Eee</Item>
220+
<Item textValue="Complex Fff">
221+
<PersonIcon />
222+
<Text>Complex Fff</Text>
223+
</Item>
224+
<Item textValue="Ggg">
225+
<PersonIcon />
226+
<Text>Label</Text>
227+
<Text slot="description">Description</Text>
228+
</Item>
229+
<Item textValue="Hhh">
230+
<PersonIcon />
231+
<Text>Label that causes overflow</Text>
232+
<Text slot="description">Description that causes overflow</Text>
233+
</Item>
234+
</Section>
235+
<Section title="Section A">{itemElementsA}</Section>
236+
<Section title="Section B">{itemElementsB}</Section>
237+
<Section key="Section C">{itemElementsC}</Section>
238+
<Section key="Section D">{itemElementsD}</Section>
239+
<Section title="Section E">{itemElementsE}</Section>
240+
</MultiSelect>
241+
</Flex>
242+
167243
<Checkbox
168244
checked={showIcons}
169245
onChange={e => setShowIcons(e.currentTarget.checked)}
170246
>
171-
Show Ions
247+
Show Icons
172248
</Checkbox>
173249

174250
<Flex direction="row" gap={14}>
@@ -191,6 +267,21 @@ export function Pickers(): JSX.Element {
191267
errorMessage="Please select an item."
192268
onInputChange={onSearch}
193269
/>
270+
<MultiSelect
271+
label="MultiSelect (Controlled)"
272+
selectedKeys={multiSelectedKeys}
273+
onChange={onMultiSelectChange}
274+
onSearchTextChange={onMultiSearch}
275+
>
276+
{filteredMultiItems.map(({ key, item }) => (
277+
<Item
278+
key={String(key)}
279+
textValue={item?.textValue ?? String(key)}
280+
>
281+
{item?.textValue ?? String(key)}
282+
</Item>
283+
))}
284+
</MultiSelect>
194285
</Flex>
195286
</Flex>
196287
</SampleSection>

packages/components/package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,20 @@
3535
"@fortawesome/react-fontawesome": "^0.2.0",
3636
"@hello-pangea/dnd": "^18.0.1",
3737
"@internationalized/date": "^3.5.5",
38+
"@react-aria/focus": "^3.21.0",
39+
"@react-aria/i18n": "^3.12.11",
40+
"@react-spectrum/label": "^3.16.17",
41+
"@react-spectrum/overlays": "^5.8.0",
3842
"@react-spectrum/theme-default": "^3.5.1",
3943
"@react-spectrum/toast": "^3.0.0-beta.16",
4044
"@react-spectrum/utils": "^3.11.5",
45+
"@react-stately/overlays": "^3.6.18",
46+
"@react-stately/utils": "^3.10.8",
4147
"@react-types/combobox": "3.13.1",
4248
"@react-types/radio": "^3.8.1",
4349
"@react-types/shared": "^3.22.1",
4450
"@react-types/textfield": "^3.9.1",
51+
"@spectrum-icons/ui": "^3.6.18",
4552
"bootstrap": "4.6.2",
4653
"classnames": "^2.3.1",
4754
"event-target-shim": "^6.0.2",

packages/components/src/spectrum/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export * from './comboBox';
2222
export * from './ListActionGroup';
2323
export * from './ListActionMenu';
2424
export * from './listView';
25+
export * from './multiSelect';
2526
export * from './picker';
2627
export * from './Heading';
2728
export * from './Text';

packages/components/src/spectrum/listView/ListView.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import { ListViewWrapper, type ListViewWrapperProps } from './ListViewWrapper';
1313
import { type ItemElementOrPrimitive } from '../shared';
1414

1515
export type ListViewProps = MultipleItemSelectionProps & {
16-
children: ItemElementOrPrimitive | ItemElementOrPrimitive[];
16+
children?:
17+
| ItemElementOrPrimitive
18+
| ItemElementOrPrimitive[]
19+
| null
20+
| undefined;
1721
/** Can be set to true or a TooltipOptions to enable item tooltips */
1822
tooltip?: boolean | TooltipOptions;
1923

0 commit comments

Comments
 (0)