@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.
- package/README.md +13 -9
- package/components/Accordion/Accordion.js +0 -1
- package/components/Avatar/Avatar.js +1 -0
- package/components/Breadcrumb/Breadcrumb.css +9 -1
- package/components/Breadcrumb/Breadcrumb.d.ts +7 -1
- package/components/Breadcrumb/Breadcrumb.js +3 -2
- package/components/Button/Button.css +18 -0
- package/components/Button/Button.d.ts +38 -16
- package/components/Button/Button.js +76 -58
- package/components/Card/Card.css +6 -0
- package/components/Card/Card.d.ts +17 -5
- package/components/Card/Card.js +101 -80
- package/components/Checkbox/Checkbox.d.ts +24 -12
- package/components/Checkbox/Checkbox.js +99 -85
- package/components/CircularButton/CircularButton.css +11 -0
- package/components/CircularButton/CircularButton.d.ts +7 -1
- package/components/CircularButton/CircularButton.js +15 -4
- package/components/CodeBlock/CodeBlock.js +10 -1
- package/components/ColorPicker/ColorPicker.css +278 -0
- package/components/ColorPicker/ColorPicker.d.ts +50 -0
- package/components/ColorPicker/ColorPicker.js +338 -0
- package/components/Combobox/Combobox.css +0 -36
- package/components/Combobox/Combobox.d.ts +19 -7
- package/components/Combobox/Combobox.js +106 -89
- package/components/CommandPalette/CommandPalette.css +1 -15
- package/components/CommandPalette/CommandPalette.js +6 -5
- package/components/ContextMenu/ContextMenu.css +262 -0
- package/components/ContextMenu/ContextMenu.d.ts +26 -0
- package/components/ContextMenu/ContextMenu.js +350 -0
- package/components/DateInput/DateInput.css +0 -36
- package/components/DateInput/DateInput.d.ts +18 -21
- package/components/DateInput/DateInput.js +76 -64
- package/components/DatePicker/DatePicker.d.ts +9 -2
- package/components/DatePicker/DatePicker.js +137 -128
- package/components/Dialog/Dialog.d.ts +15 -4
- package/components/Dialog/Dialog.js +136 -118
- package/components/Drawer/Drawer.d.ts +15 -4
- package/components/Drawer/Drawer.js +138 -119
- package/components/Dropdown/Dropdown.css +0 -36
- package/components/Dropdown/Dropdown.d.ts +24 -8
- package/components/Dropdown/Dropdown.js +219 -169
- package/components/DropdownMenu/DropdownMenu.js +10 -7
- package/components/Field/Field.css +80 -0
- package/components/Field/Field.d.ts +50 -0
- package/components/Field/Field.js +58 -0
- package/components/Field/FieldContext.d.ts +42 -0
- package/components/Field/FieldContext.js +7 -0
- package/components/FileInput/FileInput.css +0 -36
- package/components/FileInput/FileInput.d.ts +13 -17
- package/components/FileInput/FileInput.js +168 -141
- package/components/Input/Input.css +0 -43
- package/components/Input/Input.d.ts +23 -22
- package/components/Input/Input.js +93 -66
- package/components/Kbd/Kbd.css +28 -0
- package/components/Kbd/Kbd.d.ts +19 -0
- package/components/Kbd/Kbd.js +14 -0
- package/components/Popover/Popover.d.ts +0 -6
- package/components/Popover/Popover.js +22 -16
- package/components/ProgressBar/ProgressBar.js +1 -1
- package/components/RadioButton/RadioButton.d.ts +26 -13
- package/components/RadioButton/RadioButton.js +95 -70
- package/components/SelectionCard/SelectionCard.css +6 -2
- package/components/SelectionCard/SelectionCard.d.ts +10 -4
- package/components/SelectionCard/SelectionCard.js +72 -56
- package/components/Skeleton/Skeleton.css +2 -0
- package/components/Slider/Slider.d.ts +19 -10
- package/components/Slider/Slider.js +50 -40
- package/components/Spinner/Spinner.css +11 -0
- package/components/Spinner/Spinner.d.ts +2 -2
- package/components/Swatch/Swatch.css +52 -0
- package/components/Swatch/Swatch.d.ts +34 -0
- package/components/Swatch/Swatch.js +44 -0
- package/components/Table/Table.css +19 -0
- package/components/Table/Table.d.ts +10 -2
- package/components/Table/Table.js +58 -58
- package/components/Textarea/Textarea.css +0 -43
- package/components/Textarea/Textarea.d.ts +21 -22
- package/components/Textarea/Textarea.js +78 -67
- package/components/ToggleGroup/ToggleGroup.d.ts +18 -8
- package/components/ToggleGroup/ToggleGroup.js +61 -44
- package/components/ToggleSwitch/ToggleSwitch.css +7 -2
- package/components/ToggleSwitch/ToggleSwitch.d.ts +17 -9
- package/components/ToggleSwitch/ToggleSwitch.js +57 -44
- package/components/registry.d.ts +47 -10
- package/components/registry.js +5 -1
- package/components/registry.json +498 -56
- package/components/registry.json.d.ts +498 -56
- package/components/registry.json.js +4 -1
- package/index.d.ts +8 -1
- package/index.js +16 -1
- 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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
|
|
66
|
-
|
|
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:
|
|
84
|
+
export declare const Combobox: React.ForwardRefExoticComponent<ComboboxProps & React.RefAttributes<HTMLDivElement>>;
|
|
85
|
+
export {};
|