@robr0/design-system 0.2.0 → 0.4.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 +33 -28
- package/components/Accordion/Accordion.js +0 -1
- package/components/AgentStatus/AgentStatus.css +436 -0
- package/components/AgentStatus/AgentStatus.d.ts +37 -0
- package/components/AgentStatus/AgentStatus.js +53 -0
- package/components/AgentStatus/AgentStatusPatterns.d.ts +17 -0
- package/components/AgentStatus/AgentStatusPatterns.js +20 -0
- package/components/AlertDialog/AlertDialog.css +5 -5
- package/components/Avatar/Avatar.js +1 -0
- 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 +20 -2
- package/components/Button/Button.js +13 -3
- package/components/ButtonGroup/ButtonGroup.js +2 -9
- package/components/Card/Card.css +6 -0
- package/components/Checkbox/Checkbox.d.ts +17 -3
- package/components/CircularButton/CircularButton.css +11 -0
- package/components/CircularButton/CircularButton.d.ts +15 -3
- package/components/CircularButton/CircularButton.js +19 -6
- 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 +10 -2
- package/components/Combobox/Combobox.js +90 -82
- package/components/CommandPalette/CommandPalette.css +1 -15
- package/components/CommandPalette/CommandPalette.js +6 -5
- package/components/ContextMenu/ContextMenu.css +258 -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 +5 -1
- package/components/DateInput/DateInput.js +37 -33
- package/components/DatePicker/DatePicker.js +45 -34
- package/components/Dialog/Dialog.css +5 -5
- package/components/Dialog/Dialog.js +5 -4
- package/components/Drawer/Drawer.js +7 -2
- package/components/Dropdown/Dropdown.css +2 -40
- package/components/Dropdown/Dropdown.d.ts +10 -2
- package/components/Dropdown/Dropdown.js +119 -109
- package/components/DropdownMenu/DropdownMenu.css +2 -4
- 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 +5 -1
- package/components/FileInput/FileInput.js +111 -103
- package/components/Input/Input.css +0 -43
- package/components/Input/Input.d.ts +5 -1
- package/components/Input/Input.js +51 -46
- package/components/Kbd/Kbd.css +28 -0
- package/components/Kbd/Kbd.d.ts +19 -0
- package/components/Kbd/Kbd.js +14 -0
- package/components/LinkList/LinkList.d.ts +1 -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 +17 -3
- package/components/Reasoning/Reasoning.css +152 -0
- package/components/Reasoning/Reasoning.d.ts +36 -0
- package/components/Reasoning/Reasoning.js +69 -0
- package/components/SelectionCard/SelectionCard.css +6 -2
- package/components/SelectionCard/SelectionCard.d.ts +5 -1
- package/components/Skeleton/Skeleton.css +2 -0
- package/components/Slider/Slider.d.ts +5 -1
- 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.js +1 -1
- package/components/Textarea/Textarea.css +0 -43
- package/components/Textarea/Textarea.d.ts +5 -1
- package/components/Textarea/Textarea.js +37 -35
- package/components/Timeline/Timeline.d.ts +2 -0
- package/components/ToggleGroup/ToggleGroup.d.ts +10 -2
- package/components/ToggleSwitch/ToggleSwitch.css +7 -2
- package/components/ToggleSwitch/ToggleSwitch.d.ts +10 -2
- package/components/ToolCall/ToolCall.css +213 -0
- package/components/ToolCall/ToolCall.d.ts +43 -0
- package/components/ToolCall/ToolCall.js +89 -0
- package/components/registry.d.ts +47 -10
- package/components/registry.js +5 -1
- package/components/registry.json +523 -56
- package/components/registry.json.d.ts +523 -56
- package/components/registry.json.js +4 -1
- package/index.d.ts +12 -1
- package/index.js +24 -1
- package/package.json +8 -4
- package/tokens/registry.json +1 -0
- package/tokens/registry.json.d.ts +1 -0
- package/tokens/registry.json.js +1 -1
- package/tokens/tokens-motion.css +3 -1
|
@@ -13,11 +13,21 @@ type RadioButtonOwnProps = {
|
|
|
13
13
|
onValueChange?: (value: string) => void;
|
|
14
14
|
/** Additional CSS classes */
|
|
15
15
|
className?: string;
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Legacy change handler, kept for backwards compatibility.
|
|
18
|
+
*
|
|
19
|
+
* @deprecated Use `onValueChange` instead.
|
|
20
|
+
*/
|
|
17
21
|
onChange?: (value: string) => void;
|
|
18
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Legacy accessible-name prop.
|
|
24
|
+
*
|
|
25
|
+
* @deprecated Pass the native `aria-label` attribute instead.
|
|
26
|
+
*/
|
|
19
27
|
ariaLabel?: string;
|
|
20
28
|
/**
|
|
29
|
+
* Legacy form-field name.
|
|
30
|
+
*
|
|
21
31
|
* @deprecated No-op. This component renders a `<div role="radio">`, not a
|
|
22
32
|
* native `<input type="radio">`, so it does not group by name or participate
|
|
23
33
|
* in native form submission — `RadioGroup` handles grouping in React state.
|
|
@@ -47,7 +57,11 @@ type RadioGroupOwnProps = {
|
|
|
47
57
|
onValueChange?: (value: string) => void;
|
|
48
58
|
/** Additional CSS classes */
|
|
49
59
|
className?: string;
|
|
50
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Legacy change handler, kept for backwards compatibility.
|
|
62
|
+
*
|
|
63
|
+
* @deprecated Use `onValueChange` instead.
|
|
64
|
+
*/
|
|
51
65
|
onChange?: (value: string) => void;
|
|
52
66
|
};
|
|
53
67
|
export interface RadioGroupProps extends RadioGroupOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof RadioGroupOwnProps> {
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
REASONING COMPONENT
|
|
3
|
+
A model's thinking, disclosed behind a
|
|
4
|
+
one-line summary. Quiet by construction: the
|
|
5
|
+
trace is secondary text on a rail, never
|
|
6
|
+
competing with the answer beside it.
|
|
7
|
+
============================================ */
|
|
8
|
+
|
|
9
|
+
.ds-reasoning {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
width: 100%;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* ============================================
|
|
16
|
+
TRIGGER
|
|
17
|
+
============================================ */
|
|
18
|
+
|
|
19
|
+
.ds-reasoning__trigger {
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
gap: var(--gap-xs);
|
|
23
|
+
align-self: flex-start;
|
|
24
|
+
padding: var(--padding-xxs) var(--padding-xs);
|
|
25
|
+
margin-left: calc(var(--padding-xs) * -1);
|
|
26
|
+
background: none;
|
|
27
|
+
border: none;
|
|
28
|
+
border-radius: var(--radius-sm);
|
|
29
|
+
color: var(--color-text-tertiary);
|
|
30
|
+
font-family: var(--font-paragraph-sm-family);
|
|
31
|
+
font-size: var(--font-paragraph-sm-size);
|
|
32
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
33
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
34
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
transition: color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.ds-reasoning__trigger:hover {
|
|
40
|
+
color: var(--color-text-secondary);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ds-reasoning__trigger:focus-visible {
|
|
44
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
45
|
+
outline-offset: -2px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.ds-reasoning__chevron {
|
|
49
|
+
--icon-size: var(--icon-size-sm);
|
|
50
|
+
|
|
51
|
+
flex: none;
|
|
52
|
+
transition: transform var(--motion-duration-slow) var(--motion-ease-standard);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.ds-reasoning--open .ds-reasoning__chevron {
|
|
56
|
+
transform: rotate(180deg);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ============================================
|
|
60
|
+
SUMMARY
|
|
61
|
+
While the trace streams, a highlight sweeps
|
|
62
|
+
the summary left to right — the same treatment
|
|
63
|
+
AgentStatus uses, so "the model is working"
|
|
64
|
+
looks the same wherever it appears.
|
|
65
|
+
============================================ */
|
|
66
|
+
|
|
67
|
+
.ds-reasoning__summary {
|
|
68
|
+
white-space: nowrap;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.ds-reasoning--streaming .ds-reasoning__summary {
|
|
72
|
+
background-image: linear-gradient(
|
|
73
|
+
100deg,
|
|
74
|
+
var(--color-text-tertiary) 40%,
|
|
75
|
+
var(--color-text-primary) 50%,
|
|
76
|
+
var(--color-text-tertiary) 60%
|
|
77
|
+
);
|
|
78
|
+
background-size: 250% 100%;
|
|
79
|
+
background-clip: text;
|
|
80
|
+
-webkit-background-clip: text;
|
|
81
|
+
color: transparent;
|
|
82
|
+
animation: ds-reasoning-shimmer var(--motion-duration-loop-shimmer)
|
|
83
|
+
var(--motion-ease-linear) infinite;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@keyframes ds-reasoning-shimmer {
|
|
87
|
+
from {
|
|
88
|
+
background-position-x: 100%;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
to {
|
|
92
|
+
background-position-x: 0%;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* ============================================
|
|
97
|
+
PANEL
|
|
98
|
+
============================================ */
|
|
99
|
+
|
|
100
|
+
.ds-reasoning__panel {
|
|
101
|
+
display: grid;
|
|
102
|
+
grid-template-rows: 0fr;
|
|
103
|
+
visibility: hidden;
|
|
104
|
+
transition:
|
|
105
|
+
grid-template-rows var(--motion-duration-slow) var(--motion-ease-standard),
|
|
106
|
+
visibility var(--motion-duration-slow) var(--motion-ease-standard);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.ds-reasoning--open .ds-reasoning__panel {
|
|
110
|
+
grid-template-rows: 1fr;
|
|
111
|
+
visibility: visible;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.ds-reasoning__content {
|
|
115
|
+
overflow: hidden;
|
|
116
|
+
min-height: 0;
|
|
117
|
+
transition: padding-block var(--motion-duration-slow) var(--motion-ease-standard);
|
|
118
|
+
padding-left: var(--padding-sm-md);
|
|
119
|
+
/* The rail sits flush with the summary's left edge — the trigger's own
|
|
120
|
+
padding is cancelled by its negative margin, so both start at zero */
|
|
121
|
+
border-left: var(--border-md) solid var(--color-divider);
|
|
122
|
+
color: var(--color-text-secondary);
|
|
123
|
+
font-family: var(--font-paragraph-sm-family);
|
|
124
|
+
font-size: var(--font-paragraph-sm-size);
|
|
125
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
126
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
127
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.ds-reasoning--open .ds-reasoning__content {
|
|
131
|
+
padding-block: var(--padding-xs);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.ds-reasoning__content > :first-child {
|
|
135
|
+
margin-top: 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.ds-reasoning__content > :last-child {
|
|
139
|
+
margin-bottom: 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* ============================================
|
|
143
|
+
REDUCED MOTION
|
|
144
|
+
============================================ */
|
|
145
|
+
|
|
146
|
+
@media (prefers-reduced-motion: reduce) {
|
|
147
|
+
.ds-reasoning--streaming .ds-reasoning__summary {
|
|
148
|
+
background-image: none;
|
|
149
|
+
color: var(--color-text-tertiary);
|
|
150
|
+
animation: none;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by Reasoning itself — everything else falls through to the root element. */
|
|
3
|
+
type ReasoningOwnProps = {
|
|
4
|
+
/** The model is still producing the trace. Opens the panel and shimmers the summary. */
|
|
5
|
+
streaming?: boolean;
|
|
6
|
+
/** Seconds spent reasoning, shown in the summary once complete. */
|
|
7
|
+
duration?: number;
|
|
8
|
+
/** Override the summary line. By default it reports the streaming state and the duration. */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** Open state for controlled use. Pair with `onOpenChange`. */
|
|
11
|
+
open?: boolean;
|
|
12
|
+
/** Open state for uncontrolled use. Defaults to open while `streaming`. */
|
|
13
|
+
defaultOpen?: boolean;
|
|
14
|
+
/** Fires whenever the panel opens or closes, from a click or from the stream ending. */
|
|
15
|
+
onOpenChange?: (open: boolean) => void;
|
|
16
|
+
/** Additional CSS classes */
|
|
17
|
+
className?: string;
|
|
18
|
+
/** The reasoning trace. */
|
|
19
|
+
children?: React.ReactNode;
|
|
20
|
+
};
|
|
21
|
+
export interface ReasoningProps extends ReasoningOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof ReasoningOwnProps> {
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Reasoning discloses a model's thinking without letting it dominate the
|
|
25
|
+
* response: open while the trace streams in, collapsed to a one-line summary
|
|
26
|
+
* once it finishes.
|
|
27
|
+
*
|
|
28
|
+
* The auto-collapse yields to the reader — once someone has toggled the panel
|
|
29
|
+
* themselves, the stream ending no longer closes it.
|
|
30
|
+
*
|
|
31
|
+
* Only the summary line is a live region. A trace announced token by token
|
|
32
|
+
* floods a screen reader, so the body is ordinary expandable content and the
|
|
33
|
+
* announcement covers the boundaries: thinking, then thought for so long.
|
|
34
|
+
*/
|
|
35
|
+
export declare const Reasoning: React.ForwardRefExoticComponent<ReasoningProps & React.RefAttributes<HTMLDivElement>>;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useId, useState, useRef, useEffect, useCallback } from "react";
|
|
3
|
+
import "./Reasoning.css";
|
|
4
|
+
import "../../fonts/material-symbols.css";
|
|
5
|
+
const Reasoning = React.forwardRef(
|
|
6
|
+
({
|
|
7
|
+
streaming = false,
|
|
8
|
+
duration,
|
|
9
|
+
label,
|
|
10
|
+
open,
|
|
11
|
+
defaultOpen,
|
|
12
|
+
onOpenChange,
|
|
13
|
+
className = "",
|
|
14
|
+
children,
|
|
15
|
+
...rest
|
|
16
|
+
}, ref) => {
|
|
17
|
+
const baseClass = "ds-reasoning";
|
|
18
|
+
const id = useId();
|
|
19
|
+
const panelId = `${id}-panel`;
|
|
20
|
+
const triggerId = `${id}-trigger`;
|
|
21
|
+
const isControlled = open !== void 0;
|
|
22
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen ?? streaming);
|
|
23
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
24
|
+
const readerDecided = useRef(false);
|
|
25
|
+
const wasStreaming = useRef(streaming);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (streaming === wasStreaming.current) return;
|
|
28
|
+
wasStreaming.current = streaming;
|
|
29
|
+
if (readerDecided.current) return;
|
|
30
|
+
if (!isControlled) setUncontrolledOpen(streaming);
|
|
31
|
+
onOpenChange?.(streaming);
|
|
32
|
+
}, [streaming, isControlled, onOpenChange]);
|
|
33
|
+
const toggle = useCallback(() => {
|
|
34
|
+
readerDecided.current = true;
|
|
35
|
+
const next = !isOpen;
|
|
36
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
37
|
+
onOpenChange?.(next);
|
|
38
|
+
}, [isOpen, isControlled, onOpenChange]);
|
|
39
|
+
const summary = label ?? (streaming ? "Thinking" : duration !== void 0 ? `Thought for ${duration}s` : "Thought process");
|
|
40
|
+
const classes = [
|
|
41
|
+
baseClass,
|
|
42
|
+
isOpen ? `${baseClass}--open` : "",
|
|
43
|
+
streaming ? `${baseClass}--streaming` : "",
|
|
44
|
+
className
|
|
45
|
+
].filter(Boolean).join(" ");
|
|
46
|
+
return /* @__PURE__ */ jsxs("div", { ...rest, ref, className: classes, children: [
|
|
47
|
+
/* @__PURE__ */ jsxs(
|
|
48
|
+
"button",
|
|
49
|
+
{
|
|
50
|
+
type: "button",
|
|
51
|
+
id: triggerId,
|
|
52
|
+
className: `${baseClass}__trigger`,
|
|
53
|
+
"aria-expanded": isOpen,
|
|
54
|
+
"aria-controls": panelId,
|
|
55
|
+
onClick: toggle,
|
|
56
|
+
children: [
|
|
57
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__summary`, role: "status", children: summary }),
|
|
58
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__chevron material-symbols-rounded`, "aria-hidden": "true", children: "expand_more" })
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__panel`, id: panelId, role: "region", "aria-labelledby": triggerId, children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__content`, children }) })
|
|
63
|
+
] });
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
Reasoning.displayName = "Reasoning";
|
|
67
|
+
export {
|
|
68
|
+
Reasoning
|
|
69
|
+
};
|
|
@@ -232,8 +232,12 @@
|
|
|
232
232
|
.ds-selection-card__toggle-icon {
|
|
233
233
|
/* Intentionally off the --icon-size-* scale — same reason as ToggleSwitch:
|
|
234
234
|
this glyph lives inside the 20x20 toggle thumb, and the smallest scale
|
|
235
|
-
step (20px) would fill it completely.
|
|
236
|
-
|
|
235
|
+
step (20px) would fill it completely. Sized via --icon-size, not
|
|
236
|
+
font-size, so the icon's box shrinks with the glyph (see ToggleSwitch).
|
|
237
|
+
|
|
238
|
+
ds-allow(icon-size): 14px glyph inside the 20px thumb — the smallest
|
|
239
|
+
scale step would fill it edge to edge. */
|
|
240
|
+
--icon-size: 14px;
|
|
237
241
|
color: var(--color-action-primary-bg);
|
|
238
242
|
}
|
|
239
243
|
|
|
@@ -23,7 +23,11 @@ type SelectionCardOwnProps = {
|
|
|
23
23
|
name?: string;
|
|
24
24
|
/** Additional CSS classes */
|
|
25
25
|
className?: string;
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Legacy change handler, kept for backwards compatibility.
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Use `onValueChange` instead.
|
|
30
|
+
*/
|
|
27
31
|
onChange?: (value: string | string[]) => void;
|
|
28
32
|
};
|
|
29
33
|
export interface SelectionCardProps extends SelectionCardOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof SelectionCardOwnProps> {
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
var(--color-bg-container-primary) 50%,
|
|
23
23
|
transparent 100%
|
|
24
24
|
);
|
|
25
|
+
/* ds-allow(motion): the shimmer needs a symmetric in-out curve and no
|
|
26
|
+
--motion-ease-* token provides one — the duration is tokenized. */
|
|
25
27
|
animation: ds-skeleton-shimmer var(--motion-duration-loop-shimmer) ease-in-out infinite;
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -19,7 +19,11 @@ type SliderOwnProps = {
|
|
|
19
19
|
onValueChange?: (value: number) => void;
|
|
20
20
|
/** Additional CSS classes — applied to the wrapper, not the <input> */
|
|
21
21
|
className?: string;
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Legacy accessible-name prop.
|
|
24
|
+
*
|
|
25
|
+
* @deprecated Pass the native `aria-label` attribute instead.
|
|
26
|
+
*/
|
|
23
27
|
ariaLabel?: string;
|
|
24
28
|
};
|
|
25
29
|
export interface SliderProps extends SliderOwnProps, Omit<React.ComponentPropsWithoutRef<'input'>, keyof SliderOwnProps | 'type'> {
|
|
@@ -59,6 +59,17 @@
|
|
|
59
59
|
stroke: var(--color-text-secondary);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/* Inherit — both circles draw in currentColor so the spinner matches the
|
|
63
|
+
text/icon colour of whatever control contains it (e.g. a loading Button) */
|
|
64
|
+
.ds-spinner--inherit .ds-spinner__track {
|
|
65
|
+
stroke: currentColor;
|
|
66
|
+
opacity: 0.25;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.ds-spinner--inherit .ds-spinner__arc {
|
|
70
|
+
stroke: currentColor;
|
|
71
|
+
}
|
|
72
|
+
|
|
62
73
|
/* ============================================
|
|
63
74
|
ANIMATION
|
|
64
75
|
============================================ */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export interface SpinnerProps {
|
|
2
2
|
/** Size of the spinner */
|
|
3
3
|
size?: 'sm' | 'md' | 'lg';
|
|
4
|
-
/** Visual variant */
|
|
5
|
-
variant?: 'primary' | 'neutral';
|
|
4
|
+
/** Visual variant — `inherit` draws the spinner in `currentColor`, for use inside coloured controls */
|
|
5
|
+
variant?: 'primary' | 'neutral' | 'inherit';
|
|
6
6
|
/** Accessible label */
|
|
7
7
|
label?: string;
|
|
8
8
|
/** Additional CSS classes */
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
SWATCH COMPONENT
|
|
3
|
+
Clickable colour tile for palettes and pickers
|
|
4
|
+
============================================ */
|
|
5
|
+
|
|
6
|
+
/* Base */
|
|
7
|
+
|
|
8
|
+
.ds-swatch {
|
|
9
|
+
width: 24px;
|
|
10
|
+
height: 24px;
|
|
11
|
+
padding: 0;
|
|
12
|
+
border: none;
|
|
13
|
+
border-radius: var(--radius-full);
|
|
14
|
+
background-color: var(--ds-swatch-color);
|
|
15
|
+
/* A hairline inset keeps very light colours visible on the white floor */
|
|
16
|
+
box-shadow: inset 0 0 0 var(--border-xs) var(--color-bg-container-border);
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
flex-shrink: 0;
|
|
19
|
+
transition: box-shadow var(--motion-duration-base) var(--motion-ease-standard);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Sizes */
|
|
23
|
+
|
|
24
|
+
.ds-swatch--compact {
|
|
25
|
+
width: 20px;
|
|
26
|
+
height: 20px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Shapes */
|
|
30
|
+
|
|
31
|
+
.ds-swatch--square {
|
|
32
|
+
border-radius: var(--radius-sm);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* States */
|
|
36
|
+
|
|
37
|
+
.ds-swatch--selected {
|
|
38
|
+
box-shadow:
|
|
39
|
+
inset 0 0 0 var(--border-xs) var(--color-bg-container-border),
|
|
40
|
+
0 0 0 var(--border-md) var(--color-bg-page-primary),
|
|
41
|
+
0 0 0 calc(var(--border-md) * 2) var(--color-text-primary);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.ds-swatch:focus-visible {
|
|
45
|
+
outline: var(--border-md) solid var(--color-input-border-selected);
|
|
46
|
+
outline-offset: var(--border-md);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ds-swatch--disabled {
|
|
50
|
+
opacity: 0.4;
|
|
51
|
+
cursor: not-allowed;
|
|
52
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by Swatch itself — everything else falls through to the <button>. */
|
|
3
|
+
type SwatchOwnProps = {
|
|
4
|
+
/** The colour this swatch shows — any valid CSS colour, typically a hex value */
|
|
5
|
+
value: string;
|
|
6
|
+
/**
|
|
7
|
+
* Accessible name for the swatch. Defaults to the colour value, which is
|
|
8
|
+
* meaningful but terse — prefer a human name ("Teal 07") when you have one.
|
|
9
|
+
*/
|
|
10
|
+
label?: string;
|
|
11
|
+
/** Selected state — renders the selection ring and sets aria-pressed */
|
|
12
|
+
selected?: boolean;
|
|
13
|
+
/** Swatch size */
|
|
14
|
+
size?: 'default' | 'compact';
|
|
15
|
+
/** Corner treatment — circle matches the site's preset grids; square suits picker triggers */
|
|
16
|
+
shape?: 'circle' | 'square';
|
|
17
|
+
/** Whether the swatch is disabled */
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** Additional CSS classes */
|
|
20
|
+
className?: string;
|
|
21
|
+
};
|
|
22
|
+
export interface SwatchProps extends SwatchOwnProps, Omit<React.ComponentPropsWithoutRef<'button'>, keyof SwatchOwnProps | 'type'> {
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A clickable colour tile — the building block for preset palettes and
|
|
26
|
+
* picker triggers. Renders a `<button>` whose background is the `value`
|
|
27
|
+
* colour; `selected` draws the theme-aware selection ring.
|
|
28
|
+
*
|
|
29
|
+
* Purely presentational (no hooks), so it can be rendered from a Server
|
|
30
|
+
* Component; interactivity arrives through the native `onClick` you pass.
|
|
31
|
+
* Forwards a ref to the `<button>` and spreads unrecognised props onto it.
|
|
32
|
+
*/
|
|
33
|
+
export declare const Swatch: React.ForwardRefExoticComponent<SwatchProps & React.RefAttributes<HTMLButtonElement>>;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import "./Swatch.css";
|
|
4
|
+
const Swatch = React.forwardRef(
|
|
5
|
+
({
|
|
6
|
+
value,
|
|
7
|
+
label,
|
|
8
|
+
selected = false,
|
|
9
|
+
size = "default",
|
|
10
|
+
shape = "circle",
|
|
11
|
+
disabled = false,
|
|
12
|
+
className = "",
|
|
13
|
+
style,
|
|
14
|
+
...rest
|
|
15
|
+
}, ref) => {
|
|
16
|
+
const baseClass = "ds-swatch";
|
|
17
|
+
const classes = [
|
|
18
|
+
baseClass,
|
|
19
|
+
size === "compact" ? `${baseClass}--compact` : "",
|
|
20
|
+
shape === "square" ? `${baseClass}--square` : "",
|
|
21
|
+
selected ? `${baseClass}--selected` : "",
|
|
22
|
+
disabled ? `${baseClass}--disabled` : "",
|
|
23
|
+
className
|
|
24
|
+
].filter(Boolean).join(" ");
|
|
25
|
+
const swatchStyle = { ...style, "--ds-swatch-color": value };
|
|
26
|
+
return /* @__PURE__ */ jsx(
|
|
27
|
+
"button",
|
|
28
|
+
{
|
|
29
|
+
...rest,
|
|
30
|
+
ref,
|
|
31
|
+
type: "button",
|
|
32
|
+
className: classes,
|
|
33
|
+
style: swatchStyle,
|
|
34
|
+
disabled,
|
|
35
|
+
"aria-pressed": selected,
|
|
36
|
+
"aria-label": rest["aria-label"] ?? label ?? value
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
Swatch.displayName = "Swatch";
|
|
42
|
+
export {
|
|
43
|
+
Swatch
|
|
44
|
+
};
|
|
@@ -184,3 +184,22 @@
|
|
|
184
184
|
line-height: var(--font-paragraph-sm-line-height);
|
|
185
185
|
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
186
186
|
}
|
|
187
|
+
|
|
188
|
+
/* ============================================
|
|
189
|
+
SCREEN-READER-ONLY
|
|
190
|
+
Fallback text for header cells with no visible
|
|
191
|
+
label (checkbox / actions columns) — an empty
|
|
192
|
+
<th> is unannounced.
|
|
193
|
+
============================================ */
|
|
194
|
+
|
|
195
|
+
.ds-table__sr-only {
|
|
196
|
+
position: absolute;
|
|
197
|
+
width: 1px;
|
|
198
|
+
height: 1px;
|
|
199
|
+
padding: 0;
|
|
200
|
+
margin: -1px;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
clip: rect(0, 0, 0, 0);
|
|
203
|
+
white-space: nowrap;
|
|
204
|
+
border: 0;
|
|
205
|
+
}
|
|
@@ -38,7 +38,7 @@ const Table = React.forwardRef(
|
|
|
38
38
|
width: col.width,
|
|
39
39
|
textAlign: col.align || "left"
|
|
40
40
|
},
|
|
41
|
-
children: col.header
|
|
41
|
+
children: col.header || /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr-only`, children: col.key })
|
|
42
42
|
},
|
|
43
43
|
col.key
|
|
44
44
|
)) }) }),
|
|
@@ -14,19 +14,6 @@
|
|
|
14
14
|
LABEL
|
|
15
15
|
============================================ */
|
|
16
16
|
|
|
17
|
-
.ds-textarea__label {
|
|
18
|
-
font-family: var(--font-paragraph-em-family);
|
|
19
|
-
font-size: var(--font-paragraph-em-size);
|
|
20
|
-
font-weight: var(--font-paragraph-em-weight);
|
|
21
|
-
line-height: var(--font-paragraph-em-line-height);
|
|
22
|
-
letter-spacing: var(--font-paragraph-em-letter-spacing);
|
|
23
|
-
color: var(--color-text-primary);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.ds-textarea__required {
|
|
27
|
-
color: var(--color-core-accent-coral);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
17
|
/* ============================================
|
|
31
18
|
FIELD
|
|
32
19
|
============================================ */
|
|
@@ -69,24 +56,6 @@
|
|
|
69
56
|
FOOTER (helper + counter)
|
|
70
57
|
============================================ */
|
|
71
58
|
|
|
72
|
-
.ds-textarea__footer {
|
|
73
|
-
display: flex;
|
|
74
|
-
align-items: flex-start;
|
|
75
|
-
justify-content: space-between;
|
|
76
|
-
gap: var(--gap-sm);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.ds-textarea__helper {
|
|
80
|
-
font-family: var(--font-paragraph-sm-family);
|
|
81
|
-
font-size: var(--font-paragraph-sm-size);
|
|
82
|
-
font-weight: var(--font-paragraph-sm-weight);
|
|
83
|
-
line-height: var(--font-paragraph-sm-line-height);
|
|
84
|
-
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
85
|
-
color: var(--color-text-tertiary);
|
|
86
|
-
margin: 0;
|
|
87
|
-
flex: 1;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
59
|
.ds-textarea__counter {
|
|
91
60
|
font-family: var(--font-paragraph-sm-family);
|
|
92
61
|
font-size: var(--font-paragraph-sm-size);
|
|
@@ -108,10 +77,6 @@
|
|
|
108
77
|
border-color: var(--color-status-error-border);
|
|
109
78
|
}
|
|
110
79
|
|
|
111
|
-
.ds-textarea--error .ds-textarea__helper {
|
|
112
|
-
color: var(--color-status-error-border);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
80
|
.ds-textarea--error .ds-textarea__counter {
|
|
116
81
|
color: var(--color-status-error-border);
|
|
117
82
|
}
|
|
@@ -120,10 +85,6 @@
|
|
|
120
85
|
DISABLED STATE
|
|
121
86
|
============================================ */
|
|
122
87
|
|
|
123
|
-
.ds-textarea--disabled .ds-textarea__label {
|
|
124
|
-
color: var(--color-input-text-disabled);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
88
|
.ds-textarea--disabled .ds-textarea__field {
|
|
128
89
|
background-color: var(--color-input-bg-disabled);
|
|
129
90
|
border-color: var(--color-input-border-disabled);
|
|
@@ -146,7 +107,3 @@
|
|
|
146
107
|
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
147
108
|
}
|
|
148
109
|
|
|
149
|
-
.ds-textarea--compact .ds-textarea__label {
|
|
150
|
-
font-size: var(--font-paragraph-sm-size);
|
|
151
|
-
line-height: var(--font-paragraph-sm-line-height);
|
|
152
|
-
}
|
|
@@ -23,7 +23,11 @@ type TextareaOwnProps = {
|
|
|
23
23
|
onValueChange?: (value: string) => void;
|
|
24
24
|
/** Additional CSS classes — applied to the wrapper, not the <textarea> */
|
|
25
25
|
className?: string;
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Legacy accessible-name prop.
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Pass the native `aria-label` attribute instead.
|
|
30
|
+
*/
|
|
27
31
|
ariaLabel?: string;
|
|
28
32
|
};
|
|
29
33
|
export interface TextareaProps extends TextareaOwnProps, Omit<React.ComponentPropsWithoutRef<'textarea'>, keyof TextareaOwnProps> {
|