@sproutsocial/seeds-react-menu 1.17.0 → 1.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/.turbo/turbo-build.log +14 -22
  2. package/CHANGELOG.md +37 -0
  3. package/dist/esm/index.js +542 -229
  4. package/dist/esm/index.js.map +1 -1
  5. package/dist/esm/v3/index.js +793 -1038
  6. package/dist/esm/v3/index.js.map +1 -1
  7. package/dist/v3/index.d.mts +64 -38
  8. package/dist/v3/index.d.ts +64 -38
  9. package/dist/v3/index.js +813 -1058
  10. package/dist/v3/index.js.map +1 -1
  11. package/dist/v3/menu.css +947 -0
  12. package/package.json +20 -21
  13. package/src/v3/ActionMenuStyles.tsx +169 -149
  14. package/src/v3/Common/ComboboxStyles.tsx +396 -511
  15. package/src/v3/Common/SelectIcons.tsx +17 -8
  16. package/src/v3/Common/SelectItem.tsx +25 -38
  17. package/src/v3/Common/SelectStyles.tsx +146 -144
  18. package/src/v3/Common/cn.ts +38 -0
  19. package/src/v3/MenuButtonStyles.tsx +55 -34
  20. package/src/v3/MultiSearchableSelect.tsx +8 -8
  21. package/src/v3/MultiSelect.tsx +11 -16
  22. package/src/v3/SingleSelect.tsx +13 -13
  23. package/src/v3/menu.css +947 -0
  24. package/tsup.config.ts +0 -1
  25. package/dist/esm/chunk-ROQATIB7.js +0 -357
  26. package/dist/esm/chunk-ROQATIB7.js.map +0 -1
  27. package/dist/esm/v2/index.js +0 -2089
  28. package/dist/esm/v2/index.js.map +0 -1
  29. package/dist/v2/index.d.mts +0 -108
  30. package/dist/v2/index.d.ts +0 -108
  31. package/dist/v2/index.js +0 -2280
  32. package/dist/v2/index.js.map +0 -1
  33. package/src/v2/Autocomplete/Autocomplete.stories.tsx +0 -645
  34. package/src/v2/Autocomplete/MultiAutocomplete.tsx +0 -487
  35. package/src/v2/Autocomplete/SingleAutocomplete.tsx +0 -366
  36. package/src/v2/Autocomplete/index.ts +0 -2
  37. package/src/v2/Common-V2/ComboboxContent.tsx +0 -457
  38. package/src/v2/Common-V2/MenuGroup.tsx +0 -60
  39. package/src/v2/Common-V2/MenuGroupTypes.ts +0 -30
  40. package/src/v2/Common-V2/MenuHeading.tsx +0 -83
  41. package/src/v2/Common-V2/MenuItem.tsx +0 -138
  42. package/src/v2/Common-V2/Popout.tsx +0 -124
  43. package/src/v2/Common-V2/PopoutTypes.tsx +0 -109
  44. package/src/v2/Common-V2/SelectToggleButton.tsx +0 -99
  45. package/src/v2/Common-V2/index.ts +0 -11
  46. package/src/v2/Common-V2/props.ts +0 -84
  47. package/src/v2/Common-V2/styles.tsx +0 -41
  48. package/src/v2/Common-V2/types.ts +0 -16
  49. package/src/v2/Common-V2/useHighlightedIndex.ts +0 -62
  50. package/src/v2/Common-V2/utils.ts +0 -238
  51. package/src/v2/SearchableSelect/AutocompleteContent.tsx +0 -325
  52. package/src/v2/SearchableSelect/SearchableMultiSelect.tsx +0 -527
  53. package/src/v2/SearchableSelect/SearchableSelect.tsx +0 -395
  54. package/src/v2/SearchableSelect/index.ts +0 -12
  55. package/src/v2/Select/MultiSelect.tsx +0 -417
  56. package/src/v2/Select/Select.stories.tsx +0 -593
  57. package/src/v2/Select/SingleSelect.tsx +0 -285
  58. package/src/v2/Select/index.ts +0 -2
  59. package/src/v2/index.ts +0 -2
@@ -1,319 +1,250 @@
1
+ import * as React from "react";
1
2
  import { Combobox } from "@base-ui/react/combobox";
2
- import styled, { css } from "styled-components";
3
- import { focusRing } from "@sproutsocial/seeds-react-mixins";
4
3
  import Checkbox from "@sproutsocial/seeds-react-checkbox";
