rift-ds 1.12.0 → 1.13.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 (97) hide show
  1. package/README.md +8 -2
  2. package/behaviors/visually-hidden.css +24 -0
  3. package/bin/rift-ds.mjs +5 -2
  4. package/chat/ChatAgentPane.css +5 -1
  5. package/chat/ChatWidget.css +0 -36
  6. package/chat/ResponseActions.js +2 -1
  7. package/components/Accordion/Accordion.css +10 -3
  8. package/components/AgentPlan/AgentPlan.css +0 -12
  9. package/components/AgentPlan/AgentPlan.js +2 -1
  10. package/components/AgentStatus/AgentStatus.css +1 -1
  11. package/components/AnimatedNumber/AnimatedNumber.css +0 -12
  12. package/components/AnimatedNumber/AnimatedNumber.js +2 -1
  13. package/components/AppSidebar/AppSidebar.css +2 -2
  14. package/components/Attachment/Attachment.css +0 -17
  15. package/components/Attachment/AttachmentTile.js +3 -2
  16. package/components/BottomNav/BottomNav.css +0 -9
  17. package/components/BottomNav/BottomNav.js +2 -1
  18. package/components/CardStack/CardStack.css +0 -11
  19. package/components/CardStack/CardStack.js +2 -1
  20. package/components/ChatMessage/ChatMessage.css +0 -12
  21. package/components/ChatMessage/ChatMessage.js +2 -1
  22. package/components/Checkbox/Checkbox.css +34 -25
  23. package/components/Checkbox/Checkbox.d.ts +34 -0
  24. package/components/Checkbox/Checkbox.js +64 -36
  25. package/components/CodeDiff/CodeDiff.css +0 -11
  26. package/components/CodeDiff/CodeDiff.js +3 -2
  27. package/components/ColourSwatch/ColourSwatch.css +1 -0
  28. package/components/Combobox/Combobox.css +1 -8
  29. package/components/Combobox/Combobox.js +2 -1
  30. package/components/CommandPalette/CommandPalette.css +2 -25
  31. package/components/CommandPalette/CommandPalette.js +8 -5
  32. package/components/Composer/Composer.css +0 -12
  33. package/components/Composer/Composer.js +3 -2
  34. package/components/ContactCard/ContactCard.css +1 -1
  35. package/components/ContextMenu/ContextMenu.css +1 -9
  36. package/components/ContextMenu/ContextMenu.js +3 -2
  37. package/components/Dialog/Dialog.css +2 -26
  38. package/components/Dialog/Dialog.js +8 -12
  39. package/components/Drawer/Drawer.css +2 -26
  40. package/components/Drawer/Drawer.js +8 -12
  41. package/components/Dropdown/ChosenMark.css +19 -0
  42. package/components/Dropdown/Dropdown.css +0 -12
  43. package/components/Dropdown/Dropdown.d.ts +23 -0
  44. package/components/Dropdown/Dropdown.js +18 -17
  45. package/components/DropdownMenu/DropdownMenu.css +3 -9
  46. package/components/DropdownMenu/DropdownMenu.js +3 -2
  47. package/components/FilterBar/FilterBar.css +0 -8
  48. package/components/FilterBar/FilterBar.js +9 -6
  49. package/components/GanttChart/GanttChart.css +0 -13
  50. package/components/GanttChart/GanttChart.js +3 -2
  51. package/components/Inspector/InspectorToggleSwitch.js +5 -10
  52. package/components/InterruptCard/InterruptCard.css +0 -12
  53. package/components/InterruptCard/InterruptCard.js +2 -1
  54. package/components/ModelPicker/ModelPicker.css +4 -45
  55. package/components/ModelPicker/ModelPicker.js +13 -50
  56. package/components/MotionSwatch/MotionSwatch.css +1 -1
  57. package/components/NotificationCenter/NotificationCenter.css +1 -13
  58. package/components/NotificationCenter/NotificationCenter.js +2 -1
  59. package/components/PromptSuggestions/PromptSuggestions.css +0 -11
  60. package/components/PromptSuggestions/PromptSuggestions.js +3 -2
  61. package/components/QuestionCard/QuestionCard.css +13 -22
  62. package/components/QuestionCard/QuestionCard.js +8 -13
  63. package/components/RadioButton/RadioButton.css +27 -11
  64. package/components/RadioButton/RadioButton.d.ts +18 -0
  65. package/components/RadioButton/RadioButton.js +12 -2
  66. package/components/RichDropdown/RichDropdown.css +0 -9
  67. package/components/RichDropdown/RichDropdown.js +2 -8
  68. package/components/SegmentedControl/SegmentedControl.css +2 -14
  69. package/components/SegmentedControl/SegmentedControl.d.ts +7 -0
  70. package/components/SegmentedControl/SegmentedControl.js +4 -2
  71. package/components/SelectionCard/SelectionCard.css +29 -160
  72. package/components/SelectionCard/SelectionCard.js +5 -35
  73. package/components/SidebarPanel/SidebarPanel.css +1 -1
  74. package/components/SourceTrail/SourceTrail.css +0 -13
  75. package/components/SourceTrail/SourceTrail.js +2 -1
  76. package/components/SpacingSwatch/SpacingSwatch.css +1 -1
  77. package/components/Stepper/Stepper.css +0 -13
  78. package/components/Stepper/Stepper.js +2 -1
  79. package/components/Table/Table.css +0 -22
  80. package/components/Table/Table.js +3 -2
  81. package/components/ThreadPanel/ThreadPanel.css +2 -16
  82. package/components/ThreadPanel/ThreadPanel.js +3 -2
  83. package/components/ThreadTabs/ThreadTabs.css +1 -15
  84. package/components/ThreadTabs/ThreadTabs.js +2 -1
  85. package/components/TimePicker/TimePicker.css +0 -12
  86. package/components/TimePicker/TimePicker.js +2 -8
  87. package/components/ToggleGroup/ToggleGroup.css +9 -2
  88. package/components/ToggleSwitch/ToggleSwitch.css +33 -27
  89. package/components/ToggleSwitch/ToggleSwitch.d.ts +19 -0
  90. package/components/ToggleSwitch/ToggleSwitch.js +17 -10
  91. package/components/Tooltip/Tooltip.css +33 -36
  92. package/components/Tooltip/Tooltip.d.ts +10 -0
  93. package/components/Tooltip/Tooltip.js +72 -3
  94. package/components/Waveform/Waveform.css +0 -12
  95. package/components/Waveform/Waveform.js +2 -1
  96. package/index.js +10 -4
  97. package/package.json +1 -1
