@tensor_1/react 2.47.0 → 2.48.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 (183) hide show
  1. package/README.md +470 -1
  2. package/dist/{SchedulingCalendar-B6TakO2h.d.ts → SchedulingCalendar-WWyFL3Eo.d.ts} +51 -2
  3. package/dist/announce.d.ts +10 -0
  4. package/dist/announce.js +30 -0
  5. package/dist/chart-analytic.cjs +33 -25
  6. package/dist/chart-preset.cjs +23 -15
  7. package/dist/chart.cjs +23 -15
  8. package/dist/combobox-model.d.ts +10 -1
  9. package/dist/combobox-model.js +15 -0
  10. package/dist/command-palette-model.d.ts +44 -0
  11. package/dist/command-palette-model.js +36 -0
  12. package/dist/components/AccountMenu.d.ts +44 -0
  13. package/dist/components/AccountMenu.js +43 -0
  14. package/dist/components/AppShell.d.ts +45 -2
  15. package/dist/components/AppShell.js +116 -5
  16. package/dist/components/AuditLog.d.ts +128 -0
  17. package/dist/components/AuditLog.js +196 -0
  18. package/dist/components/BrandProfiles.js +4 -3
  19. package/dist/components/Breadcrumbs.d.ts +9 -2
  20. package/dist/components/Breadcrumbs.js +3 -2
  21. package/dist/components/Button.d.ts +12 -5
  22. package/dist/components/Button.js +7 -3
  23. package/dist/components/Card.d.ts +18 -1
  24. package/dist/components/Card.js +5 -1
  25. package/dist/components/ChangeHighlight.d.ts +30 -0
  26. package/dist/components/ChangeHighlight.js +21 -0
  27. package/dist/components/ChartCore.js +2 -1
  28. package/dist/components/Checkbox.d.ts +27 -1
  29. package/dist/components/Checkbox.js +31 -2
  30. package/dist/components/CodeDisplay.d.ts +65 -0
  31. package/dist/components/CodeDisplay.js +124 -0
  32. package/dist/components/Combobox.d.ts +27 -6
  33. package/dist/components/Combobox.js +195 -58
  34. package/dist/components/CommandPalette.d.ts +36 -1
  35. package/dist/components/CommandPalette.js +254 -2
  36. package/dist/components/ContactCard.d.ts +66 -0
  37. package/dist/components/ContactCard.js +74 -0
  38. package/dist/components/Count.d.ts +24 -0
  39. package/dist/components/Count.js +32 -0
  40. package/dist/components/DataWorkspace.d.ts +167 -0
  41. package/dist/components/DataWorkspace.js +383 -0
  42. package/dist/components/DateFieldParts.d.ts +2 -1
  43. package/dist/components/DateFieldParts.js +7 -0
  44. package/dist/components/DatePicker.d.ts +9 -2
  45. package/dist/components/DatePicker.js +67 -28
  46. package/dist/components/DateRangePicker.d.ts +12 -2
  47. package/dist/components/DateRangePicker.js +13 -12
  48. package/dist/components/DetailPage.d.ts +7 -1
  49. package/dist/components/DetailPage.js +2 -1
  50. package/dist/components/Dialogs.d.ts +71 -10
  51. package/dist/components/Dialogs.js +130 -30
  52. package/dist/components/DiffViewer.d.ts +23 -3
  53. package/dist/components/DiffViewer.js +26 -12
  54. package/dist/components/DiscardPrompt.js +16 -0
  55. package/dist/components/DisplayPreferences.d.ts +83 -0
  56. package/dist/components/DisplayPreferences.js +185 -0
  57. package/dist/components/EditorialHome.d.ts +23 -3
  58. package/dist/components/EditorialHome.js +16 -11
  59. package/dist/components/EntityPicker.d.ts +20 -3
  60. package/dist/components/EntityPicker.js +32 -13
  61. package/dist/components/FilterEditor.d.ts +18 -4
  62. package/dist/components/FilterEditor.js +141 -19
  63. package/dist/components/InfoTip.js +11 -12
  64. package/dist/components/InlineEdit.d.ts +87 -20
  65. package/dist/components/InlineEdit.js +197 -54
  66. package/dist/components/Input.d.ts +12 -2
  67. package/dist/components/Input.js +5 -3
  68. package/dist/components/Kbd.d.ts +6 -1
  69. package/dist/components/Kbd.js +6 -6
  70. package/dist/components/Lightbox.d.ts +41 -5
  71. package/dist/components/Lightbox.js +95 -9
  72. package/dist/components/MatchReview.d.ts +40 -1
  73. package/dist/components/MatchReview.js +130 -4
  74. package/dist/components/MetricInput.js +3 -2
  75. package/dist/components/Modal.d.ts +2 -1
  76. package/dist/components/Modal.js +13 -4
  77. package/dist/components/NavFavourites.d.ts +5 -0
  78. package/dist/components/NavFavourites.js +7 -7
  79. package/dist/components/OtpInput.d.ts +33 -0
  80. package/dist/components/OtpInput.js +123 -0
  81. package/dist/components/PageHeader.d.ts +7 -1
  82. package/dist/components/PageHeader.js +2 -2
  83. package/dist/components/Pagination.js +6 -5
  84. package/dist/components/PasswordInput.d.ts +34 -0
  85. package/dist/components/PasswordInput.js +101 -0
  86. package/dist/components/Peek.js +3 -3
  87. package/dist/components/Popover.js +2 -0
  88. package/dist/components/PrintLayout.d.ts +63 -0
  89. package/dist/components/PrintLayout.js +114 -0
  90. package/dist/components/QrCode.d.ts +47 -0
  91. package/dist/components/QrCode.js +55 -0
  92. package/dist/components/QrScanner.d.ts +95 -0
  93. package/dist/components/QrScanner.js +266 -0
  94. package/dist/components/RelationshipGraph.d.ts +32 -1
  95. package/dist/components/RelationshipGraph.js +18 -5
  96. package/dist/components/RelationshipGraphLayered.d.ts +1 -1
  97. package/dist/components/RelationshipGraphLayered.js +190 -115
  98. package/dist/components/RelationshipGraphList.js +33 -6
  99. package/dist/components/RuleBuilder.js +39 -7
  100. package/dist/components/SchedulingAgenda.d.ts +3 -1
  101. package/dist/components/SchedulingCalendar.d.ts +3 -1
  102. package/dist/components/SchedulingCalendar.js +43 -4
  103. package/dist/components/SchedulingResourceDay.d.ts +57 -0
  104. package/dist/components/SchedulingResourceDay.js +287 -0
  105. package/dist/components/SchedulingTimeGrid.d.ts +3 -1
  106. package/dist/components/SchedulingTimeline.d.ts +3 -1
  107. package/dist/components/SearchSuggest.d.ts +23 -3
  108. package/dist/components/SearchSuggest.js +48 -17
  109. package/dist/components/Segmented.d.ts +39 -4
  110. package/dist/components/Segmented.js +31 -3
  111. package/dist/components/Select.d.ts +3 -2
  112. package/dist/components/Select.js +1 -1
  113. package/dist/components/ShortcutHint.d.ts +11 -10
  114. package/dist/components/ShortcutHint.js +44 -38
  115. package/dist/components/Sidebar.d.ts +36 -4
  116. package/dist/components/Sidebar.js +37 -12
  117. package/dist/components/SortableList.d.ts +45 -0
  118. package/dist/components/SortableList.js +134 -0
  119. package/dist/components/Stat.d.ts +28 -3
  120. package/dist/components/Stat.js +13 -3
  121. package/dist/components/StatusPill.d.ts +14 -3
  122. package/dist/components/StatusPill.js +11 -3
  123. package/dist/components/Steps.js +2 -1
  124. package/dist/components/Table.d.ts +9 -2
  125. package/dist/components/Table.js +4 -2
  126. package/dist/components/TableControls.js +18 -58
  127. package/dist/components/TableOverflowProbe.d.ts +12 -0
  128. package/dist/components/TableOverflowProbe.js +27 -0
  129. package/dist/components/Tabs.d.ts +2 -1
  130. package/dist/components/Tabs.js +1 -0
  131. package/dist/components/TagInput.d.ts +67 -0
  132. package/dist/components/TagInput.js +342 -0
  133. package/dist/components/Textarea.d.ts +5 -0
  134. package/dist/components/Textarea.js +2 -2
  135. package/dist/components/TimePicker.d.ts +80 -0
  136. package/dist/components/TimePicker.js +347 -0
  137. package/dist/components/Toast.js +3 -2
  138. package/dist/components/Tooltip.d.ts +8 -4
  139. package/dist/components/Tooltip.js +24 -21
  140. package/dist/components/Tree.d.ts +8 -0
  141. package/dist/components/Tree.js +11 -5
  142. package/dist/display-preferences-model.d.ts +53 -0
  143. package/dist/display-preferences-model.js +64 -0
  144. package/dist/emoji.cjs +28 -35
  145. package/dist/filter-model.d.ts +59 -3
  146. package/dist/filter-model.js +67 -2
  147. package/dist/hooks/useChangeHighlight.d.ts +33 -0
  148. package/dist/hooks/useChangeHighlight.js +44 -0
  149. package/dist/hooks/useDialog.d.ts +5 -0
  150. package/dist/hooks/useDialog.js +3 -2
  151. package/dist/hooks/useOptimisticValue.d.ts +51 -0
  152. package/dist/hooks/useOptimisticValue.js +61 -0
  153. package/dist/hooks/useReducedMotion.d.ts +4 -1
  154. package/dist/hooks/useReducedMotion.js +7 -1
  155. package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
  156. package/dist/hooks/useResolvedFilterLabels.js +34 -0
  157. package/dist/hooks/useVirtualRows.d.ts +21 -2
  158. package/dist/hooks/useVirtualRows.js +30 -3
  159. package/dist/icons/Icon.d.ts +1 -1
  160. package/dist/index.cjs +18644 -13210
  161. package/dist/index.d.cts +3003 -699
  162. package/dist/index.d.ts +42 -16
  163. package/dist/index.js +139 -7
  164. package/dist/labels-context.d.ts +90 -3
  165. package/dist/overlay-stack.d.ts +6 -0
  166. package/dist/overlay-stack.js +13 -0
  167. package/dist/qr-model.d.ts +65 -0
  168. package/dist/qr-model.js +323 -0
  169. package/dist/relationship-graph-model.d.ts +78 -3
  170. package/dist/relationship-graph-model.js +112 -5
  171. package/dist/reorder.d.ts +30 -0
  172. package/dist/reorder.js +74 -0
  173. package/dist/rich-text.cjs +4 -2
  174. package/dist/scheduling-resource-model.d.ts +76 -0
  175. package/dist/scheduling-resource-model.js +74 -0
  176. package/dist/search-suggest-model.js +3 -1
  177. package/dist/shell-context.d.ts +11 -0
  178. package/dist/shell-context.js +7 -0
  179. package/dist/time-field-model.d.ts +46 -0
  180. package/dist/time-field-model.js +152 -0
  181. package/dist/toast-store.d.ts +17 -1
  182. package/dist/toast-store.js +23 -7
  183. package/package.json +2 -1
