@tensor_1/react 2.16.0 → 2.17.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 (66) hide show
  1. package/dist/chart-preset.cjs +15 -3
  2. package/dist/chart.cjs +15 -3
  3. package/dist/components/Alert.js +15 -7
  4. package/dist/components/AppShell.d.ts +3 -1
  5. package/dist/components/AppShell.js +3 -1
  6. package/dist/components/Avatar.js +2 -1
  7. package/dist/components/Button.js +32 -16
  8. package/dist/components/Card.d.ts +3 -1
  9. package/dist/components/Card.js +2 -2
  10. package/dist/components/ChartCore.js +15 -3
  11. package/dist/components/CommandPalette.d.ts +4 -2
  12. package/dist/components/CommandPalette.js +66 -13
  13. package/dist/components/Comments.d.ts +5 -1
  14. package/dist/components/Comments.js +1 -1
  15. package/dist/components/Composer.d.ts +8 -1
  16. package/dist/components/Composer.js +7 -2
  17. package/dist/components/DetailLayout.js +1 -1
  18. package/dist/components/Drawer.d.ts +3 -4
  19. package/dist/components/Drawer.js +6 -4
  20. package/dist/components/Field.js +6 -3
  21. package/dist/components/Inbox.d.ts +13 -3
  22. package/dist/components/Inbox.js +62 -3
  23. package/dist/components/Input.d.ts +13 -2
  24. package/dist/components/Input.js +20 -5
  25. package/dist/components/Kanban.d.ts +15 -3
  26. package/dist/components/Kanban.js +42 -10
  27. package/dist/components/Meter.d.ts +3 -1
  28. package/dist/components/Meter.js +9 -1
  29. package/dist/components/Modal.d.ts +4 -5
  30. package/dist/components/Modal.js +4 -4
  31. package/dist/components/NavFavourites.js +11 -0
  32. package/dist/components/PageHeader.d.ts +3 -1
  33. package/dist/components/PageHeader.js +2 -2
  34. package/dist/components/Peek.d.ts +3 -4
  35. package/dist/components/Peek.js +9 -6
  36. package/dist/components/Progress.d.ts +3 -1
  37. package/dist/components/Progress.js +5 -3
  38. package/dist/components/Radio.d.ts +3 -1
  39. package/dist/components/Radio.js +6 -2
  40. package/dist/components/Spinner.d.ts +3 -1
  41. package/dist/components/Spinner.js +3 -3
  42. package/dist/components/Stat.js +5 -1
  43. package/dist/components/States.d.ts +1 -0
  44. package/dist/components/States.js +7 -1
  45. package/dist/components/Table.d.ts +8 -1
  46. package/dist/components/Table.js +10 -6
  47. package/dist/components/Tabs.d.ts +13 -1
  48. package/dist/components/Tabs.js +79 -4
  49. package/dist/components/Timeline.d.ts +3 -3
  50. package/dist/components/Timeline.js +3 -3
  51. package/dist/components/Toast.js +42 -5
  52. package/dist/components/Tooltip.d.ts +3 -1
  53. package/dist/components/Tooltip.js +44 -5
  54. package/dist/components/Tree.d.ts +2 -0
  55. package/dist/components/Tree.js +26 -4
  56. package/dist/hooks/useDialog.d.ts +1 -1
  57. package/dist/hooks/useDialog.js +17 -2
  58. package/dist/hooks/useTable.d.ts +5 -0
  59. package/dist/hooks/useTable.js +20 -1
  60. package/dist/index.cjs +693 -243
  61. package/dist/index.d.cts +125 -35
  62. package/dist/index.d.ts +2 -2
  63. package/dist/index.js +2 -1
  64. package/dist/tree-model.d.ts +4 -0
  65. package/dist/tree-model.js +8 -0
  66. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -134,6 +134,7 @@ __export(src_exports, {
134
134
  SubNavItem: () => SubNavItem,
135
135
  Switch: () => Switch,
136
136
  Tab: () => Tab,
137
+ TabPanel: () => TabPanel,
137
138
  Table: () => Table,
138
139
  TableWrap: () => TableWrap,
139
140
  Tabs: () => Tabs,
@@ -257,8 +258,10 @@ function unlockBodyScroll() {
257
258
  saved = null;
258
259
  }
259
260
  }
260
- function useDialog(open) {
261
+ function useDialog(open, onClose) {
261
262
  const ref = (0, import_react.useRef)(null);
263
+ const onCloseRef = (0, import_react.useRef)(onClose);
264
+ onCloseRef.current = onClose;
262
265
  (0, import_react.useEffect)(() => {
263
266
  const el = ref.current;
264
267
  if (!el || !open) {
@@ -267,8 +270,21 @@ function useDialog(open) {
267
270
  }
268
271
  if (!el.open) el.showModal();
269
272
  lockBodyScroll();
273
+ let locked = true;
274
+ const handleClose = () => {
275
+ if (locked) {
276
+ locked = false;
277
+ unlockBodyScroll();
278
+ }
279
+ onCloseRef.current?.();
280
+ };
281
+ el.addEventListener("close", handleClose);
270
282
  return () => {
271
- unlockBodyScroll();
283
+ el.removeEventListener("close", handleClose);
284
+ if (locked) {
285
+ locked = false;
286
+ unlockBodyScroll();
287
+ }
272
288
  if (el.open) el.close();
273
289
  };
274
290
  }, [open]);
@@ -541,6 +557,24 @@ function useTable(data, options = {}) {
541
557
  const toggleAllRows = (0, import_react2.useCallback)(() => setSelected((s) => togglePage(s, pageIds)), [pageIds]);
542
558
  const clearSelection = (0, import_react2.useCallback)(() => setSelected(/* @__PURE__ */ new Set()), []);
543
559
  const togglePin = (0, import_react2.useCallback)((id) => setPinned((s) => toggleId(s, id)), []);
560
+ const [announcement, setAnnouncement] = (0, import_react2.useState)("");
561
+ const mounted = (0, import_react2.useRef)(false);
562
+ (0, import_react2.useEffect)(() => {
563
+ if (!mounted.current) return;
564
+ const key = sort[0];
565
+ setAnnouncement(key ? `Sorted by ${key.field}, ${key.dir}` : "Sort cleared");
566
+ }, [sort]);
567
+ (0, import_react2.useEffect)(() => {
568
+ if (!mounted.current) return;
569
+ setAnnouncement(`${rows.length} result${rows.length === 1 ? "" : "s"}`);
570
+ }, [filters, query]);
571
+ (0, import_react2.useEffect)(() => {
572
+ if (!mounted.current) return;
573
+ setAnnouncement(`${selected.size} selected`);
574
+ }, [selected]);
575
+ (0, import_react2.useEffect)(() => {
576
+ mounted.current = true;
577
+ }, []);
544
578
  const view = (0, import_react2.useMemo)(() => ({ sort, filters, q: query }), [sort, filters, query]);
545
579
  const viewQueryString = (0, import_react2.useMemo)(() => serializeView(view), [view]);
546
580
  const applyView = (0, import_react2.useCallback)((queryString) => {
@@ -557,6 +591,7 @@ function useTable(data, options = {}) {
557
591
  selected,
558
592
  pinned,
559
593
  selectAll,
594
+ announcement,
560
595
  toggleSort: doToggleSort,
561
596
  setSort,
562
597
  setFilters,
@@ -726,24 +761,40 @@ function useAnchoredPosition(anchor, floatingRef, { open, placement = "bottom-st
726
761
  // src/components/Button.tsx
727
762
  var import_react5 = require("react");
728
763
  var import_jsx_runtime = require("react/jsx-runtime");
764
+ var warnedIconButton = false;
729
765
  var Button = (0, import_react5.forwardRef)(
730
- ({ variant = "secondary", size = "md", icon = false, loading = false, className, children, disabled, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
731
- "button",
732
- {
733
- ref,
734
- className: cx(
735
- "uix-btn",
736
- `uix-btn--${variant}`,
737
- size !== "md" && `uix-btn--${size}`,
738
- icon && "uix-btn--icon",
739
- className
740
- ),
741
- disabled: disabled || loading,
742
- "data-loading": loading || void 0,
743
- ...props,
744
- children
766
+ ({ variant = "secondary", size = "md", icon = false, loading = false, className, children, disabled, onClick, ...props }, ref) => {
767
+ if (!warnedIconButton && icon && children == null && !props["aria-label"] && !props["aria-labelledby"] && typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
768
+ warnedIconButton = true;
769
+ console.warn("uix: icon-only <Button> has no accessible name \u2014 pass aria-label or aria-labelledby.");
745
770
  }
746
- )
771
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
772
+ "button",
773
+ {
774
+ ref,
775
+ className: cx(
776
+ "uix-btn",
777
+ `uix-btn--${variant}`,
778
+ size !== "md" && `uix-btn--${size}`,
779
+ icon && "uix-btn--icon",
780
+ className
781
+ ),
782
+ disabled,
783
+ "aria-disabled": loading || void 0,
784
+ "aria-busy": loading || void 0,
785
+ "data-loading": loading || void 0,
786
+ onClick: loading || onClick ? (e) => {
787
+ if (loading) {
788
+ e.preventDefault();
789
+ return;
790
+ }
791
+ onClick?.(e);
792
+ } : void 0,
793
+ ...props,
794
+ children
795
+ }
796
+ );
797
+ }
747
798
  );
748
799
  Button.displayName = "Button";
749
800
  function ButtonGroup({ children, className }) {
@@ -766,7 +817,22 @@ var Input = (0, import_react6.forwardRef)(
766
817
  )
767
818
  );
768
819
  Input.displayName = "Input";
769
- function InputGroup({ children, leadingIcon, trailingIcon, className }) {
820
+ function InputGroup({
821
+ children,
822
+ leadingIcon,
823
+ trailingIcon,
824
+ className,
825
+ id,
826
+ "aria-describedby": describedBy,
827
+ "aria-invalid": invalid,
828
+ "aria-required": required
829
+ }) {
830
+ const control = (0, import_react6.isValidElement)(children) && (id ?? describedBy ?? invalid ?? required) != null ? (0, import_react6.cloneElement)(children, {
831
+ id: children.props.id ?? id,
832
+ "aria-describedby": children.props["aria-describedby"] ?? describedBy,
833
+ "aria-invalid": children.props["aria-invalid"] ?? invalid,
834
+ "aria-required": children.props["aria-required"] ?? required
835
+ }) : children;
770
836
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
771
837
  "div",
772
838
  {
@@ -777,9 +843,9 @@ function InputGroup({ children, leadingIcon, trailingIcon, className }) {
777
843
  className
778
844
  ),
779
845
  children: [
780
- leadingIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "uix-input-group__icon", children: leadingIcon }),
781
- children,
782
- trailingIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "uix-input-group__icon uix-input-group__icon--trailing", children: trailingIcon })
846
+ leadingIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "uix-input-group__icon", "aria-hidden": "true", children: leadingIcon }),
847
+ control,
848
+ trailingIcon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "uix-input-group__icon uix-input-group__icon--trailing", "aria-hidden": "true", children: trailingIcon })
783
849
  ]
784
850
  }
785
851
  );
@@ -986,8 +1052,12 @@ var Radio = (0, import_react11.forwardRef)(
986
1052
  ] })
987
1053
  );
988
1054
  Radio.displayName = "Radio";
989
- function RadioGroup({ children, className }) {
990
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cx("uix-radio-group", className), children });
1055
+ function RadioGroup({ children, className, label }) {
1056
+ if (label == null) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cx("uix-radio-group", className), children });
1057
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("fieldset", { className: cx("uix-radio-group", className), children: [
1058
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("legend", { className: "uix-radio-group__legend", children: label }),
1059
+ children
1060
+ ] });
991
1061
  }
992
1062
 
993
1063
  // src/components/Switch.tsx
@@ -1009,14 +1079,17 @@ function Field({ label, hint, error, success, required, children, className, htm
1009
1079
  const uid = (0, import_react13.useId)();
1010
1080
  const msgId = `${uid}-msg`;
1011
1081
  const describedBy = error || success || hint ? msgId : void 0;
1082
+ const controlId = (0, import_react13.isValidElement)(children) ? children.props.id ?? `${uid}-ctl` : void 0;
1012
1083
  const control = (0, import_react13.isValidElement)(children) ? (0, import_react13.cloneElement)(children, {
1084
+ id: controlId,
1013
1085
  "aria-describedby": [children.props["aria-describedby"], describedBy].filter(Boolean).join(" ") || void 0,
1014
- "aria-invalid": error ? true : children.props["aria-invalid"]
1086
+ "aria-invalid": error ? true : children.props["aria-invalid"],
1087
+ "aria-required": children.props["aria-required"] ?? (required || void 0)
1015
1088
  }) : children;
1016
1089
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: cx("uix-field", className), children: [
1017
- label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "uix-field__label", htmlFor, "data-required": required || void 0, children: label }),
1090
+ label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("label", { className: "uix-field__label", htmlFor: htmlFor ?? controlId, "data-required": required || void 0, children: label }),
1018
1091
  control,
1019
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "uix-field__msg", id: msgId, children: error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "uix-field__error", role: "alert", children: error }) : success ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "uix-field__success", children: success }) : hint ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "uix-field__hint", children: hint }) : null })
1092
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "uix-field__msg", id: msgId, children: error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "uix-field__error", role: "alert", children: error }) : success ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "uix-field__success", role: "status", children: success }) : hint ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "uix-field__hint", children: hint }) : null })
1020
1093
  ] });
