@sproutsocial/seeds-react-menu 1.12.0 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +16 -16
- package/CHANGELOG.md +6 -0
- package/dist/esm/v3/index.js +23 -9
- package/dist/esm/v3/index.js.map +1 -1
- package/dist/v3/index.d.mts +3 -1
- package/dist/v3/index.d.ts +3 -1
- package/dist/v3/index.js +23 -9
- package/dist/v3/index.js.map +1 -1
- package/package.json +1 -1
- package/src/v3/MultiCombobox.stories.tsx +51 -1
- package/src/v3/MultiCombobox.tsx +26 -9
package/package.json
CHANGED
|
@@ -99,6 +99,7 @@ export const Controlled: Story = {
|
|
|
99
99
|
name: "Controlled",
|
|
100
100
|
render: () => {
|
|
101
101
|
const [selectedIds, setSelectedIds] = React.useState<string[]>(["book-2"]);
|
|
102
|
+
const [inputValue, setInputValue] = React.useState("");
|
|
102
103
|
const selected = books.filter((b) => selectedIds.includes(b.id));
|
|
103
104
|
return (
|
|
104
105
|
<div
|
|
@@ -119,9 +120,14 @@ export const Controlled: Story = {
|
|
|
119
120
|
placeholder="Search books..."
|
|
120
121
|
selectedItemIds={selectedIds}
|
|
121
122
|
onSelectedItemIdsChange={(ids: string[]) => setSelectedIds(ids)}
|
|
123
|
+
inputValue={inputValue}
|
|
124
|
+
onInputValueChange={setInputValue}
|
|
122
125
|
/>
|
|
123
126
|
)}
|
|
124
127
|
</FormField>
|
|
128
|
+
<div style={{ fontSize: 13 }}>
|
|
129
|
+
Input: <strong>"{inputValue}"</strong>
|
|
130
|
+
</div>
|
|
125
131
|
<div style={{ fontSize: 13 }}>
|
|
126
132
|
Selected:{" "}
|
|
127
133
|
<strong>
|
|
@@ -130,11 +136,14 @@ export const Controlled: Story = {
|
|
|
130
136
|
: "none"}
|
|
131
137
|
</strong>
|
|
132
138
|
</div>
|
|
133
|
-
<div style={{ display: "flex", gap: 8 }}>
|
|
139
|
+
<div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
|
|
134
140
|
<button onClick={() => setSelectedIds([])}>Clear all</button>
|
|
135
141
|
<button onClick={() => setSelectedIds(["book-5", "book-7"])}>
|
|
136
142
|
Select 1984 & Meditations
|
|
137
143
|
</button>
|
|
144
|
+
<button onClick={() => setInputValue("War")}>
|
|
145
|
+
Set input to "War"
|
|
146
|
+
</button>
|
|
138
147
|
</div>
|
|
139
148
|
</div>
|
|
140
149
|
);
|
|
@@ -182,6 +191,27 @@ export const SelectableHeadings: Story = {
|
|
|
182
191
|
|
|
183
192
|
export const SelectAll: Story = {
|
|
184
193
|
name: "Select all",
|
|
194
|
+
render: () => (
|
|
195
|
+
<div style={{ width: "600px" }}>
|
|
196
|
+
<FormField label="Pick books">
|
|
197
|
+
{({ id }) => (
|
|
198
|
+
<MultiCombobox
|
|
199
|
+
id={id}
|
|
200
|
+
data={books}
|
|
201
|
+
itemToString={itemToString}
|
|
202
|
+
renderItem={renderItem}
|
|
203
|
+
placeholder="Search books..."
|
|
204
|
+
selectHeadings
|
|
205
|
+
selectAll
|
|
206
|
+
/>
|
|
207
|
+
)}
|
|
208
|
+
</FormField>
|
|
209
|
+
</div>
|
|
210
|
+
),
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export const SelectAllWithGrouping: Story = {
|
|
214
|
+
name: "Select all with grouping",
|
|
185
215
|
render: () => (
|
|
186
216
|
<div style={{ width: "600px" }}>
|
|
187
217
|
<FormField label="Pick books">
|
|
@@ -202,6 +232,26 @@ export const SelectAll: Story = {
|
|
|
202
232
|
),
|
|
203
233
|
};
|
|
204
234
|
|
|
235
|
+
export const SelectAllLocalized: Story = {
|
|
236
|
+
name: "Select all (localized label)",
|
|
237
|
+
render: () => (
|
|
238
|
+
<div style={{ width: "600px" }}>
|
|
239
|
+
<FormField label="Pick books">
|
|
240
|
+
{({ id }) => (
|
|
241
|
+
<MultiCombobox
|
|
242
|
+
id={id}
|
|
243
|
+
data={books}
|
|
244
|
+
itemToString={itemToString}
|
|
245
|
+
renderItem={renderItem}
|
|
246
|
+
placeholder="Search books..."
|
|
247
|
+
selectAll="Tout sélectionner"
|
|
248
|
+
/>
|
|
249
|
+
)}
|
|
250
|
+
</FormField>
|
|
251
|
+
</div>
|
|
252
|
+
),
|
|
253
|
+
};
|
|
254
|
+
|
|
205
255
|
export const Virtualized: Story = {
|
|
206
256
|
name: "Virtualized",
|
|
207
257
|
render: () => (
|
package/src/v3/MultiCombobox.tsx
CHANGED
|
@@ -66,6 +66,8 @@ interface MultiComboboxBaseProps {
|
|
|
66
66
|
loadingText?: string;
|
|
67
67
|
disabled?: boolean;
|
|
68
68
|
filter?: ((item: unknown, query: string) => boolean) | null;
|
|
69
|
+
inputValue?: string;
|
|
70
|
+
onInputValueChange?: (value: string) => void;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
interface MultiComboboxDataProps<T extends DataWithId>
|
|
@@ -82,7 +84,7 @@ interface MultiComboboxDataProps<T extends DataWithId>
|
|
|
82
84
|
groupBy?: (item: T) => string;
|
|
83
85
|
renderGroupHeading?: (label: string) => React.ReactNode;
|
|
84
86
|
selectHeadings?: boolean;
|
|
85
|
-
selectAll?: boolean;
|
|
87
|
+
selectAll?: boolean | string;
|
|
86
88
|
isVirtualized?: boolean;
|
|
87
89
|
removeSelectedItems?: boolean;
|
|
88
90
|
maxTokens?: number;
|
|
@@ -127,6 +129,8 @@ export function MultiCombobox<T extends DataWithId>(
|
|
|
127
129
|
isLoading = false,
|
|
128
130
|
loadingText = "Loading...",
|
|
129
131
|
filter,
|
|
132
|
+
inputValue,
|
|
133
|
+
onInputValueChange,
|
|
130
134
|
} = props;
|
|
131
135
|
|
|
132
136
|
const isChildrenMode = "children" in props && props.children != null;
|
|
@@ -166,9 +170,12 @@ export function MultiCombobox<T extends DataWithId>(
|
|
|
166
170
|
const selectHeadings = isChildrenMode
|
|
167
171
|
? false
|
|
168
172
|
: (props as MultiComboboxDataProps<T>).selectHeadings ?? false;
|
|
169
|
-
const
|
|
173
|
+
const selectAllProp = isChildrenMode
|
|
170
174
|
? false
|
|
171
175
|
: (props as MultiComboboxDataProps<T>).selectAll ?? false;
|
|
176
|
+
const selectAll = Boolean(selectAllProp);
|
|
177
|
+
const selectAllLabel =
|
|
178
|
+
typeof selectAllProp === "string" ? selectAllProp : "Select all";
|
|
172
179
|
const isVirtualized = isChildrenMode
|
|
173
180
|
? false
|
|
174
181
|
: (props as MultiComboboxDataProps<T>).isVirtualized ?? false;
|
|
@@ -226,15 +233,20 @@ export function MultiCombobox<T extends DataWithId>(
|
|
|
226
233
|
type FlatRow = T | GroupHeaderSentinel | SelectAllSentinel;
|
|
227
234
|
|
|
228
235
|
const flatItems = React.useMemo<FlatRow[] | null>(() => {
|
|
229
|
-
if (!
|
|
236
|
+
if (!selectHeadings && !selectAll) return null;
|
|
237
|
+
if (!groups && !selectAll) return null;
|
|
230
238
|
const rows: FlatRow[] = [];
|
|
231
239
|
if (selectAll) rows.push(SELECT_ALL_SENTINEL);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
240
|
+
if (groups) {
|
|
241
|
+
for (const group of groups) {
|
|
242
|
+
rows.push(makeGroupHeaderSentinel(group.value));
|
|
243
|
+
rows.push(...group.items);
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
rows.push(...visibleData);
|
|
235
247
|
}
|
|
236
248
|
return rows;
|
|
237
|
-
}, [groups, selectHeadings, selectAll]);
|
|
249
|
+
}, [groups, visibleData, selectHeadings, selectAll]);
|
|
238
250
|
|
|
239
251
|
function setSelectedItems(items: T[]) {
|
|
240
252
|
if (!isControlled) setInternalValue(items);
|
|
@@ -308,7 +320,7 @@ export function MultiCombobox<T extends DataWithId>(
|
|
|
308
320
|
return (
|
|
309
321
|
<ComboboxSelectAllItem key="__selectAll" value={row}>
|
|
310
322
|
<ComboboxGroupHeaderCheckbox $state={state} id="__selectAll" />
|
|
311
|
-
|
|
323
|
+
{selectAllLabel}
|
|
312
324
|
</ComboboxSelectAllItem>
|
|
313
325
|
);
|
|
314
326
|
}
|
|
@@ -379,8 +391,13 @@ export function MultiCombobox<T extends DataWithId>(
|
|
|
379
391
|
virtualized={isVirtualized}
|
|
380
392
|
open={open}
|
|
381
393
|
disabled={props.disabled}
|
|
382
|
-
onOpenChange={
|
|
394
|
+
onOpenChange={(nextOpen, eventDetails) => {
|
|
395
|
+
if (!nextOpen && eventDetails.reason === "item-press") return;
|
|
396
|
+
setOpen(nextOpen);
|
|
397
|
+
}}
|
|
383
398
|
filter={filter}
|
|
399
|
+
inputValue={inputValue}
|
|
400
|
+
onInputValueChange={onInputValueChange}
|
|
384
401
|
onItemHighlighted={
|
|
385
402
|
isVirtualized
|
|
386
403
|
? (item, { reason, index }) => {
|