@sproutsocial/seeds-react-menu 1.12.2 → 1.12.3
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 +10 -10
- package/CHANGELOG.md +6 -0
- package/dist/esm/v3/index.js +149 -44
- package/dist/esm/v3/index.js.map +1 -1
- package/dist/v3/index.d.mts +4 -0
- package/dist/v3/index.d.ts +4 -0
- package/dist/v3/index.js +148 -43
- package/dist/v3/index.js.map +1 -1
- package/package.json +1 -1
- package/src/v3/MultiCombobox.tsx +21 -12
- package/src/v3/MultiSearchableSelect.tsx +211 -54
package/dist/v3/index.d.mts
CHANGED
|
@@ -262,6 +262,8 @@ interface MultiSearchableSelectDataProps<T extends DataWithId> extends MultiSear
|
|
|
262
262
|
selectAll?: boolean;
|
|
263
263
|
isVirtualized?: boolean;
|
|
264
264
|
removeSelectedItems?: boolean;
|
|
265
|
+
creatable?: boolean;
|
|
266
|
+
onCreate?: (value: string) => T;
|
|
265
267
|
children?: never;
|
|
266
268
|
}
|
|
267
269
|
interface MultiSearchableSelectChildrenProps extends MultiSearchableSelectBaseProps {
|
|
@@ -282,6 +284,8 @@ interface MultiSearchableSelectChildrenProps extends MultiSearchableSelectBasePr
|
|
|
282
284
|
selectAll?: never;
|
|
283
285
|
isVirtualized?: never;
|
|
284
286
|
removeSelectedItems?: never;
|
|
287
|
+
creatable?: never;
|
|
288
|
+
onCreate?: never;
|
|
285
289
|
}
|
|
286
290
|
type MultiSearchableSelectProps<T extends DataWithId> = MultiSearchableSelectDataProps<T> | MultiSearchableSelectChildrenProps;
|
|
287
291
|
declare function MultiSearchableSelect<T extends DataWithId>(props: MultiSearchableSelectProps<T>): react_jsx_runtime.JSX.Element;
|
package/dist/v3/index.d.ts
CHANGED
|
@@ -262,6 +262,8 @@ interface MultiSearchableSelectDataProps<T extends DataWithId> extends MultiSear
|
|
|
262
262
|
selectAll?: boolean;
|
|
263
263
|
isVirtualized?: boolean;
|
|
264
264
|
removeSelectedItems?: boolean;
|
|
265
|
+
creatable?: boolean;
|
|
266
|
+
onCreate?: (value: string) => T;
|
|
265
267
|
children?: never;
|
|
266
268
|
}
|
|
267
269
|
interface MultiSearchableSelectChildrenProps extends MultiSearchableSelectBaseProps {
|
|
@@ -282,6 +284,8 @@ interface MultiSearchableSelectChildrenProps extends MultiSearchableSelectBasePr
|
|
|
282
284
|
selectAll?: never;
|
|
283
285
|
isVirtualized?: never;
|
|
284
286
|
removeSelectedItems?: never;
|
|
287
|
+
creatable?: never;
|
|
288
|
+
onCreate?: never;
|
|
285
289
|
}
|
|
286
290
|
type MultiSearchableSelectProps<T extends DataWithId> = MultiSearchableSelectDataProps<T> | MultiSearchableSelectChildrenProps;
|
|
287
291
|
declare function MultiSearchableSelect<T extends DataWithId>(props: MultiSearchableSelectProps<T>): react_jsx_runtime.JSX.Element;
|
package/dist/v3/index.js
CHANGED
|
@@ -1765,15 +1765,23 @@ function MultiCombobox(props) {
|
|
|
1765
1765
|
const label = itemToString(item);
|
|
1766
1766
|
return label.toLowerCase().includes(query.toLowerCase());
|
|
1767
1767
|
} : filter,
|
|
1768
|
-
inputValue: creatableProp ? currentInputValue : inputValue,
|
|
1769
|
-
onInputValueChange:
|
|
1770
|
-
if (
|
|
1771
|
-
|
|
1772
|
-
|
|
1768
|
+
inputValue: creatableProp ? currentInputValue : inputValue ?? internalInputValue,
|
|
1769
|
+
onInputValueChange: (v, eventDetails) => {
|
|
1770
|
+
if (eventDetails.reason === "input-clear" && open) return;
|
|
1771
|
+
if (creatableProp) {
|
|
1772
|
+
if (skipNextInputChangeRef.current) {
|
|
1773
|
+
skipNextInputChangeRef.current = false;
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
setInternalInputValue(v);
|
|
1777
|
+
onInputValueChange?.(v);
|
|
1778
|
+
} else {
|
|
1779
|
+
if (inputValue === void 0) {
|
|
1780
|
+
setInternalInputValue(v);
|
|
1781
|
+
}
|
|
1782
|
+
onInputValueChange?.(v);
|
|
1773
1783
|
}
|
|
1774
|
-
|
|
1775
|
-
onInputValueChange?.(v);
|
|
1776
|
-
} : onInputValueChange,
|
|
1784
|
+
},
|
|
1777
1785
|
onItemHighlighted: isVirtualized ? (item, { reason, index }) => {
|
|
1778
1786
|
const virt = virtualizerRef.current;
|
|
1779
1787
|
if (!item || !virt) return;
|
|
@@ -2122,6 +2130,7 @@ function SingleSearchableSelect(props) {
|
|
|
2122
2130
|
var React11 = __toESM(require("react"));
|
|
2123
2131
|
var import_combobox6 = require("@base-ui/react/combobox");
|
|
2124
2132
|
var import_react_virtual5 = require("@tanstack/react-virtual");
|
|
2133
|
+
var import_seeds_react_icon4 = __toESM(require("@sproutsocial/seeds-react-icon"));
|
|
2125
2134
|
var import_styled_components7 = __toESM(require("styled-components"));
|
|
2126
2135
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2127
2136
|
var SelectionText2 = import_styled_components7.default.span`
|
|
@@ -2165,12 +2174,16 @@ function MultiSearchableSelect(props) {
|
|
|
2165
2174
|
const selectHeadings = isChildrenMode ? false : props.selectHeadings ?? false;
|
|
2166
2175
|
const selectAll = isChildrenMode ? false : props.selectAll ?? false;
|
|
2167
2176
|
const isVirtualized = isChildrenMode ? false : props.isVirtualized ?? false;
|
|
2177
|
+
const creatableProp = isChildrenMode ? false : props.creatable ?? false;
|
|
2178
|
+
const onCreateProp = isChildrenMode ? void 0 : props.onCreate;
|
|
2168
2179
|
const children = isChildrenMode ? props.children : void 0;
|
|
2169
2180
|
const selectedItemIds = props.selectedItemIds;
|
|
2170
2181
|
const defaultSelectedItemIds = props.defaultSelectedItemIds;
|
|
2171
2182
|
const onSelectedItemIdsChange = props.onSelectedItemIdsChange;
|
|
2172
2183
|
const { containerRef, portalContainer } = useSeedsPortalContainer();
|
|
2173
2184
|
const [open, setOpen] = React11.useState(false);
|
|
2185
|
+
const [internalInputValue, setInternalInputValue] = React11.useState("");
|
|
2186
|
+
const skipNextInputChangeRef = React11.useRef(false);
|
|
2174
2187
|
const virtualizerRef = React11.useRef(null);
|
|
2175
2188
|
const isControlled = selectedItemIds !== void 0;
|
|
2176
2189
|
const idsToItems = React11.useCallback(
|
|
@@ -2189,6 +2202,18 @@ function MultiSearchableSelect(props) {
|
|
|
2189
2202
|
() => groupBy ? groupItems(visibleData, groupBy) : null,
|
|
2190
2203
|
[visibleData, groupBy]
|
|
2191
2204
|
);
|
|
2205
|
+
const currentInputValue = internalInputValue;
|
|
2206
|
+
const creatableSentinel = React11.useMemo(() => {
|
|
2207
|
+
if (!creatableProp) return null;
|
|
2208
|
+
const trimmed = currentInputValue.trim();
|
|
2209
|
+
if (!trimmed) return null;
|
|
2210
|
+
const lowered = trimmed.toLocaleLowerCase();
|
|
2211
|
+
const exactExists = data.some(
|
|
2212
|
+
(d) => itemToString(d).trim().toLocaleLowerCase() === lowered
|
|
2213
|
+
);
|
|
2214
|
+
if (exactExists) return null;
|
|
2215
|
+
return makeCreatableSentinel(trimmed);
|
|
2216
|
+
}, [creatableProp, currentInputValue, data, itemToString]);
|
|
2192
2217
|
const flatItems = React11.useMemo(() => {
|
|
2193
2218
|
if (!groups || !selectHeadings && !selectAll) return null;
|
|
2194
2219
|
const rows = [];
|
|
@@ -2205,10 +2230,21 @@ function MultiSearchableSelect(props) {
|
|
|
2205
2230
|
onSelectedItemIdsChange(items.map((item) => item.id));
|
|
2206
2231
|
}
|
|
2207
2232
|
function handleValueChange(next) {
|
|
2233
|
+
const creatableClicked = next.find(isCreatableSentinel);
|
|
2234
|
+
if (creatableClicked) {
|
|
2235
|
+
const newItem = onCreateProp?.(creatableClicked.label);
|
|
2236
|
+
const realItems2 = next.filter(
|
|
2237
|
+
(v) => !isGroupHeaderSentinel3(v) && !isSelectAllSentinel3(v) && !isCreatableSentinel(v)
|
|
2238
|
+
);
|
|
2239
|
+
setSelectedItems(newItem ? [...realItems2, newItem] : realItems2);
|
|
2240
|
+
skipNextInputChangeRef.current = true;
|
|
2241
|
+
setInternalInputValue("");
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2208
2244
|
const selectAllClicked = next.filter(isSelectAllSentinel3);
|
|
2209
2245
|
const groupSentinels = next.filter(isGroupHeaderSentinel3);
|
|
2210
2246
|
const realItems = next.filter(
|
|
2211
|
-
(v) => !isGroupHeaderSentinel3(v) && !isSelectAllSentinel3(v)
|
|
2247
|
+
(v) => !isGroupHeaderSentinel3(v) && !isSelectAllSentinel3(v) && !isCreatableSentinel(v)
|
|
2212
2248
|
);
|
|
2213
2249
|
if (selectAllClicked.length > 0) {
|
|
2214
2250
|
const allSelected = data.every(
|
|
@@ -2242,6 +2278,15 @@ function MultiSearchableSelect(props) {
|
|
|
2242
2278
|
setSelectedItems(updated);
|
|
2243
2279
|
}
|
|
2244
2280
|
function handleSimpleValueChange(newItems) {
|
|
2281
|
+
const creatableClicked = newItems.find(isCreatableSentinel);
|
|
2282
|
+
if (creatableClicked) {
|
|
2283
|
+
const newItem = onCreateProp?.(creatableClicked.label);
|
|
2284
|
+
const realItems = newItems.filter((v) => !isCreatableSentinel(v));
|
|
2285
|
+
setSelectedItems(newItem ? [...realItems, newItem] : realItems);
|
|
2286
|
+
skipNextInputChangeRef.current = true;
|
|
2287
|
+
setInternalInputValue("");
|
|
2288
|
+
return;
|
|
2289
|
+
}
|
|
2245
2290
|
setSelectedItems(newItems);
|
|
2246
2291
|
}
|
|
2247
2292
|
function renderSentinelRow(row) {
|
|
@@ -2272,6 +2317,9 @@ function MultiSearchableSelect(props) {
|
|
|
2272
2317
|
renderGroupHeading ? renderGroupHeading(row.groupName) : row.groupName
|
|
2273
2318
|
] }, `__header-${row.groupName}`);
|
|
2274
2319
|
}
|
|
2320
|
+
if (isCreatableSentinel(row)) {
|
|
2321
|
+
return renderCreatableItem(row);
|
|
2322
|
+
}
|
|
2275
2323
|
const item = row;
|
|
2276
2324
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2277
2325
|
ComboboxItem_default,
|
|
@@ -2286,7 +2334,28 @@ function MultiSearchableSelect(props) {
|
|
|
2286
2334
|
item.id
|
|
2287
2335
|
);
|
|
2288
2336
|
}
|
|
2289
|
-
|
|
2337
|
+
function renderCreatableItem(sentinel, style, index, measureRef) {
|
|
2338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2339
|
+
ComboboxItem_default,
|
|
2340
|
+
{
|
|
2341
|
+
value: sentinel,
|
|
2342
|
+
itemId: "__creatable",
|
|
2343
|
+
label: `Create "${sentinel.label}"`,
|
|
2344
|
+
inputType: "none",
|
|
2345
|
+
renderItem: () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_seeds_react_icon4.default, { name: "plus-outline", size: "mini" }),
|
|
2347
|
+
`Create "${sentinel.label}"`
|
|
2348
|
+
] }),
|
|
2349
|
+
style,
|
|
2350
|
+
index,
|
|
2351
|
+
"data-index": index,
|
|
2352
|
+
ref: measureRef
|
|
2353
|
+
},
|
|
2354
|
+
"__creatable"
|
|
2355
|
+
);
|
|
2356
|
+
}
|
|
2357
|
+
const baseItems = flatItems ?? groups ?? (isChildrenMode ? void 0 : visibleData);
|
|
2358
|
+
const rootItems = creatableSentinel && Array.isArray(baseItems) ? [...baseItems, creatableSentinel] : baseItems;
|
|
2290
2359
|
const hasSentinels = selectAll || selectHeadings;
|
|
2291
2360
|
const rootValue = hasSentinels ? [...value] : value;
|
|
2292
2361
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Field, { children: [
|
|
@@ -2297,7 +2366,23 @@ function MultiSearchableSelect(props) {
|
|
|
2297
2366
|
multiple: true,
|
|
2298
2367
|
id,
|
|
2299
2368
|
virtualized: isVirtualized,
|
|
2300
|
-
filter,
|
|
2369
|
+
filter: creatableProp ? (item, query) => {
|
|
2370
|
+
if (isCreatableSentinel(item)) return true;
|
|
2371
|
+
if (filter) return filter(item, query);
|
|
2372
|
+
if (isGroupHeaderSentinel3(item) || isSelectAllSentinel3(item))
|
|
2373
|
+
return true;
|
|
2374
|
+
const label = itemToString(item);
|
|
2375
|
+
return label.toLowerCase().includes(query.toLowerCase());
|
|
2376
|
+
} : filter,
|
|
2377
|
+
inputValue: internalInputValue,
|
|
2378
|
+
onInputValueChange: (v, eventDetails) => {
|
|
2379
|
+
if (eventDetails.reason === "input-clear" && open) return;
|
|
2380
|
+
if (skipNextInputChangeRef.current) {
|
|
2381
|
+
skipNextInputChangeRef.current = false;
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
setInternalInputValue(v);
|
|
2385
|
+
},
|
|
2301
2386
|
open,
|
|
2302
2387
|
disabled: props.disabled,
|
|
2303
2388
|
onOpenChange: setOpen,
|
|
@@ -2320,15 +2405,17 @@ function MultiSearchableSelect(props) {
|
|
|
2320
2405
|
hasSentinels ? handleValueChange : handleSimpleValueChange
|
|
2321
2406
|
),
|
|
2322
2407
|
itemToStringLabel: (item) => {
|
|
2323
|
-
if (!item || isGroupHeaderSentinel3(item) || isSelectAllSentinel3(item))
|
|
2408
|
+
if (!item || isGroupHeaderSentinel3(item) || isSelectAllSentinel3(item) || isCreatableSentinel(item))
|
|
2324
2409
|
return "";
|
|
2325
2410
|
return itemToString(item);
|
|
2326
2411
|
},
|
|
2327
2412
|
isItemEqualToValue: (a, b) => {
|
|
2413
|
+
if (isCreatableSentinel(a) && isCreatableSentinel(b))
|
|
2414
|
+
return a.label === b.label;
|
|
2328
2415
|
if (isGroupHeaderSentinel3(a) && isGroupHeaderSentinel3(b))
|
|
2329
2416
|
return a.groupName === b.groupName;
|
|
2330
2417
|
if (isSelectAllSentinel3(a) && isSelectAllSentinel3(b)) return true;
|
|
2331
|
-
if (!isGroupHeaderSentinel3(a) && !isSelectAllSentinel3(a) && !isGroupHeaderSentinel3(b) && !isSelectAllSentinel3(b))
|
|
2418
|
+
if (!isGroupHeaderSentinel3(a) && !isSelectAllSentinel3(a) && !isCreatableSentinel(a) && !isGroupHeaderSentinel3(b) && !isSelectAllSentinel3(b) && !isCreatableSentinel(b))
|
|
2332
2419
|
return a.id === b.id;
|
|
2333
2420
|
return false;
|
|
2334
2421
|
},
|
|
@@ -2391,37 +2478,55 @@ function MultiSearchableSelect(props) {
|
|
|
2391
2478
|
itemToString,
|
|
2392
2479
|
inputType,
|
|
2393
2480
|
renderItem,
|
|
2394
|
-
renderGroupHeading
|
|
2481
|
+
renderGroupHeading,
|
|
2482
|
+
renderCreatableItem: creatableProp ? (sentinel, style, index, measureRef) => renderCreatableItem(
|
|
2483
|
+
sentinel,
|
|
2484
|
+
style,
|
|
2485
|
+
index,
|
|
2486
|
+
measureRef
|
|
2487
|
+
) : void 0
|
|
2395
2488
|
}
|
|
2396
|
-
) : children ? children : flatItems ? (row) => renderSentinelRow(row) : groups ? (group, index) =>
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
}
|
|
2423
|
-
item
|
|
2424
|
-
|
|
2489
|
+
) : children ? children : flatItems ? (row) => renderSentinelRow(row) : groups ? (group, index) => {
|
|
2490
|
+
if (isCreatableSentinel(group)) {
|
|
2491
|
+
return renderCreatableItem(group);
|
|
2492
|
+
}
|
|
2493
|
+
const g = group;
|
|
2494
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(React11.Fragment, { children: [
|
|
2495
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(ComboboxGroup, { items: g.items, children: [
|
|
2496
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(g.value) : g.value }),
|
|
2497
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_combobox6.Combobox.Collection, { children: (item) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2498
|
+
ComboboxItem_default,
|
|
2499
|
+
{
|
|
2500
|
+
value: item,
|
|
2501
|
+
itemId: String(item.id),
|
|
2502
|
+
label: itemToString(item),
|
|
2503
|
+
disabled: item.disabled,
|
|
2504
|
+
inputType,
|
|
2505
|
+
renderItem: renderItem ? () => renderItem(item) : () => itemToString(item)
|
|
2506
|
+
},
|
|
2507
|
+
item.id
|
|
2508
|
+
) })
|
|
2509
|
+
] }),
|
|
2510
|
+
index < groups.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ComboboxSeparator, {})
|
|
2511
|
+
] }, g.value);
|
|
2512
|
+
} : (item) => {
|
|
2513
|
+
if (isCreatableSentinel(item)) {
|
|
2514
|
+
return renderCreatableItem(item);
|
|
2515
|
+
}
|
|
2516
|
+
const dataItem = item;
|
|
2517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2518
|
+
ComboboxItem_default,
|
|
2519
|
+
{
|
|
2520
|
+
value: dataItem,
|
|
2521
|
+
itemId: String(dataItem.id),
|
|
2522
|
+
label: itemToString(dataItem),
|
|
2523
|
+
disabled: dataItem.disabled,
|
|
2524
|
+
inputType,
|
|
2525
|
+
renderItem: renderItem ? () => renderItem(dataItem) : () => itemToString(dataItem)
|
|
2526
|
+
},
|
|
2527
|
+
dataItem.id
|
|
2528
|
+
);
|
|
2529
|
+
}
|
|
2425
2530
|
}
|
|
2426
2531
|
)
|
|
2427
2532
|
]
|