package/README.md CHANGED
@@ -62,7 +62,13 @@ Swap the scripted transport for `createFetchTransport('/api/chat')` and the pane
62
62
 
63
63
  ## Set up your agent
64
64
 
65
- One command teaches a coding agent the system: it installs the generated agent skills into your project and prints the MCP connect line. The skills cover the library's rules, moving existing screens onto the tokens and components, and auditing styles against them.
65
+ The quickest start is one file: save [AGENTS.md](https://rift-ds.com/AGENTS.md) at your project root, or paste it into your agent. It holds the install, the setup, the rules, and where to look things up.
66
+
67
+ ```bash
68
+ curl -o AGENTS.md https://rift-ds.com/AGENTS.md
69
+ ```
70
+
71
+ For the full setup, one command teaches a coding agent the system: it installs the generated agent skills into your project and prints the MCP connect line. The skills cover the library's rules, moving existing screens onto the tokens and components, and auditing styles against them.
66
72
 
67
73
  ```bash
68
74
  npx rift-ds init
@@ -74,7 +80,7 @@ The MCP endpoint serves the component catalogue, per-component prop APIs, the to
74
80
  claude mcp add --transport http rift-ds https://rift-ds.com/api/mcp
75
81
  ```
76
82
 
77
- Every component's prop contract is also plain markdown (append `.md` to its docs URL), and [llms.txt](https://rift-ds.com/llms.txt) indexes every machine surface. A theme made in the [playground](https://rift-ds.com/playground) exports as CSS, a THEME.md and a setup prompt, so the agent can read the look as well as the code. Then just ask: "Build a settings page with Rift components."
83
+ Every component's prop contract is also plain markdown (append `.md` to its docs URL), and [llms.txt](https://rift-ds.com/llms.txt) indexes every machine surface. A theme made in the [playground](https://rift-ds.com/playground) exports as one AGENTS.md that carries the setup, your theme in words and its CSS, so the agent can read the look as well as the code. Then just ask: "Build a settings page with Rift components."
78
84
 
79
85
  ## Theming
80
86
 
@@ -0,0 +1,24 @@
1
+ /* ============================================
2
+ VISUALLY HIDDEN
3
+ The one recipe for text that is read but not
4
+ seen: a status for a live region, a control's
5
+ spoken name, a marker beside a visual state.
6
+ Every component imports this sheet and uses
7
+ ds-visually-hidden rather than writing the
8
+ recipe again (scripts/validate-shared-primitives.mjs
9
+ fails a second copy). A hidden native input
10
+ that must stay focusable is not this: it
11
+ keeps its own rule, with the reason beside it.
12
+ ============================================ */
13
+
14
+ .ds-visually-hidden {
15
+ position: absolute;
16
+ width: 1px;
17
+ height: 1px;
18
+ padding: 0;
19
+ margin: -1px;
20
+ overflow: hidden;
21
+ clip: rect(0, 0, 0, 0);
22
+ white-space: nowrap;
23
+ border: 0;
24
+ }
package/bin/rift-ds.mjs CHANGED
@@ -28,7 +28,8 @@
28
28
  * Zero dependencies by design: global fetch plus node:fs, so npx never
29
29
  * installs anything beyond the package itself. SITE_ORIGIN, SKILL_NAME,
30
30
  * MCP_SERVER_NAME and PACKAGE_NAME are stamped by build-package.mjs from
31
- * scripts/brand.mjs (the one home for brand facts); running this file
31
+ * scripts/brand.mjs (the one home for brand facts), and CHAT_SLUG from
32
+ * the chat registry, the widget page's slug; running this file
32
33
  * straight from source fails fast rather than guessing a domain.
33
34
  * SKILL_NAME is the library skill, kept only for --out without --skill,
34
35
  * which has always meant that one.
@@ -41,6 +42,7 @@ const SITE_ORIGIN = 'https://rift-ds.com';
41
42
  const SKILL_NAME = 'rift-design-system';
42
43
  const MCP_SERVER_NAME = 'rift-ds';
43
44
  const PACKAGE_NAME = 'rift-ds';
45
+ const CHAT_SLUG = 'ai-chat';
44
46
  const MANIFEST_URL = `${SITE_ORIGIN}/skill/manifest.json`;
45
47
  const DEFAULT_DIR = join('.claude', 'skills');
46
48
  const TEMPLATES_DIR = join(dirname(fileURLToPath(import.meta.url)), 'templates', 'chat');
@@ -229,7 +231,8 @@ function initChat({ app, dryRun }) {
229
231
  console.log(
230
232
  ` 4. Your layout's viewport should set interactiveWidget: "resizes-content", so the phone takeover ends above the keyboard.`
231
233
  );
232
- console.log(`\nThe widget's props, protocol and server options: ${SITE_ORIGIN}/chat`);
234
+ console.log(`\nHow to add it, the protocol and the server options: ${SITE_ORIGIN}/docs/chat`);
235
+ console.log(`Every prop: ${SITE_ORIGIN}/components/${CHAT_SLUG}`);
233
236
  }
234
237
 
235
238
  const args = process.argv.slice(2);
@@ -31,12 +31,16 @@
31
31
  margin: 0;
32
32
  }
