@sproutsocial/seeds-react-menu 1.11.0 → 1.11.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutsocial/seeds-react-menu",
3
- "version": "1.11.0",
3
+ "version": "1.11.2",
4
4
  "description": "Seeds React Menu",
5
5
  "author": "Sprout Social, Inc.",
6
6
  "license": "MIT",
@@ -42,7 +42,7 @@
42
42
  "@sproutsocial/seeds-react-icon": "^2.3.3",
43
43
  "@sproutsocial/seeds-react-input": "^1.5.12",
44
44
  "@sproutsocial/seeds-react-label": "^1.0.16",
45
- "@sproutsocial/seeds-react-popout": "^2.4.33",
45
+ "@sproutsocial/seeds-react-popout": "^2.4.34",
46
46
  "@sproutsocial/seeds-react-radio": "^1.3.16",
47
47
  "@sproutsocial/seeds-react-switch": "^1.2.28",
48
48
  "@sproutsocial/seeds-react-system-props": "^3.0.2",
@@ -57,7 +57,7 @@
57
57
  "styled-system": "^5.1.5"
58
58
  },
59
59
  "devDependencies": {
60
- "@sproutsocial/seeds-react-tooltip": "^1.1.15",
60
+ "@sproutsocial/seeds-react-tooltip": "^1.1.16",
61
61
  "@sproutsocial/eslint-config-seeds": "*",
62
62
  "@sproutsocial/seeds-react-testing-library": "*",
63
63
  "@sproutsocial/seeds-testing": "*",
@@ -38,6 +38,7 @@ function ComboboxItemInner<T>(
38
38
  data-index={dataIndex}
39
39
  style={style}
40
40
  ref={ref}
41
+ data-qa-menu-item={label}
41
42
  >
42
43
  {inputType === "radio" ? (
43
44
  <ComboboxItemIndicator
@@ -25,6 +25,11 @@ export const ComboboxInputGroup = styled(Combobox.InputGroup)`
25
25
  &:focus-within {
26
26
  ${focusRing}
27
27
  }
28
+
29
+ &[data-disabled] {
30
+ opacity: 0.4;
31
+ cursor: not-allowed;
32
+ }
28
33
  `;
29
34
 
30
35
  export const ComboboxInput = styled(Combobox.Input)`
@@ -41,6 +46,10 @@ export const ComboboxInput = styled(Combobox.Input)`
41
46
  &::placeholder {
42
47
  color: ${({ theme }) => theme.colors.text.subtext};
43
48
  }
49
+
50
+ &:disabled {
51
+ cursor: not-allowed;
52
+ }
44
53
  `;
45
54
 
46
55
  export const ComboboxTokenInput = styled(Combobox.Input)`
@@ -58,6 +67,10 @@ export const ComboboxTokenInput = styled(Combobox.Input)`
58
67
  &::placeholder {
59
68
  color: ${({ theme }) => theme.colors.text.subtext};
60
69
  }
70
+
71
+ &:disabled {
72
+ cursor: not-allowed;
73
+ }
61
74
  `;
62
75
 
63
76
  export const ComboboxActionButtons = styled.div`
@@ -323,6 +336,11 @@ export const ComboboxTokenInputGroup = styled(Combobox.InputGroup)`
323
336
  &:focus-within {
324
337
  ${focusRing}
325
338
  }
339
+
340
+ &[data-disabled] {
341
+ opacity: 0.4;
342
+ cursor: not-allowed;
343
+ }
326
344
  `;
327
345
 
328
346
  export const Token = styled.span`
@@ -388,6 +406,11 @@ export const SearchableSelectTrigger = styled(Combobox.Trigger)`
388
406
  &[data-popup-open] [data-chevron] {
389
407
  transform: rotate(-180deg);
390
408
  }
409
+
410
+ &[data-disabled] {
411
+ opacity: 0.4;
412
+ cursor: not-allowed;
413
+ }
391
414
  `;
392
415
 
393
416
  export const SearchableSelectTriggerIcon = styled(Combobox.Icon)`
@@ -472,4 +495,9 @@ export const SearchableSelectTokenTrigger = styled(Combobox.Trigger)`
472
495
  &[data-popup-open] [data-chevron] {
473
496
  transform: rotate(-180deg);
474
497
  }
498
+
499
+ &[data-disabled] {
500
+ opacity: 0.4;
501
+ cursor: not-allowed;
502
+ }
475
503
  `;
@@ -70,7 +70,11 @@ export default function SelectItem({
70
70
  hidden,
71
71
  }: SelectItemProps) {
72
72
  return (
73
- <StyledItem value={value} style={hidden ? { display: "none" } : undefined}>
73
+ <StyledItem
74
+ value={value}
75
+ style={hidden ? { display: "none" } : undefined}
76
+ data-qa-menu-item={label}
77
+ >
74
78
  {inputType === "radio" ? (
75
79
  <StyledItemIndicator
76
80
  keepMounted
@@ -44,6 +44,11 @@ export const SelectTrigger = styled(Select.Trigger)`
44
44
  &[data-popup-open] [data-chevron] {
45
45
  transform: rotate(-180deg);
46
46
  }
47
+
48
+ &[data-disabled] {
49
+ opacity: 0.4;
50
+ cursor: not-allowed;
51
+ }
47
52
  `;
48
53
 
49
54
  export const SelectValue = styled(Select.Value)`
@@ -10,12 +10,12 @@ import {
10
10
  ModalBody,
11
11
  ModalFooter,
12
12
  } from "@sproutsocial/seeds-react-modal";
13
- import SingleSelect from "./SingleSelect";
14
- import MultiSelect from "./MultiSelect";
15
- import SingleCombobox from "./SingleCombobox";
16
- import MultiCombobox from "./MultiCombobox";
17
- import SingleSearchableSelect from "./SingleSearchableSelect";
18
- import MultiSearchableSelect from "./MultiSearchableSelect";
13
+ import { SingleSelect } from "./SingleSelect";
14
+ import { MultiSelect } from "./MultiSelect";
15
+ import { SingleCombobox } from "./SingleCombobox";
16
+ import { MultiCombobox } from "./MultiCombobox";
17
+ import { SingleSearchableSelect } from "./SingleSearchableSelect";
18
+ import { MultiSearchableSelect } from "./MultiSearchableSelect";
19
19
  import { books, itemToString } from "./storyData";
20
20
 
21
21
  // ─── Shared content ───────────────────────────────────────────────────────────
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import { FormField } from "@sproutsocial/seeds-react-form-field";
4
- import MultiCombobox from "./MultiCombobox";
4
+ import { MultiCombobox } from "./MultiCombobox";
5
5
  import { books, largeBookSet, itemToString, renderItem } from "./storyData";
6
6
 
7
7
  const meta: Meta<typeof MultiCombobox> = {
@@ -64,6 +64,7 @@ interface MultiComboboxBaseProps {
64
64
  emptyText?: string;
65
65
  isLoading?: boolean;
66
66
  loadingText?: string;
67
+ disabled?: boolean;
67
68
  }
68
69
 
69
70
  interface MultiComboboxDataProps<T extends DataWithId>
@@ -115,7 +116,7 @@ export type MultiComboboxProps<T extends DataWithId> =
115
116
 
116
117
  // ─── Component ────────────────────────────────────────────────────────────────
117
118
 
118
- export default function MultiCombobox<T extends DataWithId>(
119
+ export function MultiCombobox<T extends DataWithId>(
119
120
  props: MultiComboboxProps<T>
120
121
  ) {
121
122
  const {
@@ -374,6 +375,7 @@ export default function MultiCombobox<T extends DataWithId>(
374
375
  id={id}
375
376
  virtualized={isVirtualized}
376
377
  open={open}
378
+ disabled={props.disabled}
377
379
  onOpenChange={setOpen}
378
380
  onItemHighlighted={
379
381
  isVirtualized
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import { FormField } from "@sproutsocial/seeds-react-form-field";
4
- import MultiSearchableSelect from "./MultiSearchableSelect";
4
+ import { MultiSearchableSelect } from "./MultiSearchableSelect";
5
5
  import { books, largeBookSet, itemToString, renderItem } from "./storyData";
6
6
 
7
7
  const meta: Meta<typeof MultiSearchableSelect> = {
@@ -71,6 +71,7 @@ interface MultiSearchableSelectBaseProps {
71
71
  emptyText?: string;
72
72
  isLoading?: boolean;
73
73
  loadingText?: string;
74
+ disabled?: boolean;
74
75
  }
75
76
 
76
77
  interface MultiSearchableSelectDataProps<T extends DataWithId>
@@ -121,7 +122,7 @@ export type MultiSearchableSelectProps<T extends DataWithId> =
121
122
 
122
123
  // ─── Component ────────────────────────────────────────────────────────────────
123
124
 
124
- export default function MultiSearchableSelect<T extends DataWithId>(
125
+ export function MultiSearchableSelect<T extends DataWithId>(
125
126
  props: MultiSearchableSelectProps<T>
126
127
  ) {
127
128
  const {
@@ -364,6 +365,7 @@ export default function MultiSearchableSelect<T extends DataWithId>(
364
365
  id={id}
365
366
  virtualized={isVirtualized}
366
367
  open={open}
368
+ disabled={props.disabled}
367
369
  onOpenChange={setOpen}
368
370
  onItemHighlighted={
369
371
  isVirtualized
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import { FormField } from "@sproutsocial/seeds-react-form-field";
4
- import MultiSelect from "./MultiSelect";
4
+ import { MultiSelect } from "./MultiSelect";
5
5
  import SelectItem from "./Common/SelectItem";
6
6
  import SelectGroup from "./Common/SelectGroup";
7
7
  import { books, itemToString, renderItem } from "./storyData";
@@ -169,59 +169,59 @@ export const CustomSelection: Story = {
169
169
  ),
170
170
  };
171
171
 
172
- export const CustomToken: Story = {
173
- name: "Custom renderToken",
174
- render: () => (
175
- <div style={{ width: "300px" }}>
176
- <FormField label="Pick books">
177
- {({ id }) => (
178
- <MultiSelect
179
- id={id}
180
- data={books}
181
- itemToString={itemToString}
182
- renderItem={renderItem}
183
- placeholder="Select books..."
184
- renderToken={(item) => (
185
- <span>
186
- {item.title}{" "}
187
- <span style={{ fontSize: "11px", opacity: 0.7 }}>
188
- ({item.author})
189
- </span>
190
- </span>
191
- )}
192
- />
193
- )}
194
- </FormField>
195
- </div>
196
- ),
197
- };
172
+ // export const CustomToken: Story = {
173
+ // name: "Custom renderToken",
174
+ // render: () => (
175
+ // <div style={{ width: "300px" }}>
176
+ // <FormField label="Pick books">
177
+ // {({ id }) => (
178
+ // <MultiSelect
179
+ // id={id}
180
+ // data={books}
181
+ // itemToString={itemToString}
182
+ // renderItem={renderItem}
183
+ // placeholder="Select books..."
184
+ // renderToken={(item) => (
185
+ // <span>
186
+ // {item.title}{" "}
187
+ // <span style={{ fontSize: "11px", opacity: 0.7 }}>
188
+ // ({item.author})
189
+ // </span>
190
+ // </span>
191
+ // )}
192
+ // />
193
+ // )}
194
+ // </FormField>
195
+ // </div>
196
+ // ),
197
+ // };
198
198
 
199
- export const MaxTokens: Story = {
200
- name: "Max tokens",
201
- render: () => (
202
- <div style={{ width: "300px" }}>
203
- <FormField label="Pick books">
204
- {({ id }) => (
205
- <MultiSelect
206
- id={id}
207
- data={books}
208
- itemToString={itemToString}
209
- renderItem={renderItem}
210
- placeholder="Select books..."
211
- defaultSelectedItemIds={[
212
- "book-1",
213
- "book-2",
214
- "book-3",
215
- "book-4",
216
- "book-5",
217
- ]}
218
- maxTokens={2}
219
- />
220
- )}
221
- </FormField>
222
- </div>
223
- ),
224
- };
199
+ // export const MaxTokens: Story = {
200
+ // name: "Max tokens",
201
+ // render: () => (
202
+ // <div style={{ width: "300px" }}>
203
+ // <FormField label="Pick books">
204
+ // {({ id }) => (
205
+ // <MultiSelect
206
+ // id={id}
207
+ // data={books}
208
+ // itemToString={itemToString}
209
+ // renderItem={renderItem}
210
+ // placeholder="Select books..."
211
+ // defaultSelectedItemIds={[
212
+ // "book-1",
213
+ // "book-2",
214
+ // "book-3",
215
+ // "book-4",
216
+ // "book-5",
217
+ // ]}
218
+ // maxTokens={2}
219
+ // />
220
+ // )}
221
+ // </FormField>
222
+ // </div>
223
+ // ),
224
+ // };
225
225
 
226
226
  export const RemoveSelectedItems: Story = {
227
227
  name: "Remove selected items",
@@ -42,6 +42,7 @@ const Placeholder = styled.div`
42
42
  interface MultiSelectBaseProps {
43
43
  id?: string;
44
44
  placeholder?: string;
45
+ disabled?: boolean;
45
46
  }
46
47
 
47
48
  interface MultiSelectDataProps<T extends DataWithId>
@@ -79,234 +80,13 @@ interface MultiSelectChildrenProps extends MultiSelectBaseProps {
79
80
  removeSelectedItems?: never;
80
81
  }
81
82
 
82
- /*
83
- 'use client';
84
- import * as React from 'react';
85
- import { Combobox } from '@base-ui/react/combobox';
86
-
87
- export default function ExampleAsyncMultipleCombobox() {
88
- const id = React.useId();
89
-
90
- const [searchResults, setSearchResults] = React.useState<DirectoryUser[]>([]);
91
- const [selectedValues, setSelectedValues] = React.useState<DirectoryUser[]>([]);
92
- const [searchValue, setSearchValue] = React.useState('');
93
- const [error, setError] = React.useState<string | null>(null);
94
- const [blockStartStatus, setBlockStartStatus] = React.useState(false);
95
-
96
- const [isPending, startTransition] = React.useTransition();
97
-
98
- const { contains } = Combobox.useFilter();
99
-
100
- const abortControllerRef = React.useRef<AbortController | null>(null);
101
- const selectedValuesRef = React.useRef<DirectoryUser[]>([]);
102
-
103
- const trimmedSearchValue = searchValue.trim();
104
-
105
- const items = React.useMemo(() => {
106
- if (selectedValues.length === 0) {
107
- return searchResults;
108
- }
109
-
110
- const merged = [...searchResults];
111
-
112
- selectedValues.forEach((user) => {
113
- if (!searchResults.some((result) => result.id === user.id)) {
114
- merged.push(user);
115
- }
116
- });
117
-
118
- return merged;
119
- }, [searchResults, selectedValues]);
120
-
121
- function getStatus() {
122
- if (isPending) {
123
- return (
124
- <React.Fragment>
125
- <span
126
- aria-hidden
127
- className="inline-block size-3 animate-[spin_0.75s_linear_infinite] rounded-full border border-current border-r-transparent rtl:border-r-current rtl:border-l-transparent"
128
- />
129
- Searching…
130
- </React.Fragment>
131
- );
132
- }
133
-
134
- if (error) {
135
- return error;
136
- }
137
-
138
- if (trimmedSearchValue === '' && !blockStartStatus) {
139
- return selectedValues.length > 0 ? null : 'Start typing to search people…';
140
- }
141
-
142
- if (searchResults.length === 0 && !blockStartStatus) {
143
- return `No matches for "${trimmedSearchValue}".`;
144
- }
145
-
146
- return null;
147
- }
148
-
149
- function getEmptyMessage() {
150
- if (trimmedSearchValue === '' || isPending || searchResults.length > 0 || error) {
151
- return null;
152
- }
153
-
154
- return 'Try a different search term.';
155
- }
156
-
157
- const status = getStatus();
158
- const emptyMessage = getEmptyMessage();
159
-
160
- return (
161
- <Combobox.Root
162
- items={items}
163
- itemToStringLabel={(user: DirectoryUser) => user.name}
164
- multiple
165
- filter={null}
166
- onOpenChangeComplete={(open) => {
167
- if (!open) {
168
- setSearchResults(selectedValuesRef.current);
169
- setBlockStartStatus(false);
170
- }
171
- }}
172
- onValueChange={(nextSelectedValues) => {
173
- selectedValuesRef.current = nextSelectedValues;
174
- setSelectedValues(nextSelectedValues);
175
- setSearchValue('');
176
- setError(null);
177
-
178
- if (nextSelectedValues.length === 0) {
179
- setSearchResults([]);
180
- setBlockStartStatus(false);
181
- } else {
182
- setBlockStartStatus(true);
183
- }
184
- }}
185
- onInputValueChange={(nextSearchValue, { reason }) => {
186
- setSearchValue(nextSearchValue);
187
-
188
- const controller = new AbortController();
189
- abortControllerRef.current?.abort();
190
- abortControllerRef.current = controller;
191
-
192
- if (nextSearchValue === '') {
193
- setSearchResults(selectedValuesRef.current);
194
- setError(null);
195
- setBlockStartStatus(false);
196
- return;
197
- }
198
-
199
- if (reason === 'item-press') {
200
- return;
201
- }
202
- startTransition(async () => {
203
- setError(null);
204
-
205
- const result = await searchUsers(nextSearchValue, contains);
206
-
207
- if (controller.signal.aborted) {
208
- return;
209
- }
210
-
211
- startTransition(() => {
212
- setSearchResults(result.users);
213
- setError(result.error);
214
- });
215
- });
216
- }}
217
- >
218
- <div className="flex flex-col gap-1 text-sm text-gray-900">
219
- <label className="inline-flex text-inherit font-bold" htmlFor={id}>
220
- Assign reviewers
221
- </label>
222
- <Combobox.InputGroup className="relative flex min-h-10 w-[16rem] cursor-text rounded-md border border-gray-200 bg-[canvas] px-1.5 py-1 focus-within:outline-2 focus-within:-outline-offset-1 focus-within:outline-blue-800 md:w-[20rem]">
223
- <Combobox.Chips className="flex w-full flex-wrap items-center gap-1">
224
- <Combobox.Value>
225
- {(value: DirectoryUser[]) => (
226
- <React.Fragment>
227
- {value.map((user) => (
228
- <Combobox.Chip
229
- key={user.id}
230
- className="flex cursor-default items-center gap-1 rounded-md bg-gray-100 py-1 pl-2 pr-1 text-sm text-gray-900 outline-none focus-within:bg-blue-800 focus-within:text-gray-50 [@media(hover:hover)]:[&[data-highlighted]]:bg-blue-800 [@media(hover:hover)]:[&[data-highlighted]]:text-gray-50"
231
- aria-label={user.name}
232
- >
233
- {user.name}
234
- <Combobox.ChipRemove
235
- className="inline-flex items-center justify-center rounded-md border-none bg-transparent p-[0.2rem] text-inherit hover:bg-gray-200"
236
- aria-label={`Remove ${user.name}`}
237
- >
238
- <XIcon />
239
- </Combobox.ChipRemove>
240
- </Combobox.Chip>
241
- ))}
242
- <Combobox.Input
243
- id={id}
244
- placeholder={value.length > 0 ? '' : 'e.g. Michael'}
245
- className="h-8 min-w-24 flex-1 rounded-md border-0 bg-transparent pl-2 text-base font-normal text-gray-900 outline-none placeholder:font-normal"
246
- />
247
- </React.Fragment>
248
- )}
249
- </Combobox.Value>
250
- </Combobox.Chips>
251
- </Combobox.InputGroup>
252
- </div>
253
-
254
- <Combobox.Portal>
255
- <Combobox.Positioner className="outline-none" sideOffset={4}>
256
- <Combobox.Popup
257
- className="box-border w-[var(--anchor-width)] max-h-[min(var(--available-height),23rem)] max-w-[var(--available-width)] origin-[var(--transform-origin)] overflow-y-auto scroll-pb-2 scroll-pt-2 overscroll-contain rounded-md bg-[canvas] py-2 text-gray-900 shadow-[0_10px_15px_-3px_var(--color-gray-200),0_4px_6px_-4px_var(--color-gray-200)] outline outline-1 outline-gray-200 transition-[opacity,transform,scale] duration-100 data-[ending-style]:transition-none data-[starting-style]:scale-95 data-[starting-style]:opacity-0 dark:-outline-offset-1 dark:shadow-none dark:outline-gray-300"
258
- aria-busy={isPending || undefined}
259
- >
260
- <Combobox.Status>
261
- {status ? (
262
- <div className="flex items-center gap-2 py-1 pl-4 pr-5 text-sm text-gray-600">
263
- {status}
264
- </div>
265
- ) : null}
266
- </Combobox.Status>
267
- <Combobox.Empty>
268
- {emptyMessage ? (
269
- <div className="box-border px-4 py-2 text-sm leading-4 text-gray-600">
270
- {emptyMessage}
271
- </div>
272
- ) : null}
273
- </Combobox.Empty>
274
- <Combobox.List>
275
- {(user: DirectoryUser) => (
276
- <Combobox.Item
277
- key={user.id}
278
- value={user}
279
- className="grid cursor-default select-none grid-cols-[0.75rem_1fr] items-start gap-2 py-2 pl-4 pr-5 text-base leading-[1.2rem] outline-none [@media(hover:hover)]:[&[data-highlighted]]:relative [@media(hover:hover)]:[&[data-highlighted]]:z-0 [@media(hover:hover)]:[&[data-highlighted]]:text-gray-900 [@media(hover:hover)]:[&[data-highlighted]]:before:absolute [@media(hover:hover)]:[&[data-highlighted]]:before:inset-y-0 [@media(hover:hover)]:[&[data-highlighted]]:before:inset-x-2 [@media(hover:hover)]:[&[data-highlighted]]:before:z-[-1] [@media(hover:hover)]:[&[data-highlighted]]:before:rounded [@media(hover:hover)]:[&[data-highlighted]]:before:bg-gray-100 [@media(hover:hover)]:[&[data-highlighted]]:before:content-['']"
280
- >
281
- <Combobox.ItemIndicator className="col-start-1 mt-1">
282
- <CheckIcon className="size-3" />
283
- </Combobox.ItemIndicator>
284
- <span className="col-start-2 flex flex-col gap-1">
285
- <span className="text-[0.95rem] font-bold">{user.name}</span>
286
- <span className="flex flex-wrap gap-2 text-[0.8125rem] text-gray-600">
287
- <span className="opacity-80">@{user.username}</span>
288
- <span>{user.title}</span>
289
- </span>
290
- <span className="text-xs text-gray-500">{user.email}</span>
291
- </span>
292
- </Combobox.Item>
293
- )}
294
- </Combobox.List>
295
- </Combobox.Popup>
296
- </Combobox.Positioner>
297
- </Combobox.Portal>
298
- </Combobox.Root>
299
- */
300
-
301
83
  export type MultiSelectProps<T extends DataWithId> =
302
84
  | MultiSelectDataProps<T>
303
85
  | MultiSelectChildrenProps;
304
86
 
305
87
  // ─── Component ────────────────────────────────────────────────────────────────
306
88
 
307
- export default function MultiSelect<T extends DataWithId>(
308
- props: MultiSelectProps<T>
309
- ) {
89
+ export function MultiSelect<T extends DataWithId>(props: MultiSelectProps<T>) {
310
90
  const { id, placeholder = "Select..." } = props;
311
91
 
312
92
  const isChildrenMode = "children" in props && props.children != null;
@@ -396,6 +176,7 @@ export default function MultiSelect<T extends DataWithId>(
396
176
  items={items}
397
177
  value={value}
398
178
  onValueChange={handleValueChange}
179
+ disabled={props.disabled}
399
180
  id={id}
400
181
  >
401
182
  <SelectTrigger>
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import { FormField } from "@sproutsocial/seeds-react-form-field";
4
- import SingleCombobox from "./SingleCombobox";
4
+ import { SingleCombobox } from "./SingleCombobox";
5
5
  import { books, largeBookSet, itemToString, renderItem } from "./storyData";
6
6
 
7
7
  const meta: Meta<typeof SingleCombobox> = {
@@ -29,6 +29,7 @@ interface SingleComboboxBaseProps {
29
29
  id?: string;
30
30
  placeholder?: string;
31
31
  emptyText?: string;
32
+ disabled?: boolean;
32
33
  }
33
34
 
34
35
  interface SingleComboboxDataBaseProps<T extends DataWithId>
@@ -78,7 +79,7 @@ export type SingleComboboxProps<T extends DataWithId> =
78
79
 
79
80
  // ─── Component ────────────────────────────────────────────────────────────────
80
81
 
81
- export default function SingleCombobox<T extends DataWithId>(
82
+ export function SingleCombobox<T extends DataWithId>(
82
83
  props: SingleComboboxProps<T>
83
84
  ) {
84
85
  const {
@@ -175,6 +176,7 @@ export default function SingleCombobox<T extends DataWithId>(
175
176
  isVirtualized ? data : groups ?? (isChildrenMode ? undefined : data)
176
177
  }
177
178
  virtualized={isVirtualized}
179
+ disabled={props.disabled}
178
180
  open={open}
179
181
  onOpenChange={setOpen}
180
182
  onItemHighlighted={
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import { FormField } from "@sproutsocial/seeds-react-form-field";
4
- import SingleSearchableSelect from "./SingleSearchableSelect";
4
+ import { SingleSearchableSelect } from "./SingleSearchableSelect";
5
5
  import { books, largeBookSet, itemToString, renderItem } from "./storyData";
6
6
 
7
7
  const meta: Meta<typeof SingleSearchableSelect> = {
@@ -33,6 +33,7 @@ interface SingleSearchableSelectBaseProps {
33
33
  emptyText?: string;
34
34
  isLoading?: boolean;
35
35
  loadingText?: string;
36
+ disabled?: boolean;
36
37
  }
37
38
 
38
39
  interface SingleSearchableSelectDataBaseProps<T extends DataWithId>
@@ -85,7 +86,7 @@ export type SingleSearchableSelectProps<T extends DataWithId> =
85
86
 
86
87
  // ─── Component ────────────────────────────────────────────────────────────────
87
88
 
88
- export default function SingleSearchableSelect<T extends DataWithId>(
89
+ export function SingleSearchableSelect<T extends DataWithId>(
89
90
  props: SingleSearchableSelectProps<T>
90
91
  ) {
91
92
  const {
@@ -179,6 +180,7 @@ export default function SingleSearchableSelect<T extends DataWithId>(
179
180
  <Combobox.Root
180
181
  id={id}
181
182
  value={value}
183
+ disabled={props.disabled}
182
184
  onValueChange={handleValueChange}
183
185
  itemToStringLabel={itemToString}
184
186
  isItemEqualToValue={(a, b) => a != null && b != null && a.id === b.id}