@telegraph/combobox 0.0.77 → 0.0.78
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/CHANGELOG.md +11 -0
- package/README.md +474 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.mjs +573 -492
- package/dist/esm/index.mjs.map +1 -1
- package/dist/types/Combobox/Combobox.d.ts +17 -1
- package/dist/types/Combobox/Combobox.d.ts.map +1 -1
- package/dist/types/Combobox/Combobox.helpers.d.ts +1 -5
- package/dist/types/Combobox/Combobox.helpers.d.ts.map +1 -1
- package/dist/types/Combobox/Combobox.primitives.d.ts +35 -0
- package/dist/types/Combobox/Combobox.primitives.d.ts.map +1 -0
- package/dist/types/Combobox/Combobox.types.d.ts +14 -0
- package/dist/types/Combobox/Combobox.types.d.ts.map +1 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @telegraph/combobox
|
|
2
2
|
|
|
3
|
+
## 0.0.78
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#439](https://github.com/knocklabs/telegraph/pull/439) [`0dcbd65`](https://github.com/knocklabs/telegraph/commit/0dcbd65ba294edd97cdc4159533a8516433cd3c9) Thanks [@kylemcd](https://github.com/kylemcd)! - add combobox primitive trigger components
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`0dcbd65`](https://github.com/knocklabs/telegraph/commit/0dcbd65ba294edd97cdc4159533a8516433cd3c9)]:
|
|
10
|
+
- @telegraph/button@0.0.77
|
|
11
|
+
- @telegraph/tag@0.0.82
|
|
12
|
+
- @telegraph/menu@0.0.62
|
|
13
|
+
|
|
3
14
|
## 0.0.77
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@telegraph/combobox)
|
|
4
4
|
|
|
5
5
|
# @telegraph/combobox
|
|
6
|
+
|
|
6
7
|
> A styled menu, triggered by a Select, that combines an Input and Single- or Multi-select.
|
|
7
8
|
|
|
8
9
|
## Installation Instructions
|
|
@@ -12,6 +13,479 @@ npm install @telegraph/combobox
|
|
|
12
13
|
```
|
|
13
14
|
|
|
14
15
|
### Add stylesheet
|
|
16
|
+
|
|
15
17
|
```
|
|
16
18
|
@import "@telegraph/combobox"
|
|
17
19
|
```
|
|
20
|
+
|
|
21
|
+
### Basic Usage
|
|
22
|
+
|
|
23
|
+
A combobox component that combines input and select functionality with a searchable dropdown menu.
|
|
24
|
+
|
|
25
|
+
#### `<Combobox/>`
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { Combobox } from "@telegraph/combobox";
|
|
29
|
+
import { useState } from "react";
|
|
30
|
+
|
|
31
|
+
// Single select example
|
|
32
|
+
const SingleSelectExample = () => {
|
|
33
|
+
const [value, setValue] = useState<string>("");
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Combobox.Root value={value} onValueChange={setValue}>
|
|
37
|
+
<Combobox.Trigger placeholder="Select an option..." />
|
|
38
|
+
<Combobox.Content>
|
|
39
|
+
<Combobox.Search />
|
|
40
|
+
<Combobox.Options>
|
|
41
|
+
<Combobox.Option value="option1">Option 1</Combobox.Option>
|
|
42
|
+
<Combobox.Option value="option2">Option 2</Combobox.Option>
|
|
43
|
+
</Combobox.Options>
|
|
44
|
+
</Combobox.Content>
|
|
45
|
+
</Combobox.Root>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Multi select example
|
|
50
|
+
const MultiSelectExample = () => {
|
|
51
|
+
const [values, setValues] = useState<string[]>([]);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Combobox.Root value={values} onValueChange={setValues}>
|
|
55
|
+
<Combobox.Trigger placeholder="Select options..." />
|
|
56
|
+
<Combobox.Content>
|
|
57
|
+
<Combobox.Search />
|
|
58
|
+
<Combobox.Options>
|
|
59
|
+
<Combobox.Option value="option1">Option 1</Combobox.Option>
|
|
60
|
+
<Combobox.Option value="option2">Option 2</Combobox.Option>
|
|
61
|
+
</Combobox.Options>
|
|
62
|
+
</Combobox.Content>
|
|
63
|
+
</Combobox.Root>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Type Examples
|
|
69
|
+
|
|
70
|
+
#### Single Select Types
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// String values (recommended)
|
|
74
|
+
const [value, setValue] = useState<string>("");
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### Multi Select Types
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
// String array values (recommended)
|
|
81
|
+
const [values, setValues] = useState<string[]>([]);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Accessibility
|
|
85
|
+
|
|
86
|
+
The combobox implements the [ARIA Combobox Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/), providing:
|
|
87
|
+
|
|
88
|
+
- Proper ARIA roles and attributes
|
|
89
|
+
- Keyboard navigation:
|
|
90
|
+
- `↓` / `↑`: Navigate options
|
|
91
|
+
- `Enter` / `Space`: Select option
|
|
92
|
+
- `Escape`: Close dropdown
|
|
93
|
+
- `Tab`: Move focus
|
|
94
|
+
- Screen reader announcements for selection changes
|
|
95
|
+
- Focus management
|
|
96
|
+
|
|
97
|
+
### Common Patterns
|
|
98
|
+
|
|
99
|
+
#### Form Integration
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { useForm } from "react-hook-form";
|
|
103
|
+
|
|
104
|
+
const MyForm = () => {
|
|
105
|
+
const { register, setValue } = useForm();
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<form>
|
|
109
|
+
<Combobox.Root onValueChange={(value) => setValue("field", value)}>
|
|
110
|
+
{/* ... */}
|
|
111
|
+
</Combobox.Root>
|
|
112
|
+
</form>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Custom Filtering
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
const MyCombobox = () => {
|
|
121
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
122
|
+
const options = useMemo(
|
|
123
|
+
() =>
|
|
124
|
+
allOptions.filter((opt) =>
|
|
125
|
+
opt.toLowerCase().includes(searchQuery.toLowerCase()),
|
|
126
|
+
),
|
|
127
|
+
[searchQuery],
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<Combobox.Root>
|
|
132
|
+
<Combobox.Content>
|
|
133
|
+
<Combobox.Search value={searchQuery} onValueChange={setSearchQuery} />
|
|
134
|
+
<Combobox.Options>
|
|
135
|
+
{options.map((opt) => (
|
|
136
|
+
<Combobox.Option key={opt} value={opt}>
|
|
137
|
+
{opt}
|
|
138
|
+
</Combobox.Option>
|
|
139
|
+
))}
|
|
140
|
+
</Combobox.Options>
|
|
141
|
+
</Combobox.Content>
|
|
142
|
+
</Combobox.Root>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### Async Loading
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
const AsyncCombobox = () => {
|
|
151
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
152
|
+
const [options, setOptions] = useState([]);
|
|
153
|
+
|
|
154
|
+
const loadOptions = async (query) => {
|
|
155
|
+
setIsLoading(true);
|
|
156
|
+
const results = await fetchOptions(query);
|
|
157
|
+
setOptions(results);
|
|
158
|
+
setIsLoading(false);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<Combobox.Root>
|
|
163
|
+
<Combobox.Content>
|
|
164
|
+
<Combobox.Search onValueChange={loadOptions} />
|
|
165
|
+
<Combobox.Options>
|
|
166
|
+
{isLoading ? (
|
|
167
|
+
<Box p="4" textAlign="center">
|
|
168
|
+
Loading...
|
|
169
|
+
</Box>
|
|
170
|
+
) : (
|
|
171
|
+
options.map((opt) => (
|
|
172
|
+
<Combobox.Option key={opt} value={opt}>
|
|
173
|
+
{opt}
|
|
174
|
+
</Combobox.Option>
|
|
175
|
+
))
|
|
176
|
+
)}
|
|
177
|
+
</Combobox.Options>
|
|
178
|
+
</Combobox.Content>
|
|
179
|
+
</Combobox.Root>
|
|
180
|
+
);
|
|
181
|
+
};
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Error States
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
const ErrorCombobox = () => {
|
|
188
|
+
const [error, setError] = useState("");
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<Stack gap="1">
|
|
192
|
+
<Combobox.Root errored={!!error}>{/* ... */}</Combobox.Root>
|
|
193
|
+
{error && (
|
|
194
|
+
<Text color="red" size="1">
|
|
195
|
+
{error}
|
|
196
|
+
</Text>
|
|
197
|
+
)}
|
|
198
|
+
</Stack>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Component Parts
|
|
204
|
+
|
|
205
|
+
#### `<Combobox.Root/>`
|
|
206
|
+
|
|
207
|
+
The root component that manages the state and context for the combobox.
|
|
208
|
+
|
|
209
|
+
##### Props
|
|
210
|
+
|
|
211
|
+
| Name | Type | Default | Description |
|
|
212
|
+
| -------------- | --------------------------------------------------------- | ---------- | ---------------------------------- |
|
|
213
|
+
| value | string \| string[] \| Option \| Option[] | undefined | The selected value(s) |
|
|
214
|
+
| onValueChange | (value: string \| string[] \| Option \| Option[]) => void | undefined | Callback when selection changes |
|
|
215
|
+
| layout | "truncate" \| "wrap" | "truncate" | How to display multiple selections |
|
|
216
|
+
| open | boolean | undefined | Controlled open state |
|
|
217
|
+
| defaultOpen | boolean | false | Initial open state |
|
|
218
|
+
| errored | boolean | false | Shows error styling |
|
|
219
|
+
| placeholder | string | undefined | Placeholder text |
|
|
220
|
+
| onOpenChange | (open: boolean) => void | undefined | Callback when open state changes |
|
|
221
|
+
| modal | boolean | true | Whether to render in a modal |
|
|
222
|
+
| closeOnSelect | boolean | true | Close menu after selection |
|
|
223
|
+
| clearable | boolean | false | Show clear button |
|
|
224
|
+
| disabled | boolean | false | Disable the combobox |
|
|
225
|
+
| legacyBehavior | boolean | false | Use legacy object format |
|
|
226
|
+
|
|
227
|
+
#### `<Combobox.Trigger/>`
|
|
228
|
+
|
|
229
|
+
The button that triggers the combobox dropdown.
|
|
230
|
+
|
|
231
|
+
For advanced customization of the trigger's internal components (indicator, clear button, text display, etc.), see the [Trigger Primitives](#trigger-primitives) section below.
|
|
232
|
+
|
|
233
|
+
##### Props
|
|
234
|
+
|
|
235
|
+
| Name | Type | Default | Description |
|
|
236
|
+
| ----------- | ----------------- | --------- | ---------------------- |
|
|
237
|
+
| size | "1" \| "2" \| "3" | "2" | Size of the trigger |
|
|
238
|
+
| placeholder | string | undefined | Placeholder text |
|
|
239
|
+
| children | ReactNode | undefined | Custom trigger content |
|
|
240
|
+
|
|
241
|
+
#### `<Combobox.Content/>`
|
|
242
|
+
|
|
243
|
+
The dropdown menu content container.
|
|
244
|
+
|
|
245
|
+
##### Props
|
|
246
|
+
|
|
247
|
+
Accepts all props from `TelegraphMenu.Content`
|
|
248
|
+
|
|
249
|
+
#### `<Combobox.Options/>`
|
|
250
|
+
|
|
251
|
+
Container for the option items.
|
|
252
|
+
|
|
253
|
+
##### Props
|
|
254
|
+
|
|
255
|
+
Accepts all props from `Stack` component
|
|
256
|
+
|
|
257
|
+
#### `<Combobox.Option/>`
|
|
258
|
+
|
|
259
|
+
Individual selectable option item.
|
|
260
|
+
|
|
261
|
+
##### Props
|
|
262
|
+
|
|
263
|
+
| Name | Type | Default | Description |
|
|
264
|
+
| -------- | ------- | --------- | -------------------- |
|
|
265
|
+
| value | string | required | Option value |
|
|
266
|
+
| label | string | undefined | Display label |
|
|
267
|
+
| selected | boolean | undefined | Force selected state |
|
|
268
|
+
|
|
269
|
+
#### `<Combobox.Search/>`
|
|
270
|
+
|
|
271
|
+
Search input field for filtering options.
|
|
272
|
+
|
|
273
|
+
##### Props
|
|
274
|
+
|
|
275
|
+
| Name | Type | Default | Description |
|
|
276
|
+
| ----------- | ------ | -------- | ------------------- |
|
|
277
|
+
| label | string | "Search" | Accessibility label |
|
|
278
|
+
| placeholder | string | "Search" | Input placeholder |
|
|
279
|
+
|
|
280
|
+
#### `<Combobox.Empty/>`
|
|
281
|
+
|
|
282
|
+
Empty state component shown when no options match search.
|
|
283
|
+
|
|
284
|
+
##### Props
|
|
285
|
+
|
|
286
|
+
| Name | Type | Default | Description |
|
|
287
|
+
| ------- | ----------------- | ------------------ | ------------------- |
|
|
288
|
+
| icon | IconProps \| null | SearchIcon | Empty state icon |
|
|
289
|
+
| message | string \| null | "No results found" | Empty state message |
|
|
290
|
+
|
|
291
|
+
#### `<Combobox.Create/>`
|
|
292
|
+
|
|
293
|
+
Option to create new values when none match search.
|
|
294
|
+
|
|
295
|
+
##### Props
|
|
296
|
+
|
|
297
|
+
| Name | Type | Default | Description |
|
|
298
|
+
| ----------- | --------------------------------- | --------- | ------------------------ |
|
|
299
|
+
| leadingText | string | "Create" | Text before search value |
|
|
300
|
+
| values | string[] \| Option[] | undefined | Existing values |
|
|
301
|
+
| onCreate | (value: string \| Option) => void | undefined | Creation callback |
|
|
302
|
+
|
|
303
|
+
### Primitives
|
|
304
|
+
|
|
305
|
+
The combobox includes several primitive components for advanced customization. These primitives allow you to build custom trigger layouts and behaviors while maintaining the combobox's core functionality.
|
|
306
|
+
|
|
307
|
+
#### Trigger Primitives
|
|
308
|
+
|
|
309
|
+
##### `<Combobox.Primitives.TriggerIndicator/>`
|
|
310
|
+
|
|
311
|
+
The dropdown chevron icon that rotates based on the combobox's open state.
|
|
312
|
+
|
|
313
|
+
###### Props
|
|
314
|
+
|
|
315
|
+
| Name | Type | Default | Description |
|
|
316
|
+
| ----------- | --------- | ----------- | ----------------------------------- |
|
|
317
|
+
| icon | IconProps | ChevronDown | The icon to display |
|
|
318
|
+
| aria-hidden | boolean | true | Whether to hide from screen readers |
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
<Combobox.Primitives.TriggerIndicator icon={CustomIcon} aria-hidden={false} />
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
##### `<Combobox.Primitives.TriggerClear/>`
|
|
325
|
+
|
|
326
|
+
A button to clear the current selection(s). Only shown when `clearable` is true and there are selections.
|
|
327
|
+
|
|
328
|
+
###### Props
|
|
329
|
+
|
|
330
|
+
| Name | Type | Default | Description |
|
|
331
|
+
| ------------ | ---------------------------------- | --------- | --------------------- |
|
|
332
|
+
| tooltipProps | TgphComponentProps<typeof Tooltip> | undefined | Props for the tooltip |
|
|
333
|
+
|
|
334
|
+
Accepts all props from `Button`
|
|
335
|
+
|
|
336
|
+
```tsx
|
|
337
|
+
<Combobox.Primitives.TriggerClear tooltipProps={{ delay: 300 }} />
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
##### `<Combobox.Primitives.TriggerText/>`
|
|
341
|
+
|
|
342
|
+
Displays the selected value's text or label. Used in single-select mode.
|
|
343
|
+
|
|
344
|
+
###### Props
|
|
345
|
+
|
|
346
|
+
Accepts all props from `Button.Text`
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
<Combobox.Primitives.TriggerText color="blue" weight="medium" />
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
##### `<Combobox.Primitives.TriggerPlaceholder/>`
|
|
353
|
+
|
|
354
|
+
Shows placeholder text when no value is selected.
|
|
355
|
+
|
|
356
|
+
###### Props
|
|
357
|
+
|
|
358
|
+
Accepts all props from `Button.Text`
|
|
359
|
+
|
|
360
|
+
```tsx
|
|
361
|
+
<Combobox.Primitives.TriggerPlaceholder color="gray-8" />
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
##### `<Combobox.Primitives.TriggerTagsContainer/>`
|
|
365
|
+
|
|
366
|
+
Container for selected value tags in multi-select mode. Handles tag layout and truncation.
|
|
367
|
+
|
|
368
|
+
###### Props
|
|
369
|
+
|
|
370
|
+
Accepts all props from `Stack`
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
<Combobox.Primitives.TriggerTagsContainer gap="2" wrap="wrap" />
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
##### `<Combobox.Primitives.TriggerTag/>`
|
|
377
|
+
|
|
378
|
+
A collection of components for building custom tags in multi-select mode:
|
|
379
|
+
|
|
380
|
+
###### `<Combobox.Primitives.TriggerTag.Root/>`
|
|
381
|
+
|
|
382
|
+
The base container for a tag.
|
|
383
|
+
|
|
384
|
+
Props:
|
|
385
|
+
| Name | Type | Default | Description |
|
|
386
|
+
| ---- | ---- | ------- | ----------- |
|
|
387
|
+
| value | string | required | The value this tag represents |
|
|
388
|
+
|
|
389
|
+
###### `<Combobox.Primitives.TriggerTag.Text/>`
|
|
390
|
+
|
|
391
|
+
The text content of a tag.
|
|
392
|
+
|
|
393
|
+
Props: Accepts all props from `Text`
|
|
394
|
+
|
|
395
|
+
###### `<Combobox.Primitives.TriggerTag.Button/>`
|
|
396
|
+
|
|
397
|
+
The remove button for a tag.
|
|
398
|
+
|
|
399
|
+
Props: Accepts all props from `Button`
|
|
400
|
+
|
|
401
|
+
###### `<Combobox.Primitives.TriggerTag.Default/>`
|
|
402
|
+
|
|
403
|
+
A pre-composed tag with text and remove button.
|
|
404
|
+
|
|
405
|
+
Props:
|
|
406
|
+
| Name | Type | Default | Description |
|
|
407
|
+
| ---- | ---- | ------- | ----------- |
|
|
408
|
+
| value | string | required | The value this tag represents |
|
|
409
|
+
|
|
410
|
+
Example of a custom tag layout:
|
|
411
|
+
|
|
412
|
+
```tsx
|
|
413
|
+
<Combobox.Primitives.TriggerTag.Root value="example">
|
|
414
|
+
<Icon icon={CustomIcon} />
|
|
415
|
+
<Combobox.Primitives.TriggerTag.Text>
|
|
416
|
+
Custom Tag
|
|
417
|
+
</Combobox.Primitives.TriggerTag.Text>
|
|
418
|
+
<Combobox.Primitives.TriggerTag.Button
|
|
419
|
+
icon={{ icon: XIcon, alt: "Remove" }}
|
|
420
|
+
/>
|
|
421
|
+
</Combobox.Primitives.TriggerTag.Root>
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Example of using the default tag:
|
|
425
|
+
|
|
426
|
+
```tsx
|
|
427
|
+
<Combobox.Primitives.TriggerTag.Default value="example" />
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Complete example using primitives for a custom trigger layout:
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
<Combobox.Root>
|
|
434
|
+
<Combobox.Trigger>
|
|
435
|
+
<Stack direction="row" justify="space-between" align="center" w="full">
|
|
436
|
+
{/* Left side: Text or Tags */}
|
|
437
|
+
<Box flex="1" overflow="hidden">
|
|
438
|
+
<Combobox.Primitives.TriggerTagsContainer>
|
|
439
|
+
<Combobox.Primitives.TriggerTag.Default value="tag1" />
|
|
440
|
+
<Combobox.Primitives.TriggerTag.Default value="tag2" />
|
|
441
|
+
</Combobox.Primitives.TriggerTagsContainer>
|
|
442
|
+
</Box>
|
|
443
|
+
|
|
444
|
+
{/* Right side: Clear and Indicator */}
|
|
445
|
+
<Stack direction="row" gap="1" align="center">
|
|
446
|
+
<Combobox.Primitives.TriggerClear />
|
|
447
|
+
<Box borderLeft="1" h="4" />
|
|
448
|
+
<Combobox.Primitives.TriggerIndicator />
|
|
449
|
+
</Stack>
|
|
450
|
+
</Stack>
|
|
451
|
+
</Combobox.Trigger>
|
|
452
|
+
<Combobox.Content>{/* ... */}</Combobox.Content>
|
|
453
|
+
</Combobox.Root>
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Legacy Behavior (⚠️ Deprecated)
|
|
457
|
+
|
|
458
|
+
> **Warning**: Legacy behavior is deprecated and will be removed in a future version. New implementations should use string values instead of objects.
|
|
459
|
+
|
|
460
|
+
The `legacyBehavior` prop changes how values are handled:
|
|
461
|
+
|
|
462
|
+
- When `false` (default, recommended): Values are simple strings
|
|
463
|
+
- When `true` (deprecated): Values are objects with `{ value: string; label?: string }`
|
|
464
|
+
|
|
465
|
+
#### Legacy Single Select Types
|
|
466
|
+
|
|
467
|
+
```tsx
|
|
468
|
+
// ⚠️ Deprecated - Don't use in new code
|
|
469
|
+
const [value, setValue] = useState<{ value: string; label?: string }>()
|
|
470
|
+
|
|
471
|
+
<Combobox.Root
|
|
472
|
+
value={value}
|
|
473
|
+
onValueChange={setValue}
|
|
474
|
+
legacyBehavior={true}
|
|
475
|
+
>
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
#### Legacy Multi Select Types
|
|
479
|
+
|
|
480
|
+
```tsx
|
|
481
|
+
// ⚠️ Deprecated - Don't use in new code
|
|
482
|
+
const [values, setValues] = useState<Array<{ value: string; label?: string }>>([])
|
|
483
|
+
|
|
484
|
+
<Combobox.Root
|
|
485
|
+
value={values}
|
|
486
|
+
onValueChange={setValues}
|
|
487
|
+
legacyBehavior={true}
|
|
488
|
+
>
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
This object-based value pattern is only maintained for backwards compatibility and should not be used in new code. It will be removed in a future major version.
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),G=require("@radix-ui/react-dismissable-layer"),Y=require("@radix-ui/react-portal"),U=require("@radix-ui/react-use-controllable-state"),X=require("@radix-ui/react-visually-hidden"),T=require("@telegraph/button"),V=require("@telegraph/compose-refs"),W=require("@telegraph/helpers"),C=require("@telegraph/icon"),J=require("@telegraph/input"),j=require("@telegraph/layout"),I=require("@telegraph/menu"),w=require("@telegraph/motion"),P=require("@telegraph/tag"),Z=require("@telegraph/tooltip"),Q=require("@telegraph/typography"),l=require("react");function M(e){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const o in e)if(o!=="default"){const t=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(r,o,t.get?t:{enumerable:!0,get:()=>e[o]})}}return r.default=e,Object.freeze(r)}const ee=M(Y),te=M(X),ne={0:"5",1:"6",2:"8",3:"10"},k=e=>Array.isArray(e),E=e=>typeof e=="object"&&!Array.isArray(e)||typeof e=="string"||!e,oe=e=>{const r=(n,u=[])=>(l.Children.toArray(n).forEach(a=>{l.isValidElement(a)&&(a.props.value?u.push(a):a.props.children&&r(a.props.children,u))}),u);return r(e).map(n=>{var i;const u=n;return{value:u.props.value,label:((i=u.props)==null?void 0:i.label)||u.props.children||u.props.value}})},S=(e,r)=>{if(e)return r===!0?e==null?void 0:e.value:e},D=(e,r,o)=>{if(!e||!r||r.length===0)return;const t=r.find(n=>n.value===S(e,o));if(t)return t},re=({children:e,value:r,searchQuery:o})=>{const t=F(e);return(r==null?void 0:r.toLowerCase().includes(o.toLowerCase()))||t.some(n=>n.toLowerCase().includes(o.toLowerCase()))},F=e=>{const r=l.Children.toArray(e),o=[];return r.forEach(t=>{typeof t=="string"&&o.push(t),l.isValidElement(t)&&t.props.children&&o.push(...F(t.props.children))}),o},ae=["ArrowDown","PageUp","Home"],se=["ArrowUp","PageDown","End"],H=["Enter"," "],v=l.createContext({value:void 0,onValueChange:()=>{},contentId:"",triggerId:"",open:!1,setOpen:()=>{},onOpenToggle:()=>{},clearable:!1,disabled:!1,options:[],legacyBehavior:!1}),ie=({modal:e=!0,closeOnSelect:r=!0,clearable:o=!1,disabled:t=!1,legacyBehavior:n=!1,open:u,onOpenChange:i,defaultOpen:a,value:s,onValueChange:f,errored:g,placeholder:x,layout:y,children:p,...d})=>{const m=l.useId(),b=l.useId(),h=l.useRef(null),R=l.useRef(null),A=l.useRef(null),L=l.useMemo(()=>oe(p),[p]),[N,q]=l.useState(""),[O=!1,B]=U.useControllableState({prop:u,defaultProp:a,onChange:i}),z=l.useCallback(()=>{B($=>!$)},[B]);return l.useEffect(()=>{O||q("")},[O]),c.jsx(v.Provider,{value:{contentId:m,triggerId:b,value:s,onValueChange:f,placeholder:x,open:O,setOpen:B,onOpenToggle:z,closeOnSelect:r,clearable:o,disabled:t,searchQuery:N,setSearchQuery:q,triggerRef:h,searchRef:R,contentRef:A,errored:g,layout:y,options:L,legacyBehavior:n},children:c.jsx(I.Menu.Root,{open:O,onOpenChange:B,modal:e,...d,children:p})})},ce=({value:e,...r})=>{const o=l.useContext(v),t=l.useMemo(()=>{const n=o.options.find(a=>a.value===e);if(n)return n.label||n.value;if(!o.value)return;const i=o.value.find(a=>S(a,o.legacyBehavior)===e);if(i)return i},[o.options,o.value,e,o.legacyBehavior]);return c.jsxs(P.Tag.Root,{as:w.motion.span,initializeWithAnimation:!1,initial:{opacity:0,scale:.5},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.5},transition:{duration:100,type:"spring"},"tgph-motion-key":e,size:"1",layout:"position",...r,children:[c.jsx(P.Tag.Text,{children:t}),c.jsx(P.Tag.Button,{icon:{icon:C.Lucide.X,alt:`Remove ${e}`},onClick:n=>{if(!o.onValueChange)return;const u=o.onValueChange,a=o.value.filter(s=>S(s,o.legacyBehavior)!==e);u==null||u(a),n.stopPropagation(),n.preventDefault()}})]})},le=()=>{var r;const e=l.useContext(v);if(e.value&&k(e.value)){const o=e.layout||"truncate",t=e.value.length-2,n=t.toString().split("");return e.value.length===0?c.jsx(T.Button.Text,{color:"gray",children:e.placeholder}):c.jsxs(j.Stack,{gap:"1",w:"full",wrap:o==="wrap"?"wrap":"nowrap",align:"center",style:{position:"relative",flexGrow:1},children:[c.jsx(w.AnimatePresence,{presenceMap:e.value.map(u=>({"tgph-motion-key":S(u,e.legacyBehavior)||"",value:!0})),children:e.value.map((u,i)=>{const a=S(u,e.legacyBehavior);if(a&&(o==="truncate"&&i<=1||o==="wrap"))return c.jsx(W.RefToTgphRef,{children:c.jsx(ce,{value:a})},a)})}),c.jsx(w.AnimatePresence,{presenceMap:[{"tgph-motion-key":"combobox-more",value:!0}],children:o==="truncate"&&e.value.length>2&&c.jsx(j.Stack,{as:w.motion.div,initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:100,type:"spring"},h:"full",pr:"1",pl:"8",align:"center","aria-label":`${t} more selected`,position:"absolute",right:"0",style:{backgroundImage:"linear-gradient(to left, var(--tgph-surface-1) 0 60%, transparent 90% 100%)"},children:c.jsxs(Q.Text,{as:"span",size:"1",style:{whiteSpace:"nowrap"},children:["+",c.jsxs(w.AnimatePresence,{presenceMap:n.map(u=>({"tgph-motion-key":u,value:!0})),children:[n.map(u=>c.jsx(j.Box,{as:w.motion.span,initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:100,type:"spring"},w:"2",display:"inline-block","tgph-motion-key":u,children:u},u))," "]}),"more"]})})})]})}if(e&&E(e.value)){const o=D(e.value,e.options,e.legacyBehavior),t=(o==null?void 0:o.label)||(o==null?void 0:o.value)||e.placeholder,n=e.legacyBehavior&&((r=e==null?void 0:e.value)==null?void 0:r.label);return c.jsx(T.Button.Text,{color:e.value?"default":"gray",textOverflow:"ellipsis",overflow:"hidden",children:n||t})}},ue=({size:e="2",children:r,...o})=>{const t=l.useContext(v),n=l.useMemo(()=>{if(t.value){if(E(t.value))return D(t.value,t.options,t.legacyBehavior);if(k(t.value))return t.value.map(s=>D(s,t.options,t.legacyBehavior))}},[t.value,t.options,t.legacyBehavior]),u=l.useCallback(()=>n?E(n)?(n==null?void 0:n.label)||(n==null?void 0:n.value)||t.placeholder:k(n)&&n.map(s=>(s==null?void 0:s.label)||(s==null?void 0:s.value)).join(", ")||t.placeholder:t.placeholder,[n,t.placeholder]),i=l.useMemo(()=>{var s;if(E(t.value))return t.clearable&&t.value;if(k(t.value))return t.clearable&&((s=t.value)==null?void 0:s.length)>0},[t.clearable,t.value]),a=()=>{var s,f;if(k(t.value)){const g=t.onValueChange;g==null||g([])}if(E(t.value)){const g=t.onValueChange;g==null||g(void 0)}(f=(s=t.triggerRef)==null?void 0:s.current)==null||f.focus()};return c.jsx(I.Menu.Trigger,{...o,asChild:!0,onClick:s=>{var f,g;s.preventDefault(),t.onOpenToggle(),(g=(f=t.triggerRef)==null?void 0:f.current)==null||g.focus()},onKeyDown:s=>{if(s.key==="Tab"){s.stopPropagation();return}if(H.includes(s.key)){s.preventDefault();return}if(s.key==="ArrowDown"){s.stopPropagation(),s.preventDefault(),t.onOpenToggle();return}},tgphRef:t.triggerRef,children:c.jsxs(T.Button.Root,{id:t.triggerId,type:"button",bg:"surface-1",variant:"outline",align:"center",minH:ne[e],h:"full",w:"full",py:"1",size:e,color:t.errored?"red":"gray",justify:"space-between",role:"combobox","aria-label":u(),"aria-controls":t.contentId,"aria-expanded":t.open,"aria-haspopup":"listbox","data-tgph-combobox-trigger":!0,"data-tgph-combobox-trigger-open":t.open,disabled:t.disabled,...o,children:[r?typeof r=="function"?r({value:n}):r:c.jsx(le,{}),c.jsxs(j.Stack,{align:"center",gap:"1",children:[i&&c.jsx(Z.Tooltip,{label:"Clear field",children:c.jsx(T.Button,{type:"button",icon:{icon:C.Lucide.X,alt:"Clear field"},size:"1",variant:"ghost",onClick:s=>{t.value&&(s.stopPropagation(),a())},onKeyDown:s=>{(s.key==="Enter"||s.key===" ")&&(s.stopPropagation(),a())},"data-tgph-combobox-clear":!0,style:{marginTop:"calc(-1 * var(--tgph-spacing-1)",marginBottom:"calc(-1 * var(--tgph-spacing-1)"}})}),c.jsx(T.Button.Icon,{as:w.motion.span,animate:{rotate:t.open?180:0},transition:{duration:150,type:"spring"},icon:C.Lucide.ChevronDown,"aria-hidden":!0})]})]})})},pe=({style:e,children:r,tgphRef:o,...t})=>{const n=l.useContext(v),u=l.useRef(!1),i=V.useComposedRefs(o,n.contentRef),a=l.useRef(null),[s,f]=l.useState(0),[g,x]=l.useState(!1),y=l.useCallback(p=>{const d=p==null?void 0:p.getBoundingClientRect();d&&f(d.height),g||x(!0)},[g]);return l.useEffect(()=>{const p=new ResizeObserver(d=>{for(const m of d){const b=m.target;y(b)}});return a.current&&g&&p.observe(a.current),()=>p.disconnect()},[g,y]),l.useEffect(()=>{g===!0&&n.open===!1&&x(!1)},[n.open,g]),l.useEffect(()=>{let p;return n.open&&(p=setTimeout(()=>{y(a.current)},10)),()=>p&&clearTimeout(p)},[n.open,y]),c.jsx(ee.Root,{asChild:!0,children:c.jsx(G.DismissableLayer,{onEscapeKeyDown:p=>{n.open&&(p.stopPropagation(),p.preventDefault(),n.setOpen(!1))},children:c.jsx(I.Menu.Content,{className:"tgph",mt:"1",onCloseAutoFocus:p=>{var d,m;u.current||(m=(d=n.triggerRef)==null?void 0:d.current)==null||m.focus(),u.current=!1,p.preventDefault()},bg:"surface-1",style:{width:"var(--tgph-combobox-trigger-width)",transition:"min-height 200ms ease-in-out",minHeight:s?`${s}px`:"0",...e,"--tgph-combobox-content-transform-origin":"var(--radix-popper-transform-origin)","--tgph-combobox-content-available-width":"var(--radix-popper-available-width)","--tgph-combobox-content-available-height":"calc(var(--radix-popper-available-height) - var(--tgph-spacing-8))","--tgph-combobox-trigger-width":"var(--radix-popper-anchor-width)","--tgph-combobox-trigger-height":"var(--radix-popper-anchor-height)"},...t,tgphRef:i,"data-tgph-combobox-content":!0,"data-tgph-combobox-content-open":n.open,role:void 0,"aria-orientation":void 0,onKeyDown:p=>{var m,b,h,R;p.stopPropagation();const d=(b=(m=n.contentRef)==null?void 0:m.current)==null?void 0:b.querySelectorAll("[data-tgph-combobox-option]");document.activeElement===(d==null?void 0:d[0])&&se.includes(p.key)&&((R=(h=n.searchRef)==null?void 0:h.current)==null||R.focus())},children:c.jsx(j.Stack,{direction:"column",gap:"1",tgphRef:a,children:r})})})})},fe=({...e})=>{const r=l.useContext(v);return c.jsx(j.Stack,{id:r.contentId,direction:"column",gap:"1",style:{overflowY:"auto","--max-height":e.maxHeight?void 0:"calc(var(--tgph-combobox-content-available-height) - var(--tgph-spacing-12))"},role:"listbox",...e})},_=({value:e,label:r,selected:o,onSelect:t,children:n,...u})=>{const i=l.useContext(v),[a,s]=l.useState(!1),f=i.value,g=!i.searchQuery||re({children:r||n,value:e,searchQuery:i.searchQuery}),x=k(f)?f.some(p=>S(p,i.legacyBehavior)===e):S(f,i.legacyBehavior)===e,y=p=>{var m,b;p.stopPropagation();const d=p;if(!(d.key&&!H.includes(d.key))){if(p.preventDefault(),i.closeOnSelect===!0&&i.setOpen(!1),t)return t(p);if(E(f)){const h=i.onValueChange;i.legacyBehavior===!0?h==null||h({value:e,label:r}):h==null||h(e)}else if(k(f)){const h=i.onValueChange,R=i.value,A=x?R.filter(L=>S(L,i.legacyBehavior)!==e):[...R,i.legacyBehavior===!0?{value:e,label:r}:e];h==null||h(A)}(b=(m=i.triggerRef)==null?void 0:m.current)==null||b.focus()}};if(g)return c.jsx(I.Menu.Button,{type:"button",onSelect:y,onKeyDown:y,selected:o===null?null:o??x,onFocus:()=>s(!0),onBlur:()=>s(!1),role:"option","aria-selected":x?"true":"false","data-tgph-combobox-option":!0,"data-tgph-combobox-option-focused":a,"data-tgph-combobox-option-value":e,"data-tgph-combobox-option-label":r,...u,children:r||n||e})},ge=({label:e="Search",placeholder:r="Search",tgphRef:o,value:t,onValueChange:n,...u})=>{var x;const i=l.useId(),a=l.useContext(v),s=V.useComposedRefs(o,a.searchRef),f=t??a.searchQuery,g=n??a.setSearchQuery;return l.useEffect(()=>{var d;const y=m=>{var b,h;ae.includes(m.key)&&((h=(b=a.contentRef)==null?void 0:b.current)==null||h.focus({preventScroll:!0})),m.key==="Escape"&&a.setOpen(!1),m.stopPropagation()},p=(d=a.searchRef)==null?void 0:d.current;if(p)return p.addEventListener("keydown",y),()=>{p.removeEventListener("keydown",y)}},[a]),c.jsxs(j.Box,{borderBottom:"px",px:"1",pb:"1",children:[c.jsx(te.Root,{children:c.jsx(Q.Text,{as:"label",htmlFor:i,children:e})}),c.jsx(J.Input,{id:i,variant:"ghost",placeholder:r,value:f,onChange:y=>{g(y.target.value)},LeadingComponent:c.jsx(C.Icon,{icon:C.Lucide.Search,alt:"Search Icon"}),TrailingComponent:a!=null&&a.searchQuery&&((x=a==null?void 0:a.searchQuery)==null?void 0:x.length)>0?c.jsx(T.Button,{variant:"ghost",color:"gray",icon:{icon:C.Lucide.X,alt:"Clear Search Query"},onClick:()=>{var y;return(y=a.setSearchQuery)==null?void 0:y.call(a,"")}}):null,autoFocus:!0,"data-tgph-combobox-search":!0,"aria-controls":a.contentId,...u,tgphRef:s})]})},de=({icon:e={icon:C.Lucide.Search,alt:"Search Icon"},message:r="No results found",children:o,...t})=>{const n=l.useContext(v),[u,i]=l.useState(!1);if(l.useEffect(()=>{var s,f;const a=(f=(s=n.contentRef)==null?void 0:s.current)==null?void 0:f.querySelectorAll("[data-tgph-combobox-option]");(a==null?void 0:a.length)===0?i(!0):i(!1)},[n.searchQuery,n.contentRef,o]),u)return c.jsxs(j.Stack,{gap:"1",align:"center",justify:"center",w:"full",my:"8","data-tgph-combobox-empty":!0,...t,children:[e===null?c.jsx(c.Fragment,{}):c.jsx(C.Icon,{...e}),r===null?c.jsx(c.Fragment,{}):c.jsx(Q.Text,{as:"span",children:r})]})},he=({leadingText:e="Create",values:r,onCreate:o,selected:t=null,legacyBehavior:n=!1,...u})=>{const i=l.useContext(v),a=l.useCallback(s=>!r||(r==null?void 0:r.length)===0?!1:r.some(f=>S(f,n)===s),[r,n]);if(i.searchQuery&&!a(i.searchQuery))return c.jsx(_,{leadingIcon:{icon:C.Lucide.Plus,"aria-hidden":!0},mx:"1",value:i.searchQuery,label:`${e} "${i.searchQuery}"`,selected:t,onSelect:()=>{var s;if(o&&i.value&&i.searchQuery){const f=n===!0?{value:i.searchQuery}:i.searchQuery;o(f),(s=i.setSearchQuery)==null||s.call(i,"")}},...u})},K={};Object.assign(K,{Root:ie,Trigger:ue,Content:pe,Options:fe,Option:_,Search:ge,Empty:de,Create:he});exports.Combobox=K;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),X=require("@radix-ui/react-dismissable-layer"),W=require("@radix-ui/react-portal"),J=require("@radix-ui/react-use-controllable-state"),Z=require("@radix-ui/react-visually-hidden"),B=require("@telegraph/button"),H=require("@telegraph/compose-refs"),ee=require("@telegraph/helpers"),C=require("@telegraph/icon"),te=require("@telegraph/input"),S=require("@telegraph/layout"),A=require("@telegraph/menu"),q=require("@telegraph/typography"),l=require("react"),k=require("@telegraph/motion"),M=require("@telegraph/tag"),ne=require("@telegraph/tooltip");function _(t){const n=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const e in t)if(e!=="default"){const o=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(n,e,o.get?o:{enumerable:!0,get:()=>t[e]})}}return n.default=t,Object.freeze(n)}const oe=_(W),re=_(Z),ae={0:"5",1:"6",2:"8",3:"10"},R=t=>Array.isArray(t),E=t=>typeof t=="object"&&!Array.isArray(t)||typeof t=="string"||!t,se=t=>{const n=(a,i=[])=>(l.Children.toArray(a).forEach(s=>{l.isValidElement(s)&&(s.props.value?i.push(s):s.props.children&&n(s.props.children,i))}),i);return n(t).map(a=>{var r;const i=a;return{value:i.props.value,label:((r=i.props)==null?void 0:r.label)||i.props.children||i.props.value}})},T=(t,n)=>{if(t)return n===!0?t==null?void 0:t.value:t},Q=(t,n,e)=>{if(!t||!n||n.length===0)return;const o=n.find(a=>a.value===T(t,e));if(o)return o},ie=({children:t,value:n,searchQuery:e})=>{const o=K(t);return(n==null?void 0:n.toLowerCase().includes(e.toLowerCase()))||o.some(a=>a.toLowerCase().includes(e.toLowerCase()))},K=t=>{const n=l.Children.toArray(t),e=[];return n.forEach(o=>{typeof o=="string"&&e.push(o),l.isValidElement(o)&&o.props.children&&e.push(...K(o.props.children))}),e},ce=({icon:t=C.Lucide.ChevronDown,"aria-hidden":n=!0,...e})=>{const o=l.useContext(y);return c.jsx(B.Button.Icon,{as:k.motion.span,animate:{rotate:o.open?180:0},transition:{duration:150,type:"spring"},icon:t,"aria-hidden":n,...e})},le=({tooltipProps:t,...n})=>{const e=l.useContext(y),o=()=>{var i,r;if(R(e.value)){const s=e.onValueChange;s==null||s([])}if(E(e.value)){const s=e.onValueChange;s==null||s(void 0)}(r=(i=e.triggerRef)==null?void 0:i.current)==null||r.focus()};return l.useMemo(()=>{var i;if(E(e.value))return e.clearable&&e.value;if(R(e.value))return e.clearable&&((i=e.value)==null?void 0:i.length)>0},[e.clearable,e.value])?c.jsx(ne.Tooltip,{label:"Clear field",...t,children:c.jsx(B.Button,{type:"button",icon:{icon:C.Lucide.X,alt:"Clear field"},size:"1",variant:"ghost",onClick:i=>{e.value&&(i.stopPropagation(),o())},onKeyDown:i=>{(i.key==="Enter"||i.key===" ")&&(i.stopPropagation(),o())},"data-tgph-combobox-clear":!0,style:{marginTop:"calc(-1 * var(--tgph-spacing-1)",marginBottom:"calc(-1 * var(--tgph-spacing-1)"},...n})}):null},ue=({children:t,...n})=>{const e=l.useContext(y),o=l.useMemo(()=>{var s;if(!E(e.value))return;const a=Q(e.value,e.options,e.legacyBehavior),i=(a==null?void 0:a.label)||(a==null?void 0:a.value)||e.placeholder,r=e.legacyBehavior&&((s=e==null?void 0:e.value)==null?void 0:s.label);return r||i},[e.value,e.options,e.legacyBehavior,e.placeholder]);return c.jsx(B.Button.Text,{color:e.value?"default":"gray",textOverflow:"ellipsis",overflow:"hidden",...n,children:t||o})},pe=({children:t,...n})=>{const e=l.useContext(y);return c.jsx(B.Button.Text,{color:"gray",...n,children:t||e.placeholder})},ge=({children:t})=>{const n=l.useContext(y);if(!R(n.value))return null;const e=n.layout||"truncate",a=(n.value.length-2).toString().split("");return c.jsxs(S.Stack,{gap:"1",w:"full",wrap:e==="wrap"?"wrap":"nowrap",align:"center",style:{position:"relative",flexGrow:1},children:[c.jsx(k.AnimatePresence,{presenceMap:n.value.map(i=>({"tgph-motion-key":T(i,n.legacyBehavior)||"",value:!0})),children:t}),c.jsx(k.AnimatePresence,{presenceMap:[{"tgph-motion-key":"combobox-more",value:!0}],children:e==="truncate"&&n.value.length>2&&c.jsx(S.Stack,{as:k.motion.div,initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:100,type:"spring"},h:"full",pr:"1",pl:"8",align:"center","aria-label":`${n.value.length-2} more selected`,position:"absolute",right:"0",style:{backgroundImage:"linear-gradient(to left, var(--tgph-surface-1) 0 60%, transparent 90% 100%)"},children:c.jsxs(q.Text,{as:"span",size:"1",style:{whiteSpace:"nowrap"},children:["+",c.jsxs(k.AnimatePresence,{presenceMap:a.map(i=>({"tgph-motion-key":i,value:!0})),children:[a.map(i=>c.jsx(S.Box,{as:k.motion.span,initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:100,type:"spring"},w:"2",display:"inline-block","tgph-motion-key":i,children:i},i))," "]}),"more"]})})})]})},V=l.createContext({value:""}),de=({value:t,children:n,...e})=>c.jsx(V.Provider,{value:{value:t},children:c.jsx(M.Tag.Root,{as:k.motion.span,initializeWithAnimation:!1,initial:{opacity:0,scale:.5},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.5},transition:{duration:100,type:"spring"},"tgph-motion-key":t,size:"1",layout:"position",...e,children:n})}),fe=({children:t,...n})=>{const e=l.useContext(y),o=l.useContext(V),a=l.useMemo(()=>{const i=e.options.find(p=>p.value===o.value);if(i)return i.label||i.value;if(!e.value)return;const s=e.value.find(p=>T(p,e.legacyBehavior)===o.value);if(s)return s},[e.options,e.value,o.value,e.legacyBehavior]);return c.jsx(M.Tag.Text,{...n,children:t||a})},he=({children:t,...n})=>{const e=l.useContext(y),o=l.useContext(V);return c.jsx(M.Tag.Button,{icon:{icon:C.Lucide.X,alt:`Remove ${o.value}`},onClick:a=>{if(!e.onValueChange)return;const i=e.onValueChange,s=e.value.filter(p=>T(p,e.legacyBehavior)!==o.value);i==null||i(s),a.stopPropagation(),a.preventDefault()},...n,children:t})},xe=({value:t,children:n,...e})=>c.jsxs(P.Root,{value:t,...e,children:[c.jsx(P.Text,{children:n}),c.jsx(P.Button,{})]}),P={Root:de,Text:fe,Button:he,Default:xe},j={TriggerIndicator:ce,TriggerClear:le,TriggerText:ue,TriggerPlaceholder:pe,TriggerTagsContainer:ge,TriggerTag:P},ye=["ArrowDown","PageUp","Home"],me=["ArrowUp","PageDown","End"],N=["Enter"," "],y=l.createContext({value:void 0,onValueChange:()=>{},contentId:"",triggerId:"",open:!1,setOpen:()=>{},onOpenToggle:()=>{},clearable:!1,disabled:!1,options:[],legacyBehavior:!1}),be=({modal:t=!0,closeOnSelect:n=!0,clearable:e=!1,disabled:o=!1,legacyBehavior:a=!1,open:i,onOpenChange:r,defaultOpen:s,value:p,onValueChange:g,errored:m,placeholder:v,layout:h,children:u,...d})=>{const x=l.useId(),b=l.useId(),f=l.useRef(null),w=l.useRef(null),D=l.useRef(null),L=l.useMemo(()=>se(u),[u]),[G,F]=l.useState(""),[O=!1,I]=J.useControllableState({prop:i,defaultProp:s,onChange:r}),Y=l.useCallback(()=>{I(U=>!U)},[I]);return l.useEffect(()=>{O||F("")},[O]),c.jsx(y.Provider,{value:{contentId:x,triggerId:b,value:p,onValueChange:g,placeholder:v,open:O,setOpen:I,onOpenToggle:Y,closeOnSelect:n,clearable:e,disabled:o,searchQuery:G,setSearchQuery:F,triggerRef:f,searchRef:w,contentRef:D,errored:m,layout:h,options:L,legacyBehavior:a},children:c.jsx(A.Menu.Root,{open:O,onOpenChange:I,modal:t,...d,children:u})})},ve=()=>{const t=l.useContext(y);if(t.value&&R(t.value)){const n=t.layout||"truncate";return t.value.length===0?c.jsx(j.TriggerPlaceholder,{}):c.jsx(j.TriggerTagsContainer,{children:t.value.map((e,o)=>{const a=T(e,t.legacyBehavior);if(a&&(n==="truncate"&&o<=1||n==="wrap"))return c.jsx(ee.RefToTgphRef,{children:c.jsx(j.TriggerTag.Default,{value:a})},a)})})}if(t&&E(t.value))return t.value?c.jsx(j.TriggerText,{}):c.jsx(j.TriggerPlaceholder,{})},Ce=({size:t="2",children:n,...e})=>{const o=l.useContext(y),a=l.useMemo(()=>{if(o.value){if(E(o.value))return Q(o.value,o.options,o.legacyBehavior);if(R(o.value))return o.value.map(r=>Q(r,o.options,o.legacyBehavior))}},[o.value,o.options,o.legacyBehavior]),i=l.useCallback(()=>a?E(a)?(a==null?void 0:a.label)||(a==null?void 0:a.value)||o.placeholder:R(a)&&a.map(r=>(r==null?void 0:r.label)||(r==null?void 0:r.value)).join(", ")||o.placeholder:o.placeholder,[a,o.placeholder]);return c.jsx(A.Menu.Trigger,{...e,asChild:!0,onClick:r=>{var s,p;r.preventDefault(),o.onOpenToggle(),(p=(s=o.triggerRef)==null?void 0:s.current)==null||p.focus()},onKeyDown:r=>{if(r.key==="Tab"){r.stopPropagation();return}if(N.includes(r.key)){r.preventDefault();return}if(r.key==="ArrowDown"){r.stopPropagation(),r.preventDefault(),o.onOpenToggle();return}},tgphRef:o.triggerRef,children:c.jsxs(B.Button.Root,{id:o.triggerId,type:"button",bg:"surface-1",variant:"outline",align:"center",minH:ae[t],h:"full",w:"full",py:"1",size:t,color:o.errored?"red":"gray",justify:"space-between",role:"combobox","aria-label":i(),"aria-controls":o.contentId,"aria-expanded":o.open,"aria-haspopup":"listbox","data-tgph-combobox-trigger":!0,"data-tgph-combobox-trigger-open":o.open,disabled:o.disabled,...e,children:[n?typeof n=="function"?n({value:a}):n:c.jsx(ve,{}),c.jsxs(S.Stack,{align:"center",gap:"1",children:[c.jsx(j.TriggerClear,{}),c.jsx(j.TriggerIndicator,{})]})]})})},Te=({style:t,children:n,tgphRef:e,...o})=>{const a=l.useContext(y),i=l.useRef(!1),r=H.useComposedRefs(e,a.contentRef),s=l.useRef(null),[p,g]=l.useState(0),[m,v]=l.useState(!1),h=l.useCallback(u=>{const d=u==null?void 0:u.getBoundingClientRect();d&&g(d.height),m||v(!0)},[m]);return l.useEffect(()=>{const u=new ResizeObserver(d=>{for(const x of d){const b=x.target;h(b)}});return s.current&&m&&u.observe(s.current),()=>u.disconnect()},[m,h]),l.useEffect(()=>{m===!0&&a.open===!1&&v(!1)},[a.open,m]),l.useEffect(()=>{let u;return a.open&&(u=setTimeout(()=>{h(s.current)},10)),()=>u&&clearTimeout(u)},[a.open,h]),c.jsx(oe.Root,{asChild:!0,children:c.jsx(X.DismissableLayer,{onEscapeKeyDown:u=>{a.open&&(u.stopPropagation(),u.preventDefault(),a.setOpen(!1))},children:c.jsx(A.Menu.Content,{className:"tgph",mt:"1",onCloseAutoFocus:u=>{var d,x;i.current||(x=(d=a.triggerRef)==null?void 0:d.current)==null||x.focus(),i.current=!1,u.preventDefault()},bg:"surface-1",style:{width:"var(--tgph-combobox-trigger-width)",transition:"min-height 200ms ease-in-out",minHeight:p?`${p}px`:"0",...t,"--tgph-combobox-content-transform-origin":"var(--radix-popper-transform-origin)","--tgph-combobox-content-available-width":"var(--radix-popper-available-width)","--tgph-combobox-content-available-height":"calc(var(--radix-popper-available-height) - var(--tgph-spacing-8))","--tgph-combobox-trigger-width":"var(--radix-popper-anchor-width)","--tgph-combobox-trigger-height":"var(--radix-popper-anchor-height)"},...o,tgphRef:r,"data-tgph-combobox-content":!0,"data-tgph-combobox-content-open":a.open,role:void 0,"aria-orientation":void 0,onKeyDown:u=>{var x,b,f,w;u.stopPropagation();const d=(b=(x=a.contentRef)==null?void 0:x.current)==null?void 0:b.querySelectorAll("[data-tgph-combobox-option]");document.activeElement===(d==null?void 0:d[0])&&me.includes(u.key)&&((w=(f=a.searchRef)==null?void 0:f.current)==null||w.focus())},children:c.jsx(S.Stack,{direction:"column",gap:"1",tgphRef:s,children:n})})})})},je=({...t})=>{const n=l.useContext(y);return c.jsx(S.Stack,{id:n.contentId,direction:"column",gap:"1",style:{overflowY:"auto","--max-height":t.maxHeight?void 0:"calc(var(--tgph-combobox-content-available-height) - var(--tgph-spacing-12))"},role:"listbox",...t})},z=({value:t,label:n,selected:e,onSelect:o,children:a,...i})=>{const r=l.useContext(y),[s,p]=l.useState(!1),g=r.value,m=!r.searchQuery||ie({children:n||a,value:t,searchQuery:r.searchQuery}),v=R(g)?g.some(u=>T(u,r.legacyBehavior)===t):T(g,r.legacyBehavior)===t,h=u=>{var x,b;u.stopPropagation();const d=u;if(!(d.key&&!N.includes(d.key))){if(u.preventDefault(),r.closeOnSelect===!0&&r.setOpen(!1),o)return o(u);if(E(g)){const f=r.onValueChange;r.legacyBehavior===!0?f==null||f({value:t,label:n}):f==null||f(t)}else if(R(g)){const f=r.onValueChange,w=r.value,D=v?w.filter(L=>T(L,r.legacyBehavior)!==t):[...w,r.legacyBehavior===!0?{value:t,label:n}:t];f==null||f(D)}(b=(x=r.triggerRef)==null?void 0:x.current)==null||b.focus()}};if(m)return c.jsx(A.Menu.Button,{type:"button",onSelect:h,onKeyDown:h,selected:e===null?null:e??v,onFocus:()=>p(!0),onBlur:()=>p(!1),role:"option","aria-selected":v?"true":"false","data-tgph-combobox-option":!0,"data-tgph-combobox-option-focused":s,"data-tgph-combobox-option-value":t,"data-tgph-combobox-option-label":n,...i,children:n||a||t})},Se=({label:t="Search",placeholder:n="Search",tgphRef:e,value:o,onValueChange:a,...i})=>{var v;const r=l.useId(),s=l.useContext(y),p=H.useComposedRefs(e,s.searchRef),g=o??s.searchQuery,m=a??s.setSearchQuery;return l.useEffect(()=>{var d;const h=x=>{var b,f;ye.includes(x.key)&&((f=(b=s.contentRef)==null?void 0:b.current)==null||f.focus({preventScroll:!0})),x.key==="Escape"&&s.setOpen(!1),x.stopPropagation()},u=(d=s.searchRef)==null?void 0:d.current;if(u)return u.addEventListener("keydown",h),()=>{u.removeEventListener("keydown",h)}},[s]),c.jsxs(S.Box,{borderBottom:"px",px:"1",pb:"1",children:[c.jsx(re.Root,{children:c.jsx(q.Text,{as:"label",htmlFor:r,children:t})}),c.jsx(te.Input,{id:r,variant:"ghost",placeholder:n,value:g,onChange:h=>{m(h.target.value)},LeadingComponent:c.jsx(C.Icon,{icon:C.Lucide.Search,alt:"Search Icon"}),TrailingComponent:s!=null&&s.searchQuery&&((v=s==null?void 0:s.searchQuery)==null?void 0:v.length)>0?c.jsx(B.Button,{variant:"ghost",color:"gray",icon:{icon:C.Lucide.X,alt:"Clear Search Query"},onClick:()=>{var h;return(h=s.setSearchQuery)==null?void 0:h.call(s,"")}}):null,autoFocus:!0,"data-tgph-combobox-search":!0,"aria-controls":s.contentId,...i,tgphRef:p})]})},Re=({icon:t={icon:C.Lucide.Search,alt:"Search Icon"},message:n="No results found",children:e,...o})=>{const a=l.useContext(y),[i,r]=l.useState(!1);if(l.useEffect(()=>{var p,g;const s=(g=(p=a.contentRef)==null?void 0:p.current)==null?void 0:g.querySelectorAll("[data-tgph-combobox-option]");(s==null?void 0:s.length)===0?r(!0):r(!1)},[a.searchQuery,a.contentRef,e]),i)return c.jsxs(S.Stack,{gap:"1",align:"center",justify:"center",w:"full",my:"8","data-tgph-combobox-empty":!0,...o,children:[t===null?c.jsx(c.Fragment,{}):c.jsx(C.Icon,{...t}),n===null?c.jsx(c.Fragment,{}):c.jsx(q.Text,{as:"span",children:n})]})},we=({leadingText:t="Create",values:n,onCreate:e,selected:o=null,legacyBehavior:a=!1,...i})=>{const r=l.useContext(y),s=l.useCallback(p=>!n||(n==null?void 0:n.length)===0?!1:n.some(g=>T(g,a)===p),[n,a]);if(r.searchQuery&&!s(r.searchQuery))return c.jsx(z,{leadingIcon:{icon:C.Lucide.Plus,"aria-hidden":!0},mx:"1",value:r.searchQuery,label:`${t} "${r.searchQuery}"`,selected:o,onSelect:()=>{var p;if(e&&r.value&&r.searchQuery){const g=a===!0?{value:r.searchQuery}:r.searchQuery;e(g),(p=r.setSearchQuery)==null||p.call(r,"")}},...i})},$={};Object.assign($,{Root:be,Trigger:Ce,Content:Te,Options:je,Option:z,Search:Se,Empty:Re,Create:we,Primitives:j});exports.Combobox=$;
|
|
2
2
|
//# sourceMappingURL=index.js.map
|