33
33
 
34
+ /* The chat's card surface: container fill behind a hairline, like every
35
+ card in the conversation. The radius stays a step under the rail's
36
+ --radius-600, concentric with the shell it nests in. */
34
37
  .ds-chat-agent-pane__card {
35
38
  display: flex;
36
39
  flex-direction: column;
37
40
  gap: var(--gap-200);
38
41
  padding: var(--padding-300);
39
- background-color: var(--color-bg-container-secondary);
42
+ background-color: var(--color-bg-container-primary);
43
+ border: var(--border-025) solid var(--color-bg-container-border);
40
44
  border-radius: var(--radius-400);
41
45
  }
42
46
 
@@ -61,29 +61,6 @@
61
61
  min-height: calc(40px + var(--padding-150) * 2);
62
62
  }
63
63
 
64
- /* The close button hugs the panel's clipped right edge, so its centred
65
- bottom tooltip would lose its right cap to overflow: hidden. End-align
66
- the last header tooltip to the button and walk the arrow back to the
67
- button's centre (20px in, minus half the 8px arrow). */
68
- .ds-chat-widget .ds-chat-header__actions .ds-tooltip:last-child .ds-tooltip__panel--bottom,
69
- .ds-chat-widget__rail-actions .ds-tooltip:last-child .ds-tooltip__panel--bottom {
70
- left: auto;
71
- right: 0;
72
- transform: translateY(-4px);
73
- }
74
-
75
- .ds-chat-widget .ds-chat-header__actions .ds-tooltip:last-child .ds-tooltip__panel--bottom.ds-tooltip__panel--visible,
76
- .ds-chat-widget__rail-actions .ds-tooltip:last-child .ds-tooltip__panel--bottom.ds-tooltip__panel--visible {
77
- transform: translateY(0);
78
- }
79
-
80
- .ds-chat-widget .ds-chat-header__actions .ds-tooltip:last-child .ds-tooltip__panel--bottom .ds-tooltip__arrow,
81
- .ds-chat-widget__rail-actions .ds-tooltip:last-child .ds-tooltip__panel--bottom .ds-tooltip__arrow {
82
- left: auto;
83
- right: 16px;
84
- margin-left: 0;
85
- }
86
-
87
64
  /* The placement menu's wrapper is only there to catch Escape; it must not
88
65
  become a box of its own in the header's action row. */
