rift-ds 1.11.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 (133) hide show
  1. package/README.md +8 -2
  2. package/behaviors/LinkProvider.d.ts +36 -0
  3. package/behaviors/LinkProvider.js +15 -0
  4. package/behaviors/visually-hidden.css +24 -0
  5. package/bin/rift-ds.mjs +5 -2
  6. package/chat/ChatAgentPane.css +5 -1
  7. package/chat/ChatProvider.d.ts +5 -1
  8. package/chat/ChatProvider.js +11 -1
  9. package/chat/ChatWidget.css +0 -36
  10. package/chat/ResponseActions.js +2 -1
  11. package/components/Accordion/Accordion.css +10 -3
  12. package/components/AgentPlan/AgentPlan.css +0 -12
  13. package/components/AgentPlan/AgentPlan.js +2 -1
  14. package/components/AgentStatus/AgentStatus.css +1 -1
  15. package/components/AiButton/AiButton.d.ts +7 -0
  16. package/components/AiButton/AiButton.js +4 -1
  17. package/components/AnimatedNumber/AnimatedNumber.css +0 -12
  18. package/components/AnimatedNumber/AnimatedNumber.js +2 -1
  19. package/components/AppLayout/AppLayout.d.ts +7 -0
  20. package/components/AppLayout/AppLayout.js +3 -1
  21. package/components/AppSidebar/AppSidebar.css +2 -2
  22. package/components/AppSidebar/AppSidebar.d.ts +7 -0
  23. package/components/AppSidebar/AppSidebar.js +8 -3
  24. package/components/Attachment/Attachment.css +0 -17
  25. package/components/Attachment/AttachmentTile.js +3 -2
  26. package/components/BottomNav/BottomNav.css +0 -9
  27. package/components/BottomNav/BottomNav.d.ts +7 -0
  28. package/components/BottomNav/BottomNav.js +7 -3
  29. package/components/Breadcrumb/Breadcrumb.d.ts +8 -0
  30. package/components/Breadcrumb/Breadcrumb.js +3 -2
  31. package/components/Button/Button.d.ts +7 -0
  32. package/components/Button/Button.js +4 -1
  33. package/components/Card/Card.d.ts +7 -0
  34. package/components/Card/Card.js +4 -1
  35. package/components/CardStack/CardStack.css +0 -11
  36. package/components/CardStack/CardStack.js +2 -1
  37. package/components/ChatMessage/ChatMessage.css +0 -12
  38. package/components/ChatMessage/ChatMessage.js +2 -1
  39. package/components/Checkbox/Checkbox.css +34 -25
  40. package/components/Checkbox/Checkbox.d.ts +34 -0
  41. package/components/Checkbox/Checkbox.js +64 -36
  42. package/components/CircularButton/CircularButton.d.ts +8 -0
  43. package/components/CircularButton/CircularButton.js +3 -1
  44. package/components/CodeDiff/CodeDiff.css +0 -11
  45. package/components/CodeDiff/CodeDiff.js +3 -2
  46. package/components/ColourSwatch/ColourSwatch.css +1 -0
  47. package/components/Combobox/Combobox.css +1 -8
  48. package/components/Combobox/Combobox.js +2 -1
  49. package/components/CommandPalette/CommandPalette.css +2 -25
  50. package/components/CommandPalette/CommandPalette.js +8 -5
  51. package/components/Composer/Composer.css +0 -12
  52. package/components/Composer/Composer.js +3 -2
  53. package/components/ContactCard/ContactCard.css +1 -1
  54. package/components/ContactCard/ContactCard.d.ts +7 -0
  55. package/components/ContactCard/ContactCard.js +4 -1
  56. package/components/ContextMenu/ContextMenu.css +1 -9
  57. package/components/ContextMenu/ContextMenu.js +3 -2
  58. package/components/Dialog/Dialog.css +2 -26
  59. package/components/Dialog/Dialog.js +8 -12
  60. package/components/Drawer/Drawer.css +2 -26
  61. package/components/Drawer/Drawer.js +8 -12
  62. package/components/Dropdown/ChosenMark.css +19 -0
  63. package/components/Dropdown/Dropdown.css +0 -12
  64. package/components/Dropdown/Dropdown.d.ts +23 -0
  65. package/components/Dropdown/Dropdown.js +18 -17
  66. package/components/DropdownMenu/DropdownMenu.css +3 -9
  67. package/components/DropdownMenu/DropdownMenu.js +3 -2
  68. package/components/FilterBar/FilterBar.css +0 -8
  69. package/components/FilterBar/FilterBar.js +9 -6
  70. package/components/GanttChart/GanttChart.css +0 -13
  71. package/components/GanttChart/GanttChart.js +3 -2
  72. package/components/Inspector/InspectorToggleSwitch.js +5 -10
  73. package/components/InterruptCard/InterruptCard.css +0 -12
  74. package/components/InterruptCard/InterruptCard.js +2 -1
  75. package/components/LinkList/LinkList.d.ts +8 -0
  76. package/components/LinkList/LinkList.js +3 -2
  77. package/components/ModelPicker/ModelPicker.css +4 -45
  78. package/components/ModelPicker/ModelPicker.js +13 -50
  79. package/components/MotionSwatch/MotionSwatch.css +1 -1
  80. package/components/NavList/NavList.d.ts +7 -0
  81. package/components/NavList/NavList.js +2 -0
  82. package/components/NotificationCenter/NotificationCenter.css +1 -13
  83. package/components/NotificationCenter/NotificationCenter.js +2 -1
  84. package/components/PromptSuggestions/PromptSuggestions.css +0 -11
  85. package/components/PromptSuggestions/PromptSuggestions.js +3 -2
  86. package/components/QuestionCard/QuestionCard.css +13 -22
  87. package/components/QuestionCard/QuestionCard.js +8 -13
  88. package/components/RadioButton/RadioButton.css +27 -11
  89. package/components/RadioButton/RadioButton.d.ts +18 -0
  90. package/components/RadioButton/RadioButton.js +12 -2
  91. package/components/RichDropdown/RichDropdown.css +0 -9
  92. package/components/RichDropdown/RichDropdown.js +2 -8
  93. package/components/SegmentedControl/SegmentedControl.css +2 -14
  94. package/components/SegmentedControl/SegmentedControl.d.ts +7 -0
  95. package/components/SegmentedControl/SegmentedControl.js +4 -2
  96. package/components/SelectionCard/SelectionCard.css +29 -160
  97. package/components/SelectionCard/SelectionCard.js +5 -35
  98. package/components/SidebarPanel/SidebarPanel.css +1 -1
  99. package/components/SidebarPanel/SidebarPanel.d.ts +7 -0
  100. package/components/SidebarPanel/SidebarPanel.js +4 -1
  101. package/components/SourceChip/SourceChip.d.ts +7 -0
  102. package/components/SourceChip/SourceChip.js +5 -3
  103. package/components/SourceTrail/SourceTrail.css +0 -13
  104. package/components/SourceTrail/SourceTrail.d.ts +7 -0
  105. package/components/SourceTrail/SourceTrail.js +4 -1
  106. package/components/SpacingSwatch/SpacingSwatch.css +1 -1
  107. package/components/Stepper/Stepper.css +0 -13
  108. package/components/Stepper/Stepper.js +2 -1
  109. package/components/Table/Table.css +0 -22
  110. package/components/Table/Table.js +3 -2
  111. package/components/ThreadPanel/ThreadPanel.css +2 -16
  112. package/components/ThreadPanel/ThreadPanel.d.ts +8 -0
  113. package/components/ThreadPanel/ThreadPanel.js +12 -4
  114. package/components/ThreadTabs/ThreadTabs.css +1 -15
  115. package/components/ThreadTabs/ThreadTabs.js +2 -1
  116. package/components/TimePicker/TimePicker.css +0 -12
  117. package/components/TimePicker/TimePicker.js +2 -8
  118. package/components/ToggleGroup/ToggleGroup.css +9 -2
  119. package/components/ToggleSwitch/ToggleSwitch.css +33 -27
  120. package/components/ToggleSwitch/ToggleSwitch.d.ts +19 -0
  121. package/components/ToggleSwitch/ToggleSwitch.js +17 -10
  122. package/components/Tooltip/Tooltip.css +33 -36
  123. package/components/Tooltip/Tooltip.d.ts +10 -0
  124. package/components/Tooltip/Tooltip.js +72 -3
  125. package/components/TopAppBar/TopAppBar.d.ts +7 -0
  126. package/components/TopAppBar/TopAppBar.js +4 -1
  127. package/components/Waveform/Waveform.css +0 -12
  128. package/components/Waveform/Waveform.js +2 -1
  129. package/components/Widget/Widget.d.ts +8 -0
  130. package/components/Widget/Widget.js +3 -2
  131. package/index.js +10 -4
  132. package/package.json +5 -1
  133. package/tokens/presets/mono.css +168 -168