1021
1094
  }
1022
1095
 
@@ -1024,12 +1097,12 @@ function Field({ label, hint, error, success, required, children, className, htm
1024
1097
  var import_react14 = require("react");
1025
1098
  var import_jsx_runtime10 = require("react/jsx-runtime");
1026
1099
  var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M4 4l8 8M12 4l-8 8" }) });
1027
- function Modal({ open, onClose, title, children, footer, className, style, closeLabel = "Close dialog", role = "dialog" }) {
1028
- const ref = useDialog(open);
1100
+ function Modal({ open, onClose, title, children, footer, className, closeLabel = "Close dialog", role = "dialog", ...rest }) {
1101
+ const ref = useDialog(open, onClose);
1029
1102
  const titleId = (0, import_react14.useId)();
1030
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("dialog", { ref, className: cx("uix-dialog", className), style, onClose, role, "aria-labelledby": title != null ? titleId : void 0, children: [
1103
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("dialog", { ref, className: cx("uix-dialog", className), role, "aria-labelledby": title != null ? titleId : void 0, ...rest, children: [
1031
1104
  (title != null || onClose) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "uix-dialog__header", children: [
1032
- title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { id: titleId, className: "uix-dialog__title", children: title }),
1105
+ title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: "uix-dialog__title", id: titleId, children: title }),
1033
1106
  onClose && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "uix-dialog__close", onClick: onClose, "aria-label": closeLabel, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CloseIcon, {}) })
1034
1107
  ] }),
1035
1108
  children != null && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "uix-dialog__body", children }),
@@ -1087,13 +1160,15 @@ function PromptDialog({ open, title, description, inputLabel, defaultValue = "",
1087
1160
  }
1088
1161
 
1089
1162
  // src/components/Drawer.tsx
1163
+ var import_react16 = require("react");
1090
1164
  var import_jsx_runtime12 = require("react/jsx-runtime");
1091
1165
  var CloseIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M4 4l8 8M12 4l-8 8" }) });
1092
- function Drawer({ open, onClose, title, children, footer, className }) {
1093
- const ref = useDialog(open);
1094
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("dialog", { ref, className: cx("uix-drawer", className), onClose, children: [
1166
+ function Drawer({ open, onClose, title, children, footer, className, ...rest }) {
1167
+ const ref = useDialog(open, onClose);
1168
+ const titleId = (0, import_react16.useId)();
1169
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("dialog", { ref, className: cx("uix-drawer", className), "aria-labelledby": title ? titleId : void 0, ...rest, children: [
1095
1170
  (title != null || onClose) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "uix-drawer__header", children: [
1096
- title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { fontWeight: 600, fontSize: "var(--uix-text-h3)" }, children: title }),
1171
+ title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { id: titleId, style: { fontWeight: 600, fontSize: "var(--uix-text-h3)", fontFamily: "inherit", letterSpacing: "inherit", lineHeight: "inherit" }, children: title }),
1097
1172
  onClose && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1098
1173
  "button",
1099
1174
  {
@@ -1110,27 +1185,30 @@ function Drawer({ open, onClose, title, children, footer, className }) {
1110
1185
  }
1111
1186
 
1112
1187
  // src/components/Peek.tsx
1188
+ var import_react17 = require("react");
1113
1189
  var import_jsx_runtime13 = require("react/jsx-runtime");
1114
1190
  var CloseIcon3 = () => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M4 4l8 8M12 4l-8 8" }) });
1115
1191
  var ChevronUp = () => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M2 8l4-4 4 4" }) });
1116
1192
  var ChevronDown = () => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M2 4l4 4 4-4" }) });
1117
- function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className }) {
1118
- const ref = useDialog(open);
1193
+ function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className, onClick, ...rest }) {
1194
+ const ref = useDialog(open, onClose);
1119
1195
  const hasNav = onNavPrev != null || onNavNext != null;
1196
+ const titleId = (0, import_react17.useId)();
1120
1197
  const onBackdropClick = (e) => {
1198
+ onClick?.(e);
1121
1199
  if (!onClose || e.target !== e.currentTarget) return;
1122
1200
  const r = e.currentTarget.getBoundingClientRect();
1123
1201
  if (r.width === 0) return;
1124
1202
  const outside = e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom;
1125
1203
  if (outside) onClose();
1126
1204
  };
1127
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("dialog", { ref, className: cx("uix-peek", className), onClose, onClick: onBackdropClick, children: [
1205
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("dialog", { ref, className: cx("uix-peek", className), "aria-labelledby": title ? titleId : void 0, ...rest, onClick: onBackdropClick, children: [
1128
1206
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "uix-peek__header", children: [
1129
1207
  hasNav && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "uix-peek__nav", children: [
1130
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "uix-peek__navbtn", onClick: onNavPrev, disabled: !onNavPrev, "aria-label": "Previous record", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronUp, {}) }),
1131
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "uix-peek__navbtn", onClick: onNavNext, disabled: !onNavNext, "aria-label": "Next record", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronDown, {}) })
1208
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "uix-peek__navbtn", onClick: () => onNavPrev?.(), "aria-disabled": onNavPrev ? void 0 : true, "aria-label": "Previous record", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronUp, {}) }),
1209
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "uix-peek__navbtn", onClick: () => onNavNext?.(), "aria-disabled": onNavNext ? void 0 : true, "aria-label": "Next record", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronDown, {}) })
1132
1210
  ] }),
1133
- title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "uix-peek__title", children: title }),
1211
+ title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "uix-peek__title", id: titleId, children: title }),
1134
1212
  hint && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "uix-peek__hint", children: hint }),
1135
1213
  onClose && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "uix-peek__close", onClick: onClose, "aria-label": "Close preview", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CloseIcon3, {}) })
1136
1214
  ] }),
@@ -1141,12 +1219,12 @@ function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hi
1141
1219
 
1142
1220
  // src/components/Card.tsx
1143
1221
  var import_jsx_runtime14 = require("react/jsx-runtime");
1144
- function Card({ title, subtitle, headerAction, footer, children, className, ...props }) {
1222
+ function Card({ title, titleAs: TitleTag = "div", subtitle, headerAction, footer, children, className, ...props }) {
1145
1223
  const hasHeader = title != null || subtitle != null || headerAction != null;
1146
1224
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: cx("uix-card", className), ...props, children: [
1147
1225
  hasHeader && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "uix-card__header", children: [
1148
1226
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { flex: 1 }, children: [
1149
- title && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "uix-card__title", children: title }),
1227
+ title && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TitleTag, { className: "uix-card__title", children: title }),
1150
1228
  subtitle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "uix-card__subtitle", children: subtitle })
1151
1229
  ] }),
1152
1230
  headerAction
@@ -1171,12 +1249,12 @@ function CardLink({ title, subtitle, headerAction, footer, children, className,
1171
1249
  }
1172
1250
 
1173
1251
  // src/components/Breadcrumbs.tsx
1174
- var import_react16 = require("react");
1252
+ var import_react18 = require("react");
1175
1253
  var import_jsx_runtime15 = require("react/jsx-runtime");
1176
1254
  function Breadcrumbs({ items, label, separator = "/", className, ...props }) {
1177
1255
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("nav", { "aria-label": label, className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("ol", { className: "uix-breadcrumbs", children: items.map((item, index) => {
1178
1256
  const current = item.current ?? index === items.length - 1;
1179
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react16.Fragment, { children: [
1257
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react18.Fragment, { children: [
1180
1258
  index > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("li", { className: "uix-breadcrumbs__sep", "aria-hidden": "true", children: separator }),
1181
1259
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("li", { children: item.href && !current ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("a", { href: item.href, children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "aria-current": current ? "page" : void 0, children: item.label }) })
1182
1260
  ] }, item.id ?? `${item.href ?? "current"}-${index}`);
@@ -1185,11 +1263,11 @@ function Breadcrumbs({ items, label, separator = "/", className, ...props }) {
1185
1263
 
1186
1264
  // src/components/PageHeader.tsx
1187
1265
  var import_jsx_runtime16 = require("react/jsx-runtime");
1188
- function PageHeader({ eyebrow, title, subtitle, actions, className, ...props }) {
1266
+ function PageHeader({ eyebrow, title, subtitle, actions, as: TitleTag = "h1", className, ...props }) {
1189
1267
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("header", { className: cx("uix-page-header", className), ...props, children: [
1190
1268
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "uix-page-header__titles", children: [
1191
1269
  eyebrow != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "uix-page-header__eyebrow", children: eyebrow }),
1192
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h1", { className: "uix-page-header__title", children: title }),
1270
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TitleTag, { className: "uix-page-header__title", children: title }),
1193
1271
  subtitle != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "uix-page-header__subtitle", children: subtitle })
1194
1272
  ] }),
1195
1273
  actions != null && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "uix-page-header__actions", children: actions })
@@ -1201,7 +1279,7 @@ var import_jsx_runtime17 = require("react/jsx-runtime");
1201
1279
  function DetailLayout({ side, children, className, ...props }) {
1202
1280
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: cx("uix-detail", className), ...props, children: [
1203
1281
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "uix-detail__main", children }),
1204
- side != null && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "uix-detail__side", children: side })
1282
+ side != null && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("aside", { className: "uix-detail__side", children: side })
1205
1283
  ] });
1206
1284
  }
1207
1285
 
@@ -1278,11 +1356,11 @@ function ListItem({ title, meta, trail, leading, children, className, ...props }
1278
1356
  }
1279
1357
 
1280
1358
  // src/components/DescriptionList.tsx
1281
- var import_react17 = require("react");
1359
+ var import_react19 = require("react");
1282
1360
  var import_jsx_runtime23 = require("react/jsx-runtime");
1283
1361
  function DescriptionList({ items, children, className, ...props }) {
1284
1362
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("dl", { className: cx("uix-dl", className), ...props, children: [
1285
- items?.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react17.Fragment, { children: [
1363
+ items?.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react19.Fragment, { children: [
1286
1364
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("dt", { children: item.term }),
1287
1365
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("dd", { children: item.description })
1288
1366
  ] }, item.id ?? i)),
@@ -1297,22 +1375,81 @@ function DescriptionItem({ term, children }) {
1297
1375
  }
1298
1376
 
1299
1377
  // src/components/Tabs.tsx
1300
- var import_react18 = require("react");
1378
+ var import_react20 = require("react");
1301
1379
  var import_jsx_runtime24 = require("react/jsx-runtime");
1302
- var TabsCtx = (0, import_react18.createContext)({});
1380
+ var TabsCtx = (0, import_react20.createContext)({});
1303
1381
  function Tabs({ variant = "line", value, onChange, children, className }) {
1304
- const contextValue = (0, import_react18.useMemo)(() => ({ value, onChange }), [value, onChange]);
1305
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TabsCtx.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "tablist", className: cx("uix-tabs", `uix-tabs--${variant}`, className), children }) });
1382
+ const baseId = (0, import_react20.useId)();
1383
+ const listRef = (0, import_react20.useRef)(null);
1384
+ const contextValue = (0, import_react20.useMemo)(() => ({ value, onChange, baseId }), [value, onChange, baseId]);
1385
+ const kids = import_react20.Children.toArray(children);
1386
+ const panels = kids.filter((k) => (0, import_react20.isValidElement)(k) && k.type === TabPanel);
1387
+ const tabs = kids.filter((k) => !((0, import_react20.isValidElement)(k) && k.type === TabPanel));
1388
+ (0, import_react20.useEffect)(() => {
1389
+ const list = listRef.current;
1390
+ if (!list) return;
1391
+ const all = Array.from(list.querySelectorAll('[role="tab"]'));
1392
+ const enabled = all.filter((t) => !t.matches(":disabled"));
1393
+ const active = enabled.find((t) => t.getAttribute("aria-selected") === "true") ?? enabled[0];
1394
+ for (const t of all) t.tabIndex = t === active ? 0 : -1;
1395
+ });
1396
+ const onKeyDown = (e) => {
1397
+ const items = Array.from(
1398
+ listRef.current?.querySelectorAll('[role="tab"]:not(:disabled)') ?? []
1399
+ );
1400
+ const cur = e.target.closest('[role="tab"]');
1401
+ const idx = cur ? items.indexOf(cur) : -1;
1402
+ if (idx < 0 || items.length === 0) return;
1403
+ let next;
1404
+ switch (e.key) {
1405
+ case "ArrowRight":
1406
+ next = (idx + 1) % items.length;
1407
+ break;
1408
+ case "ArrowLeft":
1409
+ next = (idx - 1 + items.length) % items.length;
1410
+ break;
1411
+ case "Home":
1412
+ next = 0;
1413
+ break;
1414
+ case "End":
1415
+ next = items.length - 1;
1416
+ break;
1417
+ default:
1418
+ return;
1419
+ }
1420
+ e.preventDefault();
1421
+ const target = items[next];
1422
+ if (target) {
1423
+ target.focus();
1424
+ target.click();
1425
+ }
1426
+ };
1427
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(TabsCtx.Provider, { value: contextValue, children: [
1428
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1429
+ "div",
1430
+ {
1431
+ ref: listRef,
1432
+ role: "tablist",
1433
+ className: cx("uix-tabs", `uix-tabs--${variant}`, className),
1434
+ onKeyDown,
1435
+ children: tabs
1436
+ }
1437
+ ),
1438
+ panels
1439
+ ] });
1306
1440
  }
1307
1441
  function Tab({ value, children, disabled, className, onClick, ...props }) {
1308
- const ctx = (0, import_react18.useContext)(TabsCtx);
1442
+ const ctx = (0, import_react20.useContext)(TabsCtx);
1309
1443
  const selected = ctx.value === value;
1310
1444
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1311
1445
  "button",
1312
1446
  {
1313
1447
  role: "tab",
1448
+ id: ctx.baseId ? `${ctx.baseId}-tab-${value}` : void 0,
1449
+ "aria-controls": ctx.baseId ? `${ctx.baseId}-panel-${value}` : void 0,
1314
1450
  className: cx("uix-tab", className),
1315
1451
  "aria-selected": selected,
1452
+ tabIndex: selected ? 0 : -1,
1316
1453
  disabled,
1317
1454
  onClick: (e) => {
1318
1455
  ctx.onChange?.(value);
@@ -1323,9 +1460,24 @@ function Tab({ value, children, disabled, className, onClick, ...props }) {
1323
1460
  }
1324
1461
  );
1325
1462
  }
1463
+ function TabPanel({ value, children, ...props }) {
1464
+ const ctx = (0, import_react20.useContext)(TabsCtx);
1465
+ if (ctx.value !== value) return null;
1466
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1467
+ "div",
1468
+ {
1469
+ role: "tabpanel",
1470
+ id: ctx.baseId ? `${ctx.baseId}-panel-${value}` : void 0,
1471
+ "aria-labelledby": ctx.baseId ? `${ctx.baseId}-tab-${value}` : void 0,
1472
+ tabIndex: 0,
1473
+ ...props,
1474
+ children
1475
+ }
1476
+ );
1477
+ }
1326
1478
 
1327
1479
  // src/components/AppShell.tsx
1328
- var import_react19 = require("react");
1480
+ var import_react21 = require("react");
1329
1481
  var import_jsx_runtime25 = require("react/jsx-runtime");
1330
1482
  function AppShell({
1331
1483
  nav,
@@ -1333,6 +1485,7 @@ function AppShell({
1333
1485
  focus,
1334
1486
  onExitFocus,
1335
1487
  mainBleed,
1488
+ mainId = "uix-main",
1336
1489
  sidebar,
1337
1490
  topbar,
1338
1491
  children,
@@ -1340,7 +1493,7 @@ function AppShell({
1340
1493
  ...props
1341
1494
  }) {
1342
1495
  const navState = nav ?? (collapsed ? "rail" : "full");
1343
- (0, import_react19.useEffect)(() => {
1496
+ (0, import_react21.useEffect)(() => {
1344
1497
  if (!focus || !onExitFocus) return;
1345
1498
  const onKey = (e) => {
1346
1499
  if (e.key === "Escape") onExitFocus();
@@ -1357,9 +1510,10 @@ function AppShell({
1357
1510
  "data-focus": focus || void 0,
1358
1511
  ...props,
1359
1512
  children: [
1513
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { className: "uix-skiplink", href: `#${mainId}`, children: "Skip to content" }),
1360
1514
  sidebar && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "uix-shell__sidebar", children: sidebar }),
1361
1515
  topbar && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "uix-shell__topbar", children: topbar }),
1362
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("main", { className: cx("uix-shell__main", mainBleed && "uix-shell__main--bleed"), children }),
1516
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("main", { id: mainId, tabIndex: -1, className: cx("uix-shell__main", mainBleed && "uix-shell__main--bleed"), children }),
1363
1517
  focus && onExitFocus && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "uix-shell__focus-exit", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", onClick: onExitFocus, children: "Esc \xB7 Exit focus" }) })
1364
1518
  ]
1365
1519
  }
@@ -1367,7 +1521,7 @@ function AppShell({
1367
1521
  }
1368
1522
 
1369
1523
  // src/components/Sidebar.tsx
1370
- var import_react20 = require("react");
1524
+ var import_react22 = require("react");
1371
1525
  var import_jsx_runtime26 = require("react/jsx-runtime");
1372
1526
  var ChevronIcon = () => /* @__PURE__ */ (0, import_jsx_runtime26.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__ */ (0, import_jsx_runtime26.jsx)("path", { d: "M2 4l4 4 4-4" }) });
1373
1527
  function Sidebar({ collapsed, nav, onToggle, brand, toggleIcon, children, expandLabel = "Expand sidebar", collapseLabel = "Collapse sidebar", className, ...props }) {
@@ -1423,12 +1577,12 @@ function NavItem({ icon, badge, active, as: Tag = "a", children, className, ...p
1423
1577
  );
1424
1578
  }
1425
1579
  function NavGroup({ icon, label, children, defaultExpanded = true, expanded: controlledExpanded, onExpandedChange }) {
1426
- const [internalExpanded, setInternalExpanded] = (0, import_react20.useState)(defaultExpanded);
1580
+ const [internalExpanded, setInternalExpanded] = (0, import_react22.useState)(defaultExpanded);
1427
1581
  const expanded = controlledExpanded ?? internalExpanded;
1428
- const panelId = (0, import_react20.useId)();
1429
- const triggerRef = (0, import_react20.useRef)(null);
1430
- const panelRef = (0, import_react20.useRef)(null);
1431
- (0, import_react20.useEffect)(() => {
1582
+ const panelId = (0, import_react22.useId)();
1583
+ const triggerRef = (0, import_react22.useRef)(null);
1584
+ const panelRef = (0, import_react22.useRef)(null);
1585
+ (0, import_react22.useEffect)(() => {
1432
1586
  panelRef.current?.toggleAttribute("inert", !expanded);
1433
1587
  if (!expanded && panelRef.current?.contains(document.activeElement)) triggerRef.current?.focus();
1434
1588
  }, [expanded]);
@@ -1507,7 +1661,7 @@ function StarButton({
1507
1661
  }
1508
1662
 
1509
1663
  // src/components/NavFavourites.tsx
1510
- var import_react21 = require("react");
1664
+ var import_react23 = require("react");
1511
1665
  var import_jsx_runtime28 = require("react/jsx-runtime");
1512
1666
  var ChevronDownIcon = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1513
1667
  "svg",
@@ -1570,13 +1724,14 @@ function NavFavourites({
1570
1724
  emptyReason,
1571
1725
  className
1572
1726
  }) {
1573
- const regionId = (0, import_react21.useId)();
1574
- const headerRef = (0, import_react21.useRef)(null);
1575
- const regionRef = (0, import_react21.useRef)(null);
1576
- const focusAfterRef = (0, import_react21.useRef)(null);
1577
- const triggerRefs = (0, import_react21.useRef)(/* @__PURE__ */ new Map());
1578
- const order = (0, import_react21.useMemo)(() => items.map((item) => item.id), [items]);
1579
- (0, import_react21.useEffect)(() => {
1727
+ const regionId = (0, import_react23.useId)();
1728
+ const headerRef = (0, import_react23.useRef)(null);
1729
+ const regionRef = (0, import_react23.useRef)(null);
1730
+ const [announcement, setAnnouncement] = (0, import_react23.useState)("");
1731
+ const focusAfterRef = (0, import_react23.useRef)(null);
1732
+ const triggerRefs = (0, import_react23.useRef)(/* @__PURE__ */ new Map());
1733
+ const order = (0, import_react23.useMemo)(() => items.map((item) => item.id), [items]);
1734
+ (0, import_react23.useEffect)(() => {
1580
1735
  const id = focusAfterRef.current;
1581
1736
  if (!id) return;
1582
1737
  focusAfterRef.current = null;
@@ -1593,7 +1748,7 @@ function NavFavourites({
1593
1748
  }
1594
1749
  onToggleCollapsed?.();
1595
1750
  };
1596
- const move = (0, import_react21.useCallback)((id, dir) => {
1751
+ const move = (0, import_react23.useCallback)((id, dir) => {
1597
1752
  const idx = order.indexOf(id);
1598
1753
  const next = idx + dir;
1599
1754
  if (idx < 0 || next < 0 || next >= order.length) return;
@@ -1602,19 +1757,22 @@ function NavFavourites({
1602
1757
  if (it === void 0) return;
1603
1758
  reordered.splice(next, 0, it);
1604
1759
  focusAfterRef.current = id;
1760
+ const moved = items.find((i) => i.id === id);
1761
+ if (moved) setAnnouncement(`${moved.label} moved to position ${next + 1} of ${order.length}`);
1605
1762
  onReorder(reordered);
1606
1763
  }, [onReorder, order]);
1607
- const remove = (0, import_react21.useCallback)((id) => {
1764
+ const remove = (0, import_react23.useCallback)((id) => {
1608
1765
  const idx = order.indexOf(id);
1609
1766
  const neighbour = order[idx + 1] ?? order[idx - 1] ?? null;
1610
1767
  focusAfterRef.current = neighbour;
1611
1768
  onRemove(id);
1612
1769
  }, [onRemove, order]);
1613
- const registerTrigger = (0, import_react21.useCallback)((id, element) => {
1770
+ const registerTrigger = (0, import_react23.useCallback)((id, element) => {
1614
1771
  if (element) triggerRefs.current.set(id, element);
1615
1772
  else triggerRefs.current.delete(id);
1616
1773
  }, []);
1617
1774
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cx("uix-favourites", className), children: [
1775
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
1618
1776
  /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1619
1777
  "button",
1620
1778
  {
@@ -1661,7 +1819,7 @@ function NavFavourites({
1661
1819
  )
1662
1820
  ] });
1663
1821
  }
1664
- var FavouriteRow = (0, import_react21.memo)(function FavouriteRow2({
1822
+ var FavouriteRow = (0, import_react23.memo)(function FavouriteRow2({
1665
1823
  item,
1666
1824
  isFirst,
1667
1825
  isLast,
@@ -1670,17 +1828,17 @@ var FavouriteRow = (0, import_react21.memo)(function FavouriteRow2({
1670
1828
  onRemove,
1671
1829
  registerTrigger
1672
1830
  }) {
1673
- const [open, setOpen] = (0, import_react21.useState)(false);
1674
- const menuId = (0, import_react21.useId)();
1675
- const triggerRef = (0, import_react21.useRef)(null);
1676
- const itemRefs = (0, import_react21.useRef)([]);
1831
+ const [open, setOpen] = (0, import_react23.useState)(false);
1832
+ const menuId = (0, import_react23.useId)();
1833
+ const triggerRef = (0, import_react23.useRef)(null);
1834
+ const itemRefs = (0, import_react23.useRef)([]);
1677
1835
  const optionsTemplate = labels.options ?? "{label} favourite options";
1678
1836
  const actions = [
1679
1837
  ...isFirst ? [] : [{ label: labels.moveUp, onSelect: () => onMove(item.id, -1) }],
1680
1838
  ...isLast ? [] : [{ label: labels.moveDown, onSelect: () => onMove(item.id, 1) }],
1681
1839
  { label: labels.remove.replace("{label}", item.label), onSelect: () => onRemove(item.id) }
1682
1840
  ];
1683
- (0, import_react21.useEffect)(() => {
1841
+ (0, import_react23.useEffect)(() => {
1684
1842
  if (open) itemRefs.current[0]?.focus();
1685
1843
  }, [open]);
1686
1844
  const closeAndReturnFocus = () => {
@@ -1696,6 +1854,12 @@ var FavouriteRow = (0, import_react21.memo)(function FavouriteRow2({
1696
1854
  } else if (e.key === "ArrowUp") {
1697
1855
  e.preventDefault();
1698
1856
  menuItems[(currentIdx - 1 + menuItems.length) % menuItems.length]?.focus();
1857
+ } else if (e.key === "Home") {
1858
+ e.preventDefault();
1859
+ menuItems[0]?.focus();
1860
+ } else if (e.key === "End") {
1861
+ e.preventDefault();
1862
+ menuItems[menuItems.length - 1]?.focus();
1699
1863
  } else if (e.key === "Escape") {
1700
1864
  e.preventDefault();
1701
1865
  closeAndReturnFocus();
@@ -1754,6 +1918,7 @@ var FavouriteRow = (0, import_react21.memo)(function FavouriteRow2({
1754
1918
  {
1755
1919
  id: menuId,
1756
1920
  role: "menu",
1921
+ "aria-label": optionsTemplate.replace("{label}", item.label),
1757
1922
  onKeyDown: onMenuKeyDown,
1758
1923
  className: "uix-favourites__menu",
1759
1924
  children: actions.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { role: "presentation", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
@@ -1785,61 +1950,108 @@ var FavouriteRow = (0, import_react21.memo)(function FavouriteRow2({
1785
1950
  // src/components/Alert.tsx
1786
1951
  var import_jsx_runtime29 = require("react/jsx-runtime");
1787
1952
  function Alert({ tone, title, icon, children, className, ...props }) {
1788
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: cx("uix-alert", tone && tone !== "neutral" && `uix-alert--${tone}`, className), ...props, children: [
1789
- icon && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__icon", children: icon }),
1790
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
1791
- title && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__title", children: title }),
1792
- children && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__body", children })
1793
- ] })
1794
- ] });
1953
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1954
+ "div",
1955
+ {
1956
+ className: cx("uix-alert", tone && tone !== "neutral" && `uix-alert--${tone}`, className),
1957
+ role: tone === "danger" || tone === "warning" ? "alert" : "status",
1958
+ ...props,
1959
+ children: [
1960
+ icon && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__icon", children: icon }),
1961
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
1962
+ title && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__title", children: title }),
1963
+ children && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__body", children })
1964
+ ] })
1965
+ ]
1966
+ }
1967
+ );
1795
1968
  }
1796
1969
 
1797
1970
  // src/components/Spinner.tsx
1798
1971
  var import_jsx_runtime30 = require("react/jsx-runtime");
1799
- function Spinner({ size = "md", accent, className, ...props }) {
1972
+ function Spinner({ size = "md", accent, label, className, ...props }) {
1800
1973
  return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1801
1974
  "span",
1802
1975
  {
1803
1976
  className: cx("uix-spinner", accent && "uix-spinner--accent", size === "lg" && "uix-spinner--lg", className),
1804
1977
  role: "status",
1805
- "aria-label": "Loading",
1806
- ...props
1978
+ ...props,
1979
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "uix-visually-hidden", children: label ?? "Loading\u2026" })
1807
1980
  }
1808
1981
  );
1809
1982
  }
1810
1983
 
1811
1984
  // src/components/Toast.tsx
1985
+ var import_react24 = require("react");
1812
1986
  var import_jsx_runtime31 = require("react/jsx-runtime");
1987
+ var ToasterContext = (0, import_react24.createContext)(null);
1813
1988
  function Toast({ title, message, tone, icon, onClose, leaving, className, ...props }) {
1814
1989
  const assertive = tone === "danger";
1990
+ const toaster = (0, import_react24.useContext)(ToasterContext);
1991
+ const bodyRef = (0, import_react24.useRef)(null);
1992
+ (0, import_react24.useEffect)(() => {
1993
+ if (assertive || !toaster) return;
1994
+ const text = bodyRef.current?.textContent?.trim();
1995
+ if (text) toaster.announce(text);
1996
+ }, []);
1997
+ const handleClose = (e) => {
1998
+ const btn = e.currentTarget;
1999
+ if (document.activeElement === btn) {
2000
+ const toasterEl = btn.closest(".uix-toaster");
2001
+ if (toasterEl) {
2002
+ const closes = Array.from(toasterEl.querySelectorAll(".uix-toast__close"));
2003
+ const i = closes.indexOf(btn);
2004
+ (closes[i + 1] ?? closes[i - 1])?.focus();
2005
+ }
2006
+ }
2007
+ onClose?.();
2008
+ };
2009
+ const ownLiveRegion = assertive || !toaster;
1815
2010
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1816
2011
  "div",
1817
2012
  {
1818
2013
  className: cx("uix-toast", tone && `uix-toast--${tone}`, className),
1819
2014
  "data-leaving": leaving || void 0,
1820
- role: assertive ? "alert" : "status",
1821
- "aria-live": assertive ? "assertive" : "polite",
2015
+ role: ownLiveRegion ? assertive ? "alert" : "status" : void 0,
2016
+ "aria-live": ownLiveRegion ? assertive ? "assertive" : "polite" : void 0,
1822
2017
  ...props,
1823
2018
  children: [
1824
2019
  icon && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "uix-toast__icon", "aria-hidden": "true", children: icon }),
1825
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "uix-toast__body", children: [
2020
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "uix-toast__body", ref: bodyRef, children: [
1826
2021
  title && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "uix-toast__title", children: title }),
1827
2022
  message && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "uix-toast__msg", children: message })
1828
2023
  ] }),
1829
- onClose && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { className: "uix-toast__close", onClick: onClose, "aria-label": "Dismiss", children: "\xD7" })
2024
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { className: "uix-toast__close", onClick: handleClose, "aria-label": "Dismiss", children: "\xD7" })
1830
2025
  ]
1831
2026
  }
1832
2027
  );
1833
2028
  }
1834
2029
  function Toaster({ children, className, ...props }) {
1835
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: cx("uix-toaster", className), ...props, children });
2030
+ const [announced, setAnnounced] = (0, import_react24.useState)("");
2031
+ const clearTimer = (0, import_react24.useRef)(null);
2032
+ const announce = (0, import_react24.useCallback)((text) => {
2033
+ setAnnounced((cur) => cur ? `${cur} ${text}` : text);
2034
+ if (clearTimer.current != null) clearTimeout(clearTimer.current);
2035
+ clearTimer.current = window.setTimeout(() => setAnnounced(""), 3e3);
2036
+ }, []);
2037
+ (0, import_react24.useEffect)(() => () => {
2038
+ if (clearTimer.current != null) clearTimeout(clearTimer.current);
2039
+ }, []);
2040
+ const ctx = (0, import_react24.useMemo)(() => ({ announce }), [announce]);
2041
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ToasterContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: cx("uix-toaster", className), role: "region", "aria-label": "Notifications", ...props, children: [
2042
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "uix-visually-hidden", role: "status", "aria-live": "polite", children: announced }),
2043
+ children
2044
+ ] }) });
1836
2045
  }
1837
2046
 
1838
2047
  // src/components/Table.tsx
1839
- var import_react22 = require("react");
2048
+ var import_react25 = require("react");
1840
2049
  var import_jsx_runtime32 = require("react/jsx-runtime");
1841
- var TableWrap = (0, import_react22.forwardRef)(function TableWrap2({ children, className, ...props }, ref) {
1842
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { ref, className: cx("uix-table-wrap", className), ...props, children });
2050
+ var TableWrap = (0, import_react25.forwardRef)(function TableWrap2({ announcement, children, className, ...props }, ref) {
2051
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { ref, className: cx("uix-table-wrap", className), ...props, children: [
2052
+ announcement != null && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
2053
+ children
2054
+ ] });
1843
2055
  });
1844
2056
  function Table({
1845
2057
  density = "standard",
@@ -1878,9 +2090,9 @@ function Th({ sortable, sortDirection, sortOrder, onSort, className, children, o
1878
2090
  "data-sort": sortable || void 0,
1879
2091
  "data-sort-order": sortOrder != null && sortOrder > 0 ? sortOrder : void 0,
1880
2092
  "aria-sort": sortDirection && sortDirection !== "none" ? sortDirection : void 0,
1881
- onClick: sortable ? onSort ?? onClick : onClick,
2093
+ onClick: sortable && onSort ? void 0 : onClick,
1882
2094
  ...props,
1883
- children
2095
+ children: sortable ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { type: "button", className: "uix-th__sortbtn", onClick: onSort, children }) : children
1884
2096
  }
1885
2097
  );
1886
2098
  }
@@ -1892,7 +2104,7 @@ function Tr({ selected, pinned, className, children, ...props }) {
1892
2104
  "tr",
1893
2105
  {
1894
2106
  className,
1895
- "aria-selected": selected || void 0,
2107
+ "data-selected": selected || void 0,
1896
2108
  "data-pinned": pinned || void 0,
1897
2109
  ...props,
1898
2110
  children
@@ -1915,13 +2127,14 @@ function RowActions({ children, className, ...props }) {
1915
2127
  function RowAction({ children, className, type = "button", ...props }) {
1916
2128
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { type, className: cx("uix-rowact", className), ...props, children });
1917
2129
  }
1918
- function ExpandToggle({ expanded, className, type = "button", ...props }) {
2130
+ function ExpandToggle({ expanded, controls, className, type = "button", ...props }) {
1919
2131
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1920
2132
  "button",
1921
2133
  {
1922
2134
  type,
1923
2135
  className: cx("uix-table__expand", className),
1924
2136
  "aria-expanded": expanded,
2137
+ "aria-controls": controls,
1925
2138
  "aria-label": expanded ? "Collapse row" : "Expand row",
1926
2139
  ...props,
1927
2140
  children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("path", { d: "M6 4l4 4-4 4" }) })
@@ -2012,15 +2225,17 @@ function StatusPill({ tone = "neutral", treatment = "filled", dot, children, cla
2012
2225
 
2013
2226
  // src/components/Progress.tsx
2014
2227
  var import_jsx_runtime35 = require("react/jsx-runtime");
2015
- function Progress({ value = 0, max = 100, indeterminate, className, ...props }) {
2016
- const pct = Math.max(0, Math.min(100, value / (max || 100) * 100));
2228
+ function Progress({ value = 0, max = 100, indeterminate, label, className, ...props }) {
2229
+ const clamped = Math.max(0, Math.min(max || 100, value));
2230
+ const pct = clamped / (max || 100) * 100;
2017
2231
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
2018
2232
  "div",
2019
2233
  {
2020
2234
  role: "progressbar",
2021
2235
  "aria-valuemin": 0,
2022
2236
  "aria-valuemax": max,
2023
- "aria-valuenow": indeterminate ? void 0 : value,
2237
+ "aria-valuenow": indeterminate ? void 0 : clamped,
2238
+ "aria-label": label,
2024
2239
  className: cx("uix-progress", indeterminate && "uix-progress--indeterminate", className),
2025
2240
  ...props,
2026
2241
  children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "uix-progress__bar", style: indeterminate ? void 0 : { width: `${pct}%` } })
@@ -2030,7 +2245,13 @@ function Progress({ value = 0, max = 100, indeterminate, className, ...props })
2030
2245
 
2031
2246
  // src/components/Meter.tsx
2032
2247
  var import_jsx_runtime36 = require("react/jsx-runtime");
2033
- function Meter({ value = 0, tone, className, ...props }) {
2248
+ var toneText = {
2249
+ warning: "warning",
2250
+ danger: "critical",
2251
+ attention: "needs attention",
2252
+ overdue: "overdue"
2253
+ };
2254
+ function Meter({ value = 0, tone, label, className, ...props }) {
2034
2255
  const pct = Math.max(0, Math.min(100, value));
2035
2256
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2036
2257
  "div",
@@ -2039,6 +2260,8 @@ function Meter({ value = 0, tone, className, ...props }) {
2039
2260
  "aria-valuenow": pct,
2040
2261
  "aria-valuemin": 0,
2041
2262
  "aria-valuemax": 100,
2263
+ "aria-valuetext": tone && tone !== "success" ? `${pct}%, ${toneText[tone]}` : void 0,
2264
+ "aria-label": label,
2042
2265
  className: cx("uix-meter", className),
2043
2266
  ...props,
2044
2267
  children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
@@ -2063,22 +2286,34 @@ function Stat({ label, value, icon, meta, trend, className, ...props }) {
2063
2286
  ] }),
2064
2287
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "uix-stat__value", children: value }),
2065
2288
  (meta != null || trend != null) && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "uix-stat__meta", children: [
2066
- trend != null && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`), children: trend.label }),
2289
+ trend != null && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`), children: [
2290
+ /* @__PURE__ */ (0, import_jsx_runtime37.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__ */ (0, import_jsx_runtime37.jsx)("path", { d: "M12 19V5m-6 6 6-6 6 6" }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("path", { d: "M12 5v14m6-6-6 6-6-6" }) }),
2291
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "uix-visually-hidden", children: trend.direction === "up" ? "up" : "down" }),
2292
+ trend.label
2293
+ ] }),
2067
2294
  meta
2068
2295
  ] })
2069
2296
  ] });
2070
2297
  }
2071
2298
 
2072
2299
  // src/components/Tooltip.tsx
2073
- var import_react23 = require("react");
2300
+ var import_react26 = require("react");
2074
2301
  var import_jsx_runtime38 = require("react/jsx-runtime");
2075
2302
  function Tooltip({ label, placement = "top", className, children, ...props }) {
2076
- const triggerRef = (0, import_react23.useRef)(null);
2077
- const bubbleRef = (0, import_react23.useRef)(null);
2078
- const [open, setOpen] = (0, import_react23.useState)(false);
2079
- const id = (0, import_react23.useId)();
2303
+ const triggerRef = (0, import_react26.useRef)(null);
2304
+ const bubbleRef = (0, import_react26.useRef)(null);
2305
+ const closeTimer = (0, import_react26.useRef)(null);
2306
+ const [open, setOpen] = (0, import_react26.useState)(false);
2307
+ const id = (0, import_react26.useId)();
2080
2308
  useAnchoredPosition(triggerRef, bubbleRef, { open, placement, offset: 6 });
2309
+ const cancelClose = () => {
2310
+ if (closeTimer.current != null) {
2311
+ clearTimeout(closeTimer.current);
2312
+ closeTimer.current = null;
2313
+ }
2314
+ };
2081
2315
  const show = () => {
2316
+ cancelClose();
2082
2317
  const b = bubbleRef.current;
2083
2318
  if (b && !b.matches(":popover-open")) {
2084
2319
  try {
@@ -2089,6 +2324,7 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2089
2324
  setOpen(true);
2090
2325
  };
2091
2326
  const hide = () => {
2327
+ cancelClose();
2092
2328
  const b = bubbleRef.current;
2093
2329
  if (b && b.matches(":popover-open")) {
2094
2330
  try {
@@ -2098,7 +2334,20 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2098
2334
  }
2099
2335
  setOpen(false);
2100
2336
  };
2101
- (0, import_react23.useEffect)(() => () => {
2337
+ const scheduleHide = () => {
2338
+ cancelClose();
2339
+ closeTimer.current = window.setTimeout(hide, 100);
2340
+ };
2341
+ (0, import_react26.useEffect)(() => {
2342
+ if (!open) return;
2343
+ const onKey = (e) => {
2344
+ if (e.key === "Escape") hide();
2345
+ };
2346
+ document.addEventListener("keydown", onKey);
2347
+ return () => document.removeEventListener("keydown", onKey);
2348
+ }, [open]);
2349
+ (0, import_react26.useEffect)(() => () => {
2350
+ if (closeTimer.current != null) clearTimeout(closeTimer.current);
2102
2351
  const b = bubbleRef.current;
2103
2352
  if (b && b.matches(":popover-open")) {
2104
2353
  try {
@@ -2108,14 +2357,19 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2108
2357
  }
2109
2358
  }, []);
2110
2359
  const bubbleAttr = { popover: "manual" };
2360
+ const single = (0, import_react26.isValidElement)(children);
2361
+ const child = single ? (0, import_react26.cloneElement)(children, {
2362
+ "aria-describedby": [children.props["aria-describedby"], id].filter(Boolean).join(" ")
2363
+ }) : children;
2111
2364
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2112
2365
  "span",
2113
2366
  {
2114
2367
  ref: triggerRef,
2115
2368
  className: cx("uix-tooltip", className),
2116
- "aria-describedby": id,
2369
+ "aria-describedby": single ? void 0 : id,
2370
+ tabIndex: single ? void 0 : 0,
2117
2371
  onMouseEnter: show,
2118
- onMouseLeave: hide,
2372
+ onMouseLeave: scheduleHide,
2119
2373
  onFocus: show,
2120
2374
  onBlur: hide,
2121
2375
  onKeyDown: (e) => {
@@ -2123,8 +2377,20 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2123
2377
  },
2124
2378
  ...props,
2125
2379
  children: [
2126
- children,
2127
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { ref: bubbleRef, id, role: "tooltip", className: "uix-tooltip__bubble", ...bubbleAttr, children: label })
2380
+ child,
2381
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2382
+ "span",
2383
+ {
2384
+ ref: bubbleRef,
2385
+ id,
2386
+ role: "tooltip",
2387
+ className: "uix-tooltip__bubble",
2388
+ onMouseEnter: cancelClose,
2389
+ onMouseLeave: scheduleHide,
2390
+ ...bubbleAttr,
2391
+ children: label
2392
+ }
2393
+ )
2128
2394
  ]
2129
2395
  }
2130
2396
  );
@@ -2184,11 +2450,17 @@ function Skeleton({ variant = "block", width, height, className, style, ...props
2184
2450
  );
2185
2451
  }
2186
2452
  function LoadingState({ rows = 3, density = "comfortable", label, className, ...props }) {
2187
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: cx("uix-stack", density === "compact" && "uix-stack--compact", className), role: "status", "aria-busy": "true", "aria-label": label, ...props, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Skeleton, { variant: "text", width: `${92 - i % 3 * 14}%` }, i)) });
2453
+ return (
2454
+ // no aria-busy: busy=true tells AT the region isn't ready and suppresses the announcement (UIX-A11Y-4)
2455
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cx("uix-stack", density === "compact" && "uix-stack--compact", className), role: "status", ...props, children: [
2456
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "uix-visually-hidden", children: label ?? "Loading" }),
2457
+ Array.from({ length: rows }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Skeleton, { variant: "text", width: `${92 - i % 3 * 14}%` }, i))
2458
+ ] })
2459
+ );
2188
2460
  }
2189
2461
 
2190
2462
  // src/components/RelativeTime.tsx
2191
- var import_react24 = require("react");
2463
+ var import_react27 = require("react");
2192
2464
 
2193
2465
  // src/relative-time-model.ts
2194
2466
  function parseDateValue(value) {
@@ -2251,12 +2523,12 @@ function RelativeTime({
2251
2523
  }) {
2252
2524
  const interval = refreshInterval === false ? 0 : Math.max(0, refreshInterval);
2253
2525
  const fixedNow = now == null ? void 0 : new Date(now).getTime();
2254
- const subscribe = (0, import_react24.useCallback)((listener) => fixedNow == null ? subscribeRelativeClock(interval, listener) : () => {
2526
+ const subscribe = (0, import_react27.useCallback)((listener) => fixedNow == null ? subscribeRelativeClock(interval, listener) : () => {
2255
2527
  }, [fixedNow, interval]);
2256
- const getSnapshot = (0, import_react24.useCallback)(() => fixedNow ?? readRelativeClock(interval), [fixedNow, interval]);
2257
- const getServerSnapshot = (0, import_react24.useCallback)(() => fixedNow ?? Date.now(), [fixedNow]);
2258
- const clock = (0, import_react24.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
2259
- const date = (0, import_react24.useMemo)(() => parseDateValue(value), [value]);
2528
+ const getSnapshot = (0, import_react27.useCallback)(() => fixedNow ?? readRelativeClock(interval), [fixedNow, interval]);
2529
+ const getServerSnapshot = (0, import_react27.useCallback)(() => fixedNow ?? Date.now(), [fixedNow]);
2530
+ const clock = (0, import_react27.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
2531
+ const date = (0, import_react27.useMemo)(() => parseDateValue(value), [value]);
2260
2532
  if (!date) return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("time", { "data-invalid": "true", suppressHydrationWarning: true, ...props, children: invalidLabel });
2261
2533
  const current = new Date(clock);
2262
2534
  const content = formatter ? formatter({ date, now: current, locale, timeZone }) : (() => {
@@ -2305,7 +2577,8 @@ var import_jsx_runtime43 = require("react/jsx-runtime");
2305
2577
  function Avatar({ size = "md", src, alt, children, status, className, ...props }) {
2306
2578
  return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: cx("uix-avatar", size !== "md" && `uix-avatar--${size}`, className), ...props, children: [
2307
2579
  src ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("img", { src, alt: alt ?? "" }) : children,
2308
- status && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-avatar__status" })
2580
+ status && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-avatar__status", "aria-hidden": "true" }),
2581
+ status && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-visually-hidden", children: "online" })
2309
2582
  ] });
2310
2583
  }
2311
2584
  function AvatarGroup({ children, className, ...props }) {
@@ -2325,7 +2598,7 @@ function UserChip({ avatar, name, sub, className, children, ...props }) {
2325
2598
  // src/components/Comments.tsx
2326
2599
  var import_jsx_runtime44 = require("react/jsx-runtime");
2327
2600
  function Comments({ children, className, ...props }) {
2328
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: cx("uix-comments", className), ...props, children });
2601
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { role: "log", className: cx("uix-comments", className), ...props, children });
2329
2602
  }
2330
2603
  function Comment({ avatar, author, meta, children, className, ...props }) {
2331
2604
  return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: cx("uix-comment", className), ...props, children: [
@@ -2342,20 +2615,25 @@ function Comment({ avatar, author, meta, children, className, ...props }) {
2342
2615
  }
2343
2616
 
2344
2617
  // src/components/Composer.tsx
2618
+ var import_react28 = require("react");
2345
2619
  var import_jsx_runtime45 = require("react/jsx-runtime");
2346
- function Composer({ children, className, ...props }) {
2347
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: cx("uix-composer", className), ...props, children });
2620
+ function Composer({ children, className, label = "Add a comment", ...props }) {
2621
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: cx("uix-composer", className), ...props, children: import_react28.Children.map(children, (child) => {
2622
+ if (!(0, import_react28.isValidElement)(child) || child.type !== "textarea") return child;
2623
+ const p = child.props;
2624
+ return p["aria-label"] || p["aria-labelledby"] || p.id ? child : (0, import_react28.cloneElement)(child, { "aria-label": label });
2625
+ }) });
2348
2626
  }
2349
2627
  function ComposerBar({ children, className, ...props }) {
2350
2628
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: cx("uix-composer__bar", className), ...props, children });
2351
2629
  }
2352
2630
 
2353
2631
  // src/components/Segmented.tsx
2354
- var import_react25 = require("react");
2632
+ var import_react29 = require("react");
2355
2633
  var import_jsx_runtime46 = require("react/jsx-runtime");
2356
- var SegmentedCtx = (0, import_react25.createContext)({});
2634
+ var SegmentedCtx = (0, import_react29.createContext)({});
2357
2635
  function Segmented({ value, onChange, children, className, ...props }) {
2358
- const contextValue = (0, import_react25.useMemo)(() => ({ value, onChange }), [value, onChange]);
2636
+ const contextValue = (0, import_react29.useMemo)(() => ({ value, onChange }), [value, onChange]);
2359
2637
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SegmentedCtx.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { role: "group", className: cx("uix-segmented", className), ...props, children }) });
2360
2638
  }
2361
2639
  function SegmentedOption({
@@ -2365,7 +2643,7 @@ function SegmentedOption({
2365
2643
  onClick,
2366
2644
  ...props
2367
2645
  }) {
2368
- const ctx = (0, import_react25.useContext)(SegmentedCtx);
2646
+ const ctx = (0, import_react29.useContext)(SegmentedCtx);
2369
2647
  const selected = ctx.value === value;
2370
2648
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2371
2649
  "button",
@@ -2384,12 +2662,12 @@ function SegmentedOption({
2384
2662
  }
2385
2663
 
2386
2664
  // src/components/TableControls.tsx
2387
- var import_react26 = require("react");
2665
+ var import_react30 = require("react");
2388
2666
  var import_jsx_runtime47 = require("react/jsx-runtime");
2389
2667
  function ViewMenu({ density, densityLabel, densityOptions, onDensityChange, zebra, freeze, columns, columnsLabel, onColumnVisibilityChange }) {
2390
- const densityLabelId = (0, import_react26.useId)();
2391
- const zebraLabelId = (0, import_react26.useId)();
2392
- const freezeLabelId = (0, import_react26.useId)();
2668
+ const densityLabelId = (0, import_react30.useId)();
2669
+ const zebraLabelId = (0, import_react30.useId)();
2670
+ const freezeLabelId = (0, import_react30.useId)();
2393
2671
  return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uix-view-menu", children: [
2394
2672
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uix-view-menu__group", children: [
2395
2673
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { id: densityLabelId, className: "uix-view-menu__label", children: densityLabel }),
@@ -2438,11 +2716,11 @@ function SavedViewMenu({ items, onSelect, onPinChange, pinLabel, unpinLabel, emp
2438
2716
  // src/components/Timeline.tsx
2439
2717
  var import_jsx_runtime48 = require("react/jsx-runtime");
2440
2718
  function Timeline({ children, className, ...props }) {
2441
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: cx("uix-timeline", className), ...props, children });
2719
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("ol", { className: cx("uix-timeline", className), ...props, children });
2442
2720
  }
2443
2721
  function TimelineItem({ node, meta, children, className, ...props }) {
2444
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: cx("uix-timeline__item", className), ...props, children: [
2445
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-timeline__rail", children: [
2722
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("li", { className: cx("uix-timeline__item", className), ...props, children: [
2723
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-timeline__rail", "aria-hidden": "true", children: [
2446
2724
  node ?? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "uix-timeline__node" }),
2447
2725
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "uix-timeline__line" })
2448
2726
  ] }),
@@ -2454,10 +2732,10 @@ function TimelineItem({ node, meta, children, className, ...props }) {
2454
2732
  }
2455
2733
 
2456
2734
  // src/components/Pipeline.tsx
2457
- var import_react27 = require("react");
2735
+ var import_react31 = require("react");
2458
2736
  var import_jsx_runtime49 = require("react/jsx-runtime");
2459
2737
  function Pipeline({ detailed = false, children, className, tabIndex, ...props }) {
2460
- const stages = detailed ? import_react27.Children.map(children, (child) => (0, import_react27.isValidElement)(child) && child.type === PipelineStage ? (0, import_react27.cloneElement)(child, { detailed: child.props.detailed ?? true }) : child) : children;
2738
+ const stages = detailed ? import_react31.Children.map(children, (child) => (0, import_react31.isValidElement)(child) && child.type === PipelineStage ? (0, import_react31.cloneElement)(child, { detailed: child.props.detailed ?? true }) : child) : children;
2461
2739
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2462
2740
  "ol",
2463
2741
  {
@@ -2573,7 +2851,7 @@ function Note({ tone, icon, children, className, ...props }) {
2573
2851
  }
2574
2852
 
2575
2853
  // src/components/Popover.tsx
2576
- var import_react28 = require("react");
2854
+ var import_react32 = require("react");
2577
2855
  var import_jsx_runtime52 = require("react/jsx-runtime");
2578
2856
  function Popover({
2579
2857
  popover = "auto",
@@ -2584,15 +2862,15 @@ function Popover({
2584
2862
  children,
2585
2863
  ...props
2586
2864
  }) {
2587
- const ref = (0, import_react28.useRef)(null);
2588
- const [open, setOpen] = (0, import_react28.useState)(false);
2865
+ const ref = (0, import_react32.useRef)(null);
2866
+ const [open, setOpen] = (0, import_react32.useState)(false);
2589
2867
  const popoverAttr = { popover };
2590
2868
  const reposition = useAnchoredPosition(anchor ?? null, ref, {
2591
2869
  open: open && !!anchor,
2592
2870
  placement,
2593
2871
  offset
2594
2872
  });
2595
- (0, import_react28.useEffect)(() => {
2873
+ (0, import_react32.useEffect)(() => {
2596
2874
  const el = ref.current;
2597
2875
  if (!el || !anchor) return;
2598
2876
  const sync = () => {
@@ -2607,34 +2885,138 @@ function Popover({
2607
2885
  }
2608
2886
 
2609
2887
  // src/components/CommandPalette.tsx
2888
+ var import_react33 = require("react");
2610
2889
  var import_jsx_runtime53 = require("react/jsx-runtime");
2890
+ var CmdkContext = (0, import_react33.createContext)(null);
2611
2891
  function CommandPalette({ inputProps, children, className, ...props }) {
2612
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: cx("uix-cmdk", className), ...props, children: [
2613
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("input", { className: "uix-cmdk__input", ...inputProps }),
2614
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uix-cmdk__list", children })
2615
- ] });
2892
+ const listId = (0, import_react33.useId)();
2893
+ const [activeId, setActiveId] = (0, import_react33.useState)(null);
2894
+ const [count, setCount] = (0, import_react33.useState)(0);
2895
+ const [announced, setAnnounced] = (0, import_react33.useState)("");
2896
+ const setActive = (0, import_react33.useCallback)((id, active) => {
2897
+ setActiveId((cur) => active ? id : cur === id ? null : cur);
2898
+ }, []);
2899
+ const registerItem = (0, import_react33.useCallback)(() => {
2900
+ setCount((c) => c + 1);
2901
+ return () => setCount((c) => c - 1);
2902
+ }, []);
2903
+ (0, import_react33.useEffect)(() => {
2904
+ const t = window.setTimeout(() => setAnnounced(`${count} result${count === 1 ? "" : "s"}`), 150);
2905
+ return () => clearTimeout(t);
2906
+ }, [count]);
2907
+ const ctx = (0, import_react33.useMemo)(() => ({ listId, setActive, registerItem }), [listId, setActive, registerItem]);
2908
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(CmdkContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: cx("uix-cmdk", className), ...props, children: [
2909
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
2910
+ "input",
2911
+ {
2912
+ className: "uix-cmdk__input",
2913
+ role: "combobox",
2914
+ "aria-expanded": "true",
2915
+ "aria-autocomplete": "list",
2916
+ "aria-controls": listId,
2917
+ "aria-activedescendant": activeId ?? void 0,
2918
+ "aria-label": "Command palette",
2919
+ ...inputProps
2920
+ }
2921
+ ),
2922
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uix-cmdk__list", role: "listbox", id: listId, children }),
2923
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uix-visually-hidden", role: "status", children: announced })
2924
+ ] }) });
2616
2925
  }
2617
2926
  function CommandGroup({ label, children }) {
2618
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
2619
- label != null && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uix-cmdk__group", children: label }),
2927
+ const labelId = (0, import_react33.useId)();
2928
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { role: "group", "aria-labelledby": label != null ? labelId : void 0, children: [
2929
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uix-cmdk__group", id: labelId, children: label }),
2620
2930
  children
2621
2931
  ] });
2622
2932
  }
2623
- function CommandItem({ icon, shortcut, active, children, className, ...props }) {
2624
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: cx("uix-cmdk__item", className), "data-active": active || void 0, ...props, children: [
2625
- icon,
2626
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { children }),
2627
- shortcut
2628
- ] });
2933
+ function CommandItem({ icon, shortcut, active, children, className, id, ...props }) {
2934
+ const ctx = (0, import_react33.useContext)(CmdkContext);
2935
+ const autoId = (0, import_react33.useId)();
2936
+ const itemId = id ?? autoId;
2937
+ (0, import_react33.useEffect)(() => ctx?.registerItem(), [ctx]);
2938
+ (0, import_react33.useEffect)(() => {
2939
+ if (!ctx || !active) return;
2940
+ ctx.setActive(itemId, true);
2941
+ return () => ctx.setActive(itemId, false);
2942
+ }, [ctx, itemId, active]);
2943
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
2944
+ "div",
2945
+ {
2946
+ className: cx("uix-cmdk__item", className),
2947
+ "data-active": active || void 0,
2948
+ id: itemId,
2949
+ role: "option",
2950
+ "aria-selected": !!active,
2951
+ ...props,
2952
+ children: [
2953
+ icon,
2954
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { children }),
2955
+ shortcut
2956
+ ]
2957
+ }
2958
+ );
2629
2959
  }
2630
2960
 
2631
2961
  // src/components/Inbox.tsx
2962
+ var import_react34 = require("react");
2632
2963
  var import_jsx_runtime54 = require("react/jsx-runtime");
2633
- function Inbox({ children, className, ...props }) {
2634
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: cx("uix-inbox", className), ...props, children });
2964
+ function Inbox({ view, children, className, ...props }) {
2965
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: cx("uix-inbox", className), "data-view": view, ...props, children });
2635
2966
  }
2967
+ var InboxListCtx = (0, import_react34.createContext)({});
2636
2968
  function InboxList({ children, className, ...props }) {
2637
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: cx("uix-inbox__list", className), role: "listbox", ...props, children });
2969
+ const listRef = (0, import_react34.useRef)(null);
2970
+ const [activeId, setActiveId] = (0, import_react34.useState)(void 0);
2971
+ const ctx = (0, import_react34.useMemo)(() => ({ activeId }), [activeId]);
2972
+ const onKeyDown = (e) => {
2973
+ const opts = Array.from(listRef.current?.querySelectorAll('[role="option"]') ?? []);
2974
+ if (opts.length === 0) return;
2975
+ const idx = opts.findIndex((el2) => el2.id === activeId);
2976
+ let next;
2977
+ switch (e.key) {
2978
+ case "ArrowDown":
2979
+ next = Math.min(idx + 1, opts.length - 1);
2980
+ break;
2981
+ case "ArrowUp":
2982
+ next = idx < 0 ? 0 : Math.max(idx - 1, 0);
2983
+ break;
2984
+ case "Home":
2985
+ next = 0;
2986
+ break;
2987
+ case "End":
2988
+ next = opts.length - 1;
2989
+ break;
2990
+ case "Enter":
2991
+ case " ":
2992
+ if (idx >= 0) {
2993
+ e.preventDefault();
2994
+ opts[idx]?.click();
2995
+ }
2996
+ return;
2997
+ default:
2998
+ return;
2999
+ }
3000
+ e.preventDefault();
3001
+ const el = opts[next];
3002
+ if (!el || !el.id) return;
3003
+ setActiveId(el.id);
3004
+ el.scrollIntoView({ block: "nearest" });
3005
+ };
3006
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(InboxListCtx.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3007
+ "div",
3008
+ {
3009
+ ref: listRef,
3010
+ className: cx("uix-inbox__list", className),
3011
+ role: "listbox",
3012
+ tabIndex: 0,
3013
+ "aria-label": "Inbox",
3014
+ "aria-activedescendant": activeId,
3015
+ onKeyDown,
3016
+ ...props,
3017
+ children
3018
+ }
3019
+ ) });
2638
3020
  }
2639
3021
  function InboxItem({
2640
3022
  subject,
@@ -2644,13 +3026,19 @@ function InboxItem({
2644
3026
  selected,
2645
3027
  children,
2646
3028
  className,
3029
+ id,
2647
3030
  ...props
2648
3031
  }) {
3032
+ const autoId = (0, import_react34.useId)();
3033
+ const itemId = id ?? autoId;
3034
+ const { activeId } = (0, import_react34.useContext)(InboxListCtx);
2649
3035
  return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
2650
3036
  "div",
2651
3037
  {
2652
3038
  role: "option",
3039
+ id: itemId,
2653
3040
  "aria-selected": selected ?? false,
3041
+ "data-active": activeId === itemId ? "" : void 0,
2654
3042
  className: cx("uix-inbox__item", className),
2655
3043
  ...unread ? { "data-unread": "" } : {},
2656
3044
  ...props,
@@ -2668,29 +3056,60 @@ function InboxDetail({ children, className, ...props }) {
2668
3056
  }
2669
3057
 
2670
3058
  // src/components/Kanban.tsx
3059
+ var import_react35 = require("react");
2671
3060
  var import_jsx_runtime55 = require("react/jsx-runtime");
2672
- function Kanban({ children, className, ...props }) {
2673
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: cx("uix-kanban", className), ...props, children });
3061
+ function Kanban({ announcement, children, className, ...props }) {
3062
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: cx("uix-kanban", className), ...props, children: [
3063
+ announcement != null && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
3064
+ children
3065
+ ] });
2674
3066
  }
2675
3067
  function KanbanColumn({ title, count, children, className, ...props }) {
3068
+ const headId = (0, import_react35.useId)();
3069
+ const hasHead = title != null || count != null;
2676
3070
  return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: cx("uix-kanban__col", className), ...props, children: [
2677
- (title != null || count != null) && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "uix-kanban__head", children: [
3071
+ hasHead && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "uix-kanban__head", id: headId, children: [
2678
3072
  title,
2679
3073
  count != null && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "uix-kanban__count", children: count })
2680
3074
  ] }),
2681
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-kanban__body", children })
3075
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-kanban__body", role: "list", "aria-labelledby": hasHead ? headId : void 0, children })
2682
3076
  ] });
2683
3077
  }
2684
- function KanbanCard({ title, meta, children, className, ...props }) {
2685
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: cx("uix-kanban__card", className), ...props, children: [
2686
- title && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-kanban__card-title", children: title }),
2687
- meta && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-kanban__card-meta", children: meta }),
2688
- children
2689
- ] });
3078
+ var MOVE_KEYS = {
3079
+ ArrowUp: "up",
3080
+ ArrowDown: "down",
3081
+ ArrowLeft: "left",
3082
+ ArrowRight: "right"
3083
+ };
3084
+ function KanbanCard({ title, meta, children, className, onMove, onKeyDown, ...props }) {
3085
+ const handleKeyDown = (e) => {
3086
+ onKeyDown?.(e);
3087
+ if (!onMove || !e.altKey || e.defaultPrevented) return;
3088
+ const dir = MOVE_KEYS[e.key];
3089
+ if (dir) {
3090
+ e.preventDefault();
3091
+ onMove(dir);
3092
+ }
3093
+ };
3094
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
3095
+ "div",
3096
+ {
3097
+ role: "listitem",
3098
+ tabIndex: 0,
3099
+ className: cx("uix-kanban__card", className),
3100
+ onKeyDown: handleKeyDown,
3101
+ ...props,
3102
+ children: [
3103
+ title && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-kanban__card-title", children: title }),
3104
+ meta && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-kanban__card-meta", children: meta }),
3105
+ children
3106
+ ]
3107
+ }
3108
+ );
2690
3109
  }
2691
3110
 
2692
3111
  // src/components/Tree.tsx
2693
- var import_react29 = require("react");
3112
+ var import_react36 = require("react");
2694
3113
 
2695
3114
  // src/tree-model.ts
2696
3115
  function flattenTree(nodes, expanded, level = 1) {
@@ -2735,6 +3154,14 @@ function treeNav(flat, currentId, key) {
2735
3154
  case " ":
2736
3155
  return cur.hasChildren ? { toggleId: cur.node.id, selectId: cur.node.id } : { selectId: cur.node.id };
2737
3156
  default:
3157
+ if (key.length === 1) {
3158
+ const q = key.toLowerCase();
3159
+ for (let step = 1; step <= flat.length; step++) {
3160
+ const f = flat[(idx + step) % flat.length];
3161
+ const label = f.node.typeaheadLabel ?? (typeof f.node.label === "string" ? f.node.label : void 0);
3162
+ if (label != null && label.toLowerCase().startsWith(q)) return { focusId: f.node.id };
3163
+ }
3164
+ }
2738
3165
  return {};
2739
3166
  }
2740
3167
  }
@@ -2802,12 +3229,12 @@ function Tree({
2802
3229
  className,
2803
3230
  ...props
2804
3231
  }) {
2805
- const [internalExpanded, setInternalExpanded] = (0, import_react29.useState)(defaultExpanded ?? /* @__PURE__ */ new Set());
3232
+ const [internalExpanded, setInternalExpanded] = (0, import_react36.useState)(defaultExpanded ?? /* @__PURE__ */ new Set());
2806
3233
  const expanded = controlledExpanded ?? internalExpanded;
2807
- const rootRef = (0, import_react29.useRef)(null);
2808
- const [focusedId, setFocusedId] = (0, import_react29.useState)(void 0);
3234
+ const rootRef = (0, import_react36.useRef)(null);
3235
+ const [focusedId, setFocusedId] = (0, import_react36.useState)(void 0);
2809
3236
  const selectable = selected !== void 0 || onSelect != null;
2810
- const handleToggle = (0, import_react29.useCallback)((id) => {
3237
+ const handleToggle = (0, import_react36.useCallback)((id) => {
2811
3238
  if (!controlledExpanded) {
2812
3239
  setInternalExpanded((prev) => {
2813
3240
  const next = new Set(prev);
@@ -2818,7 +3245,7 @@ function Tree({
2818
3245
  }
2819
3246
  onToggle?.(id);
2820
3247
  }, [controlledExpanded, onToggle]);
2821
- const flat = (0, import_react29.useMemo)(() => flattenTree(nodes, expanded), [nodes, expanded]);
3248
+ const flat = (0, import_react36.useMemo)(() => flattenTree(nodes, expanded), [nodes, expanded]);
2822
3249
  const useVirtual = virtualize ?? shouldVirtualize(flat.length);
2823
3250
  const tabbableId = focusedId ?? selected ?? nodes[0]?.id;
2824
3251
  if (useVirtual) {
@@ -2889,6 +3316,13 @@ function Tree({
2889
3316
  setFocusedId(id);
2890
3317
  break;
2891
3318
  default:
3319
+ if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
3320
+ const act = treeNav(flat, id, e.key);
3321
+ if (act.focusId !== void 0) {
3322
+ e.preventDefault();
3323
+ focusItem(rootRef.current?.querySelector(`[role="treeitem"][data-id="${CSS.escape(act.focusId)}"]`));
3324
+ }
3325
+ }
2892
3326
  break;
2893
3327
  }
2894
3328
  };
@@ -2922,12 +3356,14 @@ function VirtualTreeView({
2922
3356
  className,
2923
3357
  ...props
2924
3358
  }) {
2925
- const scrollRef = (0, import_react29.useRef)(null);
2926
- const [scrollTop, setScrollTop] = (0, import_react29.useState)(0);
2927
- const pendingFocus = (0, import_react29.useRef)(false);
3359
+ const scrollRef = (0, import_react36.useRef)(null);
3360
+ const [scrollTop, setScrollTop] = (0, import_react36.useState)(0);
3361
+ const pendingFocus = (0, import_react36.useRef)(false);
3362
+ const hadFocus = (0, import_react36.useRef)(false);
2928
3363
  const win = virtualWindow(scrollTop, maxHeight, rowHeight, flat.length);
2929
3364
  const rows = flat.slice(win.start, win.end);
2930
- (0, import_react29.useEffect)(() => {
3365
+ const windowHasTabbable = tabbableId != null && rows.some((f) => f.node.id === tabbableId);
3366
+ (0, import_react36.useEffect)(() => {
2931
3367
  if (!pendingFocus.current || focusedId == null) return;
2932
3368
  const el = scrollRef.current?.querySelector(`[role="treeitem"][data-id="${CSS.escape(focusedId)}"]`);
2933
3369
  if (el) {
@@ -2935,6 +3371,11 @@ function VirtualTreeView({
2935
3371
  pendingFocus.current = false;
2936
3372
  }
2937
3373
  }, [focusedId, win.start, win.end]);
3374
+ (0, import_react36.useEffect)(() => {
3375
+ if (!hadFocus.current || pendingFocus.current) return;
3376
+ const active = document.activeElement;
3377
+ if (active === document.body || active == null) scrollRef.current?.focus({ preventScroll: true });
3378
+ });
2938
3379
  const moveTo = (id) => {
2939
3380
  const i = flat.findIndex((f) => f.node.id === id);
2940
3381
  if (i < 0) return;
@@ -2950,6 +3391,7 @@ function VirtualTreeView({
2950
3391
  setFocusedId(id);
2951
3392
  };
2952
3393
  const onKeyDown = (e) => {
3394
+ if (e.key.length === 1 && (e.ctrlKey || e.metaKey || e.altKey)) return;
2953
3395
  const curId = e.target.closest('[role="treeitem"]')?.dataset.id ?? focusedId;
2954
3396
  const act = treeNav(flat, curId, e.key);
2955
3397
  if (act.focusId === void 0 && act.toggleId === void 0 && act.selectId === void 0) return;
@@ -2970,13 +3412,20 @@ function VirtualTreeView({
2970
3412
  ref: scrollRef,
2971
3413
  className: cx("uix-tree", "uix-tree--virtual", className),
2972
3414
  role: "tree",
3415
+ tabIndex: -1,
2973
3416
  style: { maxHeight, overflow: "auto" },
2974
3417
  onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
2975
3418
  onKeyDown,
3419
+ onFocus: () => {
3420
+ hadFocus.current = true;
3421
+ },
3422
+ onBlur: (e) => {
3423
+ if (!e.currentTarget.contains(e.relatedTarget)) hadFocus.current = false;
3424
+ },
2976
3425
  ...props,
2977
3426
  children: [
2978
- win.padTop > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("li", { "aria-hidden": "true", style: { height: win.padTop } }),
2979
- rows.map((f) => {
3427
+ win.padTop > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("li", { role: "presentation", "aria-hidden": "true", style: { height: win.padTop } }),
3428
+ rows.map((f, i) => {
2980
3429
  const rowStyle = { height: rowHeight, paddingLeft: `calc(${f.level - 1} * var(--uix-space-5))` };
2981
3430
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
2982
3431
  "li",
@@ -2988,7 +3437,7 @@ function VirtualTreeView({
2988
3437
  "aria-expanded": f.hasChildren ? f.isExpanded : void 0,
2989
3438
  "aria-selected": selectable ? selected === f.node.id : void 0,
2990
3439
  "data-id": f.node.id,
2991
- tabIndex: tabbableId === f.node.id ? 0 : -1,
3440
+ tabIndex: tabbableId === f.node.id || !windowHasTabbable && i === 0 ? 0 : -1,
2992
3441
  className: "uix-tree__item",
2993
3442
  onFocus: (e) => {
2994
3443
  if (e.target === e.currentTarget) setFocusedId(f.node.id);
@@ -3008,7 +3457,7 @@ function VirtualTreeView({
3008
3457
  f.node.id
3009
3458
  );
3010
3459
  }),
3011
- win.padBottom > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("li", { "aria-hidden": "true", style: { height: win.padBottom } })
3460
+ win.padBottom > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("li", { role: "presentation", "aria-hidden": "true", style: { height: win.padBottom } })
3012
3461
  ]
3013
3462
  }
3014
3463
  );
@@ -3427,7 +3876,7 @@ function RuleBuilder({
3427
3876
  }
3428
3877
 
3429
3878
  // src/components/BuilderCanvas.tsx
3430
- var import_react30 = require("react");
3879
+ var import_react37 = require("react");
3431
3880
  var import_jsx_runtime59 = require("react/jsx-runtime");
3432
3881
  function BuilderCanvas({
3433
3882
  items,
@@ -3443,13 +3892,13 @@ function BuilderCanvas({
3443
3892
  emptyMessage = "Add an item from the palette to begin.",
3444
3893
  className
3445
3894
  }) {
3446
- const [internalSelectedId, setInternalSelectedId] = (0, import_react30.useState)();
3447
- const [draggedId, setDraggedId] = (0, import_react30.useState)();
3448
- const propertyHeadingRef = (0, import_react30.useRef)(null);
3449
- const shouldFocusProperties = (0, import_react30.useRef)(false);
3895
+ const [internalSelectedId, setInternalSelectedId] = (0, import_react37.useState)();
3896
+ const [draggedId, setDraggedId] = (0, import_react37.useState)();
3897
+ const propertyHeadingRef = (0, import_react37.useRef)(null);
3898
+ const shouldFocusProperties = (0, import_react37.useRef)(false);
3450
3899
  const selectedId = controlledSelectedId ?? internalSelectedId;
3451
3900
  const selected = items.find((item) => item.id === selectedId);
3452
- (0, import_react30.useEffect)(() => {
3901
+ (0, import_react37.useEffect)(() => {
3453
3902
  if (shouldFocusProperties.current && selected) {
3454
3903
  propertyHeadingRef.current?.focus();
3455
3904
  shouldFocusProperties.current = false;
@@ -3540,7 +3989,7 @@ function BuilderCanvas({
3540
3989
  }
3541
3990
 
3542
3991
  // src/components/SchedulingCalendar.tsx
3543
- var import_react31 = require("react");
3992
+ var import_react38 = require("react");
3544
3993
 
3545
3994
  // src/calendar-model.ts
3546
3995
  function fromDateKey(value) {
@@ -3643,19 +4092,19 @@ function SchedulingCalendar({
3643
4092
  onRetry,
3644
4093
  className
3645
4094
  }) {
3646
- const [internalView, setInternalView] = (0, import_react31.useState)("month");
4095
+ const [internalView, setInternalView] = (0, import_react38.useState)("month");
3647
4096
  const view = controlledView ?? internalView;
3648
- const [activeDate, setActiveDate] = (0, import_react31.useState)(anchorDate);
3649
- const gridRef = (0, import_react31.useRef)(null);
3650
- const visibleEntries = (0, import_react31.useMemo)(() => entries.filter((entry) => filter?.(entry) ?? true), [entries, filter]);
3651
- const entrySpans = (0, import_react31.useMemo)(() => new Map(visibleEntries.map((entry) => [entry.id, zonedDateSpan(entry.start, entry.end, timeZone)])), [visibleEntries, timeZone]);
3652
- const overlaySpans = (0, import_react31.useMemo)(() => new Map(overlays.map((overlay) => [overlay.id, { start: overlay.start.slice(0, 10), end: overlay.end.slice(0, 10) }])), [overlays]);
3653
- const monthDays = (0, import_react31.useMemo)(() => buildMonthGrid(startOfMonth(anchorDate)), [anchorDate]);
4097
+ const [activeDate, setActiveDate] = (0, import_react38.useState)(anchorDate);
4098
+ const gridRef = (0, import_react38.useRef)(null);
4099
+ const visibleEntries = (0, import_react38.useMemo)(() => entries.filter((entry) => filter?.(entry) ?? true), [entries, filter]);
4100
+ const entrySpans = (0, import_react38.useMemo)(() => new Map(visibleEntries.map((entry) => [entry.id, zonedDateSpan(entry.start, entry.end, timeZone)])), [visibleEntries, timeZone]);
4101
+ const overlaySpans = (0, import_react38.useMemo)(() => new Map(overlays.map((overlay) => [overlay.id, { start: overlay.start.slice(0, 10), end: overlay.end.slice(0, 10) }])), [overlays]);
4102
+ const monthDays = (0, import_react38.useMemo)(() => buildMonthGrid(startOfMonth(anchorDate)), [anchorDate]);
3654
4103
  const weekday = ((/* @__PURE__ */ new Date(`${anchorDate}T00:00:00Z`)).getUTCDay() + 6) % 7;
3655
4104
  const weekStart = addCalendarDays(anchorDate, -weekday);
3656
- const weekDays = (0, import_react31.useMemo)(() => Array.from({ length: 7 }, (_, index) => addCalendarDays(weekStart, index)), [weekStart]);
3657
- const days = (0, import_react31.useMemo)(() => view === "month" ? monthDays.map((day) => day.date) : weekDays, [view, monthDays, weekDays]);
3658
- (0, import_react31.useEffect)(() => {
4105
+ const weekDays = (0, import_react38.useMemo)(() => Array.from({ length: 7 }, (_, index) => addCalendarDays(weekStart, index)), [weekStart]);
4106
+ const days = (0, import_react38.useMemo)(() => view === "month" ? monthDays.map((day) => day.date) : weekDays, [view, monthDays, weekDays]);
4107
+ (0, import_react38.useEffect)(() => {
3659
4108
  if (view !== "agenda" && !days.includes(activeDate)) setActiveDate(days[0]);
3660
4109
  }, [activeDate, days, view]);
3661
4110
  const setView = (next) => {
@@ -3739,7 +4188,7 @@ function SchedulingCalendar({
3739
4188
  }
3740
4189
 
3741
4190
  // src/components/DateRangePicker.tsx
3742
- var import_react32 = require("react");
4191
+ var import_react39 = require("react");
3743
4192
  var import_jsx_runtime61 = require("react/jsx-runtime");
3744
4193
  var monthLabel = (date, locale) => new Intl.DateTimeFormat(locale, { month: "long", year: "numeric", timeZone: "UTC" }).format(/* @__PURE__ */ new Date(`${date}T00:00:00Z`));
3745
4194
  var dateLabel2 = (date, locale) => new Intl.DateTimeFormat(locale, { dateStyle: "full", timeZone: "UTC" }).format(/* @__PURE__ */ new Date(`${date}T00:00:00Z`));
@@ -3759,25 +4208,25 @@ function DateRangePicker({
3759
4208
  disabled,
3760
4209
  className
3761
4210
  }) {
3762
- const id = (0, import_react32.useId)();
3763
- const [internalMonth, setInternalMonth] = (0, import_react32.useState)(() => startOfMonth(controlledMonth ?? value.start ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)));
4211
+ const id = (0, import_react39.useId)();
4212
+ const [internalMonth, setInternalMonth] = (0, import_react39.useState)(() => startOfMonth(controlledMonth ?? value.start ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)));
3764
4213
  const visibleMonth = startOfMonth(controlledMonth ?? internalMonth);
3765
- const [activeDate, setActiveDate] = (0, import_react32.useState)(value.end ?? value.start ?? visibleMonth);
3766
- const rootRef = (0, import_react32.useRef)(null);
3767
- const pendingFocus = (0, import_react32.useRef)(false);
4214
+ const [activeDate, setActiveDate] = (0, import_react39.useState)(value.end ?? value.start ?? visibleMonth);
4215
+ const rootRef = (0, import_react39.useRef)(null);
4216
+ const pendingFocus = (0, import_react39.useRef)(false);
3768
4217
  const count = Math.max(1, Math.min(3, months));
3769
- const calendars = (0, import_react32.useMemo)(() => Array.from({ length: count }, (_, index) => {
4218
+ const calendars = (0, import_react39.useMemo)(() => Array.from({ length: count }, (_, index) => {
3770
4219
  const month = startOfMonth(addCalendarMonths(visibleMonth, index));
3771
4220
  return { month, days: buildMonthGrid(month).filter((day) => day.inMonth) };
3772
4221
  }), [visibleMonth, count]);
3773
4222
  const rangeInvalid = invalid || !!value.start && !!value.end && value.start > value.end;
3774
- (0, import_react32.useEffect)(() => {
4223
+ (0, import_react39.useEffect)(() => {
3775
4224
  const first = calendars[0]?.days[0]?.date;
3776
4225
  const finalDays = calendars[calendars.length - 1]?.days;
3777
4226
  const last = finalDays?.[finalDays.length - 1]?.date;
3778
4227
  if (first && last && (activeDate < first || activeDate > last)) setActiveDate(first);
3779
4228
  }, [activeDate, calendars]);
3780
- (0, import_react32.useEffect)(() => {
4229
+ (0, import_react39.useEffect)(() => {
3781
4230
  if (!pendingFocus.current) return;
3782
4231
  rootRef.current?.querySelector(`[data-date="${activeDate}"]`)?.focus();
3783
4232
  pendingFocus.current = false;
@@ -3858,7 +4307,7 @@ function DateRangePicker({
3858
4307
  }
3859
4308
 
3860
4309
  // src/components/RelationshipGraph.tsx
3861
- var import_react33 = require("react");
4310
+ var import_react40 = require("react");
3862
4311
 
3863
4312
  // src/relationship-graph-model.ts
3864
4313
  function boundRelationshipGraph(nodes, edges, maxNodes = 40) {
@@ -3947,13 +4396,13 @@ function RelationshipGraph({
3947
4396
  onRetry,
3948
4397
  className
3949
4398
  }) {
3950
- const bounded = (0, import_react33.useMemo)(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
3951
- const positioned = (0, import_react33.useMemo)(() => layoutRelationshipGraph(bounded.nodes, bounded.edges, selectedId), [bounded, selectedId]);
3952
- const positionedById = (0, import_react33.useMemo)(() => new Map(positioned.map((node) => [node.id, node])), [positioned]);
3953
- const [zoom, setZoom] = (0, import_react33.useState)(1);
3954
- const [pan, setPan] = (0, import_react33.useState)({ x: 0, y: 0 });
3955
- const [focusedId, setFocusedId] = (0, import_react33.useState)(selectedId ?? positioned[0]?.id);
3956
- const svgRef = (0, import_react33.useRef)(null);
4399
+ const bounded = (0, import_react40.useMemo)(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
4400
+ const positioned = (0, import_react40.useMemo)(() => layoutRelationshipGraph(bounded.nodes, bounded.edges, selectedId), [bounded, selectedId]);
4401
+ const positionedById = (0, import_react40.useMemo)(() => new Map(positioned.map((node) => [node.id, node])), [positioned]);
4402
+ const [zoom, setZoom] = (0, import_react40.useState)(1);
4403
+ const [pan, setPan] = (0, import_react40.useState)({ x: 0, y: 0 });
4404
+ const [focusedId, setFocusedId] = (0, import_react40.useState)(selectedId ?? positioned[0]?.id);
4405
+ const svgRef = (0, import_react40.useRef)(null);
3957
4406
  const select = (id) => {
3958
4407
  const node = bounded.nodes.find((item) => item.id === id);
3959
4408
  if (node) onSelect?.(node);
@@ -4058,7 +4507,7 @@ function RelationshipGraph({
4058
4507
  }
4059
4508
 
4060
4509
  // src/components/MatchReview.tsx
4061
- var import_react34 = require("react");
4510
+ var import_react41 = require("react");
4062
4511
  var import_jsx_runtime63 = require("react/jsx-runtime");
4063
4512
  var valueText = (value) => value == null ? "\u2014" : typeof value === "string" ? value : JSON.stringify(value);
4064
4513
  function MatchReview({
@@ -4075,11 +4524,11 @@ function MatchReview({
4075
4524
  onRetry,
4076
4525
  className
4077
4526
  }) {
4078
- const [internalSelection, setInternalSelection] = (0, import_react34.useState)(/* @__PURE__ */ new Set());
4079
- const [announcement, setAnnouncement] = (0, import_react34.useState)("");
4080
- const [bulkPending, setBulkPending] = (0, import_react34.useState)(false);
4527
+ const [internalSelection, setInternalSelection] = (0, import_react41.useState)(/* @__PURE__ */ new Set());
4528
+ const [announcement, setAnnouncement] = (0, import_react41.useState)("");
4529
+ const [bulkPending, setBulkPending] = (0, import_react41.useState)(false);
4081
4530
  const selection = selectedIds ?? internalSelection;
4082
- const pending = (0, import_react34.useMemo)(() => candidates.filter((candidate) => candidate.status !== "resolved"), [candidates]);
4531
+ const pending = (0, import_react41.useMemo)(() => candidates.filter((candidate) => candidate.status !== "resolved"), [candidates]);
4083
4532
  const setSelection = (next) => {
4084
4533
  if (selectedIds === void 0) setInternalSelection(next);
4085
4534
  onSelectionChange?.(next);
@@ -4174,7 +4623,7 @@ function MatchReview({
4174
4623
  }
4175
4624
 
4176
4625
  // src/components/MetricInput.tsx
4177
- var import_react35 = require("react");
4626
+ var import_react42 = require("react");
4178
4627
 
4179
4628
  // src/metric-model.ts
4180
4629
  function decimals(value) {
@@ -4218,11 +4667,11 @@ function MetricInput({
4218
4667
  className,
4219
4668
  id: providedId
4220
4669
  }) {
4221
- const generatedId = (0, import_react35.useId)();
4670
+ const generatedId = (0, import_react42.useId)();
4222
4671
  const id = providedId ?? generatedId;
4223
4672
  const errorId = `${id}-error`;
4224
- const [text, setText] = (0, import_react35.useState)(() => format(value));
4225
- (0, import_react35.useEffect)(() => setText(format(value)), [value, format]);
4673
+ const [text, setText] = (0, import_react42.useState)(() => format(value));
4674
+ (0, import_react42.useEffect)(() => setText(format(value)), [value, format]);
4226
4675
  const commit = (input) => {
4227
4676
  const parsed = parse(input);
4228
4677
  if (input.trim() === "" || parsed !== null) {
@@ -4331,7 +4780,7 @@ function LicensePositionBar({
4331
4780
  }
4332
4781
 
4333
4782
  // src/components/BrandProfiles.tsx
4334
- var import_react37 = require("react");
4783
+ var import_react44 = require("react");
4335
4784
 
4336
4785
  // src/color-model.ts
4337
4786
  var clamp2 = (value, min, max) => Math.min(max, Math.max(min, value));
@@ -4400,7 +4849,7 @@ function meetsContrast(background, foreground, minimum = 4.5) {
4400
4849
  }
4401
4850
 
4402
4851
  // src/components/ColorPicker.tsx
4403
- var import_react36 = require("react");
4852
+ var import_react43 = require("react");
4404
4853
  var import_jsx_runtime66 = require("react/jsx-runtime");
4405
4854
  var EMPTY_COLORS = [];
4406
4855
  function ColorPicker({
@@ -4414,17 +4863,17 @@ function ColorPicker({
4414
4863
  disabled,
4415
4864
  className
4416
4865
  }) {
4417
- const id = (0, import_react36.useId)();
4418
- const triggerRef = (0, import_react36.useRef)(null);
4419
- const dialogRef = (0, import_react36.useRef)(null);
4420
- const [open, setOpen] = (0, import_react36.useState)(false);
4866
+ const id = (0, import_react43.useId)();
4867
+ const triggerRef = (0, import_react43.useRef)(null);
4868
+ const dialogRef = (0, import_react43.useRef)(null);
4869
+ const [open, setOpen] = (0, import_react43.useState)(false);
4421
4870
  const normalized = normalizeHex(value) ?? "#000000";
4422
- const [hexText, setHexText] = (0, import_react36.useState)(normalized);
4423
- const hsv = (0, import_react36.useMemo)(() => rgbToHsv(hexToRgb(normalized)), [normalized]);
4871
+ const [hexText, setHexText] = (0, import_react43.useState)(normalized);
4872
+ const hsv = (0, import_react43.useMemo)(() => rgbToHsv(hexToRgb(normalized)), [normalized]);
4424
4873
  const ratio = contrastRatio(normalized, foreground) ?? 0;
4425
4874
  const passes = ratio >= minimumContrast;
4426
- (0, import_react36.useEffect)(() => setHexText(normalized), [normalized]);
4427
- (0, import_react36.useEffect)(() => {
4875
+ (0, import_react43.useEffect)(() => setHexText(normalized), [normalized]);
4876
+ (0, import_react43.useEffect)(() => {
4428
4877
  if (!open) return;
4429
4878
  const dialog = dialogRef.current;
4430
4879
  dialog?.querySelector("input,button")?.focus();
@@ -4623,7 +5072,7 @@ function BrandProfileEditor({
4623
5072
  colorPresets = EMPTY_COLORS2,
4624
5073
  className
4625
5074
  }) {
4626
- const [announcement, setAnnouncement] = (0, import_react37.useState)("");
5075
+ const [announcement, setAnnouncement] = (0, import_react44.useState)("");
4627
5076
  const update = (patch) => onChange({ ...value, ...patch });
4628
5077
  const apply = () => {
4629
5078
  if (applyTarget !== null) applyBrandProfile(value, applyTarget);
@@ -4695,7 +5144,7 @@ function BrandProfileEditor({
4695
5144
  var BrandProfiles = BrandProfileEditor;
4696
5145
 
4697
5146
  // src/components/DiffViewer.tsx
4698
- var import_react38 = require("react");
5147
+ var import_react45 = require("react");
4699
5148
 
4700
5149
  // src/diff-model.ts
4701
5150
  function isJsonObject(value) {
@@ -4765,9 +5214,9 @@ function DiffViewer({
4765
5214
  labels = DEFAULT_LABELS,
4766
5215
  className
4767
5216
  }) {
4768
- const id = (0, import_react38.useId)();
4769
- const entries = (0, import_react38.useMemo)(() => providedEntries ?? buildThreeWayDiff(base, current, incoming), [providedEntries, base, current, incoming]);
4770
- const [internalResolutions, setInternalResolutions] = (0, import_react38.useState)({});
5217
+ const id = (0, import_react45.useId)();
5218
+ const entries = (0, import_react45.useMemo)(() => providedEntries ?? buildThreeWayDiff(base, current, incoming), [providedEntries, base, current, incoming]);
5219
+ const [internalResolutions, setInternalResolutions] = (0, import_react45.useState)({});
4771
5220
  const resolutions = controlledResolutions ?? internalResolutions;
4772
5221
  const summary = summarizeDiff(entries, resolutions);
4773
5222
  const resolve2 = (path, resolution) => {
@@ -4947,6 +5396,7 @@ function DiffViewer({
4947
5396
  SubNavItem,
4948
5397
  Switch,
4949
5398
  Tab,
5399
+ TabPanel,
4950
5400
  Table,
4951
5401
  TableWrap,
4952
5402
  Tabs,