@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.
Files changed (99) hide show
  1. package/README.md +33 -28
  2. package/components/Accordion/Accordion.js +0 -1
  3. package/components/AgentStatus/AgentStatus.css +436 -0
  4. package/components/AgentStatus/AgentStatus.d.ts +37 -0
  5. package/components/AgentStatus/AgentStatus.js +53 -0
  6. package/components/AgentStatus/AgentStatusPatterns.d.ts +17 -0
  7. package/components/AgentStatus/AgentStatusPatterns.js +20 -0
  8. package/components/AlertDialog/AlertDialog.css +5 -5
  9. package/components/Avatar/Avatar.js +1 -0
  10. package/components/Breadcrumb/Breadcrumb.d.ts +7 -1
  11. package/components/Breadcrumb/Breadcrumb.js +3 -2
  12. package/components/Button/Button.css +18 -0
  13. package/components/Button/Button.d.ts +20 -2
  14. package/components/Button/Button.js +13 -3
  15. package/components/ButtonGroup/ButtonGroup.js +2 -9
  16. package/components/Card/Card.css +6 -0
  17. package/components/Checkbox/Checkbox.d.ts +17 -3
  18. package/components/CircularButton/CircularButton.css +11 -0
  19. package/components/CircularButton/CircularButton.d.ts +15 -3
  20. package/components/CircularButton/CircularButton.js +19 -6
  21. package/components/CodeBlock/CodeBlock.js +10 -1
  22. package/components/ColorPicker/ColorPicker.css +278 -0
  23. package/components/ColorPicker/ColorPicker.d.ts +50 -0
  24. package/components/ColorPicker/ColorPicker.js +338 -0
  25. package/components/Combobox/Combobox.css +0 -36
  26. package/components/Combobox/Combobox.d.ts +10 -2
  27. package/components/Combobox/Combobox.js +90 -82
  28. package/components/CommandPalette/CommandPalette.css +1 -15
  29. package/components/CommandPalette/CommandPalette.js +6 -5
  30. package/components/ContextMenu/ContextMenu.css +258 -0
  31. package/components/ContextMenu/ContextMenu.d.ts +26 -0
  32. package/components/ContextMenu/ContextMenu.js +350 -0
  33. package/components/DateInput/DateInput.css +0 -36
  34. package/components/DateInput/DateInput.d.ts +5 -1
  35. package/components/DateInput/DateInput.js +37 -33
  36. package/components/DatePicker/DatePicker.js +45 -34
  37. package/components/Dialog/Dialog.css +5 -5
  38. package/components/Dialog/Dialog.js +5 -4
  39. package/components/Drawer/Drawer.js +7 -2
  40. package/components/Dropdown/Dropdown.css +2 -40
  41. package/components/Dropdown/Dropdown.d.ts +10 -2
  42. package/components/Dropdown/Dropdown.js +119 -109
  43. package/components/DropdownMenu/DropdownMenu.css +2 -4
  44. package/components/DropdownMenu/DropdownMenu.js +10 -7
  45. package/components/Field/Field.css +80 -0
  46. package/components/Field/Field.d.ts +50 -0
  47. package/components/Field/Field.js +58 -0
  48. package/components/Field/FieldContext.d.ts +42 -0
  49. package/components/Field/FieldContext.js +7 -0
  50. package/components/FileInput/FileInput.css +0 -36
  51. package/components/FileInput/FileInput.d.ts +5 -1
  52. package/components/FileInput/FileInput.js +111 -103
  53. package/components/Input/Input.css +0 -43
  54. package/components/Input/Input.d.ts +5 -1
  55. package/components/Input/Input.js +51 -46
  56. package/components/Kbd/Kbd.css +28 -0
  57. package/components/Kbd/Kbd.d.ts +19 -0
  58. package/components/Kbd/Kbd.js +14 -0
  59. package/components/LinkList/LinkList.d.ts +1 -0
  60. package/components/Popover/Popover.d.ts +0 -6
  61. package/components/Popover/Popover.js +22 -16
  62. package/components/ProgressBar/ProgressBar.js +1 -1
  63. package/components/RadioButton/RadioButton.d.ts +17 -3
  64. package/components/Reasoning/Reasoning.css +152 -0
  65. package/components/Reasoning/Reasoning.d.ts +36 -0
  66. package/components/Reasoning/Reasoning.js +69 -0
  67. package/components/SelectionCard/SelectionCard.css +6 -2
  68. package/components/SelectionCard/SelectionCard.d.ts +5 -1
  69. package/components/Skeleton/Skeleton.css +2 -0
  70. package/components/Slider/Slider.d.ts +5 -1
  71. package/components/Spinner/Spinner.css +11 -0
  72. package/components/Spinner/Spinner.d.ts +2 -2
  73. package/components/Swatch/Swatch.css +52 -0
  74. package/components/Swatch/Swatch.d.ts +34 -0
  75. package/components/Swatch/Swatch.js +44 -0
  76. package/components/Table/Table.css +19 -0
  77. package/components/Table/Table.js +1 -1
  78. package/components/Textarea/Textarea.css +0 -43
  79. package/components/Textarea/Textarea.d.ts +5 -1
  80. package/components/Textarea/Textarea.js +37 -35
  81. package/components/Timeline/Timeline.d.ts +2 -0
  82. package/components/ToggleGroup/ToggleGroup.d.ts +10 -2
  83. package/components/ToggleSwitch/ToggleSwitch.css +7 -2
  84. package/components/ToggleSwitch/ToggleSwitch.d.ts +10 -2
  85. package/components/ToolCall/ToolCall.css +213 -0
  86. package/components/ToolCall/ToolCall.d.ts +43 -0
  87. package/components/ToolCall/ToolCall.js +89 -0
  88. package/components/registry.d.ts +47 -10
  89. package/components/registry.js +5 -1
  90. package/components/registry.json +523 -56
  91. package/components/registry.json.d.ts +523 -56
  92. package/components/registry.json.js +4 -1
  93. package/index.d.ts +12 -1
  94. package/index.js +24 -1
  95. package/package.json +8 -4
  96. package/tokens/registry.json +1 -0
  97. package/tokens/registry.json.d.ts +1 -0
  98. package/tokens/registry.json.js +1 -1
  99. 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
- /** @deprecated Use `onValueChange` instead. */
16
+ /**
17
+ * Legacy change handler, kept for backwards compatibility.
18
+ *
19
+ * @deprecated Use `onValueChange` instead.
20
+ */
17
21
  onChange?: (value: string) => void;
18
- /** @deprecated Pass the native `aria-label` attribute instead. */
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
- /** @deprecated Use `onValueChange` instead. */
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
- font-size: 14px;
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
- /** @deprecated Use `onValueChange` instead. */
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
- /** @deprecated Pass the native `aria-label` attribute instead. */
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
- /** @deprecated Pass the native `aria-label` attribute instead. */
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> {