@@ -1,7 +1,9 @@
1
1
  "use client";
2
2
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
+ import { useLinkComponent } from "../../behaviors/LinkProvider.js";
4
5
  import "./BottomNav.css";
6
+ import "../../behaviors/visually-hidden.css";
5
7
  import "../../fonts/material-symbols.css";
6
8
  const defaultBadgeLabel = (badge) => badge === true ? ", new" : `, ${badge} new`;
7
9
  const BottomNav = React.forwardRef(
@@ -17,9 +19,11 @@ const BottomNav = React.forwardRef(
17
19
  badgeLabel = defaultBadgeLabel,
18
20
  className = "",
19
21
  style,
22
+ linkComponent,
20
23
  ...rest
21
24
  }, ref) => {
22
25
  const baseClass = "ds-bottom-nav";
26
+ const Link = useLinkComponent(linkComponent);
23
27
  const isIos = platform === "ios";
24
28
  const destinations = search && !isIos ? [...items, { key: "__search", label: search.label, icon: search.icon ?? "search", href: search.href, onClick: search.onClick }] : items;
25
29
  const activeIndex = destinations.findIndex((item) => item.key === activeKey);
@@ -57,7 +61,7 @@ const BottomNav = React.forwardRef(
57
61
  renderBadge(item.badge)
58
62
  ] }),