5
- import { StyledChevron } from "./SelectIcons";
6
-
7
- const invalidStyles = css`
8
- border-color: ${({ theme }) => theme.colors.form.border.error};
9
-
10
- ${StyledChevron} {
11
- color: ${({ theme }) => theme.colors.icon.error};
12
- }
13
- `;
14
-
15
- export const ComboboxLabel = styled.label`
16
- font-size: ${({ theme }) => theme.typography[200].fontSize};
17
- font-weight: ${({ theme }) => theme.fontWeights.semibold};
18
- color: ${({ theme }) => theme.colors.text.body};
19
- `;
20
-
21
- export const ComboboxInputGroup = styled(Combobox.InputGroup)<{
4
+ import { cn, type WithStringClassName } from "./cn";
5
+
6
+ /**
7
+ * v3 Combobox / Searchable Select surface, rendered with CSS classes from
8
+ * menu.css (imported via @sproutsocial/seeds-react-menu/base/css) instead of
9
+ * styled-components. Each export keeps its previous name and forwards
10
+ * props/refs to the underlying Base UI component; the transient `$isInvalid`
11
+ * prop is translated to a modifier class here so call sites are unchanged.
12
+ */
13
+
14
+ export const ComboboxLabel = React.forwardRef<
15
+ HTMLLabelElement,
16
+ React.ComponentProps<"label">
17
+ >(({ className, ...rest }, ref) => (
18
+ <label ref={ref} className={cn("seeds-menu-label", className)} {...rest} />
19
+ ));
20
+ ComboboxLabel.displayName = "ComboboxLabel";
21
+
22
+ type InputGroupProps = WithStringClassName<
23
+ React.ComponentProps<typeof Combobox.InputGroup>
24
+ > & {
22
25
  $isInvalid?: boolean;
23
- }>`
24
- display: flex;
25
- align-items: center;
26
- min-width: 160px;
27
- border-radius: ${({ theme }) => theme.radii[500]};
28
- border: 1px solid ${({ theme }) => theme.colors.form.border.base};
29
- background: ${({ theme }) => theme.colors.form.background.base};
30
- color: ${({ theme }) => theme.colors.text.body};
31
- transition: border-color ${({ theme }) => theme.duration.fast}
32
- ${({ theme }) => theme.easing.ease_in},
33
- box-shadow ${({ theme }) => theme.duration.fast}
34
- ${({ theme }) => theme.easing.ease_in};
35
-
36
- &:focus-within {
37
- ${focusRing}
38
- }
39
-
40
- &[data-disabled] {
41
- opacity: 0.4;
42
- cursor: not-allowed;
43
- }
44
-
45
- ${({ $isInvalid }) => $isInvalid && invalidStyles}
46
- `;
47
-
48
- export const ComboboxInput = styled(Combobox.Input)`
49
- flex: 1;
50
- min-width: 30px;
51
- padding: ${({ theme }) => theme.space[300]};
52
- border: none !important;
53
- background: transparent;
54
- font-size: ${({ theme }) => theme.typography[200].fontSize};
55
- line-height: ${({ theme }) => theme.typography[200].lineHeight};
56
- color: ${({ theme }) => theme.colors.text.body};
57
- outline: none;
58
-
59
- &::placeholder {
60
- color: ${({ theme }) => theme.colors.text.subtext};
61
- }
62
-
63
- &:disabled {
64
- cursor: not-allowed;
65
- }
66
- `;
67
-
68
- export const ComboboxTokenInput = styled(Combobox.Input)`
69
- flex: 1;
70
- min-width: 60px;
71
- padding: ${({ theme }) => theme.space[200]} ${({ theme }) => theme.space[300]}
72
- ${({ theme }) => theme.space[200]} ${({ theme }) => theme.space[350]};
73
- border: none !important;
74
- background: transparent;
75
- font-size: ${({ theme }) => theme.typography[200].fontSize};
76
- line-height: ${({ theme }) => theme.typography[200].lineHeight};
77
- color: ${({ theme }) => theme.colors.text.body};
78
- outline: none;
79
-
80
- &::placeholder {
81
- color: ${({ theme }) => theme.colors.text.subtext};
82
- }
83
-
84
- &:disabled {
85
- cursor: not-allowed;
86
- }
87
- `;
88
-
89
- export const ComboboxActionButtons = styled.div`
90
- display: flex;
91
- align-items: center;
92
- flex-shrink: 0;
93
- margin-left: auto;
94
- gap: ${({ theme }) => theme.space[100]};
95
- `;
96
-
97
- export const ComboboxClear = styled(Combobox.Clear).attrs({ tabIndex: 0 })`
98
- display: flex;
99
- align-items: center;
100
- justify-content: center;
101
- width: 20px;
102
- height: 20px;
103
- border: none;
104
- background: transparent;
105
- color: ${({ theme }) => theme.colors.icon.base};
106
- cursor: pointer;
107
- border-radius: ${({ theme }) => theme.radii[300]};
108
- padding: 0;
109
-
110
- &:hover {
111
- color: ${({ theme }) => theme.colors.text.body};
112
- }
113
-
114
- &:focus-visible {
115
- ${focusRing}
116
- }
117
-
118
- &[data-empty] {
119
- display: none;
120
- }
121
- `;
122
-
123
- export const ComboboxTrigger = styled(Combobox.Trigger)`
124
- display: flex;
125
- align-items: center;
126
- justify-content: center;
127
- width: 20px;
128
- height: 20px;
129
- border: none;
130
- background: transparent;
131
- color: ${({ theme }) => theme.colors.icon.base};
132
- cursor: default;
133
- padding: 0;
134
-
135
- &:hover {
136
- color: ${({ theme }) => theme.colors.text.body};
137
- }
138
- `;
139
-
140
- export const ComboboxPositioner = styled(Combobox.Positioner)`
141
- width: var(--anchor-width);
142
- z-index: 7;
143
- `;
144
-
145
- export const ComboboxPopup = styled(Combobox.Popup)`
146
- font-family: ${({ theme }) => theme.fontFamily};
147
- background: ${({ theme }) => theme.colors.container.background.base};
148
- border: 1px solid ${({ theme }) => theme.colors.container.border.base};
149
- border-radius: ${({ theme }) => theme.radii[500]};
150
- box-shadow: ${({ theme }) => theme.shadows.medium};
151
- outline: none;
152
- width: 100%;
153
- max-height: min(var(--available-height, 400px), 400px);
154
- overflow-y: auto;
155
- padding: 0;
156
-
157
- &[data-open] {
158
- animation: combobox-popup-in 120ms ease-out;
159
- }
160
-
161
- &[data-closed] {
162
- animation: combobox-popup-out 100ms ease-in;
163
- }
164
-
165
- @keyframes combobox-popup-in {
166
- from {
167
- opacity: 0;
168
- transform: scale(0.95);
169
- }
170
- to {
171
- opacity: 1;
172
- transform: scale(1);
173
- }
174
- }
175
-
176
- @keyframes combobox-popup-out {
177
- from {
178
- opacity: 1;
179
- transform: scale(1);
180
- }
181
- to {
182
- opacity: 0;
183
- transform: scale(0.95);
184
- }
185
- }
186
- `;
187
-
188
- export const ComboboxList = styled(Combobox.List)`
189
- padding: ${({ theme }) => theme.space[200]};
190
-
191
- &:empty {
192
- padding: 0;
193
- }
194
- `;
195
-
196
- export const ComboboxStatus = styled(Combobox.Status)`
197
- padding: ${({ theme }) => `${theme.space[300]} ${theme.space[350]}`};
198
- font-size: ${({ theme }) => theme.typography[200].fontSize};
199
- color: ${({ theme }) => theme.colors.text.subtext};
200
-
201
- &:empty {
202
- padding: 0;
203
- }
204
- `;
205
-
206
- export const ComboboxEmpty = styled(Combobox.Empty)`
207
- padding: ${({ theme }) => `${theme.space[300]} ${theme.space[350]}`};
208
- font-size: ${({ theme }) => theme.typography[200].fontSize};
209
- color: ${({ theme }) => theme.colors.text.subtext};
210
-
211
- &:empty {
212
- padding: 0;
213
- }
214
- `;
215
-
216
- export const ComboboxItem = styled(Combobox.Item)`
217
- display: flex;
218
- align-items: center;
219
- gap: ${({ theme }) => theme.space[300]};
220
- padding: ${({ theme }) => `${theme.space[300]} ${theme.space[300]}`};
221
- border-radius: ${({ theme }) => theme.radii[500]};
222
- font-size: ${({ theme }) => theme.typography[200].fontSize};
223
- color: ${({ theme }) => theme.colors.text.body};
224
- cursor: default;
225
- outline: none;
226
-
227
- &[data-highlighted] {
228
- background: ${({ theme }) => theme.colors.listItem.background.hover};
229
- }
230
-
231
- &[data-selected] {
232
- font-weight: ${({ theme }) => theme.fontWeights.semibold};
233
- }
234
-
235
- &[data-disabled] {
236
- opacity: 0.5;
237
- cursor: not-allowed;
238
- }
239
- `;
240
-
241
- export const ComboboxItemIndicator = styled(Combobox.ItemIndicator)`
242
- display: flex;
243
- align-items: center;
244
- width: ${({ theme }) => theme.space[400]};
245
- color: ${({ theme }) => theme.colors.text.body};
246
- visibility: hidden;
247
-
248
- &[data-selected] {
249
- visibility: visible;
250
- }
251
- `;
252
-
253
- export const ComboboxGroup = styled(Combobox.Group)`
254
- display: block;
255
- `;
256
-
257
- export const ComboboxGroupLabel = styled(Combobox.GroupLabel)`
258
- padding: ${({ theme }) =>
259
- `${theme.space[300]} ${theme.space[300]} ${theme.space[200]}`};
260
- font-size: ${({ theme }) => theme.typography[100].fontSize};
261
- font-weight: ${({ theme }) => theme.fontWeights.semibold};
262
- text-transform: uppercase;
263
- letter-spacing: 0.05em;
264
- color: ${({ theme }) => theme.colors.text.subtext};
265
- `;
266
-
267
- export const ComboboxSeparator = styled.div`
268
- height: 1px;
269
- margin: ${({ theme }) => `${theme.space[200]} ${theme.space[300]}`};
270
- background: ${({ theme }) => theme.colors.container.border.base};
271
- `;
272
-
273
- export const ComboboxGroupHeaderItem = styled(Combobox.Item)`
274
- display: flex;
275
- align-items: center;
276
- gap: ${({ theme }) => theme.space[300]};
277
- padding: ${({ theme }) => `${theme.space[300]} ${theme.space[300]}`};
278
- border-radius: ${({ theme }) => theme.radii[500]};
279
- font-size: ${({ theme }) => theme.typography[100].fontSize};
280
- font-weight: ${({ theme }) => theme.fontWeights.semibold};
281
- text-transform: uppercase;
282
- letter-spacing: 0.05em;
283
- color: ${({ theme }) => theme.colors.text.subtext};
284
- cursor: default;
285
- outline: none;
286
-
287
- &[data-highlighted] {
288
- background: ${({ theme }) => theme.colors.listItem.background.hover};
289
- color: ${({ theme }) => theme.colors.text.body};
290
- }
291
-
292
- &[data-disabled] {
293
- opacity: 0.4;
294
- cursor: not-allowed;
295
- pointer-events: none;
296
- }
297
- `;
298
-
299
- export const ComboboxSelectAllItem = styled(Combobox.Item)`
300
- display: flex;
301
- align-items: center;
302
- gap: ${({ theme }) => theme.space[300]};
303
- padding: ${({ theme }) => `${theme.space[300]} ${theme.space[300]}`};
304
- border-radius: ${({ theme }) => theme.radii[500]};
305
- font-size: ${({ theme }) => theme.typography[200].fontSize};
306
- font-weight: ${({ theme }) => theme.fontWeights.semibold};
307
- color: ${({ theme }) => theme.colors.text.body};
308
- cursor: default;
309
- outline: none;
310
- border-bottom: 1px solid ${({ theme }) => theme.colors.container.border.base};
311
- margin-bottom: ${({ theme }) => theme.space[200]};
312
-
313
- &[data-highlighted] {
314
- background: ${({ theme }) => theme.colors.listItem.background.hover};
315
- }
316
- `;
26
+ };
27
+
28
+ export const ComboboxInputGroup = React.forwardRef<
29
+ React.ElementRef<typeof Combobox.InputGroup>,
30
+ InputGroupProps
31
+ >(({ $isInvalid, className, ...rest }, ref) => (
32
+ <Combobox.InputGroup
33
+ ref={ref}
34
+ className={cn(
35
+ "seeds-combobox-input-group",
36
+ { "seeds-combobox-input-group--invalid": !!$isInvalid },
37
+ className
38
+ )}
39
+ {...rest}
40
+ />
41
+ ));
42
+ ComboboxInputGroup.displayName = "ComboboxInputGroup";
43
+
44
+ export const ComboboxInput = React.forwardRef<
45
+ React.ElementRef<typeof Combobox.Input>,
46
+ WithStringClassName<React.ComponentProps<typeof Combobox.Input>>
47
+ >(({ className, ...rest }, ref) => (
48
+ <Combobox.Input
49
+ ref={ref}
50
+ className={cn("seeds-combobox-input", className)}
51
+ {...rest}
52
+ />
53
+ ));
54
+ ComboboxInput.displayName = "ComboboxInput";
55
+
56
+ export const ComboboxTokenInput = React.forwardRef<
57
+ React.ElementRef<typeof Combobox.Input>,
58
+ WithStringClassName<React.ComponentProps<typeof Combobox.Input>>
59
+ >(({ className, ...rest }, ref) => (
60
+ <Combobox.Input
61
+ ref={ref}
62
+ className={cn("seeds-combobox-token-input", className)}
63
+ {...rest}
64
+ />
65
+ ));
66
+ ComboboxTokenInput.displayName = "ComboboxTokenInput";
67
+
68
+ export const ComboboxActionButtons = React.forwardRef<
69
+ HTMLDivElement,
70
+ React.ComponentProps<"div">
71
+ >(({ className, ...rest }, ref) => (
72
+ <div
73
+ ref={ref}
74
+ className={cn("seeds-combobox-action-buttons", className)}
75
+ {...rest}
76
+ />
77
+ ));
78
+ ComboboxActionButtons.displayName = "ComboboxActionButtons";
79
+
80
+ export const ComboboxClear = React.forwardRef<
81
+ React.ElementRef<typeof Combobox.Clear>,
82
+ WithStringClassName<React.ComponentProps<typeof Combobox.Clear>>
83
+ >(({ className, ...rest }, ref) => (
84
+ <Combobox.Clear
85
+ ref={ref}
86
+ tabIndex={0}
87
+ className={cn("seeds-combobox-clear", className)}
88
+ {...rest}
89
+ />
90
+ ));
91
+ ComboboxClear.displayName = "ComboboxClear";
92
+
93
+ export const ComboboxTrigger = React.forwardRef<
94
+ React.ElementRef<typeof Combobox.Trigger>,
95
+ WithStringClassName<React.ComponentProps<typeof Combobox.Trigger>>
96
+ >(({ className, ...rest }, ref) => (
97
+ <Combobox.Trigger
98
+ ref={ref}
99
+ className={cn("seeds-combobox-trigger", className)}
100
+ {...rest}
101
+ />
102
+ ));
103
+ ComboboxTrigger.displayName = "ComboboxTrigger";
104
+
105
+ export const ComboboxPositioner = React.forwardRef<
106
+ React.ElementRef<typeof Combobox.Positioner>,
107
+ WithStringClassName<React.ComponentProps<typeof Combobox.Positioner>>
108
+ >(({ className, ...rest }, ref) => (
109
+ <Combobox.Positioner
110
+ ref={ref}
111
+ className={cn("seeds-combobox-positioner", className)}
112
+ {...rest}
113
+ />
114
+ ));
115
+ ComboboxPositioner.displayName = "ComboboxPositioner";
116
+
117
+ export const ComboboxPopup = React.forwardRef<
118
+ React.ElementRef<typeof Combobox.Popup>,
119
+ WithStringClassName<React.ComponentProps<typeof Combobox.Popup>>
120
+ >(({ className, ...rest }, ref) => (
121
+ <Combobox.Popup
122
+ ref={ref}
123
+ className={cn("seeds-combobox-popup", className)}
124
+ {...rest}
125
+ />
126
+ ));
127
+ ComboboxPopup.displayName = "ComboboxPopup";
128
+
129
+ export const ComboboxList = React.forwardRef<
130
+ React.ElementRef<typeof Combobox.List>,
131
+ WithStringClassName<React.ComponentProps<typeof Combobox.List>>
132
+ >(({ className, ...rest }, ref) => (
133
+ <Combobox.List
134
+ ref={ref}
135
+ className={cn("seeds-combobox-list", className)}
136
+ {...rest}
137
+ />
138
+ ));
139
+ ComboboxList.displayName = "ComboboxList";
140
+
141
+ export const ComboboxStatus = React.forwardRef<
142
+ React.ElementRef<typeof Combobox.Status>,
143
+ WithStringClassName<React.ComponentProps<typeof Combobox.Status>>
144
+ >(({ className, ...rest }, ref) => (
145
+ <Combobox.Status
146
+ ref={ref}
147
+ className={cn("seeds-combobox-status", className)}
148
+ {...rest}
149
+ />
150
+ ));
151
+ ComboboxStatus.displayName = "ComboboxStatus";
152
+
153
+ export const ComboboxEmpty = React.forwardRef<
154
+ React.ElementRef<typeof Combobox.Empty>,
155
+ WithStringClassName<React.ComponentProps<typeof Combobox.Empty>>
156
+ >(({ className, ...rest }, ref) => (
157
+ <Combobox.Empty
158
+ ref={ref}
159
+ className={cn("seeds-combobox-empty", className)}
160
+ {...rest}
161
+ />
162
+ ));
163
+ ComboboxEmpty.displayName = "ComboboxEmpty";
164
+
165
+ export const ComboboxItem = React.forwardRef<
166
+ React.ElementRef<typeof Combobox.Item>,
167
+ WithStringClassName<React.ComponentProps<typeof Combobox.Item>>
168
+ >(({ className, ...rest }, ref) => (
169
+ <Combobox.Item
170
+ ref={ref}
171
+ className={cn("seeds-combobox-item", className)}
172
+ {...rest}
173
+ />
174
+ ));
175
+ ComboboxItem.displayName = "ComboboxItem";
176
+
177
+ export const ComboboxItemIndicator = React.forwardRef<
178
+ React.ElementRef<typeof Combobox.ItemIndicator>,
179
+ WithStringClassName<React.ComponentProps<typeof Combobox.ItemIndicator>>
180
+ >(({ className, ...rest }, ref) => (
181
+ <Combobox.ItemIndicator
182
+ ref={ref}
183
+ className={cn("seeds-combobox-item-indicator", className)}
184
+ {...rest}
185
+ />
186
+ ));
187
+ ComboboxItemIndicator.displayName = "ComboboxItemIndicator";
188
+
189
+ export const ComboboxGroup = React.forwardRef<
190
+ React.ElementRef<typeof Combobox.Group>,
191
+ WithStringClassName<React.ComponentProps<typeof Combobox.Group>>
192
+ >(({ className, ...rest }, ref) => (
193
+ <Combobox.Group
194
+ ref={ref}
195
+ className={cn("seeds-combobox-group", className)}
196
+ {...rest}
197
+ />
198
+ ));
199
+ ComboboxGroup.displayName = "ComboboxGroup";
200
+
201
+ export const ComboboxGroupLabel = React.forwardRef<
202
+ React.ElementRef<typeof Combobox.GroupLabel>,
203
+ WithStringClassName<React.ComponentProps<typeof Combobox.GroupLabel>>
204
+ >(({ className, ...rest }, ref) => (
205
+ <Combobox.GroupLabel
206
+ ref={ref}
207
+ className={cn("seeds-combobox-group-label", className)}
208
+ {...rest}
209
+ />
210
+ ));
211
+ ComboboxGroupLabel.displayName = "ComboboxGroupLabel";
212
+
213
+ export const ComboboxSeparator = React.forwardRef<
214
+ HTMLDivElement,
215
+ React.ComponentProps<"div">
216
+ >(({ className, ...rest }, ref) => (
217
+ <div
218
+ ref={ref}
219
+ className={cn("seeds-combobox-separator", className)}
220
+ {...rest}
221
+ />
222
+ ));
223
+ ComboboxSeparator.displayName = "ComboboxSeparator";
224
+
225
+ export const ComboboxGroupHeaderItem = React.forwardRef<
226
+ React.ElementRef<typeof Combobox.Item>,
227
+ WithStringClassName<React.ComponentProps<typeof Combobox.Item>>
228
+ >(({ className, ...rest }, ref) => (
229
+ <Combobox.Item
230
+ ref={ref}
231
+ className={cn("seeds-combobox-group-header-item", className)}
232
+ {...rest}
233
+ />
234
+ ));
235
+ ComboboxGroupHeaderItem.displayName = "ComboboxGroupHeaderItem";
236
+
237
+ export const ComboboxSelectAllItem = React.forwardRef<
238
+ React.ElementRef<typeof Combobox.Item>,
239
+ WithStringClassName<React.ComponentProps<typeof Combobox.Item>>
240
+ >(({ className, ...rest }, ref) => (
241
+ <Combobox.Item
242
+ ref={ref}
243
+ className={cn("seeds-combobox-select-all-item", className)}
244
+ {...rest}
245
+ />
246
+ ));
247
+ ComboboxSelectAllItem.displayName = "ComboboxSelectAllItem";
317
248
 
