@kushagradhawan/kookie-ui 0.1.65 → 0.1.66
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/components.css +15 -7
- package/dist/cjs/components/combobox.d.ts +45 -0
- package/dist/cjs/components/combobox.d.ts.map +1 -1
- package/dist/cjs/components/combobox.js +1 -1
- package/dist/cjs/components/combobox.js.map +3 -3
- package/dist/cjs/components/combobox.props.d.ts +26 -17
- package/dist/cjs/components/combobox.props.d.ts.map +1 -1
- package/dist/cjs/components/combobox.props.js +1 -1
- package/dist/cjs/components/combobox.props.js.map +2 -2
- package/dist/esm/components/combobox.d.ts +45 -0
- package/dist/esm/components/combobox.d.ts.map +1 -1
- package/dist/esm/components/combobox.js +1 -1
- package/dist/esm/components/combobox.js.map +3 -3
- package/dist/esm/components/combobox.props.d.ts +26 -17
- package/dist/esm/components/combobox.props.d.ts.map +1 -1
- package/dist/esm/components/combobox.props.js +1 -1
- package/dist/esm/components/combobox.props.js.map +2 -2
- package/package.json +1 -1
- package/schemas/base-button.json +1 -1
- package/schemas/button.json +1 -1
- package/schemas/icon-button.json +1 -1
- package/schemas/index.json +6 -6
- package/schemas/toggle-button.json +1 -1
- package/schemas/toggle-icon-button.json +1 -1
- package/src/components/combobox.css +19 -9
- package/src/components/combobox.props.tsx +11 -2
- package/src/components/combobox.tsx +132 -27
- package/styles.css +15 -7
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* Combobox styles extend BaseMenu primitives and TextField tokens for search input parity. */
|
|
1
2
|
@import './_internal/base-menu.css';
|
|
2
3
|
@import './text-field.css';
|
|
3
4
|
|
|
@@ -5,6 +6,19 @@
|
|
|
5
6
|
.rt-ComboboxContent {
|
|
6
7
|
padding: 0 !important;
|
|
7
8
|
max-height: var(--radix-popover-content-available-height);
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.rt-ComboboxCommand {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
flex: 1;
|
|
17
|
+
min-height: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.rt-ComboboxViewport {
|
|
21
|
+
padding-top: 0 !important;
|
|
8
22
|
}
|
|
9
23
|
|
|
10
24
|
.rt-BaseMenuContent:where(.rt-r-size-1) :where(.rt-ComboboxItem) {
|
|
@@ -32,21 +46,12 @@
|
|
|
32
46
|
cursor: var(--cursor-menu-item) !important;
|
|
33
47
|
}
|
|
34
48
|
|
|
35
|
-
/* Command container uses flex layout with gap */
|
|
36
|
-
.rt-ComboboxCommand {
|
|
37
|
-
display: flex;
|
|
38
|
-
flex-direction: column;
|
|
39
|
-
gap: var(--space-2);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
49
|
/* Sticky search input with consistent padding */
|
|
43
50
|
.rt-ComboboxSearch {
|
|
44
51
|
position: sticky;
|
|
45
52
|
top: 0;
|
|
46
53
|
z-index: 1;
|
|
47
54
|
padding: var(--base-menu-content-padding);
|
|
48
|
-
padding-bottom: var(--space-2);
|
|
49
|
-
border-bottom: 1px solid var(--gray-a3);
|
|
50
55
|
background-color: var(--color-panel);
|
|
51
56
|
}
|
|
52
57
|
|
|
@@ -59,6 +64,11 @@
|
|
|
59
64
|
width: 100%;
|
|
60
65
|
}
|
|
61
66
|
|
|
67
|
+
.rt-ScrollAreaRoot:where(.rt-ComboboxScrollArea) {
|
|
68
|
+
flex: 1;
|
|
69
|
+
min-height: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
62
72
|
/* Map cmdk's selected state to base-menu highlighted state */
|
|
63
73
|
.rt-BaseMenuContent:where(.rt-variant-solid) {
|
|
64
74
|
& :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']),
|
|
@@ -7,14 +7,22 @@ import type { PropDef } from '../props/prop-def.js';
|
|
|
7
7
|
|
|
8
8
|
const sizes = ['1', '2', '3'] as const;
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Shared responsive sizing + high contrast support inherited by Combobox.Root.
|
|
12
|
+
*/
|
|
10
13
|
const comboboxRootPropDefs = {
|
|
11
14
|
size: { type: 'enum', className: 'rt-r-size', values: sizes, default: '2', responsive: true },
|
|
15
|
+
...highContrastPropDef,
|
|
12
16
|
} satisfies {
|
|
13
17
|
size: PropDef<(typeof sizes)[number]>;
|
|
18
|
+
highContrast: PropDef<boolean>;
|
|
14
19
|
};
|
|
15
20
|
|
|
16
21
|
const triggerVariants = ['classic', 'surface', 'soft', 'outline', 'ghost'] as const;
|
|
17
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Token-aware props specific to Combobox.Trigger.
|
|
25
|
+
*/
|
|
18
26
|
const comboboxTriggerPropDefs = {
|
|
19
27
|
variant: { type: 'enum', className: 'rt-variant', values: triggerVariants, default: 'surface' },
|
|
20
28
|
panelBackground: {
|
|
@@ -23,7 +31,6 @@ const comboboxTriggerPropDefs = {
|
|
|
23
31
|
values: ['solid', 'translucent'],
|
|
24
32
|
},
|
|
25
33
|
material: { type: 'enum', values: ['solid', 'translucent'] },
|
|
26
|
-
...highContrastPropDef,
|
|
27
34
|
error: { type: 'boolean' },
|
|
28
35
|
loading: { type: 'boolean' },
|
|
29
36
|
disabled: { type: 'boolean' },
|
|
@@ -36,7 +43,6 @@ const comboboxTriggerPropDefs = {
|
|
|
36
43
|
variant: PropDef<(typeof triggerVariants)[number]>;
|
|
37
44
|
panelBackground: PropDef<'solid' | 'translucent'>;
|
|
38
45
|
material: PropDef<'solid' | 'translucent'>;
|
|
39
|
-
highContrast: PropDef<boolean>;
|
|
40
46
|
error: PropDef<boolean>;
|
|
41
47
|
loading: PropDef<boolean>;
|
|
42
48
|
disabled: PropDef<boolean>;
|
|
@@ -47,6 +53,9 @@ const comboboxTriggerPropDefs = {
|
|
|
47
53
|
|
|
48
54
|
const contentVariants = ['solid', 'soft'] as const;
|
|
49
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Styling props for the dropdown surface rendered by Combobox.Content.
|
|
58
|
+
*/
|
|
50
59
|
const comboboxContentPropDefs = {
|
|
51
60
|
size: { type: 'enum', className: 'rt-r-size', values: sizes, default: '2', responsive: true },
|
|
52
61
|
variant: { type: 'enum', className: 'rt-variant', values: contentVariants, default: 'solid' },
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Combobox is a compound component built on top of Popover and cmdk's Command list.
|
|
5
|
+
* It mirrors the Select API while adding search-first behaviors including filtering,
|
|
6
|
+
* async-friendly state management, and design token support for trigger, content,
|
|
7
|
+
* and input variants.
|
|
8
|
+
*/
|
|
9
|
+
|
|
3
10
|
import * as React from 'react';
|
|
4
11
|
import classNames from 'classnames';
|
|
5
12
|
import { useControllableState } from 'radix-ui/internal';
|
|
@@ -24,6 +31,9 @@ type TextFieldVariant = (typeof textFieldRootPropDefs.variant.values)[number];
|
|
|
24
31
|
type ComboboxValue = string | null;
|
|
25
32
|
type CommandFilter = (value: string, search: string, keywords?: string[]) => number;
|
|
26
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Additional props supported by Combobox.Root beyond the Radix Popover surface.
|
|
36
|
+
*/
|
|
27
37
|
type ComboboxRootOwnProps = GetPropDefTypes<typeof comboboxRootPropDefs> & {
|
|
28
38
|
value?: ComboboxValue;
|
|
29
39
|
defaultValue?: ComboboxValue;
|
|
@@ -42,6 +52,9 @@ type ComboboxRootOwnProps = GetPropDefTypes<typeof comboboxRootPropDefs> & {
|
|
|
42
52
|
disabled?: boolean;
|
|
43
53
|
};
|
|
44
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Internal context shared by all sub-components to avoid prop drilling.
|
|
57
|
+
*/
|
|
45
58
|
interface ComboboxContextValue extends ComboboxRootOwnProps {
|
|
46
59
|
open: boolean;
|
|
47
60
|
setOpen: (open: boolean) => void;
|
|
@@ -55,6 +68,10 @@ interface ComboboxContextValue extends ComboboxRootOwnProps {
|
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
const ComboboxContext = React.createContext<ComboboxContextValue | null>(null);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Utility hook that ensures consumers are wrapped in Combobox.Root.
|
|
74
|
+
*/
|
|
58
75
|
const useComboboxContext = (caller: string) => {
|
|
59
76
|
const ctx = React.useContext(ComboboxContext);
|
|
60
77
|
if (!ctx) {
|
|
@@ -63,7 +80,11 @@ const useComboboxContext = (caller: string) => {
|
|
|
63
80
|
return ctx;
|
|
64
81
|
};
|
|
65
82
|
|
|
66
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Context for values that are only available inside Content (e.g., variant, color)
|
|
85
|
+
* so that Input/Item can style themselves consistently.
|
|
86
|
+
*/
|
|
87
|
+
const ComboboxContentContext = React.createContext<{ variant: 'solid' | 'soft'; size?: string; color?: string; material?: string; highContrast?: boolean } | null>(null);
|
|
67
88
|
const useComboboxContentContext = () => {
|
|
68
89
|
const ctx = React.useContext(ComboboxContentContext);
|
|
69
90
|
return ctx; // Optional - Input might not always be in Content
|
|
@@ -71,10 +92,15 @@ const useComboboxContentContext = () => {
|
|
|
71
92
|
|
|
72
93
|
type PopoverRootProps = React.ComponentPropsWithoutRef<typeof Popover.Root>;
|
|
73
94
|
interface ComboboxRootProps extends PopoverRootProps, ComboboxRootOwnProps {}
|
|
95
|
+
/**
|
|
96
|
+
* Root component that wires up Popover behavior, controllable state,
|
|
97
|
+
* and shared context for trigger/content/input sub-components.
|
|
98
|
+
*/
|
|
74
99
|
const ComboboxRoot: React.FC<ComboboxRootProps> = (props) => {
|
|
75
100
|
const {
|
|
76
101
|
children,
|
|
77
102
|
size = comboboxRootPropDefs.size.default,
|
|
103
|
+
highContrast = comboboxRootPropDefs.highContrast.default,
|
|
78
104
|
value: valueProp,
|
|
79
105
|
defaultValue = null,
|
|
80
106
|
onValueChange,
|
|
@@ -100,7 +126,7 @@ const ComboboxRoot: React.FC<ComboboxRootProps> = (props) => {
|
|
|
100
126
|
});
|
|
101
127
|
|
|
102
128
|
const [value, setValue] = useControllableState<ComboboxValue>({
|
|
103
|
-
prop: valueProp
|
|
129
|
+
prop: valueProp,
|
|
104
130
|
defaultProp: defaultValue,
|
|
105
131
|
onChange: onValueChange,
|
|
106
132
|
});
|
|
@@ -130,6 +156,7 @@ const ComboboxRoot: React.FC<ComboboxRootProps> = (props) => {
|
|
|
130
156
|
const contextValue = React.useMemo<ComboboxContextValue>(
|
|
131
157
|
() => ({
|
|
132
158
|
size,
|
|
159
|
+
highContrast,
|
|
133
160
|
placeholder,
|
|
134
161
|
searchPlaceholder,
|
|
135
162
|
filter,
|
|
@@ -146,7 +173,25 @@ const ComboboxRoot: React.FC<ComboboxRootProps> = (props) => {
|
|
|
146
173
|
registerItemLabel,
|
|
147
174
|
handleSelect,
|
|
148
175
|
}),
|
|
149
|
-
[
|
|
176
|
+
[
|
|
177
|
+
size,
|
|
178
|
+
highContrast,
|
|
179
|
+
placeholder,
|
|
180
|
+
searchPlaceholder,
|
|
181
|
+
filter,
|
|
182
|
+
shouldFilter,
|
|
183
|
+
loop,
|
|
184
|
+
disabled,
|
|
185
|
+
open,
|
|
186
|
+
setOpen,
|
|
187
|
+
value,
|
|
188
|
+
setValue,
|
|
189
|
+
searchValue,
|
|
190
|
+
setSearchValue,
|
|
191
|
+
selectedLabel,
|
|
192
|
+
registerItemLabel,
|
|
193
|
+
handleSelect,
|
|
194
|
+
],
|
|
150
195
|
);
|
|
151
196
|
|
|
152
197
|
return (
|
|
@@ -163,15 +208,22 @@ type ComboboxTriggerElement = HTMLButtonElement;
|
|
|
163
208
|
type ComboboxTriggerOwnProps = GetPropDefTypes<typeof comboboxTriggerPropDefs>;
|
|
164
209
|
type NativeTriggerProps = Omit<React.ComponentPropsWithoutRef<'button'>, 'color'>;
|
|
165
210
|
interface ComboboxTriggerProps extends NativeTriggerProps, MarginProps, ComboboxTriggerOwnProps {}
|
|
211
|
+
/**
|
|
212
|
+
* Trigger behaves like a styled button that opens the Popover,
|
|
213
|
+
* syncing size/highContrast from Root while exposing select-like states.
|
|
214
|
+
*/
|
|
166
215
|
const ComboboxTrigger = React.forwardRef<ComboboxTriggerElement, ComboboxTriggerProps>((props, forwardedRef) => {
|
|
167
216
|
const context = useComboboxContext('Combobox.Trigger');
|
|
168
|
-
const { children, className, placeholder, disabled, readOnly, ...triggerProps } = extractProps(
|
|
169
|
-
{ size: context.size, ...props },
|
|
170
|
-
{ size: comboboxRootPropDefs.size },
|
|
217
|
+
const { children, className, placeholder, disabled, readOnly, error, loading, color, radius, ...triggerProps } = extractProps(
|
|
218
|
+
{ size: context.size, highContrast: context.highContrast, ...props },
|
|
219
|
+
{ size: comboboxRootPropDefs.size, highContrast: comboboxRootPropDefs.highContrast },
|
|
171
220
|
comboboxTriggerPropDefs,
|
|
172
221
|
marginPropDefs,
|
|
173
222
|
);
|
|
174
223
|
|
|
224
|
+
// Extract material and panelBackground separately since they need to be passed as data attributes
|
|
225
|
+
const { material, panelBackground } = props;
|
|
226
|
+
|
|
175
227
|
const isDisabled = disabled ?? context.disabled;
|
|
176
228
|
const ariaProps = React.useMemo(
|
|
177
229
|
() => ({
|
|
@@ -187,16 +239,35 @@ const ComboboxTrigger = React.forwardRef<ComboboxTriggerElement, ComboboxTrigger
|
|
|
187
239
|
<span className="rt-SelectTriggerInner">
|
|
188
240
|
<ComboboxValue placeholder={placeholder ?? context.placeholder} />
|
|
189
241
|
</span>
|
|
190
|
-
|
|
242
|
+
{loading ? (
|
|
243
|
+
<div className="rt-SelectIcon rt-SelectLoadingIcon" aria-hidden="true">
|
|
244
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
245
|
+
<circle cx="8" cy="8" r="6.5" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeDasharray="6 34" strokeDashoffset="0" className="rt-SelectLoadingSpinner" />
|
|
246
|
+
</svg>
|
|
247
|
+
</div>
|
|
248
|
+
) : (
|
|
249
|
+
<ChevronDownIcon className="rt-SelectIcon" />
|
|
250
|
+
)}
|
|
191
251
|
</>
|
|
192
252
|
);
|
|
193
253
|
|
|
254
|
+
const { type: buttonType, ...restTriggerProps } = triggerProps;
|
|
255
|
+
const resolvedButtonType = buttonType ?? 'button';
|
|
256
|
+
|
|
194
257
|
const triggerChild = (
|
|
195
258
|
<button
|
|
259
|
+
data-accent-color={color}
|
|
260
|
+
data-radius={radius}
|
|
261
|
+
data-panel-background={panelBackground}
|
|
262
|
+
data-material={material}
|
|
263
|
+
data-error={error}
|
|
264
|
+
data-loading={loading}
|
|
196
265
|
data-disabled={isDisabled || undefined}
|
|
197
266
|
data-read-only={readOnly || undefined}
|
|
198
|
-
{...
|
|
267
|
+
{...restTriggerProps}
|
|
199
268
|
{...ariaProps}
|
|
269
|
+
type={resolvedButtonType}
|
|
270
|
+
disabled={isDisabled}
|
|
200
271
|
ref={forwardedRef}
|
|
201
272
|
className={classNames('rt-reset', 'rt-SelectTrigger', 'rt-ComboboxTrigger', className)}
|
|
202
273
|
>
|
|
@@ -212,6 +283,10 @@ type ComboboxValueElement = HTMLSpanElement;
|
|
|
212
283
|
interface ComboboxValueProps extends React.ComponentPropsWithoutRef<'span'> {
|
|
213
284
|
placeholder?: string;
|
|
214
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Value mirrors Select.Value by showing the selected item's label
|
|
288
|
+
* or falling back to placeholder text supplied by the consumer or context.
|
|
289
|
+
*/
|
|
215
290
|
const ComboboxValue = React.forwardRef<ComboboxValueElement, ComboboxValueProps>(({ placeholder, children, className, ...valueProps }, forwardedRef) => {
|
|
216
291
|
const context = useComboboxContext('Combobox.Value');
|
|
217
292
|
const displayValue = context.selectedLabel ?? context.value ?? undefined;
|
|
@@ -229,6 +304,10 @@ type ComboboxContentOwnProps = GetPropDefTypes<typeof comboboxContentPropDefs> &
|
|
|
229
304
|
container?: React.ComponentPropsWithoutRef<typeof Popover.Content>['container'];
|
|
230
305
|
};
|
|
231
306
|
interface ComboboxContentProps extends Omit<ComponentPropsWithout<typeof Popover.Content, RemovedProps>, 'size'>, ComboboxContentOwnProps {}
|
|
307
|
+
/**
|
|
308
|
+
* Content renders the dropdown surface, syncing tokens from the current Theme
|
|
309
|
+
* and instantiating cmdk's Command list for roving focus + filtering.
|
|
310
|
+
*/
|
|
232
311
|
const ComboboxContent = React.forwardRef<ComboboxContentElement, ComboboxContentProps>((props, forwardedRef) => {
|
|
233
312
|
const context = useComboboxContext('Combobox.Content');
|
|
234
313
|
const themeContext = useThemeContext();
|
|
@@ -236,7 +315,7 @@ const ComboboxContent = React.forwardRef<ComboboxContentElement, ComboboxContent
|
|
|
236
315
|
|
|
237
316
|
const sizeProp = props.size ?? context.size ?? comboboxContentPropDefs.size.default;
|
|
238
317
|
const variantProp = props.variant ?? comboboxContentPropDefs.variant.default;
|
|
239
|
-
const highContrastProp = props.highContrast ?? comboboxContentPropDefs.highContrast.default;
|
|
318
|
+
const highContrastProp = props.highContrast ?? context.highContrast ?? comboboxContentPropDefs.highContrast.default;
|
|
240
319
|
|
|
241
320
|
const { className, children, color, forceMount, container, ...contentProps } = extractProps(
|
|
242
321
|
{ ...props, size: sizeProp, variant: variantProp, highContrast: highContrastProp },
|
|
@@ -269,22 +348,18 @@ const ComboboxContent = React.forwardRef<ComboboxContentElement, ComboboxContent
|
|
|
269
348
|
className={classNames('rt-PopperContent', 'rt-BaseMenuContent', 'rt-ComboboxContent', sanitizedClassName)}
|
|
270
349
|
>
|
|
271
350
|
<Theme asChild>
|
|
272
|
-
<
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
</CommandPrimitive>
|
|
285
|
-
</ComboboxContentContext.Provider>
|
|
286
|
-
</div>
|
|
287
|
-
</ScrollArea>
|
|
351
|
+
<ComboboxContentContext.Provider value={{ variant: variantProp, size: String(sizeProp), color: resolvedColor, material: effectiveMaterial, highContrast: highContrastProp }}>
|
|
352
|
+
<CommandPrimitive
|
|
353
|
+
loop={context.loop}
|
|
354
|
+
value={context.searchValue}
|
|
355
|
+
onValueChange={context.setSearchValue}
|
|
356
|
+
shouldFilter={context.shouldFilter}
|
|
357
|
+
filter={context.filter}
|
|
358
|
+
className="rt-ComboboxCommand"
|
|
359
|
+
>
|
|
360
|
+
{children}
|
|
361
|
+
</CommandPrimitive>
|
|
362
|
+
</ComboboxContentContext.Provider>
|
|
288
363
|
</Theme>
|
|
289
364
|
</Popover.Content>
|
|
290
365
|
);
|
|
@@ -297,6 +372,10 @@ interface ComboboxInputProps extends React.ComponentPropsWithoutRef<typeof Comma
|
|
|
297
372
|
endAdornment?: React.ReactNode;
|
|
298
373
|
variant?: TextFieldVariant;
|
|
299
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* Input composes TextField tokens with cmdk's Command.Input to provide
|
|
377
|
+
* automatic focus management and optional adornments.
|
|
378
|
+
*/
|
|
300
379
|
const ComboboxInput = React.forwardRef<ComboboxInputElement, ComboboxInputProps>(({ className, startAdornment, endAdornment, placeholder, variant: inputVariant, ...inputProps }, forwardedRef) => {
|
|
301
380
|
const context = useComboboxContext('Combobox.Input');
|
|
302
381
|
const contentContext = useComboboxContentContext();
|
|
@@ -307,7 +386,7 @@ const ComboboxInput = React.forwardRef<ComboboxInputElement, ComboboxInputProps>
|
|
|
307
386
|
// Map combobox variant to textfield variant: solid -> surface, soft -> soft unless overridden
|
|
308
387
|
const textFieldVariant = inputVariant ?? (contentVariant === 'solid' ? 'surface' : 'soft');
|
|
309
388
|
|
|
310
|
-
|
|
389
|
+
const inputField = (
|
|
311
390
|
<div
|
|
312
391
|
className={classNames('rt-TextFieldRoot', 'rt-ComboboxInputRoot', `rt-r-size-${context.size}`, `rt-variant-${textFieldVariant}`)}
|
|
313
392
|
data-accent-color={color}
|
|
@@ -323,18 +402,34 @@ const ComboboxInput = React.forwardRef<ComboboxInputElement, ComboboxInputProps>
|
|
|
323
402
|
) : null}
|
|
324
403
|
</div>
|
|
325
404
|
);
|
|
405
|
+
|
|
406
|
+
if (contentContext) {
|
|
407
|
+
return <div className="rt-ComboboxSearch">{inputField}</div>;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return inputField;
|
|
326
411
|
});
|
|
327
412
|
ComboboxInput.displayName = 'Combobox.Input';
|
|
328
413
|
|
|
329
414
|
type ComboboxListElement = React.ElementRef<typeof CommandPrimitive.List>;
|
|
330
415
|
interface ComboboxListProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive.List> {}
|
|
416
|
+
/**
|
|
417
|
+
* List wraps cmdk's Command.List to inherit base menu styles and provides ScrollArea for the items.
|
|
418
|
+
*/
|
|
331
419
|
const ComboboxList = React.forwardRef<ComboboxListElement, ComboboxListProps>(({ className, ...listProps }, forwardedRef) => (
|
|
332
|
-
<
|
|
420
|
+
<ScrollArea type="auto" className="rt-ComboboxScrollArea" scrollbars="vertical" size="1">
|
|
421
|
+
<div className={classNames('rt-BaseMenuViewport', 'rt-ComboboxViewport')}>
|
|
422
|
+
<CommandPrimitive.List {...listProps} ref={forwardedRef} className={classNames('rt-ComboboxList', className)} />
|
|
423
|
+
</div>
|
|
424
|
+
</ScrollArea>
|
|
333
425
|
));
|
|
334
426
|
ComboboxList.displayName = 'Combobox.List';
|
|
335
427
|
|
|
336
428
|
type ComboboxEmptyElement = React.ElementRef<typeof CommandPrimitive.Empty>;
|
|
337
429
|
interface ComboboxEmptyProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty> {}
|
|
430
|
+
/**
|
|
431
|
+
* Empty renders when no options match the search query.
|
|
432
|
+
*/
|
|
338
433
|
const ComboboxEmpty = React.forwardRef<ComboboxEmptyElement, ComboboxEmptyProps>(({ className, ...emptyProps }, forwardedRef) => (
|
|
339
434
|
<CommandPrimitive.Empty {...emptyProps} ref={forwardedRef} className={classNames('rt-ComboboxEmpty', className)} />
|
|
340
435
|
));
|
|
@@ -342,6 +437,9 @@ ComboboxEmpty.displayName = 'Combobox.Empty';
|
|
|
342
437
|
|
|
343
438
|
type ComboboxGroupElement = React.ElementRef<typeof CommandPrimitive.Group>;
|
|
344
439
|
interface ComboboxGroupProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group> {}
|
|
440
|
+
/**
|
|
441
|
+
* Group and Label mirror menu semantics for subheadings inside the list.
|
|
442
|
+
*/
|
|
345
443
|
const ComboboxGroup = React.forwardRef<ComboboxGroupElement, ComboboxGroupProps>(({ className, ...groupProps }, forwardedRef) => (
|
|
346
444
|
<CommandPrimitive.Group {...groupProps} ref={forwardedRef} className={classNames('rt-BaseMenuGroup', 'rt-ComboboxGroup', className)} />
|
|
347
445
|
));
|
|
@@ -356,6 +454,9 @@ ComboboxLabel.displayName = 'Combobox.Label';
|
|
|
356
454
|
|
|
357
455
|
type ComboboxSeparatorElement = React.ElementRef<typeof CommandPrimitive.Separator>;
|
|
358
456
|
interface ComboboxSeparatorProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator> {}
|
|
457
|
+
/**
|
|
458
|
+
* Separator visually divides logical sections of the option list.
|
|
459
|
+
*/
|
|
359
460
|
const ComboboxSeparator = React.forwardRef<ComboboxSeparatorElement, ComboboxSeparatorProps>(({ className, ...separatorProps }, forwardedRef) => (
|
|
360
461
|
<CommandPrimitive.Separator {...separatorProps} ref={forwardedRef} className={classNames('rt-BaseMenuSeparator', 'rt-ComboboxSeparator', className)} />
|
|
361
462
|
));
|
|
@@ -365,6 +466,10 @@ type ComboboxItemElement = React.ElementRef<typeof CommandPrimitive.Item>;
|
|
|
365
466
|
interface ComboboxItemProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item> {
|
|
366
467
|
label?: string;
|
|
367
468
|
}
|
|
469
|
+
/**
|
|
470
|
+
* Item wires cmdk's selection handling with Kookie UI tokens and
|
|
471
|
+
* ensures labels are registered for displaying the current value.
|
|
472
|
+
*/
|
|
368
473
|
const ComboboxItem = React.forwardRef<ComboboxItemElement, ComboboxItemProps>(({ className, children, label, value, disabled, onSelect, ...itemProps }, forwardedRef) => {
|
|
369
474
|
const context = useComboboxContext('Combobox.Item');
|
|
370
475
|
const contentContext = useComboboxContentContext();
|
package/styles.css
CHANGED
|
@@ -15216,6 +15216,17 @@
|
|
|
15216
15216
|
.rt-ComboboxContent{
|
|
15217
15217
|
padding: 0 !important;
|
|
15218
15218
|
max-height: var(--radix-popover-content-available-height);
|
|
15219
|
+
display: flex;
|
|
15220
|
+
flex-direction: column;
|
|
15221
|
+
}
|
|
15222
|
+
.rt-ComboboxCommand{
|
|
15223
|
+
display: flex;
|
|
15224
|
+
flex-direction: column;
|
|
15225
|
+
flex: 1;
|
|
15226
|
+
min-height: 0;
|
|
15227
|
+
}
|
|
15228
|
+
.rt-ComboboxViewport{
|
|
15229
|
+
padding-top: 0 !important;
|
|
15219
15230
|
}
|
|
15220
15231
|
.rt-BaseMenuContent:where(.rt-r-size-1) :where(.rt-ComboboxItem){
|
|
15221
15232
|
--base-menu-item-padding-left: calc(var(--space-5) / 1.2);
|
|
@@ -15236,18 +15247,11 @@
|
|
|
15236
15247
|
color: inherit !important;
|
|
15237
15248
|
cursor: var(--cursor-menu-item) !important;
|
|
15238
15249
|
}
|
|
15239
|
-
.rt-ComboboxCommand{
|
|
15240
|
-
display: flex;
|
|
15241
|
-
flex-direction: column;
|
|
15242
|
-
gap: var(--space-2);
|
|
15243
|
-
}
|
|
15244
15250
|
.rt-ComboboxSearch{
|
|
15245
15251
|
position: sticky;
|
|
15246
15252
|
top: 0;
|
|
15247
15253
|
z-index: 1;
|
|
15248
15254
|
padding: var(--base-menu-content-padding);
|
|
15249
|
-
padding-bottom: var(--space-2);
|
|
15250
|
-
border-bottom: 1px solid var(--gray-a3);
|
|
15251
15255
|
background-color: var(--color-panel);
|
|
15252
15256
|
}
|
|
15253
15257
|
:where([data-panel-background='translucent']) .rt-ComboboxSearch{
|
|
@@ -15258,6 +15262,10 @@
|
|
|
15258
15262
|
.rt-ComboboxSearch :where(.rt-ComboboxInputRoot){
|
|
15259
15263
|
width: 100%;
|
|
15260
15264
|
}
|
|
15265
|
+
.rt-ScrollAreaRoot:where(.rt-ComboboxScrollArea){
|
|
15266
|
+
flex: 1;
|
|
15267
|
+
min-height: 0;
|
|
15268
|
+
}
|
|
15261
15269
|
.rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']),
|
|
15262
15270
|
.rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']){
|
|
15263
15271
|
background-color: var(--accent-9);
|