89
66
  .ds-chat-widget__placement-menu {
@@ -560,19 +537,6 @@
560
537
  }
561
538
  }
562
539
 
563
- /* Visually hidden, still announced. */
564
- .ds-chat-widget__sr-only {
565
- position: absolute;
566
- width: 1px;
567
- height: 1px;
568
- margin: -1px;
569
- padding: 0;
570
- overflow: hidden;
571
- clip: rect(0 0 0 0);
572
- white-space: nowrap;
573
- border: 0;
574
- }
575
-
576
540
  /* ============================================
577
541
  THE RAILS — the optional session-history rail (leading) and agent pane
578
542
  (trailing). Wide widgets seat them inline; narrow ones summon the history
@@ -3,6 +3,7 @@ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
3
3
  import { createContext, useContext, useState, useRef, useEffect } from "react";
4
4
  import { MOTION_FEEDBACK_RESET_MS } from "../tokens/motion.js";
5
5
  import { useChatWidget } from "./context.js";
6
+ import "../behaviors/visually-hidden.css";
6
7
  const ResponseActionsLabelsContext = createContext({
7
8
  copy: "Copy response",
8
9
  copied: "Copied",
@@ -79,7 +80,7 @@ function ResponseActions({ turn }) {
79
80
  }
80
81
  )
81
82
  ] }),
82
- /* @__PURE__ */ jsx("span", { className: "ds-chat-widget__sr-only", "aria-live": "polite", children: copied ? labels.copiedAnnouncement : "" })
83
+ /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", "aria-live": "polite", children: copied ? labels.copiedAnnouncement : "" })
83
84
  ] });
84
85
  }
85
86
  export {
@@ -3,12 +3,17 @@
3
3
  Collapsible content sections
4
4
  ============================================ */
5
5
 
6
+ /* The standard card surface (container fill, hairline border,
7
+ --radius-300), the one SelectionCard's and QuestionCard's option rows
8
+ share, so a collapsible section reads as a card on the page rather than
9
+ a hairline floating over it. */
6
10
  .ds-accordion {
7
11
  display: flex;
8
12
  flex-direction: column;
9
13
  width: 100%;
10
14
  border: var(--border-025) solid var(--color-bg-container-border);
11
- border-radius: var(--radius-200);
15
+ border-radius: var(--radius-300);
16
+ background-color: var(--color-bg-container-primary);
12
17
  overflow: hidden;
13
18
  }
14
19
 
@@ -42,14 +47,16 @@
42
47
  transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
43
48
  }
44
49
 
50
+ /* Hover steps the header to the secondary fill, the collapsible-section
51
+ convention the agent cards (AgentPlan, SourceTrail, ToolCall) set. */
45
52
  .ds-accordion__trigger:hover {
46
- background-color: var(--color-action-passive-bg-hover);
53
+ background-color: var(--color-bg-container-secondary);
47
54
  }
48
55
 
49
56
  .ds-accordion__trigger:focus-visible {
50
57
  outline: 2px solid var(--color-action-primary-bg);
51
58
  outline-offset: -2px;
52
- border-radius: var(--radius-200);
59
+ border-radius: var(--radius-300);
53
60
  }
54
61
 
55
62
  /* ============================================
@@ -229,18 +229,6 @@
229
229
  this span announces it.
230
230
  ============================================ */
231
231
 
