@robr0/design-system 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +13 -9
  2. package/components/Accordion/Accordion.js +0 -1
  3. package/components/Avatar/Avatar.js +1 -0
  4. package/components/Breadcrumb/Breadcrumb.css +9 -1
  5. package/components/Breadcrumb/Breadcrumb.d.ts +7 -1
  6. package/components/Breadcrumb/Breadcrumb.js +3 -2
  7. package/components/Button/Button.css +18 -0
  8. package/components/Button/Button.d.ts +38 -16
  9. package/components/Button/Button.js +76 -58
  10. package/components/Card/Card.css +6 -0
  11. package/components/Card/Card.d.ts +17 -5
  12. package/components/Card/Card.js +101 -80
  13. package/components/Checkbox/Checkbox.d.ts +24 -12
  14. package/components/Checkbox/Checkbox.js +99 -85
  15. package/components/CircularButton/CircularButton.css +11 -0
  16. package/components/CircularButton/CircularButton.d.ts +7 -1
  17. package/components/CircularButton/CircularButton.js +15 -4
  18. package/components/CodeBlock/CodeBlock.js +10 -1
  19. package/components/ColorPicker/ColorPicker.css +278 -0
  20. package/components/ColorPicker/ColorPicker.d.ts +50 -0
  21. package/components/ColorPicker/ColorPicker.js +338 -0
  22. package/components/Combobox/Combobox.css +0 -36
  23. package/components/Combobox/Combobox.d.ts +19 -7
  24. package/components/Combobox/Combobox.js +106 -89
  25. package/components/CommandPalette/CommandPalette.css +1 -15
  26. package/components/CommandPalette/CommandPalette.js +6 -5
  27. package/components/ContextMenu/ContextMenu.css +262 -0
  28. package/components/ContextMenu/ContextMenu.d.ts +26 -0
  29. package/components/ContextMenu/ContextMenu.js +350 -0
  30. package/components/DateInput/DateInput.css +0 -36
  31. package/components/DateInput/DateInput.d.ts +18 -21
  32. package/components/DateInput/DateInput.js +76 -64
  33. package/components/DatePicker/DatePicker.d.ts +9 -2
  34. package/components/DatePicker/DatePicker.js +137 -128
  35. package/components/Dialog/Dialog.d.ts +15 -4
  36. package/components/Dialog/Dialog.js +136 -118
  37. package/components/Drawer/Drawer.d.ts +15 -4
  38. package/components/Drawer/Drawer.js +138 -119
  39. package/components/Dropdown/Dropdown.css +0 -36
  40. package/components/Dropdown/Dropdown.d.ts +24 -8
  41. package/components/Dropdown/Dropdown.js +219 -169
  42. package/components/DropdownMenu/DropdownMenu.js +10 -7
  43. package/components/Field/Field.css +80 -0
  44. package/components/Field/Field.d.ts +50 -0
  45. package/components/Field/Field.js +58 -0
  46. package/components/Field/FieldContext.d.ts +42 -0
  47. package/components/Field/FieldContext.js +7 -0
  48. package/components/FileInput/FileInput.css +0 -36
  49. package/components/FileInput/FileInput.d.ts +13 -17
  50. package/components/FileInput/FileInput.js +168 -141
  51. package/components/Input/Input.css +0 -43
  52. package/components/Input/Input.d.ts +23 -22
  53. package/components/Input/Input.js +93 -66
  54. package/components/Kbd/Kbd.css +28 -0
  55. package/components/Kbd/Kbd.d.ts +19 -0
  56. package/components/Kbd/Kbd.js +14 -0
  57. package/components/Popover/Popover.d.ts +0 -6
  58. package/components/Popover/Popover.js +22 -16
  59. package/components/ProgressBar/ProgressBar.js +1 -1
  60. package/components/RadioButton/RadioButton.d.ts +26 -13
  61. package/components/RadioButton/RadioButton.js +95 -70
  62. package/components/SelectionCard/SelectionCard.css +6 -2
  63. package/components/SelectionCard/SelectionCard.d.ts +10 -4
  64. package/components/SelectionCard/SelectionCard.js +72 -56
  65. package/components/Skeleton/Skeleton.css +2 -0
  66. package/components/Slider/Slider.d.ts +19 -10
  67. package/components/Slider/Slider.js +50 -40
  68. package/components/Spinner/Spinner.css +11 -0
  69. package/components/Spinner/Spinner.d.ts +2 -2
  70. package/components/Swatch/Swatch.css +52 -0
  71. package/components/Swatch/Swatch.d.ts +34 -0
  72. package/components/Swatch/Swatch.js +44 -0
  73. package/components/Table/Table.css +19 -0
  74. package/components/Table/Table.d.ts +10 -2
  75. package/components/Table/Table.js +58 -58
  76. package/components/Textarea/Textarea.css +0 -43
  77. package/components/Textarea/Textarea.d.ts +21 -22
  78. package/components/Textarea/Textarea.js +78 -67
  79. package/components/ToggleGroup/ToggleGroup.d.ts +18 -8
  80. package/components/ToggleGroup/ToggleGroup.js +61 -44
  81. package/components/ToggleSwitch/ToggleSwitch.css +7 -2
  82. package/components/ToggleSwitch/ToggleSwitch.d.ts +17 -9
  83. package/components/ToggleSwitch/ToggleSwitch.js +57 -44
  84. package/components/registry.d.ts +47 -10
  85. package/components/registry.js +5 -1
  86. package/components/registry.json +498 -56
  87. package/components/registry.json.d.ts +498 -56
  88. package/components/registry.json.js +4 -1
  89. package/index.d.ts +8 -1
  90. package/index.js +16 -1
  91. package/package.json +1 -1