318
249
  export function ComboboxGroupHeaderCheckbox({
319
250
  $state,
@@ -334,210 +265,164 @@ export function ComboboxGroupHeaderCheckbox({
334
265
  }
335
266
 
336
267
  // Multi-select Token components
337
- export const ComboboxToken = styled(Combobox.Chips)`
338
- display: flex;
339
- width: 100%;
340
- flex-wrap: wrap;
341
- gap: ${({ theme }) => theme.space[200]};
342
- `;
343
-
344
- export const ComboboxTokenInputGroup = styled(Combobox.InputGroup)<{
268
+ export const ComboboxToken = React.forwardRef<
269
+ React.ElementRef<typeof Combobox.Chips>,
270
+ WithStringClassName<React.ComponentProps<typeof Combobox.Chips>>
271
+ >(({ className, ...rest }, ref) => (
272
+ <Combobox.Chips
273
+ ref={ref}
274
+ className={cn("seeds-combobox-tokens", className)}
275
+ {...rest}
276
+ />
277
+ ));
278
+ ComboboxToken.displayName = "ComboboxToken";
279
+
280
+ type TokenInputGroupProps = WithStringClassName<
281
+ React.ComponentProps<typeof Combobox.InputGroup>
282
+ > & {
345
283
  $isInvalid?: boolean;
346
- }>`
347
- display: flex;
348
- align-items: center;
349
- flex-wrap: wrap;
350
- border-radius: ${({ theme }) => theme.radii[500]};
351
- border: 1px solid ${({ theme }) => theme.colors.form.border.base};
352
- background: ${({ theme }) => theme.colors.form.background.base};
353
- color: ${({ theme }) => theme.colors.text.body};
354
- padding: ${({ theme }) =>
355
- `${theme.space[200]} ${theme.space[300]} ${theme.space[200]} ${theme.space[200]}`};
356
- gap: ${({ theme }) => theme.space[200]};
357
- transition: border-color ${({ theme }) => theme.duration.fast}
358
- ${({ theme }) => theme.easing.ease_in},
359
- box-shadow ${({ theme }) => theme.duration.fast}
360
- ${({ theme }) => theme.easing.ease_in};
361
-
362
- &:focus-within {
363
- ${focusRing}
364
- }
365
-
366
- &[data-disabled] {
367
- opacity: 0.4;
368
- cursor: not-allowed;
369
- }
370
-
371
- ${({ $isInvalid }) => $isInvalid && invalidStyles}
372
- `;
373
-
374
- export const Token = styled.span`
375
- display: inline-flex;
376
- align-items: center;
377
- gap: ${({ theme }) => theme.space[200]};
378
- padding: ${({ theme }) => `${theme.space[200]} ${theme.space[300]}`};
379
- border-radius: ${({ theme }) => theme.radii[500]};
380
- border: 1px solid ${({ theme }) => theme.colors.container.border.base};
381
- background: ${({ theme }) => theme.colors.container.background.base};
382
- color: ${({ theme }) => theme.colors.text.body};
383
- font-size: ${({ theme }) => theme.typography[200].fontSize};
384
- font-weight: ${({ theme }) => theme.fontWeights.normal};
385
- line-height: 1;
386
- white-space: nowrap;
387
- transition: all ${({ theme }) => theme.duration.fast}
388
- ${({ theme }) => theme.easing.ease_inout};
389
-
390
- &:hover {
391
- box-shadow: ${({ theme }) => theme.shadows.low};
392
- border-color: ${({ theme }) => theme.colors.container.border.base};
393
- }
394
- `;
395
-
396
- export const TokenRemove = styled.button`
397
- display: flex;
398
- align-items: center;
399
- justify-content: center;
400
- border: none;
401
- background: transparent;
402
- color: inherit;
403
- cursor: pointer;
404
- padding: 0;
405
- line-height: 1;
406
-
407
- &:focus-visible {
408
- ${focusRing}
409
- }
410
- `;
284
+ };
285
+
286
+ export const ComboboxTokenInputGroup = React.forwardRef<
287
+ React.ElementRef<typeof Combobox.InputGroup>,
288
+ TokenInputGroupProps
289
+ >(({ $isInvalid, className, ...rest }, ref) => (
290
+ <Combobox.InputGroup
291
+ ref={ref}
292
+ className={cn(
293
+ "seeds-combobox-token-input-group",
294
+ { "seeds-combobox-token-input-group--invalid": !!$isInvalid },
295
+ className
296
+ )}
297
+ {...rest}
298
+ />
299
+ ));
300
+ ComboboxTokenInputGroup.displayName = "ComboboxTokenInputGroup";
301
+
302
+ export const Token = React.forwardRef<
303
+ HTMLSpanElement,
304
+ React.ComponentProps<"span">
305
+ >(({ className, ...rest }, ref) => (
306
+ <span ref={ref} className={cn("seeds-combobox-token", className)} {...rest} />
307
+ ));
308
+ Token.displayName = "Token";
309
+
310
+ export const TokenRemove = React.forwardRef<
311
+ HTMLButtonElement,
312
+ React.ComponentProps<"button">
313
+ >(({ className, ...rest }, ref) => (
314
+ <button
315
+ ref={ref}
316
+ className={cn("seeds-combobox-token-remove", className)}
317
+ {...rest}
318
+ />
319
+ ));
320
+ TokenRemove.displayName = "TokenRemove";
411
321
 
412
322
  // Searchable select components
413
323
 
414
- export const SearchableSelectTrigger = styled(Combobox.Trigger)<{
324
+ type SearchableTriggerProps = WithStringClassName<
325
+ React.ComponentProps<typeof Combobox.Trigger>
326
+ > & {
415
327
  $isInvalid?: boolean;
416
- }>`
417
- display: flex;
418
- align-items: center;
419
- justify-content: space-between;
420
- gap: ${({ theme }) => theme.space[300]};
421
- padding: ${({ theme }) => theme.space[200]} ${({ theme }) => theme.space[350]};
422
- min-width: 160px;
423
- border-radius: ${({ theme }) => theme.radii[500]};
424
- border: 1px solid ${({ theme }) => theme.colors.form.border.base};
425
- background: ${({ theme }) => theme.colors.form.background.base};
426
- font-size: ${({ theme }) => theme.typography[200].fontSize};
427
- color: ${({ theme }) => theme.colors.text.body};
428
- cursor: default;
429
- outline: none;
430
- user-select: none;
431
- transition: border-color ${({ theme }) => theme.duration.fast}
432
- ${({ theme }) => theme.easing.ease_in},
433
- box-shadow ${({ theme }) => theme.duration.fast}
434
- ${({ theme }) => theme.easing.ease_in};
435
-
436
- &:focus-visible {
437
- ${focusRing}
438
- }
439
-
440
- &[data-popup-open] [data-chevron] {
441
- transform: rotate(-180deg);
442
- }
443
-
444
- &[data-disabled] {
445
- opacity: 0.4;
446
- cursor: not-allowed;
447
- }
448
-
449
- ${({ $isInvalid }) => $isInvalid && invalidStyles}
450
- `;
451
-
452
- export const SearchableSelectTriggerIcon = styled(Combobox.Icon)`
453
- display: flex;
454
- align-items: center;
455
- color: ${({ theme }) => theme.colors.icon.base};
456
- flex-shrink: 0;
457
- `;
458
-
459
- export const SearchableSelectPlaceholder = styled.span`
460
- color: ${({ theme }) => theme.colors.text.subtext};
461
- padding: ${({ theme }) => theme.space[200]} 0;
462
- `;
328
+ };
329
+
330
+ export const SearchableSelectTrigger = React.forwardRef<
331
+ React.ElementRef<typeof Combobox.Trigger>,
332
+ SearchableTriggerProps
333
+ >(({ $isInvalid, className, ...rest }, ref) => (
334
+ <Combobox.Trigger
335
+ ref={ref}
336
+ className={cn(
337
+ "seeds-searchable-select-trigger",
338
+ { "seeds-searchable-select-trigger--invalid": !!$isInvalid },
339
+ className
340
+ )}
341
+ {...rest}
342
+ />
343
+ ));
344
+ SearchableSelectTrigger.displayName = "SearchableSelectTrigger";
345
+
346
+ export const SearchableSelectTriggerIcon = React.forwardRef<
347
+ React.ElementRef<typeof Combobox.Icon>,
348
+ WithStringClassName<React.ComponentProps<typeof Combobox.Icon>>
349
+ >(({ className, ...rest }, ref) => (
350
+ <Combobox.Icon
351
+ ref={ref}
352
+ className={cn("seeds-searchable-select-trigger-icon", className)}
353
+ {...rest}
354
+ />
355
+ ));
356
+ SearchableSelectTriggerIcon.displayName = "SearchableSelectTriggerIcon";
357
+
358
+ export const SearchableSelectPlaceholder = React.forwardRef<
359
+ HTMLSpanElement,
360
+ React.ComponentProps<"span">
361
+ >(({ className, ...rest }, ref) => (
362
+ <span
363
+ ref={ref}
364
+ className={cn("seeds-searchable-select-placeholder", className)}
365
+ {...rest}
366
+ />
367
+ ));
368
+ SearchableSelectPlaceholder.displayName = "SearchableSelectPlaceholder";
463
369
 
464
370
  export const SearchableSelectPopup = ComboboxPopup;
465
371
 
466
- export const SearchableSelectSearchContainer = styled.div`
467
- padding: ${({ theme }) => theme.space[300]};
468
- border-bottom: 1px solid ${({ theme }) => theme.colors.container.border.base};
469
- flex-shrink: 0;
470
- `;
471
-
472
- export const SearchableSelectInput = styled(Combobox.Input)`
473
- width: 100%;
474
- height: ${({ theme }) => theme.space[500]};
475
- padding: 0 ${({ theme }) => theme.space[300]};
476
- border-radius: ${({ theme }) => theme.radii[500]};
477
- border: 1px solid ${({ theme }) => theme.colors.container.border.base};
478
- background: ${({ theme }) => theme.colors.container.background.base};
479
- font-size: ${({ theme }) => theme.typography[200].fontSize};
480
- color: ${({ theme }) => theme.colors.text.body};
481
- outline: none;
482
- box-sizing: border-box;
483
-
484
- &:focus {
485
- ${focusRing}
486
- }
487
-
488
- &::placeholder {
489
- color: ${({ theme }) => theme.colors.text.subtext};
490
- }
491
- `;
492
-
493
- export const SearchableSelectList = styled(Combobox.List)`
494
- overflow-y: auto;
495
- padding: ${({ theme }) => theme.space[200]};
496
- flex: 1;
497
- min-height: 0;
498
- &:empty {
499
- padding: 0;
500
- }
501
- `;
502
-
503
- export const SearchableSelectTokenTrigger = styled(Combobox.Trigger)<{
372
+ export const SearchableSelectSearchContainer = React.forwardRef<
373
+ HTMLDivElement,
374
+ React.ComponentProps<"div">
375
+ >(({ className, ...rest }, ref) => (
376
+ <div
377
+ ref={ref}
378
+ className={cn("seeds-searchable-select-search-container", className)}
379
+ {...rest}
380
+ />
381
+ ));
382
+ SearchableSelectSearchContainer.displayName = "SearchableSelectSearchContainer";
383
+
384
+ export const SearchableSelectInput = React.forwardRef<
385
+ React.ElementRef<typeof Combobox.Input>,
386
+ WithStringClassName<React.ComponentProps<typeof Combobox.Input>>
387
+ >(({ className, ...rest }, ref) => (
388
+ <Combobox.Input
389
+ ref={ref}
390
+ className={cn("seeds-searchable-select-input", className)}
391
+ {...rest}
392
+ />
393
+ ));
394
+ SearchableSelectInput.displayName = "SearchableSelectInput";
395
+
396
+ export const SearchableSelectList = React.forwardRef<
397
+ React.ElementRef<typeof Combobox.List>,
398
+ WithStringClassName<React.ComponentProps<typeof Combobox.List>>
399
+ >(({ className, ...rest }, ref) => (
400
+ <Combobox.List
401
+ ref={ref}
402
+ className={cn("seeds-searchable-select-list", className)}
403
+ {...rest}
404
+ />
405
+ ));
406
+ SearchableSelectList.displayName = "SearchableSelectList";
407
+
408
+ type TokenTriggerProps = WithStringClassName<
409
+ React.ComponentProps<typeof Combobox.Trigger>
410
+ > & {
504
411
  $isInvalid?: boolean;
505
- }>`
506
- display: flex;
507
- align-items: center;
508
- flex-wrap: wrap;
509
- min-width: 160px;
510
- border-radius: ${({ theme }) => theme.radii[500]};
511
- border: 1px solid ${({ theme }) => theme.colors.form.border.base};
512
- background: ${({ theme }) => theme.colors.form.background.base};
513
- color: ${({ theme }) => theme.colors.text.body};
514
- padding: ${({ theme }) => theme.space[200]} ${({ theme }) => theme.space[300]};
515
- gap: ${({ theme }) => theme.space[200]};
516
- cursor: default;
517
- text-align: left;
518
- outline: none;
519
- user-select: none;
520
- transition: border-color ${({ theme }) => theme.duration.fast}
521
- ${({ theme }) => theme.easing.ease_in},
522
- box-shadow ${({ theme }) => theme.duration.fast}
523
- ${({ theme }) => theme.easing.ease_in};
524
-
525
- &:focus-visible {
526
- ${focusRing}
527
- }
528
-
529
- &[data-popup-open] {
530
- border-color: ${({ theme }) => theme.colors.blue[600]};
531
- }
532
-
533
- &[data-popup-open] [data-chevron] {
534
- transform: rotate(-180deg);
535
- }
536
-
537
- &[data-disabled] {
538
- opacity: 0.4;
539
- cursor: not-allowed;
540
- }
541
-
542
- ${({ $isInvalid }) => $isInvalid && invalidStyles}
543
- `;
412
+ };
413
+
414
+ export const SearchableSelectTokenTrigger = React.forwardRef<
415
+ React.ElementRef<typeof Combobox.Trigger>,
416
+ TokenTriggerProps
417
+ >(({ $isInvalid, className, ...rest }, ref) => (
418
+ <Combobox.Trigger
419
+ ref={ref}
420
+ className={cn(
421
+ "seeds-searchable-select-token-trigger",
422
+ { "seeds-searchable-select-token-trigger--invalid": !!$isInvalid },
423
+ className
424
+ )}
425
+ {...rest}
426
+ />
427
+ ));
428
+ SearchableSelectTokenTrigger.displayName = "SearchableSelectTokenTrigger";