232
- .ds-agent-plan__sr {
233
- position: absolute;
234
- width: 1px;
235
- height: 1px;
236
- padding: 0;
237
- margin: -1px;
238
- overflow: hidden;
239
- clip: rect(0, 0, 0, 0);
240
- white-space: nowrap;
241
- border: 0;
242
- }
243
-
244
232
  /* Icons take the colour of the text around them. Explicit, not just
245
233
  inherited by default: a consumer stylesheet that sets a colour on
246
234
  .material-symbols-rounded itself (a common global default) would
@@ -3,6 +3,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
3
3
  import React, { useId, useState, useCallback } from "react";
4
4
  import { Spinner } from "../Spinner/Spinner.js";
5
5
  import "./AgentPlan.css";
6
+ import "../../behaviors/visually-hidden.css";
6
7
  import "../../fonts/material-symbols.css";
7
8
  const STEP_ICONS = {
8
9
  pending: "circle",
@@ -88,7 +89,7 @@ const AgentPlan = React.forwardRef(
88
89
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: step.label }),
89
90
  step.detail && /* @__PURE__ */ jsx("span", { className: `${baseClass}__detail`, children: step.detail })
90
91
  ] }),
91
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr`, children: statusText[status] })
92
+ /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: statusText[status] })
92
93
  ]
93
94
  },
94
95
  index
@@ -219,7 +219,7 @@
219
219
  display: flex;
220
220
  width: 100%;
221
221
  padding: var(--padding-150) var(--padding-300);
222
- background-color: var(--color-bg-container-secondary);
222
+ background-color: var(--color-bg-container-primary);
223
223
  border: var(--border-025) solid var(--color-bg-container-border);
224
224
  border-radius: var(--radius-300);
225
225
  }
@@ -17,15 +17,3 @@
17
17
  font-variant-numeric: tabular-nums;
18
18
  }
19
19
 
20
- /* Visually hidden settled value — what a screen reader gets instead of the
21
- rolling digits. */
22
- .ds-animated-number__sr {
23
- position: absolute;
24
- width: 1px;
25
- height: 1px;
26
- margin: -1px;
27
- padding: 0;
28
- overflow: hidden;
29
- clip-path: inset(50%);
30
- white-space: nowrap;
31
- }
@@ -2,6 +2,7 @@
2
2
  import { jsxs, jsx } from "react/jsx-runtime";
3
3
  import React, { useState, useRef, useEffect } from "react";
4
4
  import "./AnimatedNumber.css";
5
+ import "../../behaviors/visually-hidden.css";
5
6
  import { MOTION_COUNT_UP_MS } from "../../tokens/motion.js";
6
7
  const REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
7
8
  const prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia(REDUCED_MOTION_QUERY).matches;
@@ -45,7 +46,7 @@ const AnimatedNumber = React.forwardRef(
45
46
  const classes = [baseClass, className].filter(Boolean).join(" ");
46
47
  return /* @__PURE__ */ jsxs("span", { ...rest, ref, className: classes, children: [
47
48
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__value`, "aria-hidden": "true", children: fmt(display) }),
48
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr`, children: fmt(value) })
49
+ /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: fmt(value) })
49
50
  ] });
50
51
  }
51
52
  );
@@ -211,7 +211,7 @@
211
211
  }
212
212
 
213
213
  .ds-app-sidebar__btn--active {
214
- background-color: var(--color-action-passive-bg-hover);
214
+ background-color: var(--color-action-passive-bg-active);
215
215
  }
216
216
 
217
217
  .ds-app-sidebar__btn-left {
@@ -357,7 +357,7 @@
357
357
  }
358
358
 
359
359
  .ds-app-sidebar__sub-btn--active {
360
- background-color: var(--color-action-passive-bg-hover);
360
+ background-color: var(--color-action-passive-bg-active);
361
361
  }
362
362
 
363
363
  .ds-app-sidebar__sub-label {
@@ -481,23 +481,6 @@ button.ds-attachment-tile__body:focus-visible,
481
481
  outline-offset: 2px;
482
482
  }
483
483
 
484
- /* ============================================
485
- VISUALLY HIDDEN
486
- ============================================ */
487
-
488
- .ds-attachment-tile__sr-only,
489
- .ds-attachment-group__sr-only {
490
- position: absolute;
491
- width: 1px;
492
- height: 1px;
493
- padding: 0;
494
- margin: -1px;
495
- overflow: hidden;
496
- clip: rect(0, 0, 0, 0);
497
- white-space: nowrap;
498
- border: 0;
499
- }
500
-
501
484
  /* ============================================
502
485
  REDUCED MOTION
503
486
  The global guard collapses the spin to a still arc, which still reads as
@@ -5,6 +5,7 @@ import { formatBytes, getFileExtension, getFileKind, getFileTypeLabel, matchesAc
5
5
  import { renderTypeMark } from "./typeMark.js";
6
6
  import "../../fonts/material-symbols.css";
7
7
  import "./Attachment.css";
8
+ import "../../behaviors/visually-hidden.css";
8
9
  const AttachmentTile = React.forwardRef(
9
10
  ({
10
11
  name,
@@ -97,7 +98,7 @@ const AttachmentTile = React.forwardRef(
97
98
  const stack = /* @__PURE__ */ jsxs("span", { className: `${baseClass}__stack`, children: [
98
99
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__mark`, children: mark }),
99
100
  /* @__PURE__ */ jsxs("span", { className: `${baseClass}__name`, title: name, children: [
100
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr-only`, children: name }),
101
+ /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: name }),
101
102
  head !== "" && /* @__PURE__ */ jsx("span", { className: `${baseClass}__name-head`, "aria-hidden": "true", children: head }),
102
103
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__name-tail`, "aria-hidden": "true", children: tail })
103
104
  ] }),
