@robr0/design-system 0.2.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 (66) hide show
  1. package/README.md +8 -6
  2. package/components/Accordion/Accordion.js +0 -1
  3. package/components/Avatar/Avatar.js +1 -0
  4. package/components/Breadcrumb/Breadcrumb.d.ts +7 -1
  5. package/components/Breadcrumb/Breadcrumb.js +3 -2
  6. package/components/Button/Button.css +18 -0
  7. package/components/Button/Button.d.ts +6 -0
  8. package/components/Button/Button.js +13 -3
  9. package/components/Card/Card.css +6 -0
  10. package/components/CircularButton/CircularButton.css +11 -0
  11. package/components/CircularButton/CircularButton.d.ts +7 -1
  12. package/components/CircularButton/CircularButton.js +15 -4
  13. package/components/CodeBlock/CodeBlock.js +10 -1
  14. package/components/ColorPicker/ColorPicker.css +278 -0
  15. package/components/ColorPicker/ColorPicker.d.ts +50 -0
  16. package/components/ColorPicker/ColorPicker.js +338 -0
  17. package/components/Combobox/Combobox.css +0 -36
  18. package/components/Combobox/Combobox.js +90 -82
  19. package/components/CommandPalette/CommandPalette.css +1 -15
  20. package/components/CommandPalette/CommandPalette.js +6 -5
  21. package/components/ContextMenu/ContextMenu.css +262 -0
  22. package/components/ContextMenu/ContextMenu.d.ts +26 -0
  23. package/components/ContextMenu/ContextMenu.js +350 -0
  24. package/components/DateInput/DateInput.css +0 -36
  25. package/components/DateInput/DateInput.js +37 -33
  26. package/components/DatePicker/DatePicker.js +45 -34
  27. package/components/Dialog/Dialog.js +5 -4
  28. package/components/Drawer/Drawer.js +7 -2
  29. package/components/Dropdown/Dropdown.css +0 -36
  30. package/components/Dropdown/Dropdown.js +119 -109
  31. package/components/DropdownMenu/DropdownMenu.js +10 -7
  32. package/components/Field/Field.css +80 -0
  33. package/components/Field/Field.d.ts +50 -0
  34. package/components/Field/Field.js +58 -0
  35. package/components/Field/FieldContext.d.ts +42 -0
  36. package/components/Field/FieldContext.js +7 -0
  37. package/components/FileInput/FileInput.css +0 -36
  38. package/components/FileInput/FileInput.js +111 -103
  39. package/components/Input/Input.css +0 -43
  40. package/components/Input/Input.js +51 -46
  41. package/components/Kbd/Kbd.css +28 -0
  42. package/components/Kbd/Kbd.d.ts +19 -0
  43. package/components/Kbd/Kbd.js +14 -0
  44. package/components/Popover/Popover.d.ts +0 -6
  45. package/components/Popover/Popover.js +22 -16
  46. package/components/ProgressBar/ProgressBar.js +1 -1
  47. package/components/SelectionCard/SelectionCard.css +6 -2
  48. package/components/Skeleton/Skeleton.css +2 -0
  49. package/components/Spinner/Spinner.css +11 -0
  50. package/components/Spinner/Spinner.d.ts +2 -2
  51. package/components/Swatch/Swatch.css +52 -0
  52. package/components/Swatch/Swatch.d.ts +34 -0
  53. package/components/Swatch/Swatch.js +44 -0
  54. package/components/Table/Table.css +19 -0
  55. package/components/Table/Table.js +1 -1
  56. package/components/Textarea/Textarea.css +0 -43
  57. package/components/Textarea/Textarea.js +37 -35
  58. package/components/ToggleSwitch/ToggleSwitch.css +7 -2
  59. package/components/registry.d.ts +47 -10
  60. package/components/registry.js +5 -1
  61. package/components/registry.json +498 -56
  62. package/components/registry.json.d.ts +498 -56
  63. package/components/registry.json.js +4 -1
  64. package/index.d.ts +8 -1
  65. package/index.js +16 -1
  66. package/package.json +1 -1
@@ -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);
@@ -1,5 +1,6 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import React, { useState, useRef, useId, useMemo, useCallback, useEffect } from "react";
3
+ import { Field } from "../Field/Field.js";
3
4
  import "./Combobox.css";
