@sproutsocial/seeds-react-menu 1.13.0 → 1.16.0

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.
@@ -134,20 +134,50 @@ function groupItems(data, groupBy) {
134
134
 
135
135
  // src/v3/Common/SelectStyles.tsx
136
136
  import { Select as Select2 } from "@base-ui/react/select";
137
- import styled2 from "styled-components";
137
+ import styled3, { css } from "styled-components";
138
138
  import { focusRing } from "@sproutsocial/seeds-react-mixins";
139
- var Field = styled2.div`
139
+
140
+ // src/v3/Common/SelectIcons.tsx
141
+ import "react";
142
+ import styled2 from "styled-components";
143
+ import { Icon as Icon2 } from "@sproutsocial/seeds-react-icon";
144
+ import { jsx as jsx2 } from "react/jsx-runtime";
145
+ var StyledChevron = styled2.div`
146
+ display: flex;
147
+ align-items: center;
148
+ transition: transform 0.15s;
149
+ ${({ $isOpen }) => $isOpen && "transform: rotate(-180deg);"}
150
+ `;
151
+ function ChevronIcon() {
152
+ return /* @__PURE__ */ jsx2(Icon2, { name: "chevron-down-outline", fixedWidth: true, "aria-hidden": true });
153
+ }
154
+ function ClearIcon() {
155
+ return /* @__PURE__ */ jsx2(Icon2, { name: "circle-x-outline", fixedWidth: true, "aria-hidden": true, size: "mini" });
156
+ }
157
+ function CheckIcon2() {
158
+ return /* @__PURE__ */ jsx2(Icon2, { name: "check-outline", fixedWidth: true, "aria-hidden": true });
159
+ }
160
+
161
+ // src/v3/Common/SelectStyles.tsx
162
+ var invalidStyles = css`
163
+ border-color: ${({ theme }) => theme.colors.form.border.error};
164
+
165
+ ${StyledChevron} {
166
+ color: ${({ theme }) => theme.colors.icon.error};
167
+ }
168
+ `;
169
+ var Field = styled3.div`
140
170
  display: ${({ $fullWidth }) => $fullWidth === false ? "inline-flex" : "flex"};
141
171
  flex-direction: column;
142
172
  gap: ${({ theme }) => theme.space[200]};
143
173
  ${({ $fullWidth }) => $fullWidth !== false && "width: 100%;"}
144
174
  `;
145
- var SelectLabel = styled2(Select2.Label)`
175
+ var SelectLabel = styled3(Select2.Label)`
146
176
  font-size: ${({ theme }) => theme.typography[200].fontSize};
147
177
  font-weight: ${({ theme }) => theme.fontWeights.semibold};
148
178
  color: ${({ theme }) => theme.colors.text.body};
149
179
  `;
150
- var SelectTrigger = styled2(Select2.Trigger)`
180
+ var SelectTrigger = styled3(Select2.Trigger)`
151
181
  display: flex;
152
182
  align-items: center;
153
183
  justify-content: space-between;
@@ -182,21 +212,23 @@ var SelectTrigger = styled2(Select2.Trigger)`
182
212
  opacity: 0.4;
183
213
  cursor: not-allowed;
184
214
  }
215
+
216
+ ${({ $isInvalid }) => $isInvalid && invalidStyles}
185
217
  `;
186
- var SelectValue = styled2(Select2.Value)`
218
+ var SelectValue = styled3(Select2.Value)`
187
219
  min-width: 0;
188
220
  overflow: hidden;
189
221
  `;
190
- var SelectIcon = styled2(Select2.Icon)`
222
+ var SelectIcon = styled3(Select2.Icon)`
191
223
  display: flex;
192
224
  align-items: center;
193
225
  color: ${({ theme }) => theme.colors.icon.base};
194
226
  flex-shrink: 0;
195
227
  `;
196
- var SelectGroup = styled2(Select2.Group)`
228
+ var SelectGroup = styled3(Select2.Group)`
197
229
  display: block;
198
230
  `;
199
- var SelectGroupLabel = styled2(Select2.GroupLabel)`
231
+ var SelectGroupLabel = styled3(Select2.GroupLabel)`
200
232
  padding: ${({ theme }) => `${theme.space[300]} ${theme.space[300]} ${theme.space[200]}`};
201
233
  font-size: ${({ theme }) => theme.typography[100].fontSize};
202
234
  font-weight: ${({ theme }) => theme.fontWeights.semibold};
@@ -204,23 +236,23 @@ var SelectGroupLabel = styled2(Select2.GroupLabel)`
204
236
  letter-spacing: 0.05em;
205
237
  color: ${({ theme }) => theme.colors.text.subtext};
206
238
  `;
207
- var SelectSeparator = styled2(Select2.Separator)`
239
+ var SelectSeparator = styled3(Select2.Separator)`
208
240
  height: 1px;
209
241
  margin: ${({ theme }) => `${theme.space[200]} ${theme.space[300]}`};
210
242
  background: ${({ theme }) => theme.colors.container.border.base};
211
243
  `;
212
- var SelectPositioner = styled2(Select2.Positioner)`
244
+ var SelectPositioner = styled3(Select2.Positioner)`
213
245
  width: var(--anchor-width);
214
246
  z-index: 7;
215
247
  `;
216
- var SelectPopup = styled2(Select2.Popup)`
248
+ var SelectPopup = styled3(Select2.Popup)`
217
249
  font-family: ${({ theme }) => theme.fontFamily};
218
250
  background: ${({ theme }) => theme.colors.container.background.base};
219
251
  border: 1px solid ${({ theme }) => theme.colors.container.border.base};
220
252
  border-radius: ${({ theme }) => theme.radii[500]};
221
253
  box-shadow: ${({ theme }) => theme.shadows.low};
222
254
  outline: none;
223
- max-height: min(var(--base-ui-available-height, 400px), 400px);
255
+ max-height: min(var(--available-height, 400px), 400px);
224
256
  overflow-y: auto;
225
257
  padding: ${({ theme }) => theme.space[200]};
226
258
 
@@ -255,27 +287,6 @@ var SelectPopup = styled2(Select2.Popup)`
255
287
  }
256
288
  `;
257
289
 
258
- // src/v3/Common/SelectIcons.tsx
259
- import "react";
260
- import styled3 from "styled-components";
261
- import { Icon as Icon2 } from "@sproutsocial/seeds-react-icon";
262
- import { jsx as jsx2 } from "react/jsx-runtime";
263
- var StyledChevron = styled3.div`
264
- display: flex;
265
- align-items: center;
266
- transition: transform 0.15s;
267
- ${({ $isOpen }) => $isOpen && "transform: rotate(-180deg);"}
268
- `;
269
- function ChevronIcon() {
270
- return /* @__PURE__ */ jsx2(Icon2, { name: "chevron-down-outline", fixedWidth: true, "aria-hidden": true });
271
- }
272
- function ClearIcon() {
273
- return /* @__PURE__ */ jsx2(Icon2, { name: "circle-x-outline", fixedWidth: true, "aria-hidden": true, size: "mini" });
274
- }
275
- function CheckIcon2() {
276
- return /* @__PURE__ */ jsx2(Icon2, { name: "check-outline", fixedWidth: true, "aria-hidden": true });
277
- }
278
-
279
290
  // src/v3/SingleSelect.tsx
280
291
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
281
292
  var StyledValue = styled4(Select3.Value)`