@@ -1,24 +1,45 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { useEffect, useId, useRef, useState } from "react";
3
+ import { forwardRef, useEffect, useId, useRef, useState } from "react";
4
4
  import { cx } from "../cx.js";
5
5
  import { useUixLabels } from "../labels-context.js";
6
+ import { SearchIcon } from "../icons/components.js";
7
+ import { useInShellDrawer } from "../shell-context.js";
8
+ import { KbdCombo, ariaKeyShortcuts, useKbdPlatform } from "./Kbd.js";
6
9
  const ChevronIcon = () => /* @__PURE__ */ jsx("svg", { className: "uix-navgroup__chevron", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M2 4l4 4 4-4" }) });
7
- function Sidebar({ collapsed, nav, onToggle, brand, toggleIcon, children, expandLabel: expandLabelProp, collapseLabel: collapseLabelProp, className, ...props }) {
10
+ function Sidebar({ collapsed, nav, onToggle, brand, toggleIcon, actions, search, footer, children, expandLabel: expandLabelProp, collapseLabel: collapseLabelProp, className, ...props }) {
8
11
  const uixLabels = useUixLabels();
9
12
  const expandLabel = expandLabelProp ?? uixLabels.sidebar?.expand ?? "Expand sidebar";
10
13
  const collapseLabel = collapseLabelProp ?? uixLabels.sidebar?.collapse ?? "Collapse sidebar";
11
- const isCollapsed = collapsed ?? nav === "rail";
12
- return /* @__PURE__ */ jsxs("nav", { className: cx("uix-sidebar", className), "data-collapsed": isCollapsed || void 0, "data-nav": nav, ...props, children: [
13
- (brand != null || onToggle) && /* @__PURE__ */ jsxs("div", { className: "uix-sidebar__head", children: [
14
+ const inDrawer = useInShellDrawer();
15
+ const isCollapsed = !inDrawer && (collapsed ?? nav === "rail");
16
+ const platform = useKbdPlatform();
17
+ return /* @__PURE__ */ jsxs("nav", { className: cx("uix-sidebar", className), "data-collapsed": isCollapsed || void 0, "data-nav": inDrawer ? void 0 : nav, ...props, children: [
18
+ (brand != null || onToggle || actions != null) && /* @__PURE__ */ jsxs("div", { className: "uix-sidebar__head", children: [
14
19
  brand && /* @__PURE__ */ jsx("div", { className: "uix-sidebar__brand", children: brand }),
20
+ actions != null && /* @__PURE__ */ jsx("div", { className: "uix-sidebar__actions", children: actions }),
15
21
  onToggle && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-sidebar__toggle", onClick: onToggle, "aria-label": isCollapsed ? expandLabel : collapseLabel, children: toggleIcon ?? /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", strokeWidth: 1.5, "aria-hidden": "true", children: [
16
22
  /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "12", height: "1.5", rx: ".75" }),
17
23
  /* @__PURE__ */ jsx("rect", { x: "3", y: "8.25", width: "8", height: "1.5", rx: ".75" }),
18
24
  /* @__PURE__ */ jsx("rect", { x: "3", y: "12.5", width: "12", height: "1.5", rx: ".75" })
19
25
  ] }) })
20
26
  ] }),
21
- children
27
+ search && /* @__PURE__ */ jsxs(
28
+ "button",
29
+ {
30
+ type: "button",
31
+ className: "uix-sidebar__search",
32
+ onClick: search.onActivate,
33
+ "aria-keyshortcuts": search.shortcut ? ariaKeyShortcuts(search.shortcut, platform) : void 0,
34
+ children: [
35
+ /* @__PURE__ */ jsx(SearchIcon, { className: "uix-sidebar__search-icon" }),
36
+ /* @__PURE__ */ jsx("span", { className: "uix-sidebar__search-label", children: search.label }),
37
+ search.shortcut && /* @__PURE__ */ jsx(KbdCombo, { className: "uix-sidebar__search-keys", keys: [...search.shortcut], platform, "aria-hidden": "true" })
38
+ ]
39
+ }
40
+ ),
41
+ children,
42
+ footer != null && /* @__PURE__ */ jsx("div", { className: "uix-sidebar__foot", children: footer })
22
43
  ] });
23
44
  }
24
45
  function SidebarSection({ label, children }) {
@@ -27,7 +48,7 @@ function SidebarSection({ label, children }) {
27
48
  children
28
49
  ] });
29
50
  }
30
- function NavItem({ icon, badge, active, as: Tag = "a", description, children, className, ...props }) {
51
+ const NavItem = forwardRef(function NavItem2({ icon, badge, active, as: Tag = "a", description, children, className, ...props }, ref) {
31
52
  const text = description == null ? /* @__PURE__ */ jsx("span", { className: "uix-navitem__label", children }) : /* @__PURE__ */ jsxs("span", { className: "uix-navitem__text", children: [
32
53
  /* @__PURE__ */ jsx("span", { className: "uix-navitem__label", children }),
33
54
  /* @__PURE__ */ jsx("span", { className: "uix-navitem__desc", children: description })
@@ -38,6 +59,7 @@ function NavItem({ icon, badge, active, as: Tag = "a", description, children, cl
38
59
  return /* @__PURE__ */ jsxs(
39
60
  "button",
40
61
  {
62
+ ref,
41
63
  type: "button",
42
64
  className: cx("uix-navitem", className),
43
65
  "aria-current": active ? "page" : void 0,
@@ -54,6 +76,7 @@ function NavItem({ icon, badge, active, as: Tag = "a", description, children, cl
54
76
  return /* @__PURE__ */ jsxs(
55
77
  "a",
56
78
  {
79
+ ref,
57
80
  className: cx("uix-navitem", className),
58
81
  "aria-current": active ? "page" : void 0,
59
82
  "data-multiline": multiline,
@@ -65,7 +88,8 @@ function NavItem({ icon, badge, active, as: Tag = "a", description, children, cl
65
88
  ]
66
89
  }
67
90
  );
68
- }
91
+ });
92
+ NavItem.displayName = "NavItem";
69
93
  function NavGroup({ icon, label, children, defaultExpanded = true, expanded: controlledExpanded, onExpandedChange }) {
70
94
  const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
71
95
  const expanded = controlledExpanded ?? internalExpanded;
@@ -101,14 +125,15 @@ function NavGroup({ icon, label, children, defaultExpanded = true, expanded: con
101
125
  /* @__PURE__ */ jsx("div", { ref: panelRef, id: panelId, className: "uix-navgroup__panel", "aria-hidden": !expanded, children: /* @__PURE__ */ jsx("div", { children }) })
102
126
  ] });
103
127
  }
104
- function SubNavItem({ active, as: Tag = "a", children, className, ...props }) {
128
+ const SubNavItem = forwardRef(function SubNavItem2({ active, as: Tag = "a", children, className, ...props }, ref) {
105
129
  const cls = cx("uix-navitem uix-subitem", className);
106
130
  if (Tag === "button") {
107
131
  const { href: _href, ...btnProps } = props;
108
- return /* @__PURE__ */ jsx("button", { type: "button", className: cls, "aria-current": active ? "page" : void 0, ...btnProps, children: /* @__PURE__ */ jsx("span", { className: "uix-navitem__label", children }) });
132
+ return /* @__PURE__ */ jsx("button", { ref, type: "button", className: cls, "aria-current": active ? "page" : void 0, ...btnProps, children: /* @__PURE__ */ jsx("span", { className: "uix-navitem__label", children }) });
109
133
  }
110
- return /* @__PURE__ */ jsx("a", { className: cls, "aria-current": active ? "page" : void 0, ...props, children: /* @__PURE__ */ jsx("span", { className: "uix-navitem__label", children }) });
111
- }
134
+ return /* @__PURE__ */ jsx("a", { ref, className: cls, "aria-current": active ? "page" : void 0, ...props, children: /* @__PURE__ */ jsx("span", { className: "uix-navitem__label", children }) });
135
+ });
136
+ SubNavItem.displayName = "SubNavItem";
112
137
  export {
113
138
  NavGroup,
114
139
  NavItem,
@@ -0,0 +1,45 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ /** Every word `SortableList` renders or announces. `{label}` is the row's name. */
5
+ interface SortableListLabels {
6
+ /** The drag grip's name. */
7
+ grip: string;
8
+ moveUp: string;
9
+ moveDown: string;
10
+ /** Polite announcement after a move: `{label}`, `{position}`, `{count}`. */
11
+ moved: string;
12
+ }
13
+ declare const DEFAULT_SORTABLE_LIST_LABELS: SortableListLabels;
14
+ /** What `renderItem` receives besides the item. */
15
+ interface SortableListItemContext {
16
+ index: number;
17
+ count: number;
18
+ /** This row is being dragged. */
19
+ dragging: boolean;
20
+ }
21
+ interface SortableListProps<T> extends Omit<HTMLAttributes<HTMLUListElement>, 'children' | 'onChange'> {
22
+ items: readonly T[];
23
+ getId: (item: T) => string;
24
+ /** The row's name in the grip, the move buttons and the announcement. Default: its id. */
25
+ getLabel?: (item: T) => string;
26
+ renderItem: (item: T, context: SortableListItemContext) => ReactNode;
27
+ /** Called with the full new order of ids after each keyboard move, and once when a drag ends. */
28
+ onReorder: (orderedIds: string[]) => void;
29
+ /** Rows show no grip and no move buttons. */
30
+ disabled?: boolean;
31
+ /** Each word defaults to `UixLabelsProvider` `sortableList`, then to English. */
32
+ labels?: Partial<SortableListLabels>;
33
+ }
34
+ /**
35
+ * A list the person reorders (HAR-1375; MOTUS C-16 photo order, TENSOR preset and start-page
36
+ * order): media, priorities, steps. Each row has a grip to drag with a pointer, and Move up /
37
+ * Move down buttons that are always there (a drag is never the only way). With focus anywhere
38
+ * in a row, Alt+↑ / Alt+↓ move it; a focused grip moves with ↑ / ↓ alone. Focus stays with the
39
+ * moved row, and a polite status says where it went. Keyboard moves are instant; a drag places
40
+ * the row under the pointer with no animation. Shares its order model with `ViewMenu`,
41
+ * `SavedViewMenu` and `NavFavourites`.
42
+ */
43
+ declare function SortableList<T>({ items, getId, getLabel, renderItem, onReorder, disabled, labels: labelOverrides, className, ...props }: SortableListProps<T>): react.JSX.Element;
44
+
45
+ export { DEFAULT_SORTABLE_LIST_LABELS, SortableList, type SortableListItemContext, type SortableListLabels, type SortableListProps };
@@ -0,0 +1,134 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { cx } from "../cx.js";
5
+ import { fillLabel } from "../fill-label.js";
6
+ import { useUixLabels } from "../labels-context.js";
7
+ import { placeId, sameOrder, useRowDrag } from "../reorder.js";
8
+ import { EditorIcon } from "./EditorIcons.js";
9
+ const DEFAULT_SORTABLE_LIST_LABELS = {
10
+ grip: "Drag to reorder: {label}",
11
+ moveUp: "Move {label} up",
12
+ moveDown: "Move {label} down",
13
+ moved: "{label} moved to position {position} of {count}"
14
+ };
15
+ const ArrowIcon = ({ dir }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: dir === "up" ? "m18 15-6-6-6 6" : "m6 9 6 6 6-6" }) });
16
+ function SortableList({
17
+ items,
18
+ getId,
19
+ getLabel,
20
+ renderItem,
21
+ onReorder,
22
+ disabled = false,
23
+ labels: labelOverrides,
24
+ className,
25
+ ...props
26
+ }) {
27
+ const labels = { ...DEFAULT_SORTABLE_LIST_LABELS, ...useUixLabels().sortableList, ...labelOverrides };
28
+ const ids = items.map(getId);
29
+ const orderKey = ids.join("\0");
30
+ const [draft, setDraft] = useState(null);
31
+ useEffect(() => setDraft(null), [orderKey]);
32
+ const order = draft && sameOrder([...draft].sort(), [...ids].sort()) ? draft : ids;
33
+ const byId = new Map(items.map((item) => [getId(item), item]));
34
+ const nameOf = (id) => {
35
+ const item = byId.get(id);
36
+ return item !== void 0 && getLabel ? getLabel(item) : id;
37
+ };
38
+ const [announcement, setAnnouncement] = useState("");
39
+ const listRef = useRef(null);
40
+ const refocus = useRef(null);
41
+ useEffect(() => {
42
+ const target = refocus.current;
43
+ refocus.current = null;
44
+ if (!target) return;
45
+ if (target.el) {
46
+ if (target.el.isConnected && document.activeElement !== target.el) target.el.focus();
47
+ return;
48
+ }
49
+ const row = Array.from(listRef.current?.children ?? []).find((child) => child.dataset.id === target.id);
50
+ if (!row) return;
51
+ const want = target.part === "up" ? ".uix-sortable__move--up" : target.part === "down" ? ".uix-sortable__move--down" : target.part === "grip" ? ".uix-sortable__grip" : null;
52
+ const other = target.part === "up" ? ".uix-sortable__move--down" : ".uix-sortable__move--up";
53
+ const button = want ? row.querySelector(want) : null;
54
+ const el = button && !button.disabled ? button : row.querySelector(other);
55
+ if (el && document.activeElement !== el) el.focus();
56
+ });
57
+ const commit = (next, id) => {
58
+ setDraft(null);
59
+ onReorder([...next]);
60
+ setAnnouncement(fillLabel(labels.moved, { label: nameOf(id), position: next.indexOf(id) + 1, count: next.length }));
61
+ };
62
+ const move = (id, delta, part, el) => {
63
+ const next = placeId(order, id, order.indexOf(id) + delta);
64
+ if (next === order) return;
65
+ refocus.current = { id, part, el };
66
+ commit(next, id);
67
+ };
68
+ const dragStart = useRef(null);
69
+ const { dragging, start } = useRowDrag(".uix-sortable__row", {
70
+ over: (id, index) => {
71
+ const next = placeId(order, id, index);
72
+ if (next !== order) setDraft(next);
73
+ },
74
+ drop: (id) => {
75
+ const begin = dragStart.current;
76
+ dragStart.current = null;
77
+ if (begin && !sameOrder(begin, order)) commit(order, id);
78
+ else setDraft(null);
79
+ },
80
+ cancel: () => {
81
+ dragStart.current = null;
82
+ setDraft(null);
83
+ }
84
+ });
85
+ const onRowKeyDown = (event, id) => {
86
+ if (disabled || !event.altKey || event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
87
+ if (event.target.closest('input, textarea, select, [contenteditable="true"]')) return;
88
+ event.preventDefault();
89
+ const target = event.target;
90
+ const part = target.closest(".uix-sortable__move--up") ? "up" : target.closest(".uix-sortable__move--down") ? "down" : target.closest(".uix-sortable__grip") ? "grip" : "row";
91
+ move(id, event.key === "ArrowUp" ? -1 : 1, part, part === "row" ? target : void 0);
92
+ };
93
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
94
+ /* @__PURE__ */ jsx("ul", { ref: listRef, className: cx("uix-sortable", className), "data-dragging": dragging ? "" : void 0, ...props, children: order.map((id, index) => {
95
+ const item = byId.get(id);
96
+ if (item === void 0) return null;
97
+ const name = nameOf(id);
98
+ return /* @__PURE__ */ jsxs("li", { className: "uix-sortable__row", "data-id": id, "data-dragging": dragging === id || void 0, onKeyDown: (event) => onRowKeyDown(event, id), children: [
99
+ !disabled && /* @__PURE__ */ jsx(
100
+ "button",
101
+ {
102
+ type: "button",
103
+ className: "uix-sortable__grip",
104
+ tabIndex: -1,
105
+ "aria-label": fillLabel(labels.grip, { label: name }),
106
+ onPointerDown: (event) => {
107
+ if (event.button !== 0) return;
108
+ event.preventDefault();
109
+ event.currentTarget.focus({ preventScroll: true });
110
+ dragStart.current = order;
111
+ start(event, id);
112
+ },
113
+ onKeyDown: (event) => {
114
+ if (event.altKey || event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
115
+ event.preventDefault();
116
+ move(id, event.key === "ArrowUp" ? -1 : 1, "grip");
117
+ },
118
+ children: /* @__PURE__ */ jsx(EditorIcon, { name: "grip" })
119
+ }
120
+ ),
121
+ /* @__PURE__ */ jsx("div", { className: "uix-sortable__content", children: renderItem(item, { index, count: order.length, dragging: dragging === id }) }),
122
+ !disabled && /* @__PURE__ */ jsxs("span", { className: "uix-sortable__moves", children: [
123
+ /* @__PURE__ */ jsx("button", { type: "button", className: "uix-sortable__move uix-sortable__move--up", "aria-label": fillLabel(labels.moveUp, { label: name }), disabled: index === 0, onClick: () => move(id, -1, "up"), children: /* @__PURE__ */ jsx(ArrowIcon, { dir: "up" }) }),
124
+ /* @__PURE__ */ jsx("button", { type: "button", className: "uix-sortable__move uix-sortable__move--down", "aria-label": fillLabel(labels.moveDown, { label: name }), disabled: index === order.length - 1, onClick: () => move(id, 1, "down"), children: /* @__PURE__ */ jsx(ArrowIcon, { dir: "down" }) })
125
+ ] })
126
+ ] }, id);
127
+ }) }),
128
+ /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", role: "status", children: announcement })
129
+ ] });
130
+ }
131
+ export {
132
+ DEFAULT_SORTABLE_LIST_LABELS,
133
+ SortableList
134
+ };
@@ -3,8 +3,15 @@ import { HTMLAttributes, ReactNode } from 'react';
3
3
  import { UixRenderLink } from '../link.js';
4
4
 
5
5
  interface StatTrend {
6
+ /** Which way the figure moved: the arrow, and the spoken "up" / "down". */
6
7
  direction: 'up' | 'down';
7
8
  label: ReactNode;
9
+ /**
10
+ * What the change means, which sets the colour (HAR-1563): `positive` green, `negative` red,
11
+ * `neutral` (default) grey. A rise in breached SLAs is `negative`; direction never picks the
12
+ * colour.
13
+ */
14
+ sentiment?: 'positive' | 'negative' | 'neutral';
8
15
  }
9
16
  interface StatProps extends HTMLAttributes<HTMLElement> {
10
17
  label: ReactNode;
@@ -15,7 +22,10 @@ interface StatProps extends HTMLAttributes<HTMLElement> {
15
22
  meta?: ReactNode;
16
23
  /** Trend chip rendered before the meta text. */
17
24
  trend?: StatTrend;
18
- /** Outline and value colour. `neutral` (default) is today's tile. */
25
+ /**
26
+ * `warning` / `danger` colour the value and put a dot of that tone before it; the border stays
27
+ * neutral (HAR-1563). `neutral` (default) is the plain tile.
28
+ */
19
29
  tone?: 'neutral' | 'warning' | 'danger';
20
30
  /** `hero` (default) is today's KPI size; `compact` is for dense fact bands. */
21
31
  size?: 'hero' | 'compact';
@@ -48,7 +58,8 @@ interface StatProps extends HTMLAttributes<HTMLElement> {
48
58
  /**
49
59
  * Makes the whole tile a link (HAR-1350; TENSOR B7, MOTUS B-A7). Server-renderable, unlike
50
60
  * `onActivate`. Ignored when `onActivate` is set. The forwarded ref reaches the `<a>` only
51
- * without `renderLink`.
61
+ * without `renderLink`. A trailing chevron in the label row marks the tile as a link at rest,
62
+ * since a touch screen has no hover (HAR-1803).
52
63
  */
53
64
  href?: string;
54
65
  /** The link tile is the current page (`aria-current="page"`). */
@@ -61,5 +72,19 @@ interface StatProps extends HTMLAttributes<HTMLElement> {
61
72
  * ref then points at that button, so a popover can anchor to it.
62
73
  */
63
74
  declare const Stat: react.ForwardRefExoticComponent<StatProps & react.RefAttributes<HTMLElement>>;
75
+ interface StatRowProps extends HTMLAttributes<HTMLDivElement> {
76
+ /**
77
+ * The narrowest a tile may get before the row puts fewer tiles side by side, as a CSS length
78
+ * (`--stat-row-min`). Default `8.5rem`, and `12rem` once a hero tile is in the row.
79
+ */
80
+ minTileWidth?: string;
81
+ children?: ReactNode;
82
+ }
83
+ /**
84
+ * A row of `Stat` tiles over `.uix-stat-row` (HAR-1803 review): as many tiles per row as fit at
85
+ * `minTileWidth`, all the same height, down to one per row on a phone. Use it instead of a fixed
86
+ * column count, which squeezes tiles until their labels break letter by letter.
87
+ */
88
+ declare function StatRow({ minTileWidth, className, style, children, ...props }: StatRowProps): react.JSX.Element;
64
89
 
65
- export { Stat, type StatProps, type StatTrend };
90
+ export { Stat, type StatProps, StatRow, type StatRowProps, type StatTrend };
@@ -2,7 +2,9 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef, useId } from "react";
3
3
  import { cx } from "../cx.js";
4
4
  import { renderUixLink } from "../link.js";
5
+ import { ChevronRightIcon } from "../icons/components.js";
5
6
  const Chevron = () => /* @__PURE__ */ jsx("span", { className: "uix-stat__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) }) });
7
+ const Go = () => /* @__PURE__ */ jsx("span", { className: "uix-stat__go", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) });
6
8
  const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, haspopup = "dialog", href, current, renderLink, className, onClick, onKeyDown, pending = false, ...props }, ref) {
7
9
  const id = useId();
8
10
  const interactive = onActivate != null;
@@ -13,6 +15,8 @@ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone =
13
15
  size === "compact" && "uix-stat--compact",
14
16
  (interactive || linked) && "uix-stat--interactive",
15
17
  linked && "uix-stat--link",
18
+ // an in-place action has no chevron: its value is underlined at rest instead (HAR-1803)
19
+ interactive && haspopup === false && "uix-stat--action",
16
20
  className
17
21
  );
18
22
  const Row = interactive || linked ? "span" : "div";
@@ -20,11 +24,12 @@ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone =
20
24
  /* @__PURE__ */ jsxs(Row, { className: "uix-stat__label", children: [
21
25
  /* @__PURE__ */ jsx("span", { id: interactive ? `${id}-label` : void 0, children: label }),
22
26
  icon,
23
- interactive && haspopup !== false && /* @__PURE__ */ jsx(Chevron, {})
27
+ interactive && haspopup !== false && /* @__PURE__ */ jsx(Chevron, {}),
28
+ linked && /* @__PURE__ */ jsx(Go, {})
24
29
  ] }),
25
30
  /* @__PURE__ */ jsx(Row, { className: "uix-stat__value", id: interactive ? `${id}-value` : void 0, children: value }),
26
31
  (meta != null || trend != null) && /* @__PURE__ */ jsxs(Row, { className: "uix-stat__meta", id: interactive ? `${id}-meta` : void 0, children: [
27
- trend != null && /* @__PURE__ */ jsxs("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`), children: [
32
+ trend != null && /* @__PURE__ */ jsxs("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`, trend.sentiment != null && trend.sentiment !== "neutral" && `uix-stat__trend--${trend.sentiment}`), children: [
28
33
  /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: trend.direction === "up" ? /* @__PURE__ */ jsx("path", { d: "M12 19V5m-6 6 6-6 6 6" }) : /* @__PURE__ */ jsx("path", { d: "M12 5v14m6-6-6 6-6-6" }) }),
29
34
  /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: trend.direction === "up" ? trendLabels?.up ?? "up" : trendLabels?.down ?? "down" }),
30
35
  trend.label
@@ -68,6 +73,11 @@ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone =
68
73
  }
69
74
  );
70
75
  });
76
+ function StatRow({ minTileWidth, className, style, children, ...props }) {
77
+ const rowStyle = minTileWidth ? { ...style, "--stat-row-min": minTileWidth } : style;
78
+ return /* @__PURE__ */ jsx("div", { className: cx("uix-stat-row", className), style: rowStyle, ...props, children });
79
+ }
71
80
  export {
72
- Stat
81
+ Stat,
82
+ StatRow
73
83
  };
@@ -1,18 +1,29 @@
1
1
  import * as react from 'react';
2
2
  import { HTMLAttributes, ReactNode } from 'react';
3
3
 
4
- type PillTone = 'neutral' | 'success' | 'info' | 'warning' | 'danger' | 'critical' | 'muted' | 'attention' | 'overdue' | 'sla-ok' | 'sla-at-risk' | 'sla-breached' | 'p1' | 'p2' | 'p3' | 'p4' | 'p5';
5
- type PillTreatment = 'filled' | 'outline';
4
+ type PillTone = 'neutral' | 'success' | 'info' | 'warning' | 'danger' | 'critical' | 'muted' | 'progress' | 'attention' | 'overdue' | 'sla-ok' | 'sla-at-risk' | 'sla-breached' | 'p1' | 'p2' | 'p3' | 'p4' | 'p5';
5
+ /**
6
+ * How loud the pill is (HAR-1563). `soft` (default) is the tinted wash; `filled` is its old name
7
+ * and still works. `dot` is the quiet one for tables: no fill, a neutral label and a coloured dot.
8
+ * `outline` is a neutral hairline with a hushed label and a dot; only `critical` keeps a toned
9
+ * border.
10
+ */
11
+ type PillTreatment = 'soft' | 'filled' | 'dot' | 'outline';
6
12
  type PillSize = 'sm' | 'md' | 'lg';
7
13
  interface StatusPillProps extends HTMLAttributes<HTMLSpanElement> {
8
14
  tone?: PillTone;
9
- /** 'filled' (default) = tinted wash; 'outline' = transparent fill + tone-tinted border. */
15
+ /**
16
+ * `soft` (default; `filled` is an alias) = tinted wash; `dot` = a coloured dot beside a neutral
17
+ * label, for dense tables; `outline` = a neutral hairline, a hushed label and a dot. `dot` and
18
+ * `outline` always draw the dot.
19
+ */
10
20
  treatment?: PillTreatment;
11
21
  /**
12
22
  * `sm` for a dense table cell or beside small text, `lg` for a page header (the public status
13
23
  * page). Default `md`, the size every pill had before (HAR-1614).
14
24
  */
15
25
  size?: PillSize;
26
+ /** Draws the tone's dot before the label. Always on for the `dot` and `outline` treatments. */
16
27
  dot?: boolean;
17
28
  children?: ReactNode;
18
29
  }
@@ -1,13 +1,21 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { cx } from "../cx.js";
3
- function StatusPill({ tone = "neutral", treatment = "filled", size = "md", dot, children, className, ...props }) {
3
+ function StatusPill({ tone = "neutral", treatment = "soft", size = "md", dot, children, className, ...props }) {
4
+ const quiet = treatment === "dot" || treatment === "outline";
4
5
  return /* @__PURE__ */ jsxs(
5
6
  "span",
6
7
  {
7
- className: cx("uix-pill", `uix-pill--${tone}`, treatment === "outline" && "uix-pill--outline", size === "sm" && "uix-pill--sm", size === "lg" && "uix-pill--lg", className),
8
+ className: cx(
9
+ "uix-pill",
10
+ `uix-pill--${tone}`,
11
+ quiet && `uix-pill--${treatment}`,
12
+ size === "sm" && "uix-pill--sm",
13
+ size === "lg" && "uix-pill--lg",
14
+ className
15
+ ),
8
16
  ...props,
9
17
  children: [
10
- dot && /* @__PURE__ */ jsx("span", { className: "uix-pill__dot", "aria-hidden": "true" }),
18
+ (dot || quiet) && /* @__PURE__ */ jsx("span", { className: "uix-pill__dot", "aria-hidden": "true" }),
11
19
  children
12
20
  ]
13
21
  }
@@ -2,6 +2,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Children, cloneElement, isValidElement, useId } from "react";
3
3
  import { cx } from "../cx.js";
4
4
  import { renderUixLink } from "../link.js";
5
+ import { XIcon } from "../icons/components.js";
5
6
  const DEFAULT_STEP_STATE_LABELS = {
6
7
  complete: "Completed",
7
8
  current: "Current step",
@@ -35,7 +36,7 @@ function Step({
35
36
  ...props
36
37
  }) {
37
38
  const titleId = useId();
38
- const glyph = marker ?? (!progress ? index + 1 : state === "complete" ? /* @__PURE__ */ jsx(Check, {}) : state === "error" ? "!" : index + 1);
39
+ const glyph = marker ?? (!progress ? index + 1 : state === "complete" ? /* @__PURE__ */ jsx(Check, {}) : state === "error" ? /* @__PURE__ */ jsx(XIcon, {}) : index + 1);
39
40
  const Title = headingLevel ? `h${headingLevel}` : "span";
40
41
  const name = /* @__PURE__ */ jsxs(Fragment, { children: [
41
42
  /* @__PURE__ */ jsx(Title, { id: children != null ? titleId : void 0, className: "uix-step__title", children: title }),
@@ -86,8 +86,15 @@ interface ExpandToggleProps extends ButtonHTMLAttributes<HTMLButtonElement> {
86
86
  declare function ExpandToggle({ expanded, controls, expandLabel, collapseLabel, className, type, ...props }: ExpandToggleProps): react.JSX.Element;
87
87
  /** Emphasised primary cell text. */
88
88
  declare function CellStrong({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
89
+ interface CellSubProps extends HTMLAttributes<HTMLSpanElement> {
90
+ /**
91
+ * Tabular numerals (HAR-1815): for a read-back code, a reference or a time, so digits line up
92
+ * down the column and a 1 is as wide as an 8.
93
+ */
94
+ tabular?: boolean;
95
+ }
89
96
  /** Secondary line under a primary cell value (muted, meta size). */
90
- declare function CellSub({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
97
+ declare function CellSub({ tabular, children, className, ...props }: CellSubProps): react.JSX.Element;
91
98
  interface MarkProps extends HTMLAttributes<HTMLElement> {
92
99
  children?: ReactNode;
93
100
  }
@@ -100,4 +107,4 @@ interface HighlightedProps {
100
107
  /** Render `text` with case-insensitive matches of `query` wrapped in <mark>. */
101
108
  declare function Highlighted({ text, query }: HighlightedProps): react.JSX.Element;
102
109
 
103
- export { BulkBar, type BulkBarProps, CellStrong, CellSub, ExpandToggle, type ExpandToggleProps, Highlighted, type HighlightedProps, Mark, type MarkProps, RowAction, type RowActionProps, RowActions, type RowActionsProps, type SortDirection, Table, type TableDensity, type TableProps, TableWrap, type TableWrapProps, Td, type TdProps, Th, type ThProps, Tr, type TrProps };
110
+ export { BulkBar, type BulkBarProps, CellStrong, CellSub, type CellSubProps, ExpandToggle, type ExpandToggleProps, Highlighted, type HighlightedProps, Mark, type MarkProps, RowAction, type RowActionProps, RowActions, type RowActionsProps, type SortDirection, Table, type TableDensity, type TableProps, TableWrap, type TableWrapProps, Td, type TdProps, Th, type ThProps, Tr, type TrProps };
@@ -3,9 +3,11 @@ import { forwardRef } from "react";
3
3
  import { cx } from "../cx.js";
4
4
  import { highlightSegments } from "../table-engine.js";
5
5
  import { BusyBar } from "./BusyBar.js";
6
+ import { TableOverflowProbe } from "./TableOverflowProbe.js";
6
7
  const TableWrap = forwardRef(function TableWrap2({ announcement, refreshing, children, className, ...props }, ref) {
7
8
  return /* @__PURE__ */ jsxs("div", { ref, className: cx("uix-table-wrap", className), "aria-busy": refreshing || void 0, ...props, children: [
8
9
  refreshing !== void 0 && /* @__PURE__ */ jsx(BusyBar, { busy: refreshing }),
10
+ /* @__PURE__ */ jsx(TableOverflowProbe, {}),
9
11
  announcement != null && /* @__PURE__ */ jsx("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
10
12
  children
11
13
  ] });
@@ -100,8 +102,8 @@ function ExpandToggle({ expanded, controls, expandLabel = "Expand row", collapse
100
102
  function CellStrong({ children, className, ...props }) {
101
103
  return /* @__PURE__ */ jsx("span", { className: cx("uix-cell-strong", className), ...props, children });
102
104
  }
103
- function CellSub({ children, className, ...props }) {
104
- return /* @__PURE__ */ jsx("span", { className: cx("uix-cell-sub", className), ...props, children });
105
+ function CellSub({ tabular, children, className, ...props }) {
106
+ return /* @__PURE__ */ jsx("span", { className: cx("uix-cell-sub", tabular && "uix-cell-sub--tabular", className), ...props, children });
105
107
  }
106
108
  function Mark({ children, className, ...props }) {
107
109
  return /* @__PURE__ */ jsx("mark", { className: cx("uix-mark", className), ...props, children });