@@ -111,7 +112,7 @@ const AttachmentTile = React.forwardRef(
111
112
  ] });
112
113
  } else if (showExcerpt) {
113
114
  content = /* @__PURE__ */ jsxs(Fragment, { children: [
114
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr-only`, children: name }),
115
+ /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: name }),
115
116
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__excerpt`, children: excerpt }),
116
117
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__corner`, children: cornerMark })
117
118
  ] });
@@ -141,15 +141,6 @@
141
141
  padding: 0;
142
142
  }
143
143
 
144
- .ds-bottom-nav__sr {
145
- position: absolute;
146
- width: 1px;
147
- height: 1px;
148
- overflow: hidden;
149
- clip-path: inset(50%);
150
- white-space: nowrap;
151
- }
152
-
153
144
  .ds-bottom-nav__search {
154
145
  display: none;
155
146
  }
@@ -3,6 +3,7 @@ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { useLinkComponent } from "../../behaviors/LinkProvider.js";
5
5
  import "./BottomNav.css";
6
+ import "../../behaviors/visually-hidden.css";
6
7
  import "../../fonts/material-symbols.css";
7
8
  const defaultBadgeLabel = (badge) => badge === true ? ", new" : `, ${badge} new`;
8
9
  const BottomNav = React.forwardRef(
@@ -60,7 +61,7 @@ const BottomNav = React.forwardRef(
60
61
  renderBadge(item.badge)
61
62
  ] }),
62
63
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: item.label }),
63
- badgeText && /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr`, children: badgeText })
64
+ badgeText && /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: badgeText })
64
65
  ] });
65
66
  const handleClick = () => {
66
67
  item.onClick?.();
@@ -93,14 +93,3 @@
93
93
 
94
94
  /* Screen-reader announcement of the deck position. */
95
95
 
96
- .ds-card-stack__sr-only {
97
- position: absolute;
98
- width: 1px;
99
- height: 1px;
100
- padding: 0;
101
- margin: -1px;
102
- overflow: hidden;
103
- clip: rect(0, 0, 0, 0);
104
- white-space: nowrap;
105
- border: 0;
106
- }
@@ -2,6 +2,7 @@
2
2
  import { jsxs, jsx } from "react/jsx-runtime";
3
3
  import React, { useState, useRef, useCallback } from "react";
4
4
  import "./CardStack.css";
5
+ import "../../behaviors/visually-hidden.css";
5
6
  const INTERACTIVE_SELECTOR = 'a, button, input, select, textarea, summary, [role="button"], [role="link"], [tabindex]';
6
7
  const NEXT_KEYS = /* @__PURE__ */ new Set(["ArrowRight", "ArrowDown", " ", "Enter"]);
7
8
  const PREV_KEYS = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowUp"]);
@@ -124,7 +125,7 @@ const CardStack = React.forwardRef(
124
125
  k
125
126
  );
126
127
  }),
127
- count > 1 && /* @__PURE__ */ jsx("div", { className: `${baseClass}__sr-only`, role: "status", children: positionLabel(index + 1, count) })
128
+ count > 1 && /* @__PURE__ */ jsx("div", { className: "ds-visually-hidden", role: "status", children: positionLabel(index + 1, count) })
128
129
  ]
129
130
  }
130
131
  );
@@ -321,18 +321,6 @@
321
321
  The pending label is for screen readers only.
322
322
  ============================================ */
323
323
 