@@ -292,6 +303,7 @@ var StyledValue = styled4(Select3.Value)`
292
303
  function SingleSelect(props) {
293
304
  const { id, placeholder, includePlaceholderItem, fullWidth = true } = props;
294
305
  const ariaDescribedBy = props["aria-describedby"];
306
+ const isInvalid = props.isInvalid;
295
307
  const isChildrenMode = "children" in props && props.children != null;
296
308
  const selectedItemId = props.selectedItemId;
297
309
  const defaultSelectedItemId = props.defaultSelectedItemId;
@@ -349,10 +361,19 @@ function SingleSelect(props) {
349
361
  onValueChange: handleValueChange,
350
362
  id,
351
363
  children: [
352
- /* @__PURE__ */ jsxs2(SelectTrigger, { "aria-describedby": ariaDescribedBy, children: [
353
- /* @__PURE__ */ jsx3(StyledValue, { placeholder, children: renderSelection && selectedItem ? renderSelection(selectedItem) : void 0 }),
354
- /* @__PURE__ */ jsx3(SelectIcon, { children: /* @__PURE__ */ jsx3(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx3(ChevronIcon, {}) }) })
355
- ] }),
364
+ /* @__PURE__ */ jsxs2(
365
+ SelectTrigger,
366
+ {
367
+ "aria-describedby": ariaDescribedBy,
368
+ "aria-invalid": isInvalid || void 0,
369
+ "aria-required": props.required || void 0,
370
+ $isInvalid: isInvalid,
371
+ children: [
372
+ /* @__PURE__ */ jsx3(StyledValue, { placeholder, children: renderSelection && selectedItem ? renderSelection(selectedItem) : void 0 }),
373
+ /* @__PURE__ */ jsx3(SelectIcon, { children: /* @__PURE__ */ jsx3(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx3(ChevronIcon, {}) }) })
374
+ ]
375
+ }
376
+ ),
356
377
  /* @__PURE__ */ jsx3(Select3.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx3(SelectPositioner, { sideOffset: 8, alignItemWithTrigger: false, children: /* @__PURE__ */ jsxs2(SelectPopup, { children: [
357
378
  /* @__PURE__ */ jsx3(Select3.ScrollUpArrow, {}),
358
379
  /* @__PURE__ */ jsx3(Select3.List, { children: children ? children : groupBy ? groupItems(data, groupBy).map((group, index, arr) => /* @__PURE__ */ jsxs2(React4.Fragment, { children: [
@@ -422,6 +443,7 @@ var Placeholder = styled5.div`
422
443
  function MultiSelect(props) {
423
444
  const { id, placeholder = "Select...", fullWidth = true } = props;
424
445
  const ariaDescribedBy = props["aria-describedby"];
446
+ const isInvalid = props.isInvalid;
425
447
  const isChildrenMode = "children" in props && props.children != null;
426
448
  const data = isChildrenMode ? [] : props.data;
427
449
  const itemToString = isChildrenMode ? () => "" : props.itemToString;
@@ -478,23 +500,32 @@ function MultiSelect(props) {
478
500
  disabled: props.disabled,
479
501
  id,
480
502
  children: [
481
- /* @__PURE__ */ jsxs3(SelectTrigger, { "aria-describedby": ariaDescribedBy, children: [
482
- /* @__PURE__ */ jsx4(SelectValue, { children: () => {
483
- if (renderSelection) return renderSelection(selectedItems);
484
- if (selectedItems.length === 0)
485
- return /* @__PURE__ */ jsx4(Placeholder, { children: placeholder });
486
- const visibleItems = maxSelections != null ? selectedItems.slice(0, maxSelections) : selectedItems;
487
- const overflowCount = maxSelections != null && selectedItems.length > maxSelections ? selectedItems.length - maxSelections : 0;
488
- const text = visibleItems.map(
489
- (item) => customRenderSelections ? customRenderSelections(item) : itemToString(item)
490
- ).join(", ");
491
- return /* @__PURE__ */ jsxs3(SelectionText, { children: [
492
- text,
493
- overflowCount > 0 ? `, +${overflowCount}` : ""
494
- ] });
495
- } }),
496
- /* @__PURE__ */ jsx4(SelectIcon, { children: /* @__PURE__ */ jsx4(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx4(ChevronIcon, {}) }) })
497
- ] }),
503
+ /* @__PURE__ */ jsxs3(
504
+ SelectTrigger,
505
+ {
506
+ "aria-describedby": ariaDescribedBy,
507
+ "aria-invalid": isInvalid || void 0,
508
+ "aria-required": props.required || void 0,
509
+ $isInvalid: isInvalid,
510
+ children: [
511
+ /* @__PURE__ */ jsx4(SelectValue, { children: () => {
512
+ if (renderSelection) return renderSelection(selectedItems);
513
+ if (selectedItems.length === 0)
514
+ return /* @__PURE__ */ jsx4(Placeholder, { children: placeholder });
515
+ const visibleItems = maxSelections != null ? selectedItems.slice(0, maxSelections) : selectedItems;
516
+ const overflowCount = maxSelections != null && selectedItems.length > maxSelections ? selectedItems.length - maxSelections : 0;
517
+ const text = visibleItems.map(
518
+ (item) => customRenderSelections ? customRenderSelections(item) : itemToString(item)
519
+ ).join(", ");
520
+ return /* @__PURE__ */ jsxs3(SelectionText, { children: [
521
+ text,
522
+ overflowCount > 0 ? `, +${overflowCount}` : ""
523
+ ] });
524
+ } }),
525
+ /* @__PURE__ */ jsx4(SelectIcon, { children: /* @__PURE__ */ jsx4(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx4(ChevronIcon, {}) }) })
526
+ ]
527
+ }
528
+ ),
498
529
  /* @__PURE__ */ jsx4(Select4.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx4(SelectPositioner, { sideOffset: 8, alignItemWithTrigger: false, children: /* @__PURE__ */ jsxs3(SelectPopup, { children: [
499
530
  /* @__PURE__ */ jsx4(Select4.ScrollUpArrow, {}),
500
531
  /* @__PURE__ */ jsx4(Select4.List, { children: children ? children : groupBy ? groupItems(data, groupBy).map((group, index, arr) => /* @__PURE__ */ jsxs3(React5.Fragment, { children: [
@@ -535,21 +566,41 @@ function MultiSelect(props) {
535
566
  }
536
567
 
537
568
  // src/v3/SingleCombobox.tsx
538
- import * as React8 from "react";
569
+ import * as React9 from "react";
539
570
  import { Combobox as Combobox3 } from "@base-ui/react/combobox";
540
571
  import "@tanstack/react-virtual";
541
572
 
542
- // src/v3/Common/ComboboxItem.tsx
573
+ // src/v3/Common/useSuppressEscapeClear.ts
543
574
  import * as React6 from "react";
575
+ function useSuppressEscapeClear(open) {
576
+ return React6.useCallback(
577
+ (event) => {
578
+ if (event.key === "Escape" && !open) {
579
+ event.stopPropagation();
580
+ }
581
+ },
582
+ [open]
583
+ );
584
+ }
585
+
586
+ // src/v3/Common/ComboboxItem.tsx
587
+ import * as React7 from "react";
544
588
  import Radio2 from "@sproutsocial/seeds-react-radio";
545
589
  import Checkbox3 from "@sproutsocial/seeds-react-checkbox";
546
590
 
547
591
  // src/v3/Common/ComboboxStyles.tsx
548
592
  import { Combobox } from "@base-ui/react/combobox";
549
- import styled6 from "styled-components";
593
+ import styled6, { css as css2 } from "styled-components";
550
594
  import { focusRing as focusRing2 } from "@sproutsocial/seeds-react-mixins";
551
595
  import Checkbox2 from "@sproutsocial/seeds-react-checkbox";
552
596
  import { jsx as jsx5 } from "react/jsx-runtime";
597
+ var invalidStyles2 = css2`
598
+ border-color: ${({ theme }) => theme.colors.form.border.error};
599
+
600
+ ${StyledChevron} {
601
+ color: ${({ theme }) => theme.colors.icon.error};
602
+ }
603
+ `;
553
604
  var ComboboxLabel = styled6.label`
554
605
  font-size: ${({ theme }) => theme.typography[200].fontSize};
555
606
  font-weight: ${({ theme }) => theme.fontWeights.semibold};
@@ -576,6 +627,8 @@ var ComboboxInputGroup = styled6(Combobox.InputGroup)`
576
627
  opacity: 0.4;
577
628
  cursor: not-allowed;
578
629
  }
630
+
631
+ ${({ $isInvalid }) => $isInvalid && invalidStyles2}
579
632
  `;
580
633
  var ComboboxInput = styled6(Combobox.Input)`
581
634
  flex: 1;
@@ -623,7 +676,7 @@ var ComboboxActionButtons = styled6.div`
623
676
  margin-left: auto;
624
677
  gap: ${({ theme }) => theme.space[100]};
625
678
  `;
626
- var ComboboxClear = styled6(Combobox.Clear)`
679
+ var ComboboxClear = styled6(Combobox.Clear).attrs({ tabIndex: 0 })`
627
680
  display: flex;
628
681
  align-items: center;
629
682
  justify-content: center;
@@ -640,6 +693,10 @@ var ComboboxClear = styled6(Combobox.Clear)`
640
693
  color: ${({ theme }) => theme.colors.text.body};
641
694
  }
642
695
 
696
+ &:focus-visible {
697
+ ${focusRing2}
698
+ }
699
+
643
700
  &[data-empty] {
644
701
  display: none;
645
702
  }
@@ -672,7 +729,7 @@ var ComboboxPopup = styled6(Combobox.Popup)`
672
729
  box-shadow: ${({ theme }) => theme.shadows.medium};
673
730
  outline: none;
674
731
  width: 100%;
675
- max-height: min(var(--base-ui-available-height, 400px), 400px);
732
+ max-height: min(var(--available-height, 400px), 400px);
676
733
  overflow-y: auto;
677
734
  padding: 0;
678
735
 
@@ -800,6 +857,12 @@ var ComboboxGroupHeaderItem = styled6(Combobox.Item)`
800
857
  background: ${({ theme }) => theme.colors.listItem.background.hover};
801
858
  color: ${({ theme }) => theme.colors.text.body};
802
859
  }
860
+
861
+ &[data-disabled] {
862
+ opacity: 0.4;
863
+ cursor: not-allowed;
864
+ pointer-events: none;
865
+ }
803
866
  `;
804
867
  var ComboboxSelectAllItem = styled6(Combobox.Item)`
805
868
  display: flex;
@@ -839,6 +902,7 @@ var ComboboxToken = styled6(Combobox.Chips)`
839
902
  display: flex;
840
903
  width: 100%;
841
904
  flex-wrap: wrap;
905
+ gap: ${({ theme }) => theme.space[200]};
842
906
  `;
843
907
  var ComboboxTokenInputGroup = styled6(Combobox.InputGroup)`
844
908
  display: flex;
@@ -863,6 +927,8 @@ var ComboboxTokenInputGroup = styled6(Combobox.InputGroup)`
863
927
  opacity: 0.4;
864
928
  cursor: not-allowed;
865
929
  }
930
+
931
+ ${({ $isInvalid }) => $isInvalid && invalidStyles2}
866
932
  `;
867
933
  var Token = styled6.span`
868
934
  display: inline-flex;
@@ -895,6 +961,10 @@ var TokenRemove = styled6.button`
895
961
  cursor: pointer;
896
962
  padding: 0;
897
963
  line-height: 1;
964
+
965
+ &:focus-visible {
966
+ ${focusRing2}
967
+ }
898
968
  `;
899
969
  var SearchableSelectTrigger = styled6(Combobox.Trigger)`
900
970
  display: flex;
@@ -928,6 +998,8 @@ var SearchableSelectTrigger = styled6(Combobox.Trigger)`
928
998
  opacity: 0.4;
929
999
  cursor: not-allowed;
930
1000
  }
1001
+
1002
+ ${({ $isInvalid }) => $isInvalid && invalidStyles2}
931
1003
  `;
932
1004
  var SearchableSelectTriggerIcon = styled6(Combobox.Icon)`
933
1005
  display: flex;
@@ -1010,6 +1082,8 @@ var SearchableSelectTokenTrigger = styled6(Combobox.Trigger)`
1010
1082
  opacity: 0.4;
1011
1083
  cursor: not-allowed;
1012
1084
  }
1085
+
1086
+ ${({ $isInvalid }) => $isInvalid && invalidStyles2}
1013
1087
  `;
1014
1088
 
1015
1089
  // src/v3/Common/ComboboxItem.tsx
@@ -1074,11 +1148,11 @@ function ComboboxItemInner({
1074
1148
  }
1075
1149
  );
1076
1150
  }
1077
- var ComboboxItem2 = React6.forwardRef(ComboboxItemInner);
1151
+ var ComboboxItem2 = React7.forwardRef(ComboboxItemInner);
1078
1152
  var ComboboxItem_default = ComboboxItem2;
1079
1153
 
1080
1154
  // src/v3/Common/VirtualizedComboboxList.tsx
1081
- import * as React7 from "react";
1155
+ import * as React8 from "react";
1082
1156
  import { Combobox as Combobox2 } from "@base-ui/react/combobox";
1083
1157
  import { useVirtualizer } from "@tanstack/react-virtual";
1084
1158
 
@@ -1115,10 +1189,11 @@ function VirtualizedComboboxList({
1115
1189
  inputType,
1116
1190
  renderItem,
1117
1191
  renderGroupHeading,
1192
+ isGroupHeaderDisabled,
1118
1193
  renderCreatableItem
1119
1194
  }) {
1120
1195
  const filteredItems = Combobox2.useFilteredItems();
1121
- const scrollElementRef = React7.useRef(null);
1196
+ const scrollElementRef = React8.useRef(null);
1122
1197
  const virtualizer = useVirtualizer({
1123
1198
  enabled: open,
1124
1199
  count: filteredItems.length,
@@ -1130,8 +1205,8 @@ function VirtualizedComboboxList({
1130
1205
  scrollPaddingStart: 4,
1131
1206
  scrollPaddingEnd: 4
1132
1207
  });
1133
- React7.useImperativeHandle(virtualizerRef, () => virtualizer);
1134
- const handleScrollRef = React7.useCallback(
1208
+ React8.useImperativeHandle(virtualizerRef, () => virtualizer);
1209
+ const handleScrollRef = React8.useCallback(
1135
1210
  (el) => {
1136
1211
  scrollElementRef.current = el;
1137
1212
  if (el) requestAnimationFrame(() => virtualizer.measure());
@@ -1217,6 +1292,7 @@ function VirtualizedComboboxList({
1217
1292
  index: virtualItem.index,
1218
1293
  "data-index": virtualItem.index,
1219
1294
  value: row,
1295
+ disabled: isGroupHeaderDisabled?.(row.groupName),
1220
1296
  style: baseStyle,
1221
1297
  ref: virtualizer.measureElement,
1222
1298
  children: [
@@ -1279,6 +1355,7 @@ function SingleCombobox(props) {
1279
1355
  fullWidth = true
1280
1356
  } = props;
1281
1357
  const ariaDescribedBy = props["aria-describedby"];
1358
+ const isInvalid = props.isInvalid;
1282
1359
  const isChildrenMode = "children" in props && props.children != null;
1283
1360
  const data = isChildrenMode ? [] : props.data;
1284
1361
  const itemToString = isChildrenMode ? (_item) => "" : props.itemToString;
@@ -1292,17 +1369,18 @@ function SingleCombobox(props) {
1292
1369
  const defaultSelectedItemId = props.defaultSelectedItemId;
1293
1370
  const onSelectedItemIdChange = props.onSelectedItemIdChange;
1294
1371
  const { containerRef, portalContainer } = useSeedsPortalContainer();
1295
- const [open, setOpen] = React8.useState(false);
1296
- const virtualizerRef = React8.useRef(null);
1372
+ const [open, setOpen] = React9.useState(false);
1373
+ const virtualizerRef = React9.useRef(null);
1374
+ const onInputKeyDownCapture = useSuppressEscapeClear(open);
1297
1375
  const isControlled = selectedItemId !== void 0;
1298
- const idToItem = React8.useCallback(
1376
+ const idToItem = React9.useCallback(
1299
1377
  (id2) => {
1300
1378
  if (id2 == null) return null;
1301
1379
  return data.find((d) => String(d.id) === String(id2)) ?? null;
1302
1380
  },
1303
1381
  [data]
1304
1382
  );
1305
- const [internalValue, setInternalValue] = React8.useState(
1383
+ const [internalValue, setInternalValue] = React9.useState(
1306
1384
  () => idToItem(defaultSelectedItemId)
1307
1385
  );
1308
1386
  const value = isControlled ? idToItem(selectedItemId) : internalValue;
@@ -1314,7 +1392,7 @@ function SingleCombobox(props) {
1314
1392
  onSelectedItemIdChange(newItem ? newItem.id : null);
1315
1393
  }
1316
1394
  }
1317
- const groups = React8.useMemo(
1395
+ const groups = React9.useMemo(
1318
1396
  () => groupBy ? groupItems(data, groupBy) : null,
1319
1397
  [data, groupBy]
1320
1398
  );
@@ -1339,29 +1417,38 @@ function SingleCombobox(props) {
1339
1417
  if (!item || !virt) return;
1340
1418
  const isStart = index === 0;
1341
1419
  const isEnd = index === virt.options.count - 1;
1342
- if (reason === "none" || reason === "keyboard" && (isStart || isEnd)) {
1420
+ if (reason === "keyboard" && (isStart || isEnd)) {
1343
1421
  queueMicrotask(() => {
1344
1422
  virt.scrollToIndex(index, {
1345
- align: isEnd ? "start" : "end"
1423
+ align: isStart ? "start" : "end"
1346
1424
  });
1347
1425
  });
1348
1426
  }
1349
1427
  } : void 0,
1350
1428
  children: [
1351
- /* @__PURE__ */ jsxs6(ComboboxInputGroup, { children: [
1352
- /* @__PURE__ */ jsx8(
1353
- ComboboxInput,
1354
- {
1355
- placeholder,
1356
- id,
1357
- "aria-describedby": ariaDescribedBy
1358
- }
1359
- ),
1360
- /* @__PURE__ */ jsxs6(ComboboxActionButtons, { children: [
1361
- /* @__PURE__ */ jsx8(ComboboxClear, { "aria-label": "Clear selection", children: /* @__PURE__ */ jsx8(ClearIcon, {}) }),
1362
- /* @__PURE__ */ jsx8(ComboboxTrigger, { "aria-label": "Open popup", children: /* @__PURE__ */ jsx8(StyledChevron, { $isOpen: open, children: /* @__PURE__ */ jsx8(ChevronIcon, {}) }) })
1363
- ] })
1364
- ] }),
1429
+ /* @__PURE__ */ jsxs6(
1430
+ ComboboxInputGroup,
1431
+ {
1432
+ $isInvalid: isInvalid,
1433
+ onKeyDownCapture: onInputKeyDownCapture,
1434
+ children: [
1435
+ /* @__PURE__ */ jsx8(
1436
+ ComboboxInput,
1437
+ {
1438
+ placeholder,
1439
+ id,
1440
+ "aria-describedby": ariaDescribedBy,
1441
+ "aria-invalid": isInvalid || void 0,
1442
+ "aria-required": props.required || void 0
1443
+ }
1444
+ ),
1445
+ /* @__PURE__ */ jsxs6(ComboboxActionButtons, { children: [
1446
+ /* @__PURE__ */ jsx8(ComboboxClear, { "aria-label": "Clear selection", children: /* @__PURE__ */ jsx8(ClearIcon, {}) }),
1447
+ /* @__PURE__ */ jsx8(ComboboxTrigger, { "aria-label": "Open popup", children: /* @__PURE__ */ jsx8(StyledChevron, { $isOpen: open, children: /* @__PURE__ */ jsx8(ChevronIcon, {}) }) })
1448
+ ] })
1449
+ ]
1450
+ }
1451
+ ),
1365
1452
  /* @__PURE__ */ jsx8(Combobox3.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx8(ComboboxPositioner, { sideOffset: 4, children: /* @__PURE__ */ jsxs6(
1366
1453
  ComboboxPopup,
1367
1454
  {
@@ -1391,7 +1478,7 @@ function SingleCombobox(props) {
1391
1478
  renderItem,
1392
1479
  renderGroupHeading
1393
1480
  }
1394
- ) : children ? children : groups ? (group, index) => /* @__PURE__ */ jsxs6(React8.Fragment, { children: [
1481
+ ) : children ? children : groups ? ((group, index) => /* @__PURE__ */ jsxs6(React9.Fragment, { children: [
1395
1482
  /* @__PURE__ */ jsxs6(ComboboxGroup, { items: group.items, children: [
1396
1483
  /* @__PURE__ */ jsx8(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(group.value) : group.value }),
1397
1484
  /* @__PURE__ */ jsx8(Combobox3.Collection, { children: (item) => /* @__PURE__ */ jsx8(
@@ -1408,7 +1495,7 @@ function SingleCombobox(props) {
1408
1495
  ) })
1409
1496
  ] }),
1410
1497
  index < groups.length - 1 && /* @__PURE__ */ jsx8(ComboboxSeparator, {})
1411
- ] }, group.value) : (item) => /* @__PURE__ */ jsx8(
1498
+ ] }, group.value)) : ((item) => /* @__PURE__ */ jsx8(
1412
1499
  ComboboxItem_default,
1413
1500
  {
1414
1501
  value: item,
@@ -1419,7 +1506,7 @@ function SingleCombobox(props) {
1419
1506
  renderItem: renderItem ? () => renderItem(item) : () => itemToString(item)
1420
1507
  },
1421
1508
  item.id
1422
- )
1509
+ ))
1423
1510
  }
1424
1511
  )
1425
1512
  ]
@@ -1432,7 +1519,7 @@ function SingleCombobox(props) {
1432
1519
  }
1433
1520
 
1434
1521
  // src/v3/MultiCombobox.tsx
1435
- import * as React9 from "react";
1522
+ import * as React10 from "react";
1436
1523
  import { Combobox as Combobox4 } from "@base-ui/react/combobox";
1437
1524
  import "@tanstack/react-virtual";
1438
1525
  import Icon3 from "@sproutsocial/seeds-react-icon";
@@ -1460,6 +1547,7 @@ function MultiCombobox(props) {
1460
1547
  fullWidth = true
1461
1548
  } = props;
1462
1549
  const ariaDescribedBy = props["aria-describedby"];
1550
+ const isInvalid = props.isInvalid;
1463
1551
  const isChildrenMode = "children" in props && props.children != null;
1464
1552
  const data = isChildrenMode ? [] : props.data;
1465
1553
  const itemToString = isChildrenMode ? (_item) => "" : props.itemToString;
@@ -1471,6 +1559,7 @@ function MultiCombobox(props) {
1471
1559
  const inputType = isChildrenMode ? "checkbox" : removeSelectedItems ? "none" : props.inputType ?? "checkbox";
1472
1560
  const groupBy = isChildrenMode ? void 0 : props.groupBy;
1473
1561
  const renderGroupHeading = isChildrenMode ? void 0 : props.renderGroupHeading;
1562
+ const isGroupHeaderDisabled = isChildrenMode ? void 0 : props.isGroupHeaderDisabled;
1474
1563
  const selectHeadings = isChildrenMode ? false : props.selectHeadings ?? false;
1475
1564
  const selectAllProp = isChildrenMode ? false : props.selectAll ?? false;
1476
1565
  const selectAll = Boolean(selectAllProp);
@@ -1483,29 +1572,31 @@ function MultiCombobox(props) {
1483
1572
  const defaultSelectedItemIds = props.defaultSelectedItemIds;
1484
1573
  const onSelectedItemIdsChange = props.onSelectedItemIdsChange;
1485
1574
  const { containerRef, portalContainer } = useSeedsPortalContainer();
1486
- const [open, setOpen] = React9.useState(false);
1487
- const [internalInputValue, setInternalInputValue] = React9.useState("");
1488
- const skipNextInputChangeRef = React9.useRef(false);
1489
- const virtualizerRef = React9.useRef(null);
1575
+ const [open, setOpen] = React10.useState(false);
1576
+ const [internalInputValue, setInternalInputValue] = React10.useState("");
1577
+ const skipNextInputChangeRef = React10.useRef(false);
1578
+ const virtualizerRef = React10.useRef(null);
1579
+ const inputRef = React10.useRef(null);
1580
+ const onInputKeyDownCapture = useSuppressEscapeClear(open);
1490
1581
  const isControlled = selectedItemIds !== void 0;
1491
- const idsToItems = React9.useCallback(
1582
+ const idsToItems = React10.useCallback(
1492
1583
  (ids) => ids.map((id2) => data.find((d) => d.id === id2)).filter((d) => d != null),
1493
1584
  [data]
1494
1585
  );
1495
- const [internalValue, setInternalValue] = React9.useState(
1586
+ const [internalValue, setInternalValue] = React10.useState(
1496
1587
  () => defaultSelectedItemIds ? idsToItems(defaultSelectedItemIds) : []
1497
1588
  );
1498
1589
  const value = isControlled ? idsToItems(selectedItemIds) : internalValue;
1499
- const visibleData = React9.useMemo(
1590
+ const visibleData = React10.useMemo(
1500
1591
  () => removeSelectedItems ? data.filter((item) => !value.some((v) => v.id === item.id)) : data,
1501
1592
  [data, value, removeSelectedItems]
1502
1593
  );
1503
- const groups = React9.useMemo(
1594
+ const groups = React10.useMemo(
1504
1595
  () => groupBy ? groupItems(visibleData, groupBy) : null,
1505
1596
  [visibleData, groupBy]
1506
1597
  );
1507
1598
  const currentInputValue = inputValue ?? internalInputValue;
1508
- const creatableSentinel = React9.useMemo(() => {
1599
+ const creatableSentinel = React10.useMemo(() => {
1509
1600
  if (!creatableProp) return null;
1510
1601
  const trimmed = currentInputValue.trim();
1511
1602
  if (!trimmed) return null;
@@ -1516,7 +1607,7 @@ function MultiCombobox(props) {
1516
1607
  if (exactExists) return null;
1517
1608
  return makeCreatableSentinel(trimmed);
1518
1609
  }, [creatableProp, currentInputValue, data, itemToString]);
1519
- const flatItems = React9.useMemo(() => {
1610
+ const flatItems = React10.useMemo(() => {
1520
1611
  if (!selectHeadings && !selectAll) return null;
1521
1612
  if (!groups && !selectAll) return null;
1522
1613
  const rows = [];
@@ -1567,6 +1658,7 @@ function MultiCombobox(props) {
1567
1658
  }
1568
1659
  let updated = [...realItems];
1569
1660
  for (const sentinel of groupSentinels) {
1661
+ if (isGroupHeaderDisabled?.(sentinel.groupName)) continue;
1570
1662
  const group = groups?.find((g) => g.value === sentinel.groupName);
1571
1663
  if (!group) continue;
1572
1664
  const allSelected = group.items.every(
@@ -1602,6 +1694,7 @@ function MultiCombobox(props) {
1602
1694
  e.preventDefault();
1603
1695
  e.stopPropagation();
1604
1696
  setSelectedItems(value.filter((v) => v.id !== item.id));
1697
+ inputRef.current?.focus();
1605
1698
  }
1606
1699
  function renderSentinelRow(row) {
1607
1700
  if (isSelectAllSentinel2(row)) {
@@ -1620,16 +1713,24 @@ function MultiCombobox(props) {
1620
1713
  (item2) => value.some((s) => s.id === item2.id)
1621
1714
  ).length;
1622
1715
  const state = selectedCount === 0 ? "none" : selectedCount === groupItemsList.length ? "all" : "partial";
1623
- return /* @__PURE__ */ jsxs7(ComboboxGroupHeaderItem, { value: row, children: [
1624
- /* @__PURE__ */ jsx9(
1625
- ComboboxGroupHeaderCheckbox,
1626
- {
1627
- $state: state,
1628
- id: `__header-${row.groupName}`
1629
- }
1630
- ),
1631
- renderGroupHeading ? renderGroupHeading(row.groupName) : row.groupName
1632
- ] }, `__header-${row.groupName}`);
1716
+ return /* @__PURE__ */ jsxs7(
1717
+ ComboboxGroupHeaderItem,
1718
+ {
1719
+ value: row,
1720
+ disabled: isGroupHeaderDisabled?.(row.groupName),
1721
+ children: [
1722
+ /* @__PURE__ */ jsx9(
1723
+ ComboboxGroupHeaderCheckbox,
1724
+ {
1725
+ $state: state,
1726
+ id: `__header-${row.groupName}`
1727
+ }
1728
+ ),
1729
+ renderGroupHeading ? renderGroupHeading(row.groupName) : row.groupName
1730
+ ]
1731
+ },
1732
+ `__header-${row.groupName}`
1733
+ );
1633
1734
  }
1634
1735
  if (isCreatableSentinel(row)) {
1635
1736
  return renderCreatableItem(row);
@@ -1683,7 +1784,10 @@ function MultiCombobox(props) {
1683
1784
  open,
1684
1785
  disabled: props.disabled,
1685
1786
  onOpenChange: (nextOpen, eventDetails) => {
1686
- if (!nextOpen && eventDetails.reason === "item-press") return;
1787
+ if (!nextOpen && eventDetails.reason === "item-press") {
1788
+ eventDetails.cancel();
1789
+ return;
1790
+ }
1687
1791
  setOpen(nextOpen);
1688
1792
  },
1689
1793
  filter: creatableProp ? (item, query) => {
@@ -1716,10 +1820,10 @@ function MultiCombobox(props) {
1716
1820
  if (!item || !virt) return;
1717
1821
  const isStart = index === 0;
1718
1822
  const isEnd = index === virt.options.count - 1;
1719
- if (reason === "none" || reason === "keyboard" && (isStart || isEnd)) {
1823
+ if (reason === "keyboard" && (isStart || isEnd)) {
1720
1824
  queueMicrotask(() => {
1721
1825
  virt.scrollToIndex(index, {
1722
- align: isEnd ? "start" : "end"
1826
+ align: isStart ? "start" : "end"
1723
1827
  });
1724
1828
  });
1725
1829
  }
@@ -1746,42 +1850,52 @@ function MultiCombobox(props) {
1746
1850
  },
1747
1851
  items: rootItems,
1748
1852
  children: [
1749
- /* @__PURE__ */ jsx9(ComboboxTokenInputGroup, { children: /* @__PURE__ */ jsxs7(ComboboxToken, { children: [
1750
- renderSelection ? renderSelection(value) : (() => {
1751
- const visibleTokens = maxTokens != null ? value.slice(0, maxTokens) : value;
1752
- const overflow = maxTokens != null ? value.length - maxTokens : 0;
1753
- return /* @__PURE__ */ jsxs7(Fragment6, { children: [
1754
- visibleTokens.map((item) => /* @__PURE__ */ jsxs7(Token, { children: [
1755
- renderToken ? renderToken(item) : itemToString(item),
1756
- /* @__PURE__ */ jsx9(
1757
- TokenRemove,
1758
- {
1759
- "aria-label": `Remove ${itemToString(item)}`,
1760
- onPointerDown: (e) => e.preventDefault(),
1761
- onClick: (e) => removeItem(item, e),
1762
- children: /* @__PURE__ */ jsx9(Icon3, { name: "x-outline", size: "mini" })
1763
- }
1764
- )
1765
- ] }, item.id)),
1766
- overflow > 0 && /* @__PURE__ */ jsxs7(Token, { children: [
1767
- "+",
1768
- overflow
1769
- ] }, "__overflow")
1770
- ] });
1771
- })(),
1772
- /* @__PURE__ */ jsx9(
1773
- ComboboxTokenInput,
1774
- {
1775
- id,
1776
- placeholder: value.length > 0 ? "" : placeholder,
1777
- "aria-describedby": ariaDescribedBy
1778
- }
1779
- ),
1780
- /* @__PURE__ */ jsxs7(ComboboxActionButtons, { children: [
1781
- /* @__PURE__ */ jsx9(ComboboxClear, { "aria-label": "Clear all", children: /* @__PURE__ */ jsx9(ClearIcon, {}) }),
1782
- /* @__PURE__ */ jsx9(ComboboxTrigger, { "aria-label": "Open popup", children: /* @__PURE__ */ jsx9(StyledChevron, { $isOpen: open, children: /* @__PURE__ */ jsx9(ChevronIcon, {}) }) })
1783
- ] })
1784
- ] }) }),
1853
+ /* @__PURE__ */ jsx9(
1854
+ ComboboxTokenInputGroup,
1855
+ {
1856
+ $isInvalid: isInvalid,
1857
+ onKeyDownCapture: onInputKeyDownCapture,
1858
+ children: /* @__PURE__ */ jsxs7(ComboboxToken, { children: [
1859
+ renderSelection ? renderSelection(value) : (() => {
1860
+ const visibleTokens = maxTokens != null ? value.slice(0, maxTokens) : value;
1861
+ const overflow = maxTokens != null ? value.length - maxTokens : 0;
1862
+ return /* @__PURE__ */ jsxs7(Fragment6, { children: [
1863
+ visibleTokens.map((item) => /* @__PURE__ */ jsxs7(Token, { children: [
1864
+ renderToken ? renderToken(item) : itemToString(item),
1865
+ /* @__PURE__ */ jsx9(
1866
+ TokenRemove,
1867
+ {
1868
+ "aria-label": `Remove ${itemToString(item)}`,
1869
+ onPointerDown: (e) => e.preventDefault(),
1870
+ onClick: (e) => removeItem(item, e),
1871
+ children: /* @__PURE__ */ jsx9(Icon3, { name: "x-outline", size: "mini" })
1872
+ }
1873
+ )
1874
+ ] }, item.id)),
1875
+ overflow > 0 && /* @__PURE__ */ jsxs7(Token, { children: [
1876
+ "+",
1877
+ overflow
1878
+ ] }, "__overflow")
1879
+ ] });
1880
+ })(),
1881
+ /* @__PURE__ */ jsx9(
1882
+ ComboboxTokenInput,
1883
+ {
1884
+ ref: inputRef,
1885
+ id,
1886
+ placeholder: value.length > 0 ? "" : placeholder,
1887
+ "aria-describedby": ariaDescribedBy,
1888
+ "aria-invalid": isInvalid || void 0,
1889
+ "aria-required": props.required || void 0
1890
+ }
1891
+ ),
1892
+ /* @__PURE__ */ jsxs7(ComboboxActionButtons, { children: [
1893
+ /* @__PURE__ */ jsx9(ComboboxClear, { "aria-label": "Clear all", children: /* @__PURE__ */ jsx9(ClearIcon, {}) }),
1894
+ /* @__PURE__ */ jsx9(ComboboxTrigger, { "aria-label": "Open popup", children: /* @__PURE__ */ jsx9(StyledChevron, { $isOpen: open, children: /* @__PURE__ */ jsx9(ChevronIcon, {}) }) })
1895
+ ] })
1896
+ ] })
1897
+ }
1898
+ ),
1785
1899
  /* @__PURE__ */ jsx9(Combobox4.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx9(ComboboxPositioner, { sideOffset: 4, children: /* @__PURE__ */ jsxs7(
1786
1900
  ComboboxPopup,
1787
1901
  {
@@ -1812,6 +1926,7 @@ function MultiCombobox(props) {
1812
1926
  inputType,
1813
1927
  renderItem,
1814
1928
  renderGroupHeading,
1929
+ isGroupHeaderDisabled,
1815
1930
  renderCreatableItem: creatableProp ? (sentinel, style, index, measureRef) => renderCreatableItem(
1816
1931
  sentinel,
1817
1932
  style,
@@ -1819,12 +1934,12 @@ function MultiCombobox(props) {
1819
1934
  measureRef
1820
1935
  ) : void 0
1821
1936
  }
1822
- ) : children ? children : flatItems ? (row) => renderSentinelRow(row) : groups ? (group, index) => {
1937
+ ) : children ? children : flatItems ? ((row) => renderSentinelRow(row)) : groups ? ((group, index) => {
1823
1938
  if (isCreatableSentinel(group)) {
1824
1939
  return renderCreatableItem(group);
1825
1940
  }
1826
1941
  const g = group;
1827
- return /* @__PURE__ */ jsxs7(React9.Fragment, { children: [
1942
+ return /* @__PURE__ */ jsxs7(React10.Fragment, { children: [
1828
1943
  /* @__PURE__ */ jsxs7(ComboboxGroup, { items: g.items, children: [
1829
1944
  /* @__PURE__ */ jsx9(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(g.value) : g.value }),
1830
1945
  /* @__PURE__ */ jsx9(Combobox4.Collection, { children: (item) => /* @__PURE__ */ jsx9(
@@ -1842,7 +1957,7 @@ function MultiCombobox(props) {
1842
1957
  ] }),
1843
1958
  index < groups.length - 1 && /* @__PURE__ */ jsx9(ComboboxSeparator, {})
1844
1959
  ] }, g.value);
1845
- } : (item) => {
1960
+ }) : ((item) => {
1846
1961
  if (isCreatableSentinel(item)) {
1847
1962
  return renderCreatableItem(item);
1848
1963
  }
@@ -1859,7 +1974,7 @@ function MultiCombobox(props) {
1859
1974
  },
1860
1975
  dataItem.id
1861
1976
  );
1862
- }
1977
+ })
1863
1978
  }
1864
1979
  )
1865
1980
  ]
@@ -1872,7 +1987,7 @@ function MultiCombobox(props) {
1872
1987
  }
1873
1988
 
1874
1989
  // src/v3/SingleSearchableSelect.tsx
1875
- import * as React10 from "react";
1990
+ import * as React11 from "react";
1876
1991
  import { Combobox as Combobox5 } from "@base-ui/react/combobox";
1877
1992
  import "@tanstack/react-virtual";
1878
1993
  import { Fragment as Fragment8, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
@@ -1889,6 +2004,7 @@ function SingleSearchableSelect(props) {
1889
2004
  fullWidth = true
1890
2005
  } = props;
1891
2006
  const ariaDescribedBy = props["aria-describedby"];
2007
+ const isInvalid = props.isInvalid;
1892
2008
  const isChildrenMode = "children" in props && props.children != null;
1893
2009
  const data = isChildrenMode ? [] : props.data;
1894
2010
  const itemToString = isChildrenMode ? (_item) => "" : props.itemToString;
@@ -1903,17 +2019,17 @@ function SingleSearchableSelect(props) {
1903
2019
  const defaultSelectedItemId = props.defaultSelectedItemId;
1904
2020
  const onSelectedItemIdChange = props.onSelectedItemIdChange;
1905
2021
  const { containerRef, portalContainer } = useSeedsPortalContainer();
1906
- const [open, setOpen] = React10.useState(false);
1907
- const virtualizerRef = React10.useRef(null);
2022
+ const [open, setOpen] = React11.useState(false);
2023
+ const virtualizerRef = React11.useRef(null);
1908
2024
  const isControlled = selectedItemId !== void 0;
1909
- const idToItem = React10.useCallback(
2025
+ const idToItem = React11.useCallback(
1910
2026
  (id2) => {
1911
2027
  if (id2 == null) return null;
1912
2028
  return data.find((d) => String(d.id) === String(id2)) ?? null;
1913
2029
  },
1914
2030
  [data]
1915
2031
  );
1916
- const [internalValue, setInternalValue] = React10.useState(
2032
+ const [internalValue, setInternalValue] = React11.useState(
1917
2033
  () => idToItem(defaultSelectedItemId)
1918
2034
  );
1919
2035
  const value = isControlled ? idToItem(selectedItemId) : internalValue;
@@ -1924,7 +2040,7 @@ function SingleSearchableSelect(props) {
1924
2040
  onSelectedItemIdChange(realItem ? realItem.id : null);
1925
2041
  }
1926
2042
  }
1927
- const groups = React10.useMemo(
2043
+ const groups = React11.useMemo(
1928
2044
  () => groupBy ? groupItems(data, groupBy) : null,
1929
2045
  [data, groupBy]
1930
2046
  );
@@ -1954,19 +2070,29 @@ function SingleSearchableSelect(props) {
1954
2070
  if (!item || !virt) return;
1955
2071
  const isStart = index === 0;
1956
2072
  const isEnd = index === virt.options.count - 1;
1957
- if (reason === "none" || reason === "keyboard" && (isStart || isEnd)) {
2073
+ if (reason === "keyboard" && (isStart || isEnd)) {
1958
2074
  queueMicrotask(() => {
1959
2075
  virt.scrollToIndex(index, {
1960
- align: isEnd ? "start" : "end"
2076
+ align: isStart ? "start" : "end"
1961
2077
  });
1962
2078
  });
1963
2079
  }
1964
2080
  } : void 0,
1965
2081
  children: [
1966
- /* @__PURE__ */ jsxs8(SearchableSelectTrigger, { id, "aria-describedby": ariaDescribedBy, children: [
1967
- /* @__PURE__ */ jsx10(SearchableSelectPlaceholder, { children: /* @__PURE__ */ jsx10(Combobox5.Value, { placeholder, children: value ? renderSelection ? renderSelection(value) : itemToString(value) : placeholder }) }),
1968
- /* @__PURE__ */ jsx10(SearchableSelectTriggerIcon, { children: /* @__PURE__ */ jsx10(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx10(ChevronIcon, {}) }) })
1969
- ] }),
2082
+ /* @__PURE__ */ jsxs8(
2083
+ SearchableSelectTrigger,
2084
+ {
2085
+ id,
2086
+ "aria-describedby": ariaDescribedBy,
2087
+ "aria-invalid": isInvalid || void 0,
2088
+ "aria-required": props.required || void 0,
2089
+ $isInvalid: isInvalid,
2090
+ children: [
2091
+ /* @__PURE__ */ jsx10(SearchableSelectPlaceholder, { children: /* @__PURE__ */ jsx10(Combobox5.Value, { placeholder, children: value ? renderSelection ? renderSelection(value) : itemToString(value) : placeholder }) }),
2092
+ /* @__PURE__ */ jsx10(SearchableSelectTriggerIcon, { children: /* @__PURE__ */ jsx10(StyledChevron, { "data-chevron": true, children: /* @__PURE__ */ jsx10(ChevronIcon, {}) }) })
2093
+ ]
2094
+ }
2095
+ ),
1970
2096
  /* @__PURE__ */ jsx10(Combobox5.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx10(ComboboxPositioner, { sideOffset: 4, children: /* @__PURE__ */ jsxs8(
1971
2097
  SearchableSelectPopup,
1972
2098
  {
@@ -2004,7 +2130,7 @@ function SingleSearchableSelect(props) {
2004
2130
  inputType,
2005
2131
  renderItem
2006
2132
  }
2007
- ) : children ? children : groups ? (group, index) => /* @__PURE__ */ jsxs8(React10.Fragment, { children: [
2133
+ ) : children ? children : groups ? ((group, index) => /* @__PURE__ */ jsxs8(React11.Fragment, { children: [
2008
2134
  /* @__PURE__ */ jsxs8(ComboboxGroup, { items: group.items, children: [
2009
2135
  /* @__PURE__ */ jsx10(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(group.value) : group.value }),
2010
2136
  /* @__PURE__ */ jsx10(Combobox5.Collection, { children: (item) => /* @__PURE__ */ jsx10(
@@ -2021,7 +2147,7 @@ function SingleSearchableSelect(props) {
2021
2147
  ) })
2022
2148
  ] }),
2023
2149
  index < groups.length - 1 && /* @__PURE__ */ jsx10(ComboboxSeparator, {})
2024
- ] }, group.value) : /* @__PURE__ */ jsxs8(Fragment8, { children: [
2150
+ ] }, group.value)) : /* @__PURE__ */ jsxs8(Fragment8, { children: [
2025
2151
  includePlaceholderItem && /* @__PURE__ */ jsx10(
2026
2152
  ComboboxItem_default,
2027
2153
  {
@@ -2057,7 +2183,7 @@ function SingleSearchableSelect(props) {
2057
2183
  }
2058
2184
 
2059
2185
  // src/v3/MultiSearchableSelect.tsx
2060
- import * as React11 from "react";
2186
+ import * as React12 from "react";
2061
2187
  import { Combobox as Combobox6 } from "@base-ui/react/combobox";
2062
2188
  import "@tanstack/react-virtual";
2063
2189
  import Icon4 from "@sproutsocial/seeds-react-icon";
@@ -2091,6 +2217,7 @@ function MultiSearchableSelect(props) {
2091
2217
  fullWidth = true
2092
2218
  } = props;
2093
2219
  const ariaDescribedBy = props["aria-describedby"];
2220
+ const isInvalid = props.isInvalid;
2094
2221
  const isChildrenMode = "children" in props && props.children != null;
2095
2222
  const data = isChildrenMode ? [] : props.data;
2096
2223
  const itemToString = isChildrenMode ? (_item) => "" : props.itemToString;
@@ -2112,29 +2239,29 @@ function MultiSearchableSelect(props) {
2112
2239
  const defaultSelectedItemIds = props.defaultSelectedItemIds;
2113
2240
  const onSelectedItemIdsChange = props.onSelectedItemIdsChange;
2114
2241
  const { containerRef, portalContainer } = useSeedsPortalContainer();
2115
- const [open, setOpen] = React11.useState(false);
2116
- const [internalInputValue, setInternalInputValue] = React11.useState("");
2117
- const skipNextInputChangeRef = React11.useRef(false);
2118
- const virtualizerRef = React11.useRef(null);
2242
+ const [open, setOpen] = React12.useState(false);
2243
+ const [internalInputValue, setInternalInputValue] = React12.useState("");
2244
+ const skipNextInputChangeRef = React12.useRef(false);
2245
+ const virtualizerRef = React12.useRef(null);
2119
2246
  const isControlled = selectedItemIds !== void 0;
2120
- const idsToItems = React11.useCallback(
2247
+ const idsToItems = React12.useCallback(
2121
2248
  (ids) => ids.map((id2) => data.find((d) => d.id === id2)).filter((d) => d != null),
2122
2249
  [data]
2123
2250
  );
2124
- const [internalValue, setInternalValue] = React11.useState(
2251
+ const [internalValue, setInternalValue] = React12.useState(
2125
2252
  () => defaultSelectedItemIds ? idsToItems(defaultSelectedItemIds) : []
2126
2253
  );
2127
2254
  const value = isControlled ? idsToItems(selectedItemIds) : internalValue;
2128
- const visibleData = React11.useMemo(
2255
+ const visibleData = React12.useMemo(
2129
2256
  () => removeSelectedItems ? data.filter((item) => !value.some((v) => v.id === item.id)) : data,
2130
2257
  [data, value, removeSelectedItems]
2131
2258
  );
2132
- const groups = React11.useMemo(
2259
+ const groups = React12.useMemo(
2133
2260
  () => groupBy ? groupItems(visibleData, groupBy) : null,
2134
2261
  [visibleData, groupBy]
2135
2262
  );
2136
2263
  const currentInputValue = internalInputValue;
2137
- const creatableSentinel = React11.useMemo(() => {
2264
+ const creatableSentinel = React12.useMemo(() => {
2138
2265
  if (!creatableProp) return null;
2139
2266
  const trimmed = currentInputValue.trim();
2140
2267
  if (!trimmed) return null;
@@ -2145,7 +2272,7 @@ function MultiSearchableSelect(props) {
2145
2272
  if (exactExists) return null;
2146
2273
  return makeCreatableSentinel(trimmed);
2147
2274
  }, [creatableProp, currentInputValue, data, itemToString]);
2148
- const flatItems = React11.useMemo(() => {
2275
+ const flatItems = React12.useMemo(() => {
2149
2276
  if (!groups || !selectHeadings && !selectAll) return null;
2150
2277
  const rows = [];
2151
2278
  if (selectAll) rows.push(SELECT_ALL_SENTINEL2);
@@ -2322,10 +2449,10 @@ function MultiSearchableSelect(props) {
2322
2449
  if (!item || !virt) return;
2323
2450
  const isStart = index === 0;
2324
2451
  const isEnd = index === virt.options.count - 1;
2325
- if (reason === "none" || reason === "keyboard" && (isStart || isEnd)) {
2452
+ if (reason === "keyboard" && (isStart || isEnd)) {
2326
2453
  queueMicrotask(() => {
2327
2454
  virt.scrollToIndex(index, {
2328
- align: isEnd ? "start" : "end"
2455
+ align: isStart ? "start" : "end"
2329
2456
  });
2330
2457
  });
2331
2458
  }
@@ -2357,6 +2484,9 @@ function MultiSearchableSelect(props) {
2357
2484
  {
2358
2485
  id,
2359
2486
  "aria-describedby": ariaDescribedBy,
2487
+ "aria-invalid": isInvalid || void 0,
2488
+ "aria-required": props.required || void 0,
2489
+ $isInvalid: isInvalid,
2360
2490
  children: [
2361
2491
  renderSelection ? renderSelection(value) : value.length > 0 ? (() => {
2362
2492
  const visibleItems = maxSelections != null ? value.slice(0, maxSelections) : value;
@@ -2417,12 +2547,12 @@ function MultiSearchableSelect(props) {
2417
2547
  measureRef
2418
2548
  ) : void 0
2419
2549
  }
2420
- ) : children ? children : flatItems ? (row) => renderSentinelRow(row) : groups ? (group, index) => {
2550
+ ) : children ? children : flatItems ? ((row) => renderSentinelRow(row)) : groups ? ((group, index) => {
2421
2551
  if (isCreatableSentinel(group)) {
2422
2552
  return renderCreatableItem(group);
2423
2553
  }
2424
2554
  const g = group;
2425
- return /* @__PURE__ */ jsxs9(React11.Fragment, { children: [
2555
+ return /* @__PURE__ */ jsxs9(React12.Fragment, { children: [
2426
2556
  /* @__PURE__ */ jsxs9(ComboboxGroup, { items: g.items, children: [
2427
2557
  /* @__PURE__ */ jsx11(ComboboxGroupLabel, { children: renderGroupHeading ? renderGroupHeading(g.value) : g.value }),
2428
2558
  /* @__PURE__ */ jsx11(Combobox6.Collection, { children: (item) => /* @__PURE__ */ jsx11(
@@ -2440,7 +2570,7 @@ function MultiSearchableSelect(props) {
2440
2570
  ] }),
2441
2571
  index < groups.length - 1 && /* @__PURE__ */ jsx11(ComboboxSeparator, {})
2442
2572
  ] }, g.value);
2443
- } : (item) => {
2573
+ }) : ((item) => {
2444
2574
  if (isCreatableSentinel(item)) {
2445
2575
  return renderCreatableItem(item);
2446
2576
  }
@@ -2457,7 +2587,7 @@ function MultiSearchableSelect(props) {
2457
2587
  },
2458
2588
  dataItem.id
2459
2589
  );
2460
- }
2590
+ })
2461
2591
  }
2462
2592
  )
2463
2593
  ]
@@ -2470,7 +2600,7 @@ function MultiSearchableSelect(props) {
2470
2600
  }
2471
2601
 
2472
2602
  // src/v3/ActionMenu.tsx
2473
- import * as React12 from "react";
2603
+ import * as React13 from "react";
2474
2604
  import { Menu as Menu2 } from "@base-ui/react/menu";
2475
2605
  import Radio3 from "@sproutsocial/seeds-react-radio";
2476
2606
  import Checkbox4 from "@sproutsocial/seeds-react-checkbox";
@@ -2478,23 +2608,25 @@ import { Icon as Icon5 } from "@sproutsocial/seeds-react-icon";
2478
2608
 
2479
2609
  // src/v3/ActionMenuStyles.tsx
2480
2610
  import { Menu } from "@base-ui/react/menu";
2481
- import styled8, { css } from "styled-components";
2611
+ import styled8, { css as css3 } from "styled-components";
2482
2612
  import "@sproutsocial/seeds-react-mixins";
2483
2613
  var ActionMenuTrigger = styled8(Menu.Trigger)``;
2484
2614
  var ActionMenuPositioner = styled8(Menu.Positioner)`
2485
2615
  min-width: var(--anchor-width);
2486
2616
  z-index: 7;
2487
2617
  `;
2488
- var ActionMenuPopup = styled8(Menu.Popup)`
2618
+ var ActionMenuPopup = styled8(Menu.Popup).attrs({
2619
+ "data-base-ui-swipe-ignore": ""
2620
+ })`
2489
2621
  font-family: ${({ theme }) => theme.fontFamily};
2490
2622
  background: ${({ theme }) => theme.colors.container.background.base};
2491
2623
  border: 1px solid ${({ theme }) => theme.colors.container.border.base};
2492
2624
  border-radius: ${({ theme }) => theme.radii[500]};
2493
2625
  box-shadow: ${({ theme }) => theme.shadows.low};
2494
2626
  outline: none;
2495
- max-height: min(var(--base-ui-available-height, 400px), 400px);
2627
+ max-height: min(var(--available-height, 400px), 400px);
2496
2628
  overflow-y: auto;
2497
- padding: ${({ theme }) => theme.space[200]};
2629
+ padding: ${({ theme }) => theme.space[300]};
2498
2630
 
2499
2631
  &[data-open] {
2500
2632
  animation: action-menu-popup-in 120ms ease-out;
@@ -2530,19 +2662,16 @@ var ActionMenuGroup = styled8(Menu.Group)`
2530
2662
  display: block;
2531
2663
  `;
2532
2664
  var ActionMenuGroupLabel = styled8(Menu.GroupLabel)`
2533
- padding: ${({ theme }) => `${theme.space[300]} ${theme.space[300]} ${theme.space[200]}`};
2665
+ padding: ${({ theme }) => `${theme.space[300]}`};
2534
2666
  font-size: ${({ theme }) => theme.typography[100].fontSize};
2535
- font-weight: ${({ theme }) => theme.fontWeights.semibold};
2536
- text-transform: uppercase;
2537
- letter-spacing: 0.05em;
2538
- color: ${({ theme }) => theme.colors.text.subtext};
2667
+ color: ${({ theme }) => theme.colors.text.body};
2539
2668
  `;
2540
2669
  var ActionMenuSeparator = styled8(Menu.Separator)`
2541
2670
  height: 1px;
2542
- margin: ${({ theme }) => `${theme.space[200]} ${theme.space[300]}`};
2671
+ margin: ${({ theme }) => `${theme.space[300]} -${theme.space[300]}`};
2543
2672
  background: ${({ theme }) => theme.colors.container.border.base};
2544
2673
  `;
2545
- var menuItemStyles = css`
2674
+ var menuItemStyles = css3`
2546
2675
  box-sizing: border-box;
2547
2676
  display: block;
2548
2677
  width: 100%;
@@ -2671,7 +2800,7 @@ function MenuRadioGroup({
2671
2800
  );
2672
2801
  }
2673
2802
  function MenuItem(props) {
2674
- const generatedId = React12.useId();
2803
+ const generatedId = React13.useId();
2675
2804
  if (props.type === "checkbox") {
2676
2805
  const {
2677
2806
  children: children2,
@@ -2812,6 +2941,81 @@ function MenuSubTrigger({
2812
2941
  }
2813
2942
  );
2814
2943
  }
2944
+
2945
+ // src/v3/MenuButton.tsx
2946
+ import "react";
2947
+ import "@sproutsocial/seeds-react-button";
2948
+ import { Icon as Icon6 } from "@sproutsocial/seeds-react-icon";
2949
+
2950
+ // src/v3/MenuButtonStyles.tsx
2951
+ import styled9 from "styled-components";
2952
+ import { Button } from "@sproutsocial/seeds-react-button";
2953
+ var MenuButtonContainer = styled9.div`
2954
+ display: inline-flex;
2955
+ gap: 1px;
2956
+ `;
2957
+ var MainButton = styled9(Button)`
2958
+ && {
2959
+ border-top-right-radius: 0;
2960
+ border-bottom-right-radius: 0;
2961
+ }
2962
+ `;
2963
+ var TriggerButton = styled9(Button)`
2964
+ && {
2965
+ border-top-left-radius: 0;
2966
+ border-bottom-left-radius: 0;
2967
+ }
2968
+
2969
+ .Icon-svg {
2970
+ transition: transform ${({ theme }) => theme.duration.fast} ease;
2971
+ }
2972
+
2973
+ &[data-popup-open] .Icon-svg {
2974
+ transform: rotate(180deg);
2975
+ }
2976
+ `;
2977
+
2978
+ // src/v3/MenuButton.tsx
2979
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2980
+ function MenuButton({
2981
+ actionMenu,
2982
+ appearance = "primary",
2983
+ size,
2984
+ disabled,
2985
+ menuButtonAriaLabel,
2986
+ children,
2987
+ ...rest
2988
+ }) {
2989
+ return /* @__PURE__ */ jsxs11(MenuButtonContainer, { children: [
2990
+ /* @__PURE__ */ jsx13(
2991
+ MainButton,
2992
+ {
2993
+ appearance,
2994
+ size,
2995
+ disabled,
2996
+ ...rest,
2997
+ children
2998
+ }
2999
+ ),
3000
+ /* @__PURE__ */ jsx13(
3001
+ ActionMenu,
3002
+ {
3003
+ disabled,
3004
+ trigger: /* @__PURE__ */ jsx13(
3005
+ TriggerButton,
3006
+ {
3007
+ appearance,
3008
+ size,
3009
+ disabled,
3010
+ ariaLabel: menuButtonAriaLabel,
3011
+ children: /* @__PURE__ */ jsx13(Icon6, { name: "chevron-down-outline", fixedWidth: true, "aria-hidden": true })
3012
+ }
3013
+ ),
3014
+ children: actionMenu
3015
+ }
3016
+ )
3017
+ ] });
3018
+ }
2815
3019
  export {
2816
3020
  ActionMenu,
2817
3021
  ComboboxActionButtons,
@@ -2836,6 +3040,7 @@ export {
2836
3040
  ComboboxTokenInput,
2837
3041
  ComboboxTokenInputGroup,
2838
3042
  ComboboxTrigger,
3043
+ MenuButton,
2839
3044
  MenuGroup,
2840
3045
  MenuItem,
2841
3046
  MenuRadioGroup,