@@ -0,0 +1,50 @@
1
+ import { default as React } from 'react';
2
+ /** Props owned by ColorPicker itself — everything else falls through to the trigger <button>. */
3
+ type ColorPickerOwnProps = {
4
+ /** Field label text */
5
+ label?: string;
6
+ /** Current colour as a hex string — 3, 6 or 8 digit, with or without `#` */
7
+ value?: string;
8
+ /** Initial colour for uncontrolled use */
9
+ defaultValue?: string;
10
+ /**
11
+ * Convenience callback receiving the colour as an uppercase hex string
12
+ * (`#RRGGBB`, or `#RRGGBBAA` when `showAlpha` and alpha < 100%). Fires
13
+ * live while dragging.
14
+ */
15
+ onValueChange?: (value: string) => void;
16
+ /** Show the current hex value as text inside the trigger */
17
+ showText?: boolean;
18
+ /** Add an alpha (opacity) slider and emit 8-digit hex when alpha < 100% */
19
+ showAlpha?: boolean;
20
+ /** Component size */
21
+ size?: 'default' | 'compact';
22
+ /** Whether the picker is disabled */
23
+ disabled?: boolean;
24
+ /** Whether the field is required */
25
+ required?: boolean;
26
+ /** Error state */
27
+ error?: boolean;
28
+ /** Helper or error message */
29
+ helperText?: string;
30
+ /**
31
+ * When set, a hidden `<input type="hidden">` carries the current hex value
32
+ * under this name so the picker participates in native form submission.
33
+ */
34
+ name?: string;
35
+ /** Additional CSS classes — applied to the wrapper, not the trigger */
36
+ className?: string;
37
+ };
38
+ export interface ColorPickerProps extends ColorPickerOwnProps, Omit<React.ComponentPropsWithoutRef<'button'>, keyof ColorPickerOwnProps | 'type'> {
39
+ }
40
+ /**
41
+ * Colour picker: a swatch trigger that opens a panel with a
42
+ * saturation/brightness area, hue slider, optional alpha slider and a hex
43
+ * field. Works controlled (`value` + `onValueChange`) or uncontrolled
44
+ * (`defaultValue`).
45
+ *
46
+ * Forwards a ref to the trigger `<button>` and spreads unrecognised props
47
+ * onto it.
48
+ */
49
+ export declare const ColorPicker: React.ForwardRefExoticComponent<ColorPickerProps & React.RefAttributes<HTMLButtonElement>>;
50
+ export {};
@@ -0,0 +1,338 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import React, { useState, useRef, useEffect, useCallback } from "react";
3
+ import { Field } from "../Field/Field.js";
4
+ import "./ColorPicker.css";
5
+ const clamp = (n, min, max) => Math.min(max, Math.max(min, n));
6
+ function parseHex(input) {
7
+ const hex = input.trim().replace(/^#/, "");
8
+ if (!/^([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(hex)) return null;
9
+ let r, g, b;
10
+ let a = 255;
11
+ if (hex.length === 3) {
12
+ r = parseInt(hex[0] + hex[0], 16);
13
+ g = parseInt(hex[1] + hex[1], 16);
14
+ b = parseInt(hex[2] + hex[2], 16);
15
+ } else {
16
+ r = parseInt(hex.slice(0, 2), 16);
17
+ g = parseInt(hex.slice(2, 4), 16);
18
+ b = parseInt(hex.slice(4, 6), 16);
19
+ if (hex.length === 8) a = parseInt(hex.slice(6, 8), 16);
20
+ }
21
+ const max = Math.max(r, g, b);
22
+ const min = Math.min(r, g, b);
23
+ const d = max - min;
24
+ let h = 0;
25
+ if (d !== 0) {
26
+ if (max === r) h = 60 * ((g - b) / d % 6);
27
+ else if (max === g) h = 60 * ((b - r) / d + 2);
28
+ else h = 60 * ((r - g) / d + 4);
29
+ }
30
+ if (h < 0) h += 360;
31
+ return {
32
+ // h stays a float — rounding it here makes the hex → HSV → hex round
33
+ // trip drift by one on some colours.
34
+ h: clamp(h, 0, 359.999),
35
+ s: max === 0 ? 0 : d / max * 100,
36
+ v: max / 255 * 100,
37
+ a: a / 255 * 100
38
+ };
39
+ }
40
+ function hsvToRgb({ h, s, v }) {
41
+ const sf = s / 100;
42
+ const vf = v / 100;
43
+ const c = vf * sf;
44
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
45
+ const m = vf - c;
46
+ const [r, g, b] = h < 60 ? [c, x, 0] : h < 120 ? [x, c, 0] : h < 180 ? [0, c, x] : h < 240 ? [0, x, c] : h < 300 ? [x, 0, c] : [c, 0, x];
47
+ return [Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255)];
48
+ }
49
+ const channelHex = (n) => n.toString(16).padStart(2, "0").toUpperCase();
50
+ function formatHex(hsva, withAlpha) {
51
+ const [r, g, b] = hsvToRgb(hsva);
52
+ const base = `#${channelHex(r)}${channelHex(g)}${channelHex(b)}`;
53
+ if (withAlpha && hsva.a < 100) {
54
+ return base + channelHex(Math.round(hsva.a / 100 * 255));
55
+ }
56
+ return base;
57
+ }
58
+ function toCssColor(hsva) {
59
+ const [r, g, b] = hsvToRgb(hsva);
60
+ return `rgba(${r}, ${g}, ${b}, ${hsva.a / 100})`;
61
+ }
62
+ const ColorPicker = React.forwardRef(
63
+ ({
64
+ label,
65
+ value,
66
+ defaultValue = "#118AB2",
67
+ onValueChange,
68
+ showText = false,
69
+ showAlpha = false,
70
+ size = "default",
71
+ disabled = false,
72
+ required = false,
73
+ error = false,
74
+ helperText,
75
+ name,
76
+ className = "",
77
+ id,
78
+ ...rest
79
+ }, ref) => {
80
+ const baseClass = "ds-colorpicker";
81
+ const [isOpen, setIsOpen] = useState(false);
82
+ const [hsva, setHsva] = useState(
83
+ () => parseHex(value ?? defaultValue) ?? { h: 0, s: 0, v: 0, a: 100 }
84
+ );
85
+ const [hexDraft, setHexDraft] = useState(null);
86
+ const rootRef = useRef(null);
87
+ const triggerRef = useRef(null);
88
+ const satRef = useRef(null);
89
+ const hsvaRef = useRef(hsva);
90
+ hsvaRef.current = hsva;
91
+ const lastEmitted = useRef(null);
92
+ const setTriggerRef = (node) => {
93
+ triggerRef.current = node;
94
+ if (typeof ref === "function") ref(node);
95
+ else if (ref) ref.current = node;
96
+ };
97
+ useEffect(() => {
98
+ if (value == null || value === lastEmitted.current) return;
99
+ const parsed = parseHex(value);
100
+ if (parsed) setHsva(parsed);
101
+ }, [value]);
102
+ const commit = useCallback(
103
+ (next) => {
104
+ setHsva(next);
105
+ const hex = formatHex(next, showAlpha);
106
+ lastEmitted.current = hex;
107
+ onValueChange?.(hex);
108
+ },
109
+ [onValueChange, showAlpha]
110
+ );
111
+ useEffect(() => {
112
+ if (!isOpen) return;
113
+ const onMouseDown = (e) => {
114
+ if (rootRef.current && !rootRef.current.contains(e.target)) {
115
+ setIsOpen(false);
116
+ setHexDraft(null);
117
+ }
118
+ };
119
+ document.addEventListener("mousedown", onMouseDown);
120
+ return () => document.removeEventListener("mousedown", onMouseDown);
121
+ }, [isOpen]);
122
+ const handleRootKeyDown = (e) => {
123
+ if (e.key === "Escape" && isOpen) {
124
+ e.stopPropagation();
125
+ setIsOpen(false);
126
+ setHexDraft(null);
127
+ triggerRef.current?.focus();
128
+ }
129
+ };
130
+ const updateFromPointer = useCallback(
131
+ (clientX, clientY) => {
132
+ const el = satRef.current;
133
+ if (!el) return;
134
+ const rect = el.getBoundingClientRect();
135
+ const s = clamp((clientX - rect.left) / rect.width * 100, 0, 100);
136
+ const v = clamp((1 - (clientY - rect.top) / rect.height) * 100, 0, 100);
137
+ commit({ ...hsvaRef.current, s, v });
138
+ },
139
+ [commit]
140
+ );
141
+ const handleSatPointerDown = (e) => {
142
+ e.preventDefault();
143
+ e.currentTarget.setPointerCapture(e.pointerId);
144
+ e.currentTarget.focus();
145
+ updateFromPointer(e.clientX, e.clientY);
146
+ };
147
+ const handleSatPointerMove = (e) => {
148
+ if (e.currentTarget.hasPointerCapture(e.pointerId)) {
149
+ updateFromPointer(e.clientX, e.clientY);
150
+ }
151
+ };
152
+ const handleSatKeyDown = (e) => {
153
+ const step = e.shiftKey ? 10 : 2;
154
+ const { h, s, v, a } = hsvaRef.current;
155
+ switch (e.key) {
156
+ case "ArrowLeft":
157
+ e.preventDefault();
158
+ commit({ h, s: clamp(s - step, 0, 100), v, a });
159
+ break;
160
+ case "ArrowRight":
161
+ e.preventDefault();
162
+ commit({ h, s: clamp(s + step, 0, 100), v, a });
163
+ break;
164
+ case "ArrowUp":
165
+ e.preventDefault();
166
+ commit({ h, s, v: clamp(v + step, 0, 100), a });
167
+ break;
168
+ case "ArrowDown":
169
+ e.preventDefault();
170
+ commit({ h, s, v: clamp(v - step, 0, 100), a });
171
+ break;
172
+ }
173
+ };
174
+ const displayHex = formatHex(hsva, showAlpha);
175
+ const handleHexChange = (e) => {
176
+ const text = e.target.value;
177
+ setHexDraft(text);
178
+ const parsed = parseHex(text);
179
+ if (parsed) {
180
+ const keepAlpha = text.replace(/^#/, "").length < 8;
181
+ commit(keepAlpha ? { ...parsed, a: hsvaRef.current.a } : parsed);
182
+ }
183
+ };
184
+ const inputId = id || name || label?.toLowerCase().replace(/\s+/g, "-");
185
+ const cssColor = toCssColor(hsva);
186
+ const solidHex = formatHex({ ...hsva, a: 100 }, false);
187
+ const classes = [
188
+ baseClass,
189
+ size === "compact" ? `${baseClass}--compact` : "",
190
+ isOpen ? `${baseClass}--open` : "",
191
+ error ? `${baseClass}--error` : "",
192
+ disabled ? `${baseClass}--disabled` : "",
193
+ className
194
+ ].filter(Boolean).join(" ");
195
+ return /* @__PURE__ */ jsxs(
196
+ Field,
197
+ {
198
+ ref: rootRef,
199
+ className: classes,
200
+ label,
201
+ helperText,
202
+ error,
203
+ required,
204
+ disabled,
205
+ size,
206
+ id: inputId,
207
+ onKeyDown: handleRootKeyDown,
208
+ children: [
209
+ /* @__PURE__ */ jsxs(
210
+ "button",
211
+ {
212
+ ...rest,
213
+ ref: setTriggerRef,
214
+ type: "button",
215
+ id: inputId,
216
+ className: `${baseClass}__trigger`,
217
+ disabled,
218
+ "aria-haspopup": "dialog",
219
+ "aria-expanded": isOpen,
220
+ "aria-describedby": helperText ? `${inputId}-helper` : rest["aria-describedby"],
221
+ "aria-invalid": error || void 0,
222
+ "aria-label": rest["aria-label"] ?? (!label ? `Choose colour, ${displayHex}` : void 0),
223
+ onClick: () => {
224
+ if (!disabled) setIsOpen((prev) => !prev);
225
+ },
226
+ children: [
227
+ /* @__PURE__ */ jsx(
228
+ "span",
229
+ {
230
+ className: `${baseClass}__trigger-swatch`,
231
+ style: { "--ds-cp-color": cssColor },
232
+ "aria-hidden": "true"
233
+ }
234
+ ),
235
+ showText && /* @__PURE__ */ jsx("span", { className: `${baseClass}__trigger-text`, children: displayHex })
236
+ ]
237
+ }
238
+ ),
239
+ name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: displayHex }),
240
+ isOpen && /* @__PURE__ */ jsxs(
241
+ "div",
242
+ {
243
+ className: `${baseClass}__panel`,
244
+ role: "dialog",
245
+ "aria-label": label ? `${label} colour picker` : "Colour picker",
246
+ style: {
247
+ "--ds-cp-hue": hsva.h,
248
+ "--ds-cp-color": cssColor,
249
+ "--ds-cp-solid": solidHex
250
+ },
251
+ children: [
252
+ /* @__PURE__ */ jsx(
253
+ "div",
254
+ {
255
+ ref: satRef,
256
+ className: `${baseClass}__saturation`,
257
+ role: "slider",
258
+ tabIndex: 0,
259
+ "aria-label": "Saturation and brightness",
260
+ "aria-valuemin": 0,
261
+ "aria-valuemax": 100,
262
+ "aria-valuenow": Math.round(hsva.v),
263
+ "aria-valuetext": `Saturation ${Math.round(hsva.s)}%, brightness ${Math.round(hsva.v)}%`,
264
+ onPointerDown: handleSatPointerDown,
265
+ onPointerMove: handleSatPointerMove,
266
+ onKeyDown: handleSatKeyDown,
267
+ style: {
268
+ "--ds-cp-x": `${hsva.s}%`,
269
+ "--ds-cp-y": `${100 - hsva.v}%`
270
+ },
271
+ children: /* @__PURE__ */ jsx("span", { className: `${baseClass}__handle` })
272
+ }
273
+ ),
274
+ /* @__PURE__ */ jsxs("div", { className: `${baseClass}__controls`, children: [
275
+ /* @__PURE__ */ jsxs("div", { className: `${baseClass}__sliders`, children: [
276
+ /* @__PURE__ */ jsx(
277
+ "input",
278
+ {
279
+ type: "range",
280
+ className: `${baseClass}__hue`,
281
+ min: 0,
282
+ max: 359,
283
+ step: 1,
284
+ value: Math.round(hsva.h),
285
+ "aria-label": "Hue",
286
+ onChange: (e) => commit({ ...hsvaRef.current, h: Number(e.target.value) })
287
+ }
288
+ ),
289
+ showAlpha && /* @__PURE__ */ jsx(
290
+ "input",
291
+ {
292
+ type: "range",
293
+ className: `${baseClass}__alpha`,
294
+ min: 0,
295
+ max: 100,
296
+ step: 1,
297
+ value: Math.round(hsva.a),
298
+ "aria-label": "Alpha",
299
+ onChange: (e) => commit({ ...hsvaRef.current, a: Number(e.target.value) })
300
+ }
301
+ )
302
+ ] }),
303
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__preview`, "aria-hidden": "true" })
304
+ ] }),
305
+ /* @__PURE__ */ jsxs("div", { className: `${baseClass}__inputs`, children: [
306
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__hash`, "aria-hidden": "true", children: "#" }),
307
+ /* @__PURE__ */ jsx(
308
+ "input",
309
+ {
310
+ type: "text",
311
+ className: `${baseClass}__hex-field`,
312
+ value: (hexDraft ?? displayHex).replace(/^#/, ""),
313
+ maxLength: 8,
314
+ spellCheck: false,
315
+ autoComplete: "off",
316
+ "aria-label": "Hex colour value",
317
+ onChange: handleHexChange,
318
+ onFocus: () => setHexDraft(displayHex.replace(/^#/, "")),
319
+ onBlur: () => setHexDraft(null)
320
+ }
321
+ ),
322
+ showAlpha && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__alpha-value`, children: [
323
+ Math.round(hsva.a),
324
+ "%"
325
+ ] })
326
+ ] })
327
+ ]
328
+ }
329
+ )
330
+ ]
331
+ }
332
+ );
333
+ }
334
+ );
335
+ ColorPicker.displayName = "ColorPicker";
336
+ export {
337
+ ColorPicker
338
+ };
@@ -16,19 +16,6 @@
16
16
  LABEL
17
17
  ============================================ */
18
18
 
19
- .ds-combobox__label {
20
- font-family: var(--font-paragraph-em-family);
21
- font-size: var(--font-paragraph-em-size);
22
- font-weight: var(--font-paragraph-em-weight);
23
- line-height: var(--font-paragraph-em-line-height);
24
- letter-spacing: var(--font-paragraph-em-letter-spacing);
25
- color: var(--color-text-primary);
26
- }
27
-
28
- .ds-combobox__required {
29
- color: var(--color-core-accent-coral);
30
- }
31
-
32
19
  /* ============================================
33
20
  CONTROL
34
21
  ============================================ */
@@ -324,16 +311,6 @@
324
311
  HELPER TEXT
325
312
  ============================================ */
326
313
 
327
- .ds-combobox__helper {
328
- font-family: var(--font-paragraph-sm-family);
329
- font-size: var(--font-paragraph-sm-size);
330
- font-weight: var(--font-paragraph-sm-weight);
331
- line-height: var(--font-paragraph-sm-line-height);
332
- letter-spacing: var(--font-paragraph-sm-letter-spacing);
333
- color: var(--color-text-tertiary);
334
- margin: 0;
335
- }
336
-
337
314
  /* ============================================
338
315
  ERROR STATE
339
316
  ============================================ */
@@ -342,18 +319,10 @@
342
319
  border-color: var(--color-status-error-border);
343
320
  }
344
321
 
345
- .ds-combobox--error .ds-combobox__helper {
346
- color: var(--color-status-error-border);
347
- }
348
-
349
322
  /* ============================================
350
323
  DISABLED STATE
351
324
  ============================================ */
352
325
 
353
- .ds-combobox--disabled .ds-combobox__label {
354
- color: var(--color-input-text-disabled);
355
- }
356
-
357
326
  .ds-combobox--disabled .ds-combobox__control {
358
327
  background-color: var(--color-input-bg-disabled);
359
328
  border-color: var(--color-input-border-disabled);
@@ -378,11 +347,6 @@
378
347
  padding: var(--padding-xs) var(--padding-sm-md); /* 6px 12px */
379
348
  }
380
349
 
381
- .ds-combobox--compact .ds-combobox__label {
382
- font-size: var(--font-paragraph-sm-size);
383
- line-height: var(--font-paragraph-sm-line-height);
384
- }
385
-
386
350
  .ds-combobox--compact .ds-combobox__input,
387
351
  .ds-combobox--compact .ds-combobox__option-label {
388
352
  font-size: var(--font-paragraph-sm-em-size);
@@ -15,7 +15,8 @@ export interface ComboboxOptionGroup {
15
15
  /** Options within the group */
16
16
  options: ComboboxOption[];
17
17
  }
18
- export interface ComboboxProps {
18
+ /** Props owned by Combobox itself — everything else falls through to the wrapper. */
19
+ type ComboboxOwnProps = {
19
20
  /** Combobox label text */
20
21
  label?: string;
21
22
  /** Placeholder shown in the text field when nothing is selected */
@@ -51,23 +52,34 @@ export interface ComboboxProps {
51
52
  * Called with the new selection — a `string` in single mode,
52
53
  * `string[]` when `multiple` is set.
53
54
  */
54
- onChange?: (value: string | string[]) => void;
55
+ onValueChange?: (value: string | string[]) => void;
55
56
  /** Called as the user types, for async/server-side filtering */
56
57
  onSearchChange?: (query: string) => void;
57
58
  /** Skip built-in filtering — use when options are filtered upstream */
58
59
  manualFiltering?: boolean;
59
60
  /** Additional CSS classes */
60
61
  className?: string;
61
- /** Accessible name override */
62
+ /** @deprecated Use `onValueChange` instead. */
63
+ onChange?: (value: string | string[]) => void;
64
+ /** @deprecated Pass the native `aria-label` attribute instead. */
62
65
  ariaLabel?: string;
63
- /** HTML name attribute */
66
+ /**
67
+ * Used only as a fallback for deriving the element id (`id || name || generated`).
68
+ *
69
+ * Note: Combobox renders a `<div>` wrapper around a text input, not a native
70
+ * `<select>`, so `name` does **not** make the selection participate in native
71
+ * form submission.
72
+ */
64
73
  name?: string;
65
- /** HTML id attribute */
66
- id?: string;
74
+ };
75
+ export interface ComboboxProps extends ComboboxOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof ComboboxOwnProps> {
67
76
  }
68
77
  /**
69
78
  * Combobox component — a text field combined with a filterable listbox.
70
79
  * Unlike Dropdown (a static select), it narrows options as the user types
71
80
  * and supports multi-select chips and async option loading.
81
+ *
82
+ * Forwards a ref to the wrapping element and spreads unrecognised props onto it.
72
83
  */
73
- export declare const Combobox: ({ label, placeholder, value, options, groups, multiple, size, disabled, required, error, helperText, loading, emptyMessage, clearable, onChange, onSearchChange, manualFiltering, className, ariaLabel, name, id, }: ComboboxProps) => React.JSX.Element;
84
+ export declare const Combobox: React.ForwardRefExoticComponent<ComboboxProps & React.RefAttributes<HTMLDivElement>>;
85
+ export {};