Skip to content

Commit 42bb933

Browse files
committed
Add delimiter example to ComboBox
1 parent c334869 commit 42bb933

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

site/docs/components/combo-box/examples.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,9 @@ This functionality allows users to input information that might not be covered b
191191
Use `OverlayProps` to pass props to the overlay that is rendered when the combo box is open. For example, you can set a maximum height for the overlay.
192192

193193
<LivePreview componentName="combo-box" exampleName="OverlayProps" />
194+
195+
## Delimiter character
196+
197+
In some cases, you may want to enable users to select multiple options by typing a delimiter character. This can be by using a controlled `ComboBox` and the `onPaste` event handler.
198+
199+
<LivePreview componentName="combo-box" exampleName="Delimiter" />
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { Card, ComboBox, Option, StackLayout } from "@salt-ds/core";
2+
import {
3+
type ChangeEvent,
4+
type ReactElement,
5+
type SyntheticEvent,
6+
useState,
7+
} from "react";
8+
9+
const people = Array.from({ length: 50 }, (_, i) => ({
10+
name: `Person ${i + 1}`,
11+
email: `person${i + 1}@example.com`,
12+
}));
13+
14+
export const Delimiter = (): ReactElement => {
15+
const [value, setValue] = useState("");
16+
const [selectedValues, setSelectedValues] = useState<string[]>([]);
17+
18+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
19+
const value = event.target.value;
20+
21+
if (value.includes(";")) {
22+
const newItems = value.split(";").filter(Boolean);
23+
setSelectedValues((old) => old.concat(newItems));
24+
setValue("");
25+
return;
26+
}
27+
28+
setValue(value);
29+
};
30+
31+
const handleSelectionChange = (
32+
event: SyntheticEvent,
33+
newSelected: string[],
34+
) => {
35+
const removed = selectedValues.filter((v) => !newSelected.includes(v));
36+
setSelectedValues(newSelected);
37+
38+
if ("key" in event && event.key === "Backspace") {
39+
setValue(removed[0]);
40+
} else {
41+
setValue("");
42+
}
43+
};
44+
45+
return (
46+
<StackLayout>
47+
<Card>
48+
Example text to copy:
49+
<br />
50+
<br />
51+
52+
</Card>
53+
<ComboBox
54+
multiselect
55+
onChange={handleChange}
56+
onSelectionChange={handleSelectionChange}
57+
selected={selectedValues}
58+
value={value}
59+
style={{ width: "266px" }}
60+
onPaste={(event) => {
61+
event?.preventDefault();
62+
// This can be changed to support different delimiters
63+
const newItems = event.clipboardData
64+
.getData("Text")
65+
.trim()
66+
.split(";");
67+
setSelectedValues((old) => old.concat(newItems));
68+
}}
69+
>
70+
{people
71+
.filter(
72+
(person) =>
73+
person.name.toLowerCase().includes(value.trim().toLowerCase()) ||
74+
person.email.toLowerCase().includes(value.trim().toLowerCase()),
75+
)
76+
.map((person) => (
77+
<Option value={person.email} key={person.email}>
78+
{person.name} ({person.email})
79+
</Option>
80+
))}
81+
</ComboBox>
82+
</StackLayout>
83+
);
84+
};

site/src/examples/combo-box/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from "./ClearSelection";
33
export * from "./ComplexOptions";
44
export * from "./CustomFiltering";
55
export * from "./Default";
6+
export * from "./Delimiter";
67
export * from "./Disabled";
78
export * from "./DisabledOption";
89
export * from "./EmptyMessage";

0 commit comments

Comments
 (0)