@sproutsocial/seeds-react-menu 1.12.1 → 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.
@@ -291,6 +291,7 @@ var StyledValue = styled4(Select3.Value)`
291
291
  `;
292
292
  function SingleSelect(props) {
293
293
  const { id, placeholder, includePlaceholderItem } = props;
294
+ const ariaDescribedBy = props["aria-describedby"];
294
295
  const isChildrenMode = "children" in props && props.children != null;
295
296
  const selectedItemId = props.selectedItemId;
296
297
  const defaultSelectedItemId = props.defaultSelectedItemId;
@@ -348,7 +349,7 @@ function SingleSelect(props) {
348
349
  onValueChange: handleValueChange,
349
350
  id,
350
351
  children: [
351
- /* @__PURE__ */ jsxs2(SelectTrigger, { children: [
352
+ /* @__PURE__ */ jsxs2(SelectTrigger, { "aria-describedby": ariaDescribedBy, children: [
352
353
  /* @__PURE__ */ jsx3(StyledValue, { placeholder, children: renderSelection && selectedItem ? renderSelection(selectedItem) : void 0 }),
353
354
  /* @__PURE__ */ jsx3(SelectIcon, { children: /* @__PURE__ */ jsx3(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx3(ChevronIcon, {}) }) })
354
355
  ] }),
@@ -420,6 +421,7 @@ var Placeholder = styled5.div`
420
421
  `;
421
422
  function MultiSelect(props) {
422
423
  const { id, placeholder = "Select..." } = props;
424
+ const ariaDescribedBy = props["aria-describedby"];
423
425
  const isChildrenMode = "children" in props && props.children != null;
424
426
  const data = isChildrenMode ? [] : props.data;
425
427
  const itemToString = isChildrenMode ? () => "" : props.itemToString;
@@ -476,7 +478,7 @@ function MultiSelect(props) {
476
478
  disabled: props.disabled,
477
479
  id,
478
480
  children: [
479
- /* @__PURE__ */ jsxs3(SelectTrigger, { children: [
481
+ /* @__PURE__ */ jsxs3(SelectTrigger, { "aria-describedby": ariaDescribedBy, children: [
480
482
  /* @__PURE__ */ jsx4(SelectValue, { children: () => {
481
483
  if (renderSelection) return renderSelection(selectedItems);
482
484
  if (selectedItems.length === 0)
@@ -1087,6 +1089,12 @@ function makePlaceholderSentinel(label) {
1087
1089
  function isPlaceholderSentinel(v) {
1088
1090
  return typeof v === "object" && v !== null && "__placeholder" in v;
1089
1091
  }
1092
+ function makeCreatableSentinel(label) {
1093
+ return { __creatable: true, label };
1094
+ }
1095
+ function isCreatableSentinel(v) {
1096
+ return typeof v === "object" && v !== null && "__creatable" in v;
1097
+ }
1090
1098
 
1091
1099
  // src/v3/Common/VirtualizedComboboxList.tsx
1092
1100
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -1106,7 +1114,8 @@ function VirtualizedComboboxList({
1106
1114
  itemToString,
1107
1115
  inputType,
1108
1116
  renderItem,
1109
- renderGroupHeading
1117
+ renderGroupHeading,
1118
+ renderCreatableItem
1110
1119
  }) {
1111
1120
  const filteredItems = Combobox2.useFilteredItems();
1112
1121
  const scrollElementRef = React7.useRef(null);
@@ -1224,6 +1233,17 @@ function VirtualizedComboboxList({
1224
1233
  virtualItem.key
1225
1234
  );
1226
1235
  }
1236
+ if (isCreatableSentinel(row)) {
1237
+ if (renderCreatableItem) {
1238
+ return renderCreatableItem(
1239
+ row,
1240
+ baseStyle,
1241
+ virtualItem.index,
1242
+ virtualizer.measureElement
1243
+ );
1244
+ }
1245
+ return null;
1246
+ }
1227
1247
  const item = row;
1228
1248
  return /* @__PURE__ */ jsx7(
1229
1249
  ComboboxItem_default,
@@ -1257,6 +1277,7 @@ function SingleCombobox(props) {
1257
1277
  emptyText = "No results found.",
1258
1278
  filter
1259
1279
  } = props;
1280
+ const ariaDescribedBy = props["aria-describedby"];
1260
1281
  const isChildrenMode = "children" in props && props.children != null;
1261
1282
  const data = isChildrenMode ? [] : props.data;
1262
1283
  const itemToString = isChildrenMode ? (_item) => "" : props.itemToString;
@@ -1327,7 +1348,14 @@ function SingleCombobox(props) {
1327
1348
  } : void 0,
1328
1349
  children: [
1329
1350
  /* @__PURE__ */ jsxs6(ComboboxInputGroup, { children: [
1330
- /* @__PURE__ */ jsx8(ComboboxInput, { placeholder, id }),
1351
+ /* @__PURE__ */ jsx8(
1352
+ ComboboxInput,
1353
+ {
1354
+ placeholder,
1355
+ id,
1356
+ "aria-describedby": ariaDescribedBy
1357
+ }
1358
+ ),
1331
1359
  /* @__PURE__ */ jsxs6(ComboboxActionButtons, { children: [
1332
1360
  /* @__PURE__ */ jsx8(ComboboxClear, { "aria-label": "Clear selection", children: /* @__PURE__ */ jsx8(ClearIcon, {}) }),
1333
1361
  /* @__PURE__ */ jsx8(ComboboxTrigger, { "aria-label": "Open popup", children: /* @__PURE__ */ jsx8(StyledChevron, { $isOpen: open, children: /* @__PURE__ */ jsx8(ChevronIcon, {}) }) })
@@ -1429,6 +1457,7 @@ function MultiCombobox(props) {
1429
1457
  inputValue,
1430
1458
  onInputValueChange
1431
1459
  } = props;
1460
+ const ariaDescribedBy = props["aria-describedby"];
1432
1461
  const isChildrenMode = "children" in props && props.children != null;
1433
1462
  const data = isChildrenMode ? [] : props.data;
1434
1463
  const itemToString = isChildrenMode ? (_item) => "" : props.itemToString;
@@ -1445,12 +1474,16 @@ function MultiCombobox(props) {
1445
1474
  const selectAll = Boolean(selectAllProp);
1446
1475
  const selectAllLabel = typeof selectAllProp === "string" ? selectAllProp : "Select all";
1447
1476
  const isVirtualized = isChildrenMode ? false : props.isVirtualized ?? false;
1477
+ const creatableProp = isChildrenMode ? false : props.creatable ?? false;
1478
+ const onCreateProp = isChildrenMode ? void 0 : props.onCreate;
1448
1479
  const children = isChildrenMode ? props.children : void 0;
1449
1480
  const selectedItemIds = props.selectedItemIds;
1450
1481
  const defaultSelectedItemIds = props.defaultSelectedItemIds;
1451
1482
  const onSelectedItemIdsChange = props.onSelectedItemIdsChange;
1452
1483
  const { containerRef, portalContainer } = useSeedsPortalContainer();
1453
1484
  const [open, setOpen] = React9.useState(false);
1485
+ const [internalInputValue, setInternalInputValue] = React9.useState("");
1486
+ const skipNextInputChangeRef = React9.useRef(false);
1454
1487
  const virtualizerRef = React9.useRef(null);
1455
1488
  const isControlled = selectedItemIds !== void 0;
1456
1489
  const idsToItems = React9.useCallback(
@@ -1469,6 +1502,18 @@ function MultiCombobox(props) {
1469
1502
  () => groupBy ? groupItems(visibleData, groupBy) : null,
1470
1503
  [visibleData, groupBy]
1471
1504
  );
1505
+ const currentInputValue = inputValue ?? internalInputValue;
1506
+ const creatableSentinel = React9.useMemo(() => {
1507
+ if (!creatableProp) return null;
1508
+ const trimmed = currentInputValue.trim();
1509
+ if (!trimmed) return null;
1510
+ const lowered = trimmed.toLocaleLowerCase();
1511
+ const exactExists = data.some(
1512
+ (d) => itemToString(d).trim().toLocaleLowerCase() === lowered
1513
+ );
1514
+ if (exactExists) return null;
1515
+ return makeCreatableSentinel(trimmed);
1516
+ }, [creatableProp, currentInputValue, data, itemToString]);
1472
1517
  const flatItems = React9.useMemo(() => {
1473
1518
  if (!selectHeadings && !selectAll) return null;
1474
1519
  if (!groups && !selectAll) return null;
@@ -1490,6 +1535,18 @@ function MultiCombobox(props) {
1490
1535
  onSelectedItemIdsChange(items.map((item) => item.id));
1491
1536
  }
1492
1537
  function handleValueChange(next) {
1538
+ const creatableClicked = next.find(isCreatableSentinel);
1539
+ if (creatableClicked) {
1540
+ const newItem = onCreateProp?.(creatableClicked.label);
1541
+ const realItems2 = next.filter(
1542
+ (v) => !isGroupHeaderSentinel2(v) && !isSelectAllSentinel2(v) && !isCreatableSentinel(v)
1543
+ );
1544
+ setSelectedItems(newItem ? [...realItems2, newItem] : realItems2);
1545
+ skipNextInputChangeRef.current = true;
1546
+ setInternalInputValue("");
1547
+ onInputValueChange?.("");
1548
+ return;
1549
+ }
1493
1550
  const selectAllClicked = next.filter(isSelectAllSentinel2);
1494
1551
  const groupSentinels = next.filter(isGroupHeaderSentinel2);
1495
1552
  const realItems = next.filter(
@@ -1527,6 +1584,16 @@ function MultiCombobox(props) {
1527
1584
  setSelectedItems(updated);
1528
1585
  }
1529
1586
  function handleSimpleValueChange(newItems) {
1587
+ const creatableClicked = newItems.find(isCreatableSentinel);
1588
+ if (creatableClicked) {
1589
+ const newItem = onCreateProp?.(creatableClicked.label);
1590
+ const realItems = newItems.filter((v) => !isCreatableSentinel(v));
1591
+ setSelectedItems(newItem ? [...realItems, newItem] : realItems);
1592
+ skipNextInputChangeRef.current = true;
1593
+ setInternalInputValue("");
1594
+ onInputValueChange?.("");
1595
+ return;
1596
+ }
1530
1597
  setSelectedItems(newItems);
1531
1598
  }
1532
1599
  function removeItem(item, e) {
@@ -1562,6 +1629,9 @@ function MultiCombobox(props) {
1562
1629
  renderGroupHeading ? renderGroupHeading(row.groupName) : row.groupName
1563
1630
  ] }, `__header-${row.groupName}`);
1564
1631
  }
1632
+ if (isCreatableSentinel(row)) {
1633
+ return renderCreatableItem(row);
1634
+ }
1565
1635
  const item = row;
1566
1636
  return /* @__PURE__ */ jsx9(
1567
1637
  ComboboxItem_default,
@@ -1576,7 +1646,28 @@ function MultiCombobox(props) {
1576
1646
  item.id
1577
1647
  );
1578
1648
  }
1579
- const rootItems = flatItems ?? groups ?? (isChildrenMode ? void 0 : visibleData);
1649
+ function renderCreatableItem(sentinel, style, index, measureRef) {
1650
+ return /* @__PURE__ */ jsx9(
1651
+ ComboboxItem_default,
1652
+ {
1653
+ value: sentinel,
1654
+ itemId: "__creatable",
1655
+ label: `Create "${sentinel.label}"`,
1656
+ inputType: "none",
1657
+ renderItem: () => /* @__PURE__ */ jsxs7(Fragment6, { children: [
1658
+ /* @__PURE__ */ jsx9(Icon3, { name: "plus-outline", size: "mini" }),
1659
+ `Create "${sentinel.label}"`
1660
+ ] }),
1661
+ style,
1662
+ index,
1663
+ "data-index": index,
1664
+ ref: measureRef
1665
+ },
1666
+ "__creatable"
1667
+ );
1668
+ }
1669
+ const baseItems = flatItems ?? groups ?? (isChildrenMode ? void 0 : visibleData);
1670
+ const rootItems = creatableSentinel && Array.isArray(baseItems) ? [...baseItems, creatableSentinel] : baseItems;
1580
1671
  const hasSentinels = selectAll || selectHeadings;
1581
1672
  const rootValue = hasSentinels ? [...value] : value;
1582
1673
  return /* @__PURE__ */ jsxs7(Field, { children: [
@@ -1593,9 +1684,31 @@ function MultiCombobox(props) {
1593
1684
  if (!nextOpen && eventDetails.reason === "item-press") return;
1594
1685
  setOpen(nextOpen);
1595
1686
  },
1596
- filter,
1597
- inputValue,
1598
- onInputValueChange,
1687
+ filter: creatableProp ? (item, query) => {
1688
+ if (isCreatableSentinel(item)) return true;
1689
+ if (filter) return filter(item, query);
1690
+ if (isGroupHeaderSentinel2(item) || isSelectAllSentinel2(item))
1691
+ return true;
1692
+ const label = itemToString(item);
1693
+ return label.toLowerCase().includes(query.toLowerCase());
1694
+ } : filter,
1695
+ inputValue: creatableProp ? currentInputValue : inputValue ?? internalInputValue,
1696
+ onInputValueChange: (v, eventDetails) => {
1697
+ if (eventDetails.reason === "input-clear" && open) return;
1698
+ if (creatableProp) {
1699
+ if (skipNextInputChangeRef.current) {
1700
+ skipNextInputChangeRef.current = false;
1701
+ return;
1702
+ }
1703
+ setInternalInputValue(v);
1704
+ onInputValueChange?.(v);
1705
+ } else {
1706
+ if (inputValue === void 0) {
1707
+ setInternalInputValue(v);
1708
+ }
1709
+ onInputValueChange?.(v);
1710
+ }
1711
+ },
1599
1712
  onItemHighlighted: isVirtualized ? (item, { reason, index }) => {
1600
1713
  const virt = virtualizerRef.current;
1601
1714
  if (!item || !virt) return;
@@ -1615,15 +1728,17 @@ function MultiCombobox(props) {
1615
1728
  hasSentinels ? handleValueChange : handleSimpleValueChange
1616
1729
  ),
1617
1730
  itemToStringLabel: (item) => {
1618
- if (!item || isGroupHeaderSentinel2(item) || isSelectAllSentinel2(item))
1731
+ if (!item || isGroupHeaderSentinel2(item) || isSelectAllSentinel2(item) || isCreatableSentinel(item))
1619
1732
  return "";
1620
1733
  return itemToString(item);
1621
1734
  },
1622
1735
  isItemEqualToValue: (a, b) => {
1736
+ if (isCreatableSentinel(a) && isCreatableSentinel(b))
1737
+ return a.label === b.label;
1623
1738
  if (isGroupHeaderSentinel2(a) && isGroupHeaderSentinel2(b))
1624
1739
  return a.groupName === b.groupName;
1625
1740
  if (isSelectAllSentinel2(a) && isSelectAllSentinel2(b)) return true;
1626
- if (!isGroupHeaderSentinel2(a) && !isSelectAllSentinel2(a) && !isGroupHeaderSentinel2(b) && !isSelectAllSentinel2(b))
1741
+ if (!isGroupHeaderSentinel2(a) && !isSelectAllSentinel2(a) && !isCreatableSentinel(a) && !isGroupHeaderSentinel2(b) && !isSelectAllSentinel2(b) && !isCreatableSentinel(b))
1627
1742
  return a.id === b.id;
1628
1743
  return false;
1629
1744
  },
@@ -1656,7 +1771,8 @@ function MultiCombobox(props) {
1656
1771
  ComboboxTokenInput,
1657
1772
  {
1658
1773
  id,
1659
- placeholder: value.length > 0 ? "" : placeholder
1774
+ placeholder: value.length > 0 ? "" : placeholder,
1775
+ "aria-describedby": ariaDescribedBy
1660
1776
  }
1661
1777
  ),
1662
1778
  /* @__PURE__ */ jsxs7(ComboboxActionButtons, { children: [
@@ -1693,37 +1809,55 @@ function MultiCombobox(props) {
1693
1809
  itemToString,
1694
1810
  inputType,
1695
1811
  renderItem,
1696
- renderGroupHeading
1812
+ renderGroupHeading,
1813
+ renderCreatableItem: creatableProp ? (sentinel, style, index, measureRef) => renderCreatableItem(
1814
+ sentinel,
1815
+ style,
1816
+ index,
1817
+ measureRef
1818
+ ) : void 0
1697
1819
  }
1698
- ) : children ? children : flatItems ? (row) => renderSentinelRow(row) : groups ? (group, index) => /* @__PURE__ */ jsxs7(React9.Fragment, { children: [
1699
- /* @__PURE__ */ jsxs7(ComboboxGroup, { items: group.items, children: [
1700
- /* @__PURE__ */ jsx9(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(group.value) : group.value }),
1701
- /* @__PURE__ */ jsx9(Combobox4.Collection, { children: (item) => /* @__PURE__ */ jsx9(
1702
- ComboboxItem_default,
1703
- {
1704
- value: item,
1705
- itemId: String(item.id),
1706
- label: itemToString(item),
1707
- disabled: item.disabled,
1708
- inputType,
1709
- renderItem: renderItem ? () => renderItem(item) : () => itemToString(item)
1710
- },
1711
- item.id
1712
- ) })
1713
- ] }),
1714
- index < groups.length - 1 && /* @__PURE__ */ jsx9(ComboboxSeparator, {})
1715
- ] }, group.value) : (item) => /* @__PURE__ */ jsx9(
1716
- ComboboxItem_default,
1717
- {
1718
- value: item,
1719
- itemId: String(item.id),
1720
- label: itemToString(item),
1721
- disabled: item.disabled,
1722
- inputType,
1723
- renderItem: renderItem ? () => renderItem(item) : () => itemToString(item)
1724
- },
1725
- item.id
1726
- )
1820
+ ) : children ? children : flatItems ? (row) => renderSentinelRow(row) : groups ? (group, index) => {
1821
+ if (isCreatableSentinel(group)) {
1822
+ return renderCreatableItem(group);
1823
+ }
1824
+ const g = group;
1825
+ return /* @__PURE__ */ jsxs7(React9.Fragment, { children: [
1826
+ /* @__PURE__ */ jsxs7(ComboboxGroup, { items: g.items, children: [
1827
+ /* @__PURE__ */ jsx9(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(g.value) : g.value }),
1828
+ /* @__PURE__ */ jsx9(Combobox4.Collection, { children: (item) => /* @__PURE__ */ jsx9(
1829
+ ComboboxItem_default,
1830
+ {
1831
+ value: item,
1832
+ itemId: String(item.id),
1833
+ label: itemToString(item),
1834
+ disabled: item.disabled,
1835
+ inputType,
1836
+ renderItem: renderItem ? () => renderItem(item) : () => itemToString(item)
1837
+ },
1838
+ item.id
1839
+ ) })
1840
+ ] }),
1841
+ index < groups.length - 1 && /* @__PURE__ */ jsx9(ComboboxSeparator, {})
1842
+ ] }, g.value);
1843
+ } : (item) => {
1844
+ if (isCreatableSentinel(item)) {
1845
+ return renderCreatableItem(item);
1846
+ }
1847
+ const dataItem = item;
1848
+ return /* @__PURE__ */ jsx9(
1849
+ ComboboxItem_default,
1850
+ {
1851
+ value: dataItem,
1852
+ itemId: String(dataItem.id),
1853
+ label: itemToString(dataItem),
1854
+ disabled: dataItem.disabled,
1855
+ inputType,
1856
+ renderItem: renderItem ? () => renderItem(dataItem) : () => itemToString(dataItem)
1857
+ },
1858
+ dataItem.id
1859
+ );
1860
+ }
1727
1861
  }
1728
1862
  )
1729
1863
  ]
@@ -1751,6 +1885,7 @@ function SingleSearchableSelect(props) {
1751
1885
  loadingText = "Loading...",
1752
1886
  filter
1753
1887
  } = props;
1888
+ const ariaDescribedBy = props["aria-describedby"];
1754
1889
  const isChildrenMode = "children" in props && props.children != null;
1755
1890
  const data = isChildrenMode ? [] : props.data;
1756
1891
  const itemToString = isChildrenMode ? (_item) => "" : props.itemToString;
@@ -1825,7 +1960,7 @@ function SingleSearchableSelect(props) {
1825
1960
  }
1826
1961
  } : void 0,
1827
1962
  children: [
1828
- /* @__PURE__ */ jsxs8(SearchableSelectTrigger, { id, children: [
1963
+ /* @__PURE__ */ jsxs8(SearchableSelectTrigger, { id, "aria-describedby": ariaDescribedBy, children: [
1829
1964
  /* @__PURE__ */ jsx10(SearchableSelectPlaceholder, { children: /* @__PURE__ */ jsx10(Combobox5.Value, { placeholder, children: value ? renderSelection ? renderSelection(value) : itemToString(value) : placeholder }) }),
1830
1965
  /* @__PURE__ */ jsx10(SearchableSelectTriggerIcon, { children: /* @__PURE__ */ jsx10(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx10(ChevronIcon, {}) }) })
1831
1966
  ] }),
@@ -1922,8 +2057,9 @@ function SingleSearchableSelect(props) {
1922
2057
  import * as React11 from "react";
1923
2058
  import { Combobox as Combobox6 } from "@base-ui/react/combobox";
1924
2059
  import "@tanstack/react-virtual";
2060
+ import Icon4 from "@sproutsocial/seeds-react-icon";
1925
2061
  import styled7 from "styled-components";
1926
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2062
+ import { Fragment as Fragment10, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1927
2063
  var SelectionText2 = styled7.span`
1928
2064
  flex: 1;
1929
2065
  overflow: hidden;
@@ -1950,6 +2086,7 @@ function MultiSearchableSelect(props) {
1950
2086
  loadingText = "Loading...",
1951
2087
  filter
1952
2088
  } = props;
2089
+ const ariaDescribedBy = props["aria-describedby"];
1953
2090
  const isChildrenMode = "children" in props && props.children != null;
1954
2091
  const data = isChildrenMode ? [] : props.data;
1955
2092
  const itemToString = isChildrenMode ? (_item) => "" : props.itemToString;
@@ -1964,12 +2101,16 @@ function MultiSearchableSelect(props) {
1964
2101
  const selectHeadings = isChildrenMode ? false : props.selectHeadings ?? false;
1965
2102
  const selectAll = isChildrenMode ? false : props.selectAll ?? false;
1966
2103
  const isVirtualized = isChildrenMode ? false : props.isVirtualized ?? false;
2104
+ const creatableProp = isChildrenMode ? false : props.creatable ?? false;
2105
+ const onCreateProp = isChildrenMode ? void 0 : props.onCreate;
1967
2106
  const children = isChildrenMode ? props.children : void 0;
1968
2107
  const selectedItemIds = props.selectedItemIds;
1969
2108
  const defaultSelectedItemIds = props.defaultSelectedItemIds;
1970
2109
  const onSelectedItemIdsChange = props.onSelectedItemIdsChange;
1971
2110
  const { containerRef, portalContainer } = useSeedsPortalContainer();
1972
2111
  const [open, setOpen] = React11.useState(false);
2112
+ const [internalInputValue, setInternalInputValue] = React11.useState("");
2113
+ const skipNextInputChangeRef = React11.useRef(false);
1973
2114
  const virtualizerRef = React11.useRef(null);
1974
2115
  const isControlled = selectedItemIds !== void 0;
1975
2116
  const idsToItems = React11.useCallback(
@@ -1988,6 +2129,18 @@ function MultiSearchableSelect(props) {
1988
2129
  () => groupBy ? groupItems(visibleData, groupBy) : null,
1989
2130
  [visibleData, groupBy]
1990
2131
  );
2132
+ const currentInputValue = internalInputValue;
2133
+ const creatableSentinel = React11.useMemo(() => {
2134
+ if (!creatableProp) return null;
2135
+ const trimmed = currentInputValue.trim();
2136
+ if (!trimmed) return null;
2137
+ const lowered = trimmed.toLocaleLowerCase();
2138
+ const exactExists = data.some(
2139
+ (d) => itemToString(d).trim().toLocaleLowerCase() === lowered
2140
+ );
2141
+ if (exactExists) return null;
2142
+ return makeCreatableSentinel(trimmed);
2143
+ }, [creatableProp, currentInputValue, data, itemToString]);
1991
2144
  const flatItems = React11.useMemo(() => {
1992
2145
  if (!groups || !selectHeadings && !selectAll) return null;
1993
2146
  const rows = [];
@@ -2004,10 +2157,21 @@ function MultiSearchableSelect(props) {
2004
2157
  onSelectedItemIdsChange(items.map((item) => item.id));
2005
2158
  }
2006
2159
  function handleValueChange(next) {
2160
+ const creatableClicked = next.find(isCreatableSentinel);
2161
+ if (creatableClicked) {
2162
+ const newItem = onCreateProp?.(creatableClicked.label);
2163
+ const realItems2 = next.filter(
2164
+ (v) => !isGroupHeaderSentinel3(v) && !isSelectAllSentinel3(v) && !isCreatableSentinel(v)
2165
+ );
2166
+ setSelectedItems(newItem ? [...realItems2, newItem] : realItems2);
2167
+ skipNextInputChangeRef.current = true;
2168
+ setInternalInputValue("");
2169
+ return;
2170
+ }
2007
2171
  const selectAllClicked = next.filter(isSelectAllSentinel3);
2008
2172
  const groupSentinels = next.filter(isGroupHeaderSentinel3);
2009
2173
  const realItems = next.filter(
2010
- (v) => !isGroupHeaderSentinel3(v) && !isSelectAllSentinel3(v)
2174
+ (v) => !isGroupHeaderSentinel3(v) && !isSelectAllSentinel3(v) && !isCreatableSentinel(v)
2011
2175
  );
2012
2176
  if (selectAllClicked.length > 0) {
2013
2177
  const allSelected = data.every(
@@ -2041,6 +2205,15 @@ function MultiSearchableSelect(props) {
2041
2205
  setSelectedItems(updated);
2042
2206
  }
2043
2207
  function handleSimpleValueChange(newItems) {
2208
+ const creatableClicked = newItems.find(isCreatableSentinel);
2209
+ if (creatableClicked) {
2210
+ const newItem = onCreateProp?.(creatableClicked.label);
2211
+ const realItems = newItems.filter((v) => !isCreatableSentinel(v));
2212
+ setSelectedItems(newItem ? [...realItems, newItem] : realItems);
2213
+ skipNextInputChangeRef.current = true;
2214
+ setInternalInputValue("");
2215
+ return;
2216
+ }
2044
2217
  setSelectedItems(newItems);
2045
2218
  }
2046
2219
  function renderSentinelRow(row) {
@@ -2071,6 +2244,9 @@ function MultiSearchableSelect(props) {
2071
2244
  renderGroupHeading ? renderGroupHeading(row.groupName) : row.groupName
2072
2245
  ] }, `__header-${row.groupName}`);
2073
2246
  }
2247
+ if (isCreatableSentinel(row)) {
2248
+ return renderCreatableItem(row);
2249
+ }
2074
2250
  const item = row;
2075
2251
  return /* @__PURE__ */ jsx11(
2076
2252
  ComboboxItem_default,
@@ -2085,7 +2261,28 @@ function MultiSearchableSelect(props) {
2085
2261
  item.id
2086
2262
  );
2087
2263
  }
2088
- const rootItems = flatItems ?? groups ?? (isChildrenMode ? void 0 : visibleData);
2264
+ function renderCreatableItem(sentinel, style, index, measureRef) {
2265
+ return /* @__PURE__ */ jsx11(
2266
+ ComboboxItem_default,
2267
+ {
2268
+ value: sentinel,
2269
+ itemId: "__creatable",
2270
+ label: `Create "${sentinel.label}"`,
2271
+ inputType: "none",
2272
+ renderItem: () => /* @__PURE__ */ jsxs9(Fragment10, { children: [
2273
+ /* @__PURE__ */ jsx11(Icon4, { name: "plus-outline", size: "mini" }),
2274
+ `Create "${sentinel.label}"`
2275
+ ] }),
2276
+ style,
2277
+ index,
2278
+ "data-index": index,
2279
+ ref: measureRef
2280
+ },
2281
+ "__creatable"
2282
+ );
2283
+ }
2284
+ const baseItems = flatItems ?? groups ?? (isChildrenMode ? void 0 : visibleData);
2285
+ const rootItems = creatableSentinel && Array.isArray(baseItems) ? [...baseItems, creatableSentinel] : baseItems;
2089
2286
  const hasSentinels = selectAll || selectHeadings;
2090
2287
  const rootValue = hasSentinels ? [...value] : value;
2091
2288
  return /* @__PURE__ */ jsxs9(Field, { children: [
@@ -2096,7 +2293,23 @@ function MultiSearchableSelect(props) {
2096
2293
  multiple: true,
2097
2294
  id,
2098
2295
  virtualized: isVirtualized,
2099
- filter,
2296
+ filter: creatableProp ? (item, query) => {
2297
+ if (isCreatableSentinel(item)) return true;
2298
+ if (filter) return filter(item, query);
2299
+ if (isGroupHeaderSentinel3(item) || isSelectAllSentinel3(item))
2300
+ return true;
2301
+ const label = itemToString(item);
2302
+ return label.toLowerCase().includes(query.toLowerCase());
2303
+ } : filter,
2304
+ inputValue: internalInputValue,
2305
+ onInputValueChange: (v, eventDetails) => {
2306
+ if (eventDetails.reason === "input-clear" && open) return;
2307
+ if (skipNextInputChangeRef.current) {
2308
+ skipNextInputChangeRef.current = false;
2309
+ return;
2310
+ }
2311
+ setInternalInputValue(v);
2312
+ },
2100
2313
  open,
2101
2314
  disabled: props.disabled,
2102
2315
  onOpenChange: setOpen,
@@ -2119,34 +2332,43 @@ function MultiSearchableSelect(props) {
2119
2332
  hasSentinels ? handleValueChange : handleSimpleValueChange
2120
2333
  ),
2121
2334
  itemToStringLabel: (item) => {
2122
- if (!item || isGroupHeaderSentinel3(item) || isSelectAllSentinel3(item))
2335
+ if (!item || isGroupHeaderSentinel3(item) || isSelectAllSentinel3(item) || isCreatableSentinel(item))
2123
2336
  return "";
2124
2337
  return itemToString(item);
2125
2338
  },
2126
2339
  isItemEqualToValue: (a, b) => {
2340
+ if (isCreatableSentinel(a) && isCreatableSentinel(b))
2341
+ return a.label === b.label;
2127
2342
  if (isGroupHeaderSentinel3(a) && isGroupHeaderSentinel3(b))
2128
2343
  return a.groupName === b.groupName;
2129
2344
  if (isSelectAllSentinel3(a) && isSelectAllSentinel3(b)) return true;
2130
- if (!isGroupHeaderSentinel3(a) && !isSelectAllSentinel3(a) && !isGroupHeaderSentinel3(b) && !isSelectAllSentinel3(b))
2345
+ if (!isGroupHeaderSentinel3(a) && !isSelectAllSentinel3(a) && !isCreatableSentinel(a) && !isGroupHeaderSentinel3(b) && !isSelectAllSentinel3(b) && !isCreatableSentinel(b))
2131
2346
  return a.id === b.id;
2132
2347
  return false;
2133
2348
  },
2134
2349
  items: rootItems,
2135
2350
  children: [
2136
- /* @__PURE__ */ jsxs9(SearchableSelectTokenTrigger, { id, children: [
2137
- renderSelection ? renderSelection(value) : value.length > 0 ? (() => {
2138
- const visibleItems = maxSelections != null ? value.slice(0, maxSelections) : value;
2139
- const overflowCount = maxSelections != null && value.length > maxSelections ? value.length - maxSelections : 0;
2140
- const text = visibleItems.map(
2141
- (item) => customRenderSelections ? customRenderSelections(item) : itemToString(item)
2142
- ).join(", ");
2143
- return /* @__PURE__ */ jsxs9(SelectionText2, { children: [
2144
- text,
2145
- overflowCount > 0 ? `, +${overflowCount}` : ""
2146
- ] });
2147
- })() : /* @__PURE__ */ jsx11(SearchableSelectPlaceholder, { children: placeholder }),
2148
- /* @__PURE__ */ jsx11(SearchableSelectTriggerIcon, { style: { marginLeft: "auto" }, children: /* @__PURE__ */ jsx11(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx11(ChevronIcon, {}) }) })
2149
- ] }),
2351
+ /* @__PURE__ */ jsxs9(
2352
+ SearchableSelectTokenTrigger,
2353
+ {
2354
+ id,
2355
+ "aria-describedby": ariaDescribedBy,
2356
+ children: [
2357
+ renderSelection ? renderSelection(value) : value.length > 0 ? (() => {
2358
+ const visibleItems = maxSelections != null ? value.slice(0, maxSelections) : value;
2359
+ const overflowCount = maxSelections != null && value.length > maxSelections ? value.length - maxSelections : 0;
2360
+ const text = visibleItems.map(
2361
+ (item) => customRenderSelections ? customRenderSelections(item) : itemToString(item)
2362
+ ).join(", ");
2363
+ return /* @__PURE__ */ jsxs9(SelectionText2, { children: [
2364
+ text,
2365
+ overflowCount > 0 ? `, +${overflowCount}` : ""
2366
+ ] });
2367
+ })() : /* @__PURE__ */ jsx11(SearchableSelectPlaceholder, { children: placeholder }),
2368
+ /* @__PURE__ */ jsx11(SearchableSelectTriggerIcon, { style: { marginLeft: "auto" }, children: /* @__PURE__ */ jsx11(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx11(ChevronIcon, {}) }) })
2369
+ ]
2370
+ }
2371
+ ),
2150
2372
  /* @__PURE__ */ jsx11(Combobox6.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx11(ComboboxPositioner, { sideOffset: 4, children: /* @__PURE__ */ jsxs9(
2151
2373
  SearchableSelectPopup,
2152
2374
  {
@@ -2183,37 +2405,55 @@ function MultiSearchableSelect(props) {
2183
2405
  itemToString,
2184
2406
  inputType,
2185
2407
  renderItem,
2186
- renderGroupHeading
2408
+ renderGroupHeading,
2409
+ renderCreatableItem: creatableProp ? (sentinel, style, index, measureRef) => renderCreatableItem(
2410
+ sentinel,
2411
+ style,
2412
+ index,
2413
+ measureRef
2414
+ ) : void 0
2187
2415
  }
2188
- ) : children ? children : flatItems ? (row) => renderSentinelRow(row) : groups ? (group, index) => /* @__PURE__ */ jsxs9(React11.Fragment, { children: [
2189
- /* @__PURE__ */ jsxs9(ComboboxGroup, { items: group.items, children: [
2190
- /* @__PURE__ */ jsx11(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(group.value) : group.value }),
2191
- /* @__PURE__ */ jsx11(Combobox6.Collection, { children: (item) => /* @__PURE__ */ jsx11(
2192
- ComboboxItem_default,
2193
- {
2194
- value: item,
2195
- itemId: String(item.id),
2196
- label: itemToString(item),
2197
- disabled: item.disabled,
2198
- inputType,
2199
- renderItem: renderItem ? () => renderItem(item) : () => itemToString(item)
2200
- },
2201
- item.id
2202
- ) })
2203
- ] }),
2204
- index < groups.length - 1 && /* @__PURE__ */ jsx11(ComboboxSeparator, {})
2205
- ] }, group.value) : (item) => /* @__PURE__ */ jsx11(
2206
- ComboboxItem_default,
2207
- {
2208
- value: item,
2209
- itemId: String(item.id),
2210
- label: itemToString(item),
2211
- disabled: item.disabled,
2212
- inputType,
2213
- renderItem: renderItem ? () => renderItem(item) : () => itemToString(item)
2214
- },
2215
- item.id
2216
- )
2416
+ ) : children ? children : flatItems ? (row) => renderSentinelRow(row) : groups ? (group, index) => {
2417
+ if (isCreatableSentinel(group)) {
2418
+ return renderCreatableItem(group);
2419
+ }
2420
+ const g = group;
2421
+ return /* @__PURE__ */ jsxs9(React11.Fragment, { children: [
2422
+ /* @__PURE__ */ jsxs9(ComboboxGroup, { items: g.items, children: [
2423
+ /* @__PURE__ */ jsx11(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(g.value) : g.value }),
2424
+ /* @__PURE__ */ jsx11(Combobox6.Collection, { children: (item) => /* @__PURE__ */ jsx11(
2425
+ ComboboxItem_default,
2426
+ {
2427
+ value: item,
2428
+ itemId: String(item.id),
2429
+ label: itemToString(item),
2430
+ disabled: item.disabled,
2431
+ inputType,
2432
+ renderItem: renderItem ? () => renderItem(item) : () => itemToString(item)
2433
+ },
2434
+ item.id
2435
+ ) })
2436
+ ] }),
2437
+ index < groups.length - 1 && /* @__PURE__ */ jsx11(ComboboxSeparator, {})
2438
+ ] }, g.value);
2439
+ } : (item) => {
2440
+ if (isCreatableSentinel(item)) {
2441
+ return renderCreatableItem(item);
2442
+ }
2443
+ const dataItem = item;
2444
+ return /* @__PURE__ */ jsx11(
2445
+ ComboboxItem_default,
2446
+ {
2447
+ value: dataItem,
2448
+ itemId: String(dataItem.id),
2449
+ label: itemToString(dataItem),
2450
+ disabled: dataItem.disabled,
2451
+ inputType,
2452
+ renderItem: renderItem ? () => renderItem(dataItem) : () => itemToString(dataItem)
2453
+ },
2454
+ dataItem.id
2455
+ );
2456
+ }
2217
2457
  }
2218
2458
  )
2219
2459
  ]