324
- .ds-chat-message__sr-only {
325
- position: absolute;
326
- width: 1px;
327
- height: 1px;
328
- padding: 0;
329
- margin: -1px;
330
- overflow: hidden;
331
- clip: rect(0, 0, 0, 0);
332
- white-space: nowrap;
333
- border: 0;
334
- }
335
-
336
324
  /* ============================================
337
325
  REDUCED MOTION
338
326
  The global guard collapses the loop to its
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import React from "react";
3
3
  import "./ChatMessage.css";
4
+ import "../../behaviors/visually-hidden.css";
4
5
  const ChatMessage = React.forwardRef(
5
6
  ({
6
7
  role = "assistant",
@@ -55,7 +56,7 @@ const ChatMessage = React.forwardRef(
55
56
  ] }),
56
57
  attachments && /* @__PURE__ */ jsx("div", { className: `${baseClass}__attachments`, children: attachments }),
57
58
  showContent && /* @__PURE__ */ jsx("div", { className: `${baseClass}__content`, children: pending ? /* @__PURE__ */ jsxs("span", { className: `${baseClass}__pending`, role: "status", children: [
58
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr-only`, children: pendingLabel }),
59
+ /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: pendingLabel }),
59
60
  /* @__PURE__ */ jsxs("span", { className: `${baseClass}__dots`, "aria-hidden": "true", children: [
60
61
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__dot` }),
61
62
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__dot` }),
@@ -1,6 +1,14 @@
1
1
  /* ============================================
2
2
  CHECKBOX COMPONENT
3
- Custom checkbox with check / indeterminate icon
3
+ Custom checkbox with check / indeterminate icon.
4
+ The box is CheckboxIndicator, a presentational
5
+ piece every host that offers a checkbox draws
6
+ (Checkbox itself, SelectionCard, QuestionCard,
7
+ FilterBar's multi-select rows): its state is
8
+ keyed on the box's own modifiers, so a host
9
+ needs no classes of its own to show it, and a
10
+ host that carries the ds-control-host class
11
+ lights it on hover.
4
12
  ============================================ */
5
13
 
6
14
  .ds-checkbox {
@@ -12,7 +20,7 @@
12
20
  }
13
21
 
14
22
  /* ============================================
15
- BOX
23
+ BOX — CheckboxIndicator
16
24
  ============================================ */
17
25
 
18
26
  .ds-checkbox__box {
@@ -20,10 +28,10 @@
20
28
  width: 24px;
21
29
  height: 24px;
22
30
  box-sizing: border-box;
23
- border: var(--border-050) solid var(--color-bg-container-border);
31
+ border: var(--border-050) solid var(--color-input-border-primary);
24
32
  border-radius: var(--radius-200); /* 8px */
25
- background-color: var(--color-bg-container-primary-transparent);
26
- display: flex;
33
+ background-color: var(--color-input-bg-primary);
34
+ display: inline-flex;
27
35
  align-items: center;
28
36
  justify-content: center;
29
37
  flex-shrink: 0;
@@ -82,48 +90,49 @@
82
90
  }
83
91
 
84
92
  /* ============================================
85
- CHECKED STATE
86
- ============================================ */
87
-
88
- .ds-checkbox--checked .ds-checkbox__box {
89
- background-color: var(--color-action-primary-bg);
90
- border-color: var(--color-action-primary-bg);
91
- }
92
-
93
- .ds-checkbox--checked .ds-checkbox__icon {
94
- opacity: 1;
95
- }
96
-
97
- /* ============================================
98
- INDETERMINATE STATE
93
+ CHECKED and INDETERMINATE STATES
94
+ Keyed on the box, so an indicator drawn by
95
+ another host shows the same states.
99
96
  ============================================ */
100
97
 
101
- .ds-checkbox--indeterminate .ds-checkbox__box {
98
+ .ds-checkbox__box--checked,
99
+ .ds-checkbox__box--indeterminate {
102
100
  background-color: var(--color-action-primary-bg);
103
101
  border-color: var(--color-action-primary-bg);
104
102
  }
105
103
 
106
- .ds-checkbox--indeterminate .ds-checkbox__icon {
104
+ .ds-checkbox__box--checked .ds-checkbox__icon,
105
+ .ds-checkbox__box--indeterminate .ds-checkbox__icon {
107
106
  opacity: 1;
108
107
  }
109
108
 
110
109
  /* ============================================
111
110
  HOVER STATE
111
+ Any host carrying ds-control-host lights the
112
+ box when it is hovered and not disabled.
112
113
  ============================================ */
113
114
 
114
- .ds-checkbox:not(.ds-checkbox--disabled):hover .ds-checkbox__box {
115
+ .ds-control-host:not(:disabled):not([aria-disabled='true']):hover .ds-checkbox__box {
115
116
  border-color: var(--color-action-primary-bg);
116
117
  }
117
118
 
118
- .ds-checkbox--checked:not(.ds-checkbox--disabled):hover .ds-checkbox__box {
119
+ .ds-control-host:not(:disabled):not([aria-disabled='true']):hover .ds-checkbox__box--checked,
120
+ .ds-control-host:not(:disabled):not([aria-disabled='true']):hover .ds-checkbox__box--indeterminate {
119
121
  background-color: var(--color-action-primary-bg-hover);
120
122
  border-color: var(--color-action-primary-bg-hover);
121
123
  }
122
124
 
123
125
  /* ============================================
124
126
  FOCUS STATE
127
+ The standalone control rings its own box; a
128
+ host that is itself the target (a card, a
129
+ row) rings its own edge instead.
125
130
  ============================================ */
126
131
 
132
+ .ds-checkbox:focus-visible {
133
+ outline: none;
134
+ }
135
+
127
136
  .ds-checkbox:focus-visible .ds-checkbox__box {
128
137
  outline: 2px solid var(--color-action-primary-bg);
129
138
  outline-offset: 2px;
@@ -142,12 +151,12 @@
142
151
  SIZE — COMPACT
143
152
  ============================================ */
144
153
 
145
- .ds-checkbox--compact .ds-checkbox__box {
154
+ .ds-checkbox__box--compact {
146
155
  width: 20px;
147
156
  height: 20px;
148
157
  }
149
158
 
150
- .ds-checkbox--compact .ds-checkbox__icon {
159
+ .ds-checkbox__box--compact .ds-checkbox__icon {
151
160
  width: 12px;
152
161
  height: 12px;
153
162
  }
@@ -88,4 +88,38 @@ type CheckboxGroupOwnProps = {
88
88
  export interface CheckboxGroupProps extends CheckboxGroupOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof CheckboxGroupOwnProps> {
89
89
  }
90
90
  export declare const CheckboxGroup: React.ForwardRefExoticComponent<CheckboxGroupProps & React.RefAttributes<HTMLDivElement>>;
91
+ /** Props owned by CheckboxIndicator itself — everything else falls through to the <span>. */
92
+ type CheckboxIndicatorOwnProps = {
93
+ /** Whether the box shows its check. */
94
+ checked?: boolean;
95
+ /** Whether the box shows the minus of an indeterminate state (ignored when `checked`). */
96
+ indeterminate?: boolean;
97
+ /** Box size: `default` is 24px, `compact` 20px. */
98
+ size?: 'default' | 'compact';
99
+ /** Additional CSS classes */
100
+ className?: string;
101
+ };
102
+ export interface CheckboxIndicatorProps extends CheckboxIndicatorOwnProps, Omit<React.ComponentPropsWithoutRef<'span'>, keyof CheckboxIndicatorOwnProps | 'children'> {
103
+ }
104
+ /**
105
+ * The checkbox's box, as a presentational piece for a host that is itself
106
+ * the control: SelectionCard's checkbox mode, QuestionCard's multi rows and
107
+ * FilterBar's multi-select options draw it, so a checkbox looks the same
108
+ * wherever a choice is offered. Hidden from assistive technology; the host
109
+ * carries `role="checkbox"` or `aria-selected` and the state. A host that
110
+ * adds the `ds-control-host` class to its interactive root lights the box
111
+ * on hover, the way Checkbox does.
112
+ */
113
+ export declare const CheckboxIndicator: React.ForwardRefExoticComponent<CheckboxIndicatorProps & React.RefAttributes<HTMLSpanElement>>;
114
+ /** Props owned by the glyphs themselves — everything else falls through to the <svg>. */
115
+ type ControlGlyphOwnProps = {
116
+ /** Additional CSS classes; the default is the checkbox icon's, which sizes and colours it. */
117
+ className?: string;
118
+ };
119
+ export interface ControlGlyphProps extends ControlGlyphOwnProps, Omit<React.ComponentPropsWithoutRef<'svg'>, keyof ControlGlyphOwnProps | 'children'> {
120
+ }
121
+ /** The check glyph. */
122
+ export declare const CheckIcon: React.ForwardRefExoticComponent<ControlGlyphProps & React.RefAttributes<SVGSVGElement>>;
123
+ /** The minus glyph, for an indeterminate checkbox. */
124
+ export declare const MinusIcon: React.ForwardRefExoticComponent<ControlGlyphProps & React.RefAttributes<SVGSVGElement>>;
91
125
  export {};