4
5
  import "../../fonts/material-symbols.css";
5
6
  const Combobox = React.forwardRef(({
@@ -223,97 +224,104 @@ const Combobox = React.forwardRef(({
223
224
  );
224
225
  };
225
226
  const hasSelection = selectedValues.length > 0;
226
- return /* @__PURE__ */ jsxs("div", { ...rest, className: classes, ref: setRootRef, children: [
227
- label && /* @__PURE__ */ jsxs("label", { className: `${baseClass}__label`, htmlFor: inputId, children: [
227
+ return /* @__PURE__ */ jsxs(
228
+ Field,
229
+ {
230
+ ...rest,
231
+ className: classes,
232
+ ref: setRootRef,
228
233
  label,
229
- required && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__required`, "aria-hidden": "true", children: [
230
- " ",
231
- "*"
232
- ] })
233
- ] }),
234
- /* @__PURE__ */ jsxs("div", { className: `${baseClass}__control`, onClick: () => inputRef.current?.focus(), children: [
235
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__search-icon material-symbols-rounded`, "aria-hidden": "true", children: "search" }),
236
- /* @__PURE__ */ jsxs("div", { className: `${baseClass}__field`, children: [
237
- multiple && selectedOptions.map((option) => /* @__PURE__ */ jsxs("span", { className: `${baseClass}__chip`, children: [
238
- option.label,
239
- /* @__PURE__ */ jsx(
234
+ helperText,
235
+ error,
236
+ required,
237
+ disabled,
238
+ size,
239
+ id: inputId,
240
+ children: [
241
+ /* @__PURE__ */ jsxs("div", { className: `${baseClass}__control`, onClick: () => inputRef.current?.focus(), children: [
242
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__search-icon material-symbols-rounded`, "aria-hidden": "true", children: "search" }),
243
+ /* @__PURE__ */ jsxs("div", { className: `${baseClass}__field`, children: [
244
+ multiple && selectedOptions.map((option) => /* @__PURE__ */ jsxs("span", { className: `${baseClass}__chip`, children: [
245
+ option.label,
246
+ /* @__PURE__ */ jsx(
247
+ "button",
248
+ {
249
+ type: "button",
250
+ className: `${baseClass}__chip-remove`,
251
+ onClick: (e) => {
252
+ e.stopPropagation();
253
+ handleRemove(option.value);
254
+ },
255
+ disabled,
256
+ "aria-label": `Remove ${option.label}`,
257
+ children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", "aria-hidden": "true", children: "close" })
258
+ }
259
+ )
260
+ ] }, option.value)),
261
+ /* @__PURE__ */ jsx(
262
+ "input",
263
+ {
264
+ ref: inputRef,
265
+ id: inputId,
266
+ name,
267
+ type: "text",
268
+ className: `${baseClass}__input`,
269
+ role: "combobox",
270
+ autoComplete: "off",
271
+ "aria-expanded": isOpen,
272
+ "aria-controls": listboxId,
273
+ "aria-autocomplete": "list",
274
+ "aria-activedescendant": activeOptionId,
275
+ "aria-label": ariaLabel || rest["aria-label"] || (!label ? placeholder : void 0),
276
+ "aria-describedby": helperText ? `${inputId}-helper` : void 0,
277
+ "aria-invalid": error || void 0,
278
+ "aria-required": required || void 0,
279
+ placeholder: multiple && hasSelection ? "" : placeholder,
280
+ value: inputValue,
281
+ disabled,
282
+ onChange: (e) => handleQueryChange(e.target.value),
283
+ onFocus: openMenu,
284
+ onKeyDown: handleKeyDown
285
+ }
286
+ )
287
+ ] }),
288
+ clearable && hasSelection && !disabled && /* @__PURE__ */ jsx(
240
289
  "button",
241
290
  {
242
291
  type: "button",
243
- className: `${baseClass}__chip-remove`,
292
+ className: `${baseClass}__clear`,
244
293
  onClick: (e) => {
245
294
  e.stopPropagation();
246
- handleRemove(option.value);
295
+ handleClear();
247
296
  },
248
- disabled,
249
- "aria-label": `Remove ${option.label}`,
297
+ "aria-label": "Clear selection",
250
298
  children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", "aria-hidden": "true", children: "close" })
251
299
  }
252
- )
253
- ] }, option.value)),
254
- /* @__PURE__ */ jsx(
255
- "input",
256
- {
257
- ref: inputRef,
258
- id: inputId,
259
- name,
260
- type: "text",
261
- className: `${baseClass}__input`,
262
- role: "combobox",
263
- autoComplete: "off",
264
- "aria-expanded": isOpen,
265
- "aria-controls": listboxId,
266
- "aria-autocomplete": "list",
267
- "aria-activedescendant": activeOptionId,
268
- "aria-label": ariaLabel || rest["aria-label"] || (!label ? placeholder : void 0),
269
- "aria-describedby": helperText ? `${inputId}-helper` : void 0,
270
- "aria-invalid": error || void 0,
271
- "aria-required": required || void 0,
272
- placeholder: multiple && hasSelection ? "" : placeholder,
273
- value: inputValue,
274
- disabled,
275
- onChange: (e) => handleQueryChange(e.target.value),
276
- onFocus: openMenu,
277
- onKeyDown: handleKeyDown
278
- }
279
- )
280
- ] }),
281
- clearable && hasSelection && !disabled && /* @__PURE__ */ jsx(
282
- "button",
283
- {
284
- type: "button",
285
- className: `${baseClass}__clear`,
286
- onClick: (e) => {
287
- e.stopPropagation();
288
- handleClear();
289
- },
290
- "aria-label": "Clear selection",
291
- children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", "aria-hidden": "true", children: "close" })
292
- }
293
- ),
294
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__chevron material-symbols-rounded`, "aria-hidden": "true", children: "expand_more" })
295
- ] }),
296
- isOpen && /* @__PURE__ */ jsxs("ul", { className: `${baseClass}__menu`, role: "listbox", id: listboxId, ref: listRef, children: [
297
- loading && /* @__PURE__ */ jsx("li", { className: `${baseClass}__status`, role: "presentation", children: "Loading…" }),
298
- !loading && filteredOptions.length === 0 && /* @__PURE__ */ jsx("li", { className: `${baseClass}__status`, role: "presentation", children: emptyMessage }),
299
- !loading && (isGrouped ? (() => {
300
- let flatIndex = 0;
301
- return filteredGroups.map((group) => /* @__PURE__ */ jsxs("li", { className: `${baseClass}__group`, role: "none", children: [
302
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__group-label`, role: "presentation", children: group.label }),
303
- /* @__PURE__ */ jsx(
304
- "ul",
305
- {
306
- className: `${baseClass}__group-list`,
307
- role: "group",
308
- "aria-label": group.label,
309
- children: group.options.map((option) => renderOption(option, flatIndex++))
310
- }
311
- )
312
- ] }, group.label));
313
- })() : filteredOptions.map((option, index) => renderOption(option, index)))
314
- ] }),
315
- helperText && /* @__PURE__ */ jsx("p", { className: `${baseClass}__helper`, id: `${inputId}-helper`, children: helperText })
316
- ] });
300
+ ),
301
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__chevron material-symbols-rounded`, "aria-hidden": "true", children: "expand_more" })
302
+ ] }),
303
+ isOpen && /* @__PURE__ */ jsxs("ul", { className: `${baseClass}__menu`, role: "listbox", id: listboxId, ref: listRef, children: [
304
+ loading && /* @__PURE__ */ jsx("li", { className: `${baseClass}__status`, role: "presentation", children: "Loading…" }),
305
+ !loading && filteredOptions.length === 0 && /* @__PURE__ */ jsx("li", { className: `${baseClass}__status`, role: "presentation", children: emptyMessage }),
306
+ !loading && (isGrouped ? (() => {
307
+ let flatIndex = 0;
308
+ return filteredGroups.map((group) => /* @__PURE__ */ jsxs("li", { className: `${baseClass}__group`, role: "none", children: [
309
+ /* @__PURE__ */ jsx("span", { className: `${baseClass}__group-label`, role: "presentation", children: group.label }),
310
+ /* @__PURE__ */ jsx(
311
+ "ul",
312
+ {
313
+ className: `${baseClass}__group-list`,
314
+ role: "group",
315
+ "aria-label": group.label,
316
+ children: group.options.map((option) => renderOption(option, flatIndex++))
317
+ }
318
+ )
319
+ ] }, group.label));
320
+ })() : filteredOptions.map((option, index) => renderOption(option, index)))
321
+ ] })
322
+ ]
323
+ }
324
+ );
317
325
  });
318
326
  Combobox.displayName = "Combobox";
319
327
  export {
@@ -241,21 +241,7 @@
241
241
  flex-shrink: 0;
242
242
  }
243
243
 
244
- .ds-command-palette__key {
245
- display: inline-flex;
246
- align-items: center;
247
- justify-content: center;
248
- min-width: 20px;
249
- padding: var(--padding-xxxs) var(--padding-xxs);
250
- border: var(--border-xs) solid var(--color-bg-container-border);
251
- border-radius: var(--radius-xs);
252
- background-color: var(--color-bg-container-primary);
253
- font-family: var(--font-paragraph-sm-family);
254
- font-size: var(--font-paragraph-sm-size);
255
- font-weight: var(--font-paragraph-sm-em-weight);
256
- line-height: var(--font-paragraph-sm-line-height);
257
- color: var(--color-text-tertiary);
258
- }
244
+ /* Keycaps render through the Kbd component (compact size) */
259
245
 
260
246
  /* ============================================
261
247
  FOOTER HINTS
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { useState, useRef, useId, useSyncExternalStore, useCallback, useMemo, useEffect } from "react";
3
3
  import ReactDOM from "react-dom";
4
+ import { Kbd } from "../Kbd/Kbd.js";
4
5
  import "./CommandPalette.css";
5
6
  import "../../fonts/material-symbols.css";
6
7
  const emptySubscribe = () => () => {
@@ -225,7 +226,7 @@ const CommandPalette = ({
225
226
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__command-label`, children: command.label }),
226
227
  command.description && /* @__PURE__ */ jsx("span", { className: `${baseClass}__command-description`, children: command.description })
227
228
  ] }),
228
- command.shortcut && command.shortcut.length > 0 && /* @__PURE__ */ jsx("span", { className: `${baseClass}__shortcut`, children: command.shortcut.map((key, i) => /* @__PURE__ */ jsx("kbd", { className: `${baseClass}__key`, children: key }, i)) })
229
+ command.shortcut && command.shortcut.length > 0 && /* @__PURE__ */ jsx("span", { className: `${baseClass}__shortcut`, children: command.shortcut.map((key, i) => /* @__PURE__ */ jsx(Kbd, { size: "compact", children: key }, i)) })
229
230
  ]
230
231
  },
231
232
  command.id
@@ -238,16 +239,16 @@ const CommandPalette = ({
238
239
  ] }),
239
240
  !hideFooter && /* @__PURE__ */ jsxs("div", { className: `${baseClass}__footer`, children: [
240
241
  /* @__PURE__ */ jsxs("span", { className: `${baseClass}__hint`, children: [
241
- /* @__PURE__ */ jsx("kbd", { className: `${baseClass}__key`, children: "↑" }),
242
- /* @__PURE__ */ jsx("kbd", { className: `${baseClass}__key`, children: "↓" }),
242
+ /* @__PURE__ */ jsx(Kbd, { size: "compact", children: "↑" }),
243
+ /* @__PURE__ */ jsx(Kbd, { size: "compact", children: "↓" }),
243
244
  "to navigate"
244
245
  ] }),
245
246
  /* @__PURE__ */ jsxs("span", { className: `${baseClass}__hint`, children: [
246
- /* @__PURE__ */ jsx("kbd", { className: `${baseClass}__key`, children: "↵" }),
247
+ /* @__PURE__ */ jsx(Kbd, { size: "compact", children: "↵" }),
247
248
  "to select"
248
249
  ] }),
249
250
  /* @__PURE__ */ jsxs("span", { className: `${baseClass}__hint`, children: [
250
- /* @__PURE__ */ jsx("kbd", { className: `${baseClass}__key`, children: "esc" }),
251
+ /* @__PURE__ */ jsx(Kbd, { size: "compact", children: "esc" }),
251
252
  "to close"
252
253
  ] })
253
254
  ] })