59
63
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: item.label }),
60
- badgeText && /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr`, children: badgeText })
64
+ badgeText && /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: badgeText })
61
65
  ] });
62
66
  const handleClick = () => {
63
67
  item.onClick?.();
@@ -69,7 +73,7 @@ const BottomNav = React.forwardRef(
69
73
  className: `${baseClass}__slot`,
70
74
  inert: isMinimized && !isActive,
71
75
  children: item.href ? /* @__PURE__ */ jsx(
72
- "a",
76
+ Link,
73
77
  {
74
78
  className: itemClasses,
75
79
  href: item.href,
@@ -92,7 +96,7 @@ const BottomNav = React.forwardRef(
92
96
  );
93
97
  }) })
94
98
  ] }),
95
- isIos && search && (search.href ? /* @__PURE__ */ jsx("a", { className: `${baseClass}__search`, href: search.href, onClick: search.onClick, "aria-label": search.label, children: renderIcon(search.icon ?? "search") }) : /* @__PURE__ */ jsx("button", { type: "button", className: `${baseClass}__search`, onClick: search.onClick, "aria-label": search.label, children: renderIcon(search.icon ?? "search") }))
99
+ isIos && search && (search.href ? /* @__PURE__ */ jsx(Link, { className: `${baseClass}__search`, href: search.href, onClick: search.onClick, "aria-label": search.label, children: renderIcon(search.icon ?? "search") }) : /* @__PURE__ */ jsx("button", { type: "button", className: `${baseClass}__search`, onClick: search.onClick, "aria-label": search.label, children: renderIcon(search.icon ?? "search") }))
96
100
  ] });
97
101
  }
98
102
  );
@@ -1,4 +1,5 @@
1
1
  import { default as React } from 'react';
2
+ import { LinkComponent } from '../../behaviors/LinkProvider';
2
3
  export interface BreadcrumbItem {
3
4
  /** Display label */
4
5
  label: string;
@@ -19,6 +20,13 @@ type BreadcrumbOwnProps = {
19
20
  * @deprecated Pass the native `aria-label` attribute instead.
20
21
  */
21
22
  ariaLabel?: string;
23
+ /**
24
+ * The component its links render with, such as Next.js's `Link`, so they
25
+ * navigate through the app's router; a plain `<a>` when unset. This
26
+ * component can render on the server, so it never reads a LinkProvider:
27
+ * pass the prop even under one.
28
+ */
29
+ linkComponent?: LinkComponent;
22
30
  };
23
31
  export interface BreadcrumbProps extends BreadcrumbOwnProps, Omit<React.ComponentPropsWithoutRef<'nav'>, keyof BreadcrumbOwnProps | 'children'> {
24
32
  }
@@ -3,8 +3,9 @@ import React from "react";
3
3
  import "./Breadcrumb.css";
4
4
  import "../../fonts/material-symbols.css";
5
5
  const Breadcrumb = React.forwardRef(
6
- ({ items, maxItems, className = "", ariaLabel, ...rest }, ref) => {
6
+ ({ items, maxItems, className = "", ariaLabel, linkComponent, ...rest }, ref) => {
7
7
  const baseClass = "ds-breadcrumb";
8
+ const Link = linkComponent ?? "a";
8
9
  const classes = [baseClass, className].filter(Boolean).join(" ");
9
10
  const shouldCollapse = maxItems !== void 0 && maxItems >= 2 && items.length > maxItems;
10
11
  let visibleItems;
@@ -28,7 +29,7 @@ const Breadcrumb = React.forwardRef(
28
29
  }
29
30
  return /* @__PURE__ */ jsxs("li", { className: `${baseClass}__item`, children: [
30
31
  index > 0 && /* @__PURE__ */ jsx("span", { className: `${baseClass}__separator material-symbols-rounded`, "aria-hidden": "true", children: "chevron_right" }),
31
- isLast || !item.href ? /* @__PURE__ */ jsx("span", { className: `${baseClass}__current`, "aria-current": "page", children: item.label }) : /* @__PURE__ */ jsx("a", { href: item.href, className: `${baseClass}__link`, children: item.label })
32
+ isLast || !item.href ? /* @__PURE__ */ jsx("span", { className: `${baseClass}__current`, "aria-current": "page", children: item.label }) : /* @__PURE__ */ jsx(Link, { href: item.href, className: `${baseClass}__link`, children: item.label })
32
33
  ] }, index);
33
34
  }) }) });
34
35
  }
@@ -1,4 +1,5 @@
1
1
  import { default as React } from 'react';
2
+ import { LinkComponent } from '../../behaviors/LinkProvider';
2
3
  /** Props owned by Button itself — everything else falls through to the DOM node. */
3
4
  type ButtonOwnProps = {
4
5
  /** Button text content */
@@ -39,6 +40,12 @@ type ButtonOwnProps = {
39
40
  target?: string;
40
41
  /** Optional rel attribute for links */
41
42
  rel?: string;
43
+ /**
44
+ * The component the link renders with, such as Next.js's `Link`, so it
45
+ * navigates through the app's router. Wins over a LinkProvider's; a plain
46
+ * `<a>` when neither is set.
47
+ */
48
+ linkComponent?: LinkComponent;
42
49
  /** Marks this link as the current page (adds aria-current="page") */
43
50
  ariaCurrent?: boolean;
44
51
  /** Additional CSS classes */
@@ -2,6 +2,7 @@
2
2
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import { Spinner } from "../Spinner/Spinner.js";
5
+ import { useLinkComponent } from "../../behaviors/LinkProvider.js";
5
6
  import "./Button.css";
6
7
  import "../../fonts/material-symbols.css";
7
8
  const LEGACY_VARIANTS = {
@@ -33,6 +34,7 @@ const Button = React.forwardRef(
33
34
  href,
34
35
  target,
35
36
  rel,
37
+ linkComponent,
36
38
  ariaCurrent,
37
39
  className = "",
38
40
  priority,
@@ -42,6 +44,7 @@ const Button = React.forwardRef(
42
44
  ...rest
43
45
  }, ref) => {
44
46
  const baseClass = "ds-button";
47
+ const Link = useLinkComponent(linkComponent);
45
48
  const resolvedVariant = resolveButtonCell(variant ?? priority ?? "primary", tone);
46
49
  const isDisabled = disabled ?? state === "disabled";
47
50
  const resolvedState = state ?? (isDisabled ? "disabled" : "default");
@@ -73,7 +76,7 @@ const Button = React.forwardRef(
73
76
  ] });
74
77
  if (href && !isDisabled && !isLoading) {
75
78
  return /* @__PURE__ */ jsx(
76
- "a",
79
+ Link,
77
80
  {
78
81
  ...rest,
79
82
  ref,
@@ -1,4 +1,5 @@
1
1
  import { default as React } from 'react';
2
+ import { LinkComponent } from '../../behaviors/LinkProvider';
2
3
  /** Props owned by Card itself — everything else falls through to the DOM node. */
3
4
  type CardOwnProps = {
4
5
  /** Card variant */
@@ -34,6 +35,12 @@ type CardOwnProps = {
34
35
  dek?: string;
35
36
  /** Render as a disabled placeholder (no href, dimmed, not interactive) */
36
37
  placeholder?: boolean;
38
+ /**
39
+ * The component the link renders with, such as Next.js's `Link`, so it
40
+ * navigates through the app's router. Wins over a LinkProvider's; a plain
41
+ * `<a>` when neither is set.
42
+ */
43
+ linkComponent?: LinkComponent;
37
44
  };
38
45
  export interface CardProps extends CardOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof CardOwnProps> {
39
46
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
3
  import React from "react";
4
+ import { useLinkComponent } from "../../behaviors/LinkProvider.js";
4
5
  import "./Card.css";
5
6
  import "../../fonts/material-symbols.css";
6
7
  const Card = React.forwardRef(
@@ -20,8 +21,10 @@ const Card = React.forwardRef(
20
21
  companyName,
21
22
  dek,
22
23
  placeholder = false,
24
+ linkComponent,
23
25
  ...rest
24
26
  }, ref) => {
27
+ const Link = useLinkComponent(linkComponent);
25
28
  if (variant === "case-study") {
26
29
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
27
30
  /* @__PURE__ */ jsx("div", { className: "ds-card--case-study__cover-wrap", children: cover ? /* @__PURE__ */ jsx("div", { className: "ds-card--case-study__cover-slot", children: cover }) : coverSrc ? /* @__PURE__ */ jsx(
@@ -67,7 +70,7 @@ const Card = React.forwardRef(
67
70
  );
68
71
  }
69
72
  return /* @__PURE__ */ jsx(
70
- "a",
73
+ Link,
71
74
  {
72
75
  ...rest,
73
76
  ref,
@@ -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 {};
@@ -1,41 +1,8 @@
1
1
  "use client";
2
- import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import React, { useState, useId } from "react";
4
4
  import { Field } from "../Field/Field.js";
5
5
  import "./Checkbox.css";
6
- const CheckIcon = () => /* @__PURE__ */ jsx(
7
- "svg",
8
- {
9
- className: "ds-checkbox__icon",
10
- width: "14",
11
- height: "14",
12
- viewBox: "0 0 14 14",
13
- fill: "none",
14
- "aria-hidden": "true",
15
- children: /* @__PURE__ */ jsx(
16
- "path",
17
- {
18
- d: "M2 7.5L5.5 11L12 3",
19
- stroke: "currentColor",
20
- strokeWidth: "2",
21
- strokeLinecap: "round",
22
- strokeLinejoin: "round"
23
- }
24
- )
25
- }
26
- );
27
- const MinusIcon = () => /* @__PURE__ */ jsx(
28
- "svg",
29
- {
30
- className: "ds-checkbox__icon",
31
- width: "14",
32
- height: "14",
33
- viewBox: "0 0 14 14",
34
- fill: "none",
35
- "aria-hidden": "true",
36
- children: /* @__PURE__ */ jsx("path", { d: "M2 7H12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
37
- }
38
- );
39
6
  const Checkbox = React.forwardRef(
40
7
  ({
41
8
  label,
@@ -64,6 +31,7 @@ const Checkbox = React.forwardRef(
64
31
  const describedBy = helperId ?? rest["aria-describedby"];
65
32
  const classes = [
66
33
  baseClass,
34
+ "ds-control-host",
67
35
  size === "compact" ? `${baseClass}--compact` : "",
68
36
  checked ? `${baseClass}--checked` : "",
69
37
  indeterminate && !checked ? `${baseClass}--indeterminate` : "",
@@ -105,7 +73,7 @@ const Checkbox = React.forwardRef(
105
73
  "aria-invalid": error || void 0,
106
74
  tabIndex: disabled ? -1 : 0,
107
75
  children: [
108
- /* @__PURE__ */ jsx("div", { className: `${baseClass}__box`, children: indeterminate && !checked ? /* @__PURE__ */ jsx(MinusIcon, {}) : /* @__PURE__ */ jsx(CheckIcon, {}) }),
76
+ /* @__PURE__ */ jsx(CheckboxIndicator, { checked, indeterminate, size }),
109
77
  helperText ? /* @__PURE__ */ jsxs("span", { className: `${baseClass}__text`, children: [
110
78
  label && /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: label }),
111
79
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__helper`, id: helperId, children: helperText })
@@ -180,7 +148,67 @@ const CheckboxGroup = React.forwardRef(
180
148
  }
181
149
  );
182
150
  CheckboxGroup.displayName = "CheckboxGroup";
151
+ const CheckboxIndicator = React.forwardRef(
152
+ ({ checked = false, indeterminate = false, size = "default", className = "", ...rest }, ref) => {
153
+ const base = "ds-checkbox__box";
154
+ const classes = [
155
+ base,
156
+ checked ? `${base}--checked` : "",
157
+ indeterminate && !checked ? `${base}--indeterminate` : "",
158
+ size === "compact" ? `${base}--compact` : "",
159
+ className
160
+ ].filter(Boolean).join(" ");
161
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", ...rest, ref, className: classes, children: indeterminate && !checked ? /* @__PURE__ */ jsx(MinusIcon, {}) : /* @__PURE__ */ jsx(CheckIcon, {}) });
162
+ }
163
+ );
164
+ CheckboxIndicator.displayName = "CheckboxIndicator";
165
+ const CheckIcon = React.forwardRef(
166
+ ({ className = "ds-checkbox__icon", ...rest }, ref) => /* @__PURE__ */ jsx(
167
+ "svg",
168
+ {
169
+ width: "14",
170
+ height: "14",
171
+ viewBox: "0 0 14 14",
172
+ fill: "none",
173
+ "aria-hidden": "true",
174
+ ...rest,
175
+ ref,
176
+ className,
177
+ children: /* @__PURE__ */ jsx(
178
+ "path",
179
+ {
180
+ d: "M2 7.5L5.5 11L12 3",
181
+ stroke: "currentColor",
182
+ strokeWidth: "2",
183
+ strokeLinecap: "round",
184
+ strokeLinejoin: "round"
185
+ }
186
+ )
187
+ }
188
+ )
189
+ );
190
+ CheckIcon.displayName = "CheckIcon";
191
+ const MinusIcon = React.forwardRef(
192
+ ({ className = "ds-checkbox__icon", ...rest }, ref) => /* @__PURE__ */ jsx(
193
+ "svg",
194
+ {
195
+ width: "14",
196
+ height: "14",
197
+ viewBox: "0 0 14 14",
198
+ fill: "none",
199
+ "aria-hidden": "true",
200
+ ...rest,
201
+ ref,
202
+ className,
203
+ children: /* @__PURE__ */ jsx("path", { d: "M2 7H12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
204
+ }
205
+ )
206
+ );
207
+ MinusIcon.displayName = "MinusIcon";
183
208
  export {
209
+ CheckIcon,
184
210
  Checkbox,
185
- CheckboxGroup
211
+ CheckboxGroup,
212
+ CheckboxIndicator,
213
+ MinusIcon
186
214
  };
@@ -1,4 +1,5 @@
1
1
  import { default as React } from 'react';
2
+ import { LinkComponent } from '../../behaviors/LinkProvider';
2
3
  /** Props owned by CircularButton itself — everything else falls through to the DOM node. */
3
4
  type CircularButtonOwnProps = {
4
5
  /** The icon — Material Symbol name (string) or custom element (ReactNode) */
@@ -65,6 +66,13 @@ type CircularButtonOwnProps = {
65
66
  rel?: string;
66
67
  /** Additional CSS classes */
67
68
  className?: string;
69
+ /**
70
+ * The component the link renders with, such as Next.js's `Link`, so it
71
+ * navigates through the app's router; a plain `<a>` when unset. This
72
+ * component can render on the server, so it never reads a LinkProvider:
73
+ * pass the prop even under one.
74
+ */
75
+ linkComponent?: LinkComponent;
68
76
  };
69
77
  export interface CircularButtonProps extends CircularButtonOwnProps, Omit<React.ComponentPropsWithoutRef<'button'>, keyof CircularButtonOwnProps | 'type'> {
70
78
  }
@@ -32,9 +32,11 @@ const CircularButton = React.forwardRef(
32
32
  target,
33
33
  rel,
34
34
  className = "",
35
+ linkComponent,
35
36
  ...rest
36
37
  }, ref) => {
37
38
  const baseClass = "ds-circular-button";
39
+ const Link = linkComponent ?? "a";
38
40
  const resolvedVariant = resolveCircularButtonCell(variant ?? priority ?? "primary", tone);
39
41
  const isDisabled = disabled ?? state === "disabled";
40
42
  const resolvedState = state ?? (isDisabled ? "disabled" : "default");
@@ -49,7 +51,7 @@ const CircularButton = React.forwardRef(
49
51
  ].filter(Boolean).join(" ");
50
52
  const children = isLoading ? /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon`, "aria-hidden": "true", children: /* @__PURE__ */ jsx(Spinner, { size: size === "compact" ? "sm" : "md", tone: "inherit" }) }) : /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon${typeof icon === "string" ? " material-symbols-rounded" : ""}`, "aria-hidden": "true", children: icon });
51
53
  const control = href && !isDisabled && !isLoading ? /* @__PURE__ */ jsx(
52
- "a",
54
+ Link,
53
55
  {
54
56
  ...rest,
55
57
  ref,
@@ -162,14 +162,3 @@
162
162
  itself is decorative (aria-hidden).
163
163
  ============================================ */
164
164
 
165
- .ds-codediff__sr-only {
166
- position: absolute;
167
- width: 1px;
168
- height: 1px;
169
- padding: 0;
170
- margin: -1px;
171
- overflow: hidden;
172
- clip: rect(0, 0, 0, 0);
173
- white-space: nowrap;
174
- border: 0;
175
- }
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import React from "react";
3
3
  import "./CodeDiff.css";
4
+ import "../../behaviors/visually-hidden.css";
4
5
  const HUNK_HEADER = /^@@\s+-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s+@@/;
5
6
  function parseUnifiedDiff(diff) {
6
7
  const rawLines = diff.replace(/\n$/, "").split("\n");
@@ -109,7 +110,7 @@ const CodeDiff = React.forwardRef(
109
110
  ]
110
111
  }
111
112
  ),
112
- /* @__PURE__ */ jsx("span", { className: `${baseClass}__sr-only`, children: statsLabel(additions, deletions) })
113
+ /* @__PURE__ */ jsx("span", { className: "ds-visually-hidden", children: statsLabel(additions, deletions) })
113
114
  ] })
114
115
  ] }),
115
116
  /* @__PURE__ */ jsx(
@@ -136,7 +137,7 @@ const CodeDiff = React.forwardRef(
136
137
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__gutter`, "aria-hidden": "true", children: line.newLine ?? "" })
137
138
  ] }),
138
139
  /* @__PURE__ */ jsx("span", { className: `${baseClass}__marker`, "aria-hidden": "true", children: line.type === "add" ? "+" : line.type === "remove" ? "-" : "" }),
139
- changeLabel && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__sr-only`, children: [
140
+ changeLabel && /* @__PURE__ */ jsxs("span", { className: "ds-visually-hidden", children: [
140
141
  changeLabel,
141
142
  " "
142
143
  ] }),
@@ -18,6 +18,7 @@
18
18
  /* Appearance */
19
19
  border: var(--border-025) solid var(--color-bg-container-border);
20
20
  border-radius: var(--radius-600); /* 24px */
21
+ background-color: var(--color-bg-container-primary);
21
22
  padding: var(--padding-500); /* 20px */
22
23
  overflow: hidden;
23
24
  position: relative;