@tensor_1/react 2.19.2 → 2.21.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 (70) hide show
  1. package/README.md +14 -0
  2. package/dist/{ChartCore-Do6gRBN3.d.cts → ChartCore-DzWe10bN.d.cts} +16 -1
  3. package/dist/chart-preset.cjs +25 -13
  4. package/dist/chart-preset.d.cts +2 -2
  5. package/dist/chart-preset.d.ts +1 -1
  6. package/dist/chart-preset.js +2 -1
  7. package/dist/chart.cjs +25 -13
  8. package/dist/chart.d.cts +2 -2
  9. package/dist/chart.d.ts +1 -1
  10. package/dist/chart.js +2 -1
  11. package/dist/components/AppShell.d.ts +5 -1
  12. package/dist/components/AppShell.js +4 -2
  13. package/dist/components/Avatar.d.ts +3 -1
  14. package/dist/components/Avatar.js +2 -2
  15. package/dist/components/BrandProfiles.d.ts +29 -2
  16. package/dist/components/BrandProfiles.js +45 -20
  17. package/dist/components/BuilderCanvas.d.ts +27 -2
  18. package/dist/components/BuilderCanvas.js +45 -22
  19. package/dist/components/Chart.d.ts +1 -1
  20. package/dist/components/Chart.js +2 -1
  21. package/dist/components/ChartCore.d.ts +17 -2
  22. package/dist/components/ChartCore.js +24 -13
  23. package/dist/components/ColorPicker.d.ts +24 -2
  24. package/dist/components/ColorPicker.js +38 -20
  25. package/dist/components/CommandPalette.d.ts +3 -1
  26. package/dist/components/CommandPalette.js +2 -2
  27. package/dist/components/CopyButton.d.ts +25 -0
  28. package/dist/components/CopyButton.js +52 -0
  29. package/dist/components/DateRangePicker.d.ts +21 -2
  30. package/dist/components/DateRangePicker.js +26 -6
  31. package/dist/components/DetailPage.d.ts +22 -3
  32. package/dist/components/DetailPage.js +33 -3
  33. package/dist/components/DiffViewer.d.ts +34 -3
  34. package/dist/components/DiffViewer.js +60 -40
  35. package/dist/components/Drawer.d.ts +3 -1
  36. package/dist/components/Drawer.js +2 -2
  37. package/dist/components/Inbox.d.ts +3 -1
  38. package/dist/components/Inbox.js +2 -2
  39. package/dist/components/MatchReview.d.ts +49 -2
  40. package/dist/components/MatchReview.js +72 -30
  41. package/dist/components/Meter.d.ts +3 -1
  42. package/dist/components/Meter.js +3 -2
  43. package/dist/components/Pagination.d.ts +10 -2
  44. package/dist/components/Pagination.js +11 -4
  45. package/dist/components/Peek.d.ts +7 -1
  46. package/dist/components/Peek.js +4 -4
  47. package/dist/components/RelationshipGraph.js +6 -2
  48. package/dist/components/RuleBuilder.d.ts +42 -2
  49. package/dist/components/RuleBuilder.js +71 -37
  50. package/dist/components/SchedulingCalendar.d.ts +25 -2
  51. package/dist/components/SchedulingCalendar.js +38 -15
  52. package/dist/components/Stat.d.ts +24 -3
  53. package/dist/components/Stat.js +51 -10
  54. package/dist/components/Table.d.ts +11 -3
  55. package/dist/components/Table.js +5 -8
  56. package/dist/components/Tabs.d.ts +14 -1
  57. package/dist/components/Tabs.js +88 -19
  58. package/dist/components/Toast.d.ts +6 -2
  59. package/dist/components/Toast.js +4 -4
  60. package/dist/components/Tree.d.ts +9 -1
  61. package/dist/components/Tree.js +55 -8
  62. package/dist/copy-model.d.ts +12 -0
  63. package/dist/copy-model.js +12 -0
  64. package/dist/fill-label.d.ts +7 -0
  65. package/dist/fill-label.js +9 -0
  66. package/dist/index.cjs +1480 -1004
  67. package/dist/index.d.cts +387 -30
  68. package/dist/index.d.ts +11 -10
  69. package/dist/index.js +20 -9
  70. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -50,8 +50,18 @@ __export(src_exports, {
50
50
  ConfirmDialog: () => ConfirmDialog,
51
51
  ContentList: () => ContentList,
52
52
  ContentListItem: () => ContentListItem,
53
+ CopyButton: () => CopyButton,
54
+ DEFAULT_BRAND_PROFILE_EDITOR_LABELS: () => DEFAULT_BRAND_PROFILE_EDITOR_LABELS,
55
+ DEFAULT_BUILDER_CANVAS_LABELS: () => DEFAULT_BUILDER_CANVAS_LABELS,
56
+ DEFAULT_COLOR_PICKER_LABELS: () => DEFAULT_COLOR_PICKER_LABELS,
57
+ DEFAULT_DATE_RANGE_PICKER_LABELS: () => DEFAULT_DATE_RANGE_PICKER_LABELS,
58
+ DEFAULT_DIFF_VIEWER_LABELS: () => DEFAULT_DIFF_VIEWER_LABELS,
59
+ DEFAULT_MATCH_REVIEW_LABELS: () => DEFAULT_MATCH_REVIEW_LABELS,
60
+ DEFAULT_PAGINATION_LABELS: () => DEFAULT_PAGINATION_LABELS,
53
61
  DEFAULT_RELATIONSHIP_GRAPH_LABELS: () => DEFAULT_RELATIONSHIP_GRAPH_LABELS,
62
+ DEFAULT_RULE_BUILDER_LABELS: () => DEFAULT_RULE_BUILDER_LABELS,
54
63
  DEFAULT_SAVE_STATUS_LABELS: () => DEFAULT_SAVE_STATUS_LABELS,
64
+ DEFAULT_SCHEDULING_CALENDAR_LABELS: () => DEFAULT_SCHEDULING_CALENDAR_LABELS,
55
65
  DateRangePicker: () => DateRangePicker,
56
66
  DescriptionItem: () => DescriptionItem,
57
67
  DescriptionList: () => DescriptionList,
@@ -1171,7 +1181,7 @@ function PromptDialog({ open, title, description, inputLabel, defaultValue = "",
1171
1181
  var import_react16 = require("react");
1172
1182
  var import_jsx_runtime12 = require("react/jsx-runtime");
1173
1183
  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" }) });
1174
- function Drawer({ open, onClose, title, children, footer, className, ...rest }) {
1184
+ function Drawer({ open, onClose, title, children, footer, closeLabel = "Close drawer", className, ...rest }) {
1175
1185
  const ref = useDialog(open, onClose);
1176
1186
  const titleId = (0, import_react16.useId)();
1177
1187
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("dialog", { ref, className: cx("uix-drawer", className), "aria-labelledby": title ? titleId : void 0, ...rest, children: [
@@ -1182,7 +1192,7 @@ function Drawer({ open, onClose, title, children, footer, className, ...rest })
1182
1192
  {
1183
1193
  style: { marginLeft: "auto", border: 0, background: "transparent", color: "var(--uix-text-muted)", cursor: "pointer", width: 30, height: 30, display: "grid", placeItems: "center", borderRadius: "var(--uix-radius-sm)" },
1184
1194
  onClick: onClose,
1185
- "aria-label": "Close drawer",
1195
+ "aria-label": closeLabel,
1186
1196
  children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CloseIcon2, {})
1187
1197
  }
1188
1198
  )
@@ -1198,7 +1208,7 @@ var import_jsx_runtime13 = require("react/jsx-runtime");
1198
1208
  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" }) });
1199
1209
  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" }) });
1200
1210
  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" }) });
1201
- function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className, onClick, ...rest }) {
1211
+ function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, previousLabel = "Previous record", nextLabel = "Next record", closeLabel = "Close preview", className, onClick, ...rest }) {
1202
1212
  const ref = useDialog(open, onClose);
1203
1213
  const hasNav = onNavPrev != null || onNavNext != null;
1204
1214
  const titleId = (0, import_react17.useId)();
@@ -1213,12 +1223,12 @@ function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hi
1213
1223
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("dialog", { ref, className: cx("uix-peek", className), "aria-labelledby": title ? titleId : void 0, ...rest, onClick: onBackdropClick, children: [
1214
1224
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "uix-peek__header", children: [
1215
1225
  hasNav && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "uix-peek__nav", children: [
1216
- /* @__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, {}) }),
1217
- /* @__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, {}) })
1226
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "uix-peek__navbtn", onClick: () => onNavPrev?.(), "aria-disabled": onNavPrev ? void 0 : true, "aria-label": previousLabel, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronUp, {}) }),
1227
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "uix-peek__navbtn", onClick: () => onNavNext?.(), "aria-disabled": onNavNext ? void 0 : true, "aria-label": nextLabel, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronDown, {}) })
1218
1228
  ] }),
1219
1229
  title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "uix-peek__title", id: titleId, children: title }),
1220
1230
  hint && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "uix-peek__hint", children: hint }),
1221
- 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, {}) })
1231
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "uix-peek__close", onClick: onClose, "aria-label": closeLabel, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CloseIcon3, {}) })
1222
1232
  ] }),
1223
1233
  children != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "uix-peek__body", children }),
1224
1234
  footer != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "uix-peek__footer", children: footer })
@@ -1292,16 +1302,46 @@ function DetailLayout({ side, children, className, ...props }) {
1292
1302
  }
1293
1303
 
1294
1304
  // src/components/DetailPage.tsx
1305
+ var import_react19 = require("react");
1295
1306
  var import_jsx_runtime18 = require("react/jsx-runtime");
1296
- function DetailPage({ back, eyebrow, title, subtitle, actions, tabs, metrics, side, children, tabsLabel, className, ...props }) {
1307
+ var plainLink = ({ href, className, children, onClick, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("a", { href, className, onClick, ...rest, children });
1308
+ var isPlainLeftClick = (e) => e.button === 0 && !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey;
1309
+ function DetailPage({
1310
+ back,
1311
+ eyebrow,
1312
+ title,
1313
+ subtitle,
1314
+ actions,
1315
+ tabs,
1316
+ metrics,
1317
+ side,
1318
+ children,
1319
+ tabsLabel,
1320
+ renderLink = plainLink,
1321
+ onTabSelect,
1322
+ className,
1323
+ ...props
1324
+ }) {
1297
1325
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: cx("uix-detail-page", className), ...props, children: [
1298
- back && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("a", { className: "uix-link uix-link--quiet uix-detail-page__back", href: back.href, children: back.label }),
1326
+ back && renderLink({ href: back.href, className: "uix-link uix-link--quiet uix-detail-page__back", children: back.label }),
1299
1327
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PageHeader, { eyebrow, title, subtitle, actions }),
1300
1328
  metrics && metrics.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dl", { className: "uix-detail-page__metrics", children: metrics.map((metric) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
1301
1329
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { children: metric.label }),
1302
1330
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { children: metric.value })
1303
1331
  ] }, metric.id)) }),
1304
- tabs && tabs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("nav", { className: "uix-tabs", "aria-label": tabsLabel, children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("a", { className: "uix-tab", "aria-current": tab.active ? "page" : void 0, href: tab.href, children: tab.label }, tab.id)) }),
1332
+ tabs && tabs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("nav", { className: "uix-tabs", "aria-label": tabsLabel, children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react19.Fragment, { children: renderLink({
1333
+ href: tab.href,
1334
+ className: "uix-tab",
1335
+ children: tab.label,
1336
+ ...tab.active ? { "aria-current": "page" } : {},
1337
+ ...onTabSelect ? {
1338
+ onClick: (e) => {
1339
+ if (!isPlainLeftClick(e)) return;
1340
+ e.preventDefault();
1341
+ onTabSelect(tab.id);
1342
+ }
1343
+ } : {}
1344
+ }) }, tab.id)) }),
1305
1345
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DetailLayout, { side, children })
1306
1346
  ] });
1307
1347
  }
@@ -1364,11 +1404,11 @@ function ListItem({ title, meta, trail, leading, children, className, ...props }
1364
1404
  }
1365
1405
 
1366
1406
  // src/components/DescriptionList.tsx
1367
- var import_react19 = require("react");
1407
+ var import_react20 = require("react");
1368
1408
  var import_jsx_runtime23 = require("react/jsx-runtime");
1369
1409
  function DescriptionList({ items, children, className, ...props }) {
1370
1410
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("dl", { className: cx("uix-dl", className), ...props, children: [
1371
- items?.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react19.Fragment, { children: [
1411
+ items?.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react20.Fragment, { children: [
1372
1412
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("dt", { children: item.term }),
1373
1413
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("dd", { children: item.description })
1374
1414
  ] }, item.id ?? i)),
@@ -1383,24 +1423,65 @@ function DescriptionItem({ term, children }) {
1383
1423
  }
1384
1424
 
1385
1425
  // src/components/Tabs.tsx
1386
- var import_react20 = require("react");
1426
+ var import_react21 = require("react");
1387
1427
  var import_jsx_runtime24 = require("react/jsx-runtime");
1388
- var TabsCtx = (0, import_react20.createContext)({});
1389
- function Tabs({ variant = "line", value, onChange, children, className }) {
1390
- const baseId = (0, import_react20.useId)();
1391
- const listRef = (0, import_react20.useRef)(null);
1392
- const contextValue = (0, import_react20.useMemo)(() => ({ value, onChange, baseId }), [value, onChange, baseId]);
1393
- const kids = import_react20.Children.toArray(children);
1394
- const panels = kids.filter((k) => (0, import_react20.isValidElement)(k) && k.type === TabPanel);
1395
- const tabs = kids.filter((k) => !((0, import_react20.isValidElement)(k) && k.type === TabPanel));
1396
- (0, import_react20.useEffect)(() => {
1397
- const list = listRef.current;
1398
- if (!list) return;
1399
- const all = Array.from(list.querySelectorAll('[role="tab"]'));
1428
+ var TabsCtx = (0, import_react21.createContext)({});
1429
+ var Chevron = ({ d }) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("path", { d }) });
1430
+ var inlineOffset = (el, rtl) => rtl ? -el.scrollLeft : el.scrollLeft;
1431
+ function Tabs({ variant = "line", value, onChange, children, className, overflow = "wrap", activation = "automatic" }) {
1432
+ const baseId = (0, import_react21.useId)();
1433
+ const listRef = (0, import_react21.useRef)(null);
1434
+ const contextValue = (0, import_react21.useMemo)(() => ({ value, onChange, baseId }), [value, onChange, baseId]);
1435
+ const scroll = overflow === "scroll";
1436
+ const [hidden, setHidden] = (0, import_react21.useState)({ start: false, end: false });
1437
+ const kids = import_react21.Children.toArray(children);
1438
+ const panels = kids.filter((k) => (0, import_react21.isValidElement)(k) && k.type === TabPanel);
1439
+ const tabs = kids.filter((k) => !((0, import_react21.isValidElement)(k) && k.type === TabPanel));
1440
+ (0, import_react21.useEffect)(() => {
1441
+ const list2 = listRef.current;
1442
+ if (!list2) return;
1443
+ const all = Array.from(list2.querySelectorAll('[role="tab"]'));
1400
1444
  const enabled = all.filter((t) => !t.matches(":disabled"));
1401
1445
  const active = enabled.find((t) => t.getAttribute("aria-selected") === "true") ?? enabled[0];
1402
1446
  for (const t of all) t.tabIndex = t === active ? 0 : -1;
1403
1447
  });
1448
+ (0, import_react21.useEffect)(() => {
1449
+ const list2 = listRef.current;
1450
+ if (!scroll || !list2) return;
1451
+ const measure = () => {
1452
+ const rtl = getComputedStyle(list2).direction === "rtl";
1453
+ const pos = inlineOffset(list2, rtl);
1454
+ const max = list2.scrollWidth - list2.clientWidth;
1455
+ const next = { start: pos > 1, end: pos < max - 1 };
1456
+ setHidden((prev) => prev.start === next.start && prev.end === next.end ? prev : next);
1457
+ };
1458
+ measure();
1459
+ list2.addEventListener("scroll", measure, { passive: true });
1460
+ if (typeof ResizeObserver === "undefined") return () => list2.removeEventListener("scroll", measure);
1461
+ const observer = new ResizeObserver(measure);
1462
+ observer.observe(list2);
1463
+ for (const tab of Array.from(list2.children)) observer.observe(tab);
1464
+ return () => {
1465
+ list2.removeEventListener("scroll", measure);
1466
+ observer.disconnect();
1467
+ };
1468
+ });
1469
+ (0, import_react21.useEffect)(() => {
1470
+ const list2 = listRef.current;
1471
+ const tab = list2?.querySelector('[role="tab"][aria-selected="true"]');
1472
+ if (!scroll || !list2 || !tab) return;
1473
+ const outer = list2.getBoundingClientRect();
1474
+ const inner = tab.getBoundingClientRect();
1475
+ const reserve = list2.scrollWidth > list2.clientWidth ? Number.parseFloat(getComputedStyle(list2).getPropertyValue("--uix-control-h")) || 0 : 0;
1476
+ if (inner.left < outer.left + reserve) list2.scrollBy({ left: inner.left - outer.left - reserve });
1477
+ else if (inner.right > outer.right - reserve) list2.scrollBy({ left: inner.right - outer.right + reserve });
1478
+ }, [scroll, value]);
1479
+ const page = (direction) => {
1480
+ const list2 = listRef.current;
1481
+ if (!list2) return;
1482
+ const rtl = getComputedStyle(list2).direction === "rtl";
1483
+ list2.scrollBy({ left: direction * (rtl ? -1 : 1) * list2.clientWidth * 0.8 });
1484
+ };
1404
1485
  const onKeyDown = (e) => {
1405
1486
  const items = Array.from(
1406
1487
  listRef.current?.querySelectorAll('[role="tab"]:not(:disabled)') ?? []
@@ -1427,27 +1508,55 @@ function Tabs({ variant = "line", value, onChange, children, className }) {
1427
1508
  }
1428
1509
  e.preventDefault();
1429
1510
  const target = items[next];
1430
- if (target) {
1431
- target.focus();
1432
- target.click();
1433
- }
1511
+ if (!target) return;
1512
+ target.focus();
1513
+ if (activation === "automatic") target.click();
1434
1514
  };
1515
+ const list = /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1516
+ "div",
1517
+ {
1518
+ ref: listRef,
1519
+ role: "tablist",
1520
+ className: cx("uix-tabs", `uix-tabs--${variant}`, scroll && "uix-tabs--scroll", className),
1521
+ onKeyDown,
1522
+ children: tabs
1523
+ }
1524
+ );
1435
1525
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(TabsCtx.Provider, { value: contextValue, children: [
1436
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1437
- "div",
1438
- {
1439
- ref: listRef,
1440
- role: "tablist",
1441
- className: cx("uix-tabs", `uix-tabs--${variant}`, className),
1442
- onKeyDown,
1443
- children: tabs
1444
- }
1445
- ),
1526
+ scroll ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "uix-tabs-scroller", children: [
1527
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1528
+ "button",
1529
+ {
1530
+ type: "button",
1531
+ className: "uix-tabs-scroller__prev",
1532
+ "aria-hidden": "true",
1533
+ tabIndex: -1,
1534
+ hidden: !hidden.start,
1535
+ onMouseDown: (e) => e.preventDefault(),
1536
+ onClick: () => page(-1),
1537
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Chevron, { d: "m15 18-6-6 6-6" })
1538
+ }
1539
+ ),
1540
+ list,
1541
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1542
+ "button",
1543
+ {
1544
+ type: "button",
1545
+ className: "uix-tabs-scroller__next",
1546
+ "aria-hidden": "true",
1547
+ tabIndex: -1,
1548
+ hidden: !hidden.end,
1549
+ onMouseDown: (e) => e.preventDefault(),
1550
+ onClick: () => page(1),
1551
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Chevron, { d: "m9 18 6-6-6-6" })
1552
+ }
1553
+ )
1554
+ ] }) : list,
1446
1555
  panels
1447
1556
  ] });
1448
1557
  }
1449
1558
  function Tab({ value, children, disabled, className, onClick, ...props }) {
1450
- const ctx = (0, import_react20.useContext)(TabsCtx);
1559
+ const ctx = (0, import_react21.useContext)(TabsCtx);
1451
1560
  const selected = ctx.value === value;
1452
1561
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1453
1562
  "button",
@@ -1469,7 +1578,7 @@ function Tab({ value, children, disabled, className, onClick, ...props }) {
1469
1578
  );
1470
1579
  }
1471
1580
  function TabPanel({ value, children, keepMounted, ...props }) {
1472
- const ctx = (0, import_react20.useContext)(TabsCtx);
1581
+ const ctx = (0, import_react21.useContext)(TabsCtx);
1473
1582
  const selected = ctx.value === value;
1474
1583
  if (!selected && !keepMounted) return null;
1475
1584
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
@@ -1487,7 +1596,7 @@ function TabPanel({ value, children, keepMounted, ...props }) {
1487
1596
  }
1488
1597
 
1489
1598
  // src/components/AppShell.tsx
1490
- var import_react21 = require("react");
1599
+ var import_react22 = require("react");
1491
1600
  var import_jsx_runtime25 = require("react/jsx-runtime");
1492
1601
  function AppShell({
1493
1602
  nav,
@@ -1499,11 +1608,13 @@ function AppShell({
1499
1608
  sidebar,
1500
1609
  topbar,
1501
1610
  children,
1611
+ skipToContentLabel = "Skip to content",
1612
+ exitFocusLabel = "Esc \xB7 Exit focus",
1502
1613
  className,
1503
1614
  ...props
1504
1615
  }) {
1505
1616
  const navState = nav ?? (collapsed ? "rail" : "full");
1506
- (0, import_react21.useEffect)(() => {
1617
+ (0, import_react22.useEffect)(() => {
1507
1618
  if (!focus || !onExitFocus) return;
1508
1619
  const onKey = (e) => {
1509
1620
  if (e.key === "Escape") onExitFocus();
@@ -1520,18 +1631,18 @@ function AppShell({
1520
1631
  "data-focus": focus || void 0,
1521
1632
  ...props,
1522
1633
  children: [
1523
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { className: "uix-skiplink", href: `#${mainId}`, children: "Skip to content" }),
1634
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { className: "uix-skiplink", href: `#${mainId}`, children: skipToContentLabel }),
1524
1635
  sidebar && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "uix-shell__sidebar", children: sidebar }),
1525
1636
  topbar && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "uix-shell__topbar", children: topbar }),
1526
1637
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("main", { id: mainId, tabIndex: -1, className: cx("uix-shell__main", mainBleed && "uix-shell__main--bleed"), children }),
1527
- 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" }) })
1638
+ 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: exitFocusLabel }) })
1528
1639
  ]
1529
1640
  }
1530
1641
  );
1531
1642
  }
1532
1643
 
1533
1644
  // src/components/Sidebar.tsx
1534
- var import_react22 = require("react");
1645
+ var import_react23 = require("react");
1535
1646
  var import_jsx_runtime26 = require("react/jsx-runtime");
1536
1647
  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" }) });
1537
1648
  function Sidebar({ collapsed, nav, onToggle, brand, toggleIcon, children, expandLabel = "Expand sidebar", collapseLabel = "Collapse sidebar", className, ...props }) {
@@ -1587,12 +1698,12 @@ function NavItem({ icon, badge, active, as: Tag = "a", children, className, ...p
1587
1698
  );
1588
1699
  }
1589
1700
  function NavGroup({ icon, label, children, defaultExpanded = true, expanded: controlledExpanded, onExpandedChange }) {
1590
- const [internalExpanded, setInternalExpanded] = (0, import_react22.useState)(defaultExpanded);
1701
+ const [internalExpanded, setInternalExpanded] = (0, import_react23.useState)(defaultExpanded);
1591
1702
  const expanded = controlledExpanded ?? internalExpanded;
1592
- const panelId = (0, import_react22.useId)();
1593
- const triggerRef = (0, import_react22.useRef)(null);
1594
- const panelRef = (0, import_react22.useRef)(null);
1595
- (0, import_react22.useEffect)(() => {
1703
+ const panelId = (0, import_react23.useId)();
1704
+ const triggerRef = (0, import_react23.useRef)(null);
1705
+ const panelRef = (0, import_react23.useRef)(null);
1706
+ (0, import_react23.useEffect)(() => {
1596
1707
  panelRef.current?.toggleAttribute("inert", !expanded);
1597
1708
  if (!expanded && panelRef.current?.contains(document.activeElement)) triggerRef.current?.focus();
1598
1709
  }, [expanded]);
@@ -1670,10 +1781,71 @@ function StarButton({
1670
1781
  );
1671
1782
  }
1672
1783
 
1673
- // src/components/NavFavourites.tsx
1674
- var import_react23 = require("react");
1784
+ // src/components/CopyButton.tsx
1785
+ var import_react24 = require("react");
1786
+
1787
+ // src/copy-model.ts
1788
+ async function copyText(value, clipboard = globalThis.navigator?.clipboard) {
1789
+ if (!clipboard || typeof clipboard.writeText !== "function") return false;
1790
+ try {
1791
+ await clipboard.writeText(value);
1792
+ return true;
1793
+ } catch {
1794
+ return false;
1795
+ }
1796
+ }
1797
+
1798
+ // src/components/CopyButton.tsx
1675
1799
  var import_jsx_runtime28 = require("react/jsx-runtime");
1676
- var ChevronDownIcon = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1800
+ var CONFIRM_MS = 1500;
1801
+ var CopyGlyph = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1802
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2" }),
1803
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
1804
+ ] });
1805
+ var CheckGlyph = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M20 6 9 17l-5-5" }) });
1806
+ function CopyButton({ value, label, copiedLabel, failedLabel, className }) {
1807
+ const [outcome, setOutcome] = (0, import_react24.useState)("idle");
1808
+ const copied = outcome === "copied";
1809
+ const timer = (0, import_react24.useRef)(void 0);
1810
+ const mounted = (0, import_react24.useRef)(true);
1811
+ (0, import_react24.useEffect)(() => {
1812
+ mounted.current = true;
1813
+ return () => {
1814
+ mounted.current = false;
1815
+ clearTimeout(timer.current);
1816
+ };
1817
+ }, []);
1818
+ const onClick = async () => {
1819
+ const ok = await copyText(value);
1820
+ if (!mounted.current) return;
1821
+ clearTimeout(timer.current);
1822
+ if (!ok && !failedLabel) {
1823
+ setOutcome("idle");
1824
+ return;
1825
+ }
1826
+ setOutcome(ok ? "copied" : "failed");
1827
+ timer.current = setTimeout(() => setOutcome("idle"), CONFIRM_MS);
1828
+ };
1829
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
1830
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1831
+ "button",
1832
+ {
1833
+ type: "button",
1834
+ className: cx("uix-btn", "uix-btn--ghost", "uix-btn--icon", "uix-btn--sm", "uix-copy-button", className),
1835
+ "aria-label": label,
1836
+ "data-copied": copied || void 0,
1837
+ onClick,
1838
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(CheckGlyph, {}) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(CopyGlyph, {})
1839
+ }
1840
+ ),
1841
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { role: "status", className: "uix-visually-hidden", children: outcome === "copied" ? copiedLabel : outcome === "failed" ? failedLabel : "" })
1842
+ ] });
1843
+ }
1844
+
1845
+ // src/components/NavFavourites.tsx
1846
+ var import_react25 = require("react");
1847
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1848
+ var ChevronDownIcon = () => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1677
1849
  "svg",
1678
1850
  {
1679
1851
  width: "12",
@@ -1686,10 +1858,10 @@ var ChevronDownIcon = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1686
1858
  strokeLinejoin: "round",
1687
1859
  "aria-hidden": "true",
1688
1860
  className: "uix-favourites__chevron",
1689
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "m6 9 6 6 6-6" })
1861
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "m6 9 6 6 6-6" })
1690
1862
  }
1691
1863
  );
1692
- var ChevronRightIcon = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1864
+ var ChevronRightIcon = () => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1693
1865
  "svg",
1694
1866
  {
1695
1867
  width: "12",
@@ -1702,10 +1874,10 @@ var ChevronRightIcon = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1702
1874
  strokeLinejoin: "round",
1703
1875
  "aria-hidden": "true",
1704
1876
  className: "uix-favourites__chevron",
1705
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "m9 18 6-6-6-6" })
1877
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { d: "m9 18 6-6-6-6" })
1706
1878
  }
1707
1879
  );
1708
- var MoreIcon = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1880
+ var MoreIcon = () => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1709
1881
  "svg",
1710
1882
  {
1711
1883
  width: "14",
@@ -1718,9 +1890,9 @@ var MoreIcon = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1718
1890
  strokeLinejoin: "round",
1719
1891
  "aria-hidden": "true",
1720
1892
  children: [
1721
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("circle", { cx: "12", cy: "12", r: "1" }),
1722
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("circle", { cx: "12", cy: "5", r: "1" }),
1723
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("circle", { cx: "12", cy: "19", r: "1" })
1893
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("circle", { cx: "12", cy: "12", r: "1" }),
1894
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("circle", { cx: "12", cy: "5", r: "1" }),
1895
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("circle", { cx: "12", cy: "19", r: "1" })
1724
1896
  ]
1725
1897
  }
1726
1898
  );
@@ -1734,14 +1906,14 @@ function NavFavourites({
1734
1906
  emptyReason,
1735
1907
  className
1736
1908
  }) {
1737
- const regionId = (0, import_react23.useId)();
1738
- const headerRef = (0, import_react23.useRef)(null);
1739
- const regionRef = (0, import_react23.useRef)(null);
1740
- const [announcement, setAnnouncement] = (0, import_react23.useState)("");
1741
- const focusAfterRef = (0, import_react23.useRef)(null);
1742
- const triggerRefs = (0, import_react23.useRef)(/* @__PURE__ */ new Map());
1743
- const order = (0, import_react23.useMemo)(() => items.map((item) => item.id), [items]);
1744
- (0, import_react23.useEffect)(() => {
1909
+ const regionId = (0, import_react25.useId)();
1910
+ const headerRef = (0, import_react25.useRef)(null);
1911
+ const regionRef = (0, import_react25.useRef)(null);
1912
+ const [announcement, setAnnouncement] = (0, import_react25.useState)("");
1913
+ const focusAfterRef = (0, import_react25.useRef)(null);
1914
+ const triggerRefs = (0, import_react25.useRef)(/* @__PURE__ */ new Map());
1915
+ const order = (0, import_react25.useMemo)(() => items.map((item) => item.id), [items]);
1916
+ (0, import_react25.useEffect)(() => {
1745
1917
  const id = focusAfterRef.current;
1746
1918
  if (!id) return;
1747
1919
  focusAfterRef.current = null;
@@ -1758,7 +1930,7 @@ function NavFavourites({
1758
1930
  }
1759
1931
  onToggleCollapsed?.();
1760
1932
  };
1761
- const move = (0, import_react23.useCallback)((id, dir) => {
1933
+ const move = (0, import_react25.useCallback)((id, dir) => {
1762
1934
  const idx = order.indexOf(id);
1763
1935
  const next = idx + dir;
1764
1936
  if (idx < 0 || next < 0 || next >= order.length) return;
@@ -1771,19 +1943,19 @@ function NavFavourites({
1771
1943
  if (moved) setAnnouncement(`${moved.label} moved to position ${next + 1} of ${order.length}`);
1772
1944
  onReorder(reordered);
1773
1945
  }, [onReorder, order]);
1774
- const remove = (0, import_react23.useCallback)((id) => {
1946
+ const remove = (0, import_react25.useCallback)((id) => {
1775
1947
  const idx = order.indexOf(id);
1776
1948
  const neighbour = order[idx + 1] ?? order[idx - 1] ?? null;
1777
1949
  focusAfterRef.current = neighbour;
1778
1950
  onRemove(id);
1779
1951
  }, [onRemove, order]);
1780
- const registerTrigger = (0, import_react23.useCallback)((id, element) => {
1952
+ const registerTrigger = (0, import_react25.useCallback)((id, element) => {
1781
1953
  if (element) triggerRefs.current.set(id, element);
1782
1954
  else triggerRefs.current.delete(id);
1783
1955
  }, []);
1784
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cx("uix-favourites", className), children: [
1785
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
1786
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1956
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: cx("uix-favourites", className), children: [
1957
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
1958
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1787
1959
  "button",
1788
1960
  {
1789
1961
  ref: headerRef,
@@ -1793,26 +1965,26 @@ function NavFavourites({
1793
1965
  onClick: handleToggle,
1794
1966
  className: "uix-favourites__heading uix-text-eyebrow",
1795
1967
  children: [
1796
- collapsed ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRightIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronDownIcon, {}),
1968
+ collapsed ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ChevronRightIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ChevronDownIcon, {}),
1797
1969
  labels.heading
1798
1970
  ]
1799
1971
  }
1800
1972
  ),
1801
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1973
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1802
1974
  "ul",
1803
1975
  {
1804
1976
  ref: regionRef,
1805
1977
  id: regionId,
1806
1978
  hidden: collapsed,
1807
1979
  className: "uix-favourites__list",
1808
- children: items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1980
+ children: items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1809
1981
  "li",
1810
1982
  {
1811
1983
  className: "uix-favourites__empty uix-text-meta",
1812
1984
  "data-empty-reason": emptyReason,
1813
1985
  children: labels.empty
1814
1986
  }
1815
- ) : items.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1987
+ ) : items.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1816
1988
  FavouriteRow,
1817
1989
  {
1818
1990
  item,
@@ -1829,7 +2001,7 @@ function NavFavourites({
1829
2001
  )
1830
2002
  ] });
1831
2003
  }
1832
- var FavouriteRow = (0, import_react23.memo)(function FavouriteRow2({
2004
+ var FavouriteRow = (0, import_react25.memo)(function FavouriteRow2({
1833
2005
  item,
1834
2006
  isFirst,
1835
2007
  isLast,
@@ -1838,17 +2010,17 @@ var FavouriteRow = (0, import_react23.memo)(function FavouriteRow2({
1838
2010
  onRemove,
1839
2011
  registerTrigger
1840
2012
  }) {
1841
- const [open, setOpen] = (0, import_react23.useState)(false);
1842
- const menuId = (0, import_react23.useId)();
1843
- const triggerRef = (0, import_react23.useRef)(null);
1844
- const itemRefs = (0, import_react23.useRef)([]);
2013
+ const [open, setOpen] = (0, import_react25.useState)(false);
2014
+ const menuId = (0, import_react25.useId)();
2015
+ const triggerRef = (0, import_react25.useRef)(null);
2016
+ const itemRefs = (0, import_react25.useRef)([]);
1845
2017
  const optionsTemplate = labels.options ?? "{label} favourite options";
1846
2018
  const actions = [
1847
2019
  ...isFirst ? [] : [{ label: labels.moveUp, onSelect: () => onMove(item.id, -1) }],
1848
2020
  ...isLast ? [] : [{ label: labels.moveDown, onSelect: () => onMove(item.id, 1) }],
1849
2021
  { label: labels.remove.replace("{label}", item.label), onSelect: () => onRemove(item.id) }
1850
2022
  ];
1851
- (0, import_react23.useEffect)(() => {
2023
+ (0, import_react25.useEffect)(() => {
1852
2024
  if (open) itemRefs.current[0]?.focus();
1853
2025
  }, [open]);
1854
2026
  const closeAndReturnFocus = () => {
@@ -1889,14 +2061,14 @@ var FavouriteRow = (0, import_react23.memo)(function FavouriteRow2({
1889
2061
  };
1890
2062
  return (
1891
2063
  // biome-ignore lint/a11y/noStaticElementInteractions: keyboard accelerators on the row; the focusable controls inside carry their own semantics.
1892
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
2064
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1893
2065
  "li",
1894
2066
  {
1895
2067
  className: "uix-favourites__row",
1896
2068
  onKeyDown: onRowKeyDown,
1897
2069
  children: [
1898
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "uix-favourites__link", children: item.link }),
1899
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2070
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-favourites__link", children: item.link }),
2071
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1900
2072
  "button",
1901
2073
  {
1902
2074
  ref: (el) => {
@@ -1910,11 +2082,11 @@ var FavouriteRow = (0, import_react23.memo)(function FavouriteRow2({
1910
2082
  "aria-label": optionsTemplate.replace("{label}", item.label),
1911
2083
  onClick: () => setOpen((v) => !v),
1912
2084
  className: "uix-favourites__menu-trigger",
1913
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MoreIcon, {})
2085
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(MoreIcon, {})
1914
2086
  }
1915
2087
  ),
1916
- open ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
1917
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2088
+ open ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
2089
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1918
2090
  "div",
1919
2091
  {
1920
2092
  "aria-hidden": "true",
@@ -1923,7 +2095,7 @@ var FavouriteRow = (0, import_react23.memo)(function FavouriteRow2({
1923
2095
  className: "uix-favourites__backdrop"
1924
2096
  }
1925
2097
  ),
1926
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2098
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1927
2099
  "ul",
1928
2100
  {
1929
2101
  id: menuId,
@@ -1931,7 +2103,7 @@ var FavouriteRow = (0, import_react23.memo)(function FavouriteRow2({
1931
2103
  "aria-label": optionsTemplate.replace("{label}", item.label),
1932
2104
  onKeyDown: onMenuKeyDown,
1933
2105
  className: "uix-favourites__menu",
1934
- children: actions.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { role: "presentation", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2106
+ children: actions.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("li", { role: "presentation", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1935
2107
  "button",
1936
2108
  {
1937
2109
  ref: (el) => {
@@ -1958,19 +2130,19 @@ var FavouriteRow = (0, import_react23.memo)(function FavouriteRow2({
1958
2130
  });
1959
2131
 
1960
2132
  // src/components/Alert.tsx
1961
- var import_jsx_runtime29 = require("react/jsx-runtime");
2133
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1962
2134
  function Alert({ tone, title, icon, children, className, ...props }) {
1963
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
2135
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1964
2136
  "div",
1965
2137
  {
1966
2138
  className: cx("uix-alert", tone && tone !== "neutral" && `uix-alert--${tone}`, className),
1967
2139
  role: tone === "danger" || tone === "warning" ? "alert" : "status",
1968
2140
  ...props,
1969
2141
  children: [
1970
- icon && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__icon", children: icon }),
1971
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
1972
- title && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__title", children: title }),
1973
- children && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "uix-alert__body", children })
2142
+ icon && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "uix-alert__icon", children: icon }),
2143
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { children: [
2144
+ title && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "uix-alert__title", children: title }),
2145
+ children && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "uix-alert__body", children })
1974
2146
  ] })
1975
2147
  ]
1976
2148
  }
@@ -1978,28 +2150,28 @@ function Alert({ tone, title, icon, children, className, ...props }) {
1978
2150
  }
1979
2151
 
1980
2152
  // src/components/Spinner.tsx
1981
- var import_jsx_runtime30 = require("react/jsx-runtime");
2153
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1982
2154
  function Spinner({ size = "md", accent, label, className, ...props }) {
1983
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2155
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1984
2156
  "span",
1985
2157
  {
1986
2158
  className: cx("uix-spinner", accent && "uix-spinner--accent", size === "lg" && "uix-spinner--lg", className),
1987
2159
  role: "status",
1988
2160
  ...props,
1989
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "uix-visually-hidden", children: label ?? "Loading\u2026" })
2161
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "uix-visually-hidden", children: label ?? "Loading\u2026" })
1990
2162
  }
1991
2163
  );
1992
2164
  }
1993
2165
 
1994
2166
  // src/components/Toast.tsx
1995
- var import_react24 = require("react");
1996
- var import_jsx_runtime31 = require("react/jsx-runtime");
1997
- var ToasterContext = (0, import_react24.createContext)(null);
1998
- function Toast({ title, message, tone, icon, onClose, leaving, className, ...props }) {
2167
+ var import_react26 = require("react");
2168
+ var import_jsx_runtime32 = require("react/jsx-runtime");
2169
+ var ToasterContext = (0, import_react26.createContext)(null);
2170
+ function Toast({ title, message, tone, icon, onClose, leaving, dismissLabel = "Dismiss", className, ...props }) {
1999
2171
  const assertive = tone === "danger";
2000
- const toaster = (0, import_react24.useContext)(ToasterContext);
2001
- const bodyRef = (0, import_react24.useRef)(null);
2002
- (0, import_react24.useEffect)(() => {
2172
+ const toaster = (0, import_react26.useContext)(ToasterContext);
2173
+ const bodyRef = (0, import_react26.useRef)(null);
2174
+ (0, import_react26.useEffect)(() => {
2003
2175
  if (assertive || !toaster) return;
2004
2176
  const text = bodyRef.current?.textContent?.trim();
2005
2177
  if (text) toaster.announce(text);
@@ -2017,7 +2189,7 @@ function Toast({ title, message, tone, icon, onClose, leaving, className, ...pro
2017
2189
  onClose?.();
2018
2190
  };
2019
2191
  const ownLiveRegion = assertive || !toaster;
2020
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
2192
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
2021
2193
  "div",
2022
2194
  {
2023
2195
  className: cx("uix-toast", tone && `uix-toast--${tone}`, className),
@@ -2026,40 +2198,40 @@ function Toast({ title, message, tone, icon, onClose, leaving, className, ...pro
2026
2198
  "aria-live": ownLiveRegion ? assertive ? "assertive" : "polite" : void 0,
2027
2199
  ...props,
2028
2200
  children: [
2029
- icon && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "uix-toast__icon", "aria-hidden": "true", children: icon }),
2030
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "uix-toast__body", ref: bodyRef, children: [
2031
- title && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "uix-toast__title", children: title }),
2032
- message && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "uix-toast__msg", children: message })
2201
+ icon && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "uix-toast__icon", "aria-hidden": "true", children: icon }),
2202
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "uix-toast__body", ref: bodyRef, children: [
2203
+ title && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "uix-toast__title", children: title }),
2204
+ message && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "uix-toast__msg", children: message })
2033
2205
  ] }),
2034
- onClose && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { className: "uix-toast__close", onClick: handleClose, "aria-label": "Dismiss", children: "\xD7" })
2206
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { className: "uix-toast__close", onClick: handleClose, "aria-label": dismissLabel, children: "\xD7" })
2035
2207
  ]
2036
2208
  }
2037
2209
  );
2038
2210
  }
2039
- function Toaster({ children, className, ...props }) {
2040
- const [announced, setAnnounced] = (0, import_react24.useState)("");
2041
- const clearTimer = (0, import_react24.useRef)(null);
2042
- const announce = (0, import_react24.useCallback)((text) => {
2211
+ function Toaster({ children, regionLabel = "Notifications", className, ...props }) {
2212
+ const [announced, setAnnounced] = (0, import_react26.useState)("");
2213
+ const clearTimer = (0, import_react26.useRef)(null);
2214
+ const announce = (0, import_react26.useCallback)((text) => {
2043
2215
  setAnnounced((cur) => cur ? `${cur} ${text}` : text);
2044
2216
  if (clearTimer.current != null) clearTimeout(clearTimer.current);
2045
2217
  clearTimer.current = window.setTimeout(() => setAnnounced(""), 3e3);
2046
2218
  }, []);
2047
- (0, import_react24.useEffect)(() => () => {
2219
+ (0, import_react26.useEffect)(() => () => {
2048
2220
  if (clearTimer.current != null) clearTimeout(clearTimer.current);
2049
2221
  }, []);
2050
- const ctx = (0, import_react24.useMemo)(() => ({ announce }), [announce]);
2051
- 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: [
2052
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "uix-visually-hidden", role: "status", "aria-live": "polite", children: announced }),
2222
+ const ctx = (0, import_react26.useMemo)(() => ({ announce }), [announce]);
2223
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ToasterContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cx("uix-toaster", className), role: "region", "aria-label": regionLabel, ...props, children: [
2224
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "uix-visually-hidden", role: "status", "aria-live": "polite", children: announced }),
2053
2225
  children
2054
2226
  ] }) });
2055
2227
  }
2056
2228
 
2057
2229
  // src/components/Table.tsx
2058
- var import_react25 = require("react");
2059
- var import_jsx_runtime32 = require("react/jsx-runtime");
2060
- var TableWrap = (0, import_react25.forwardRef)(function TableWrap2({ announcement, children, className, ...props }, ref) {
2061
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { ref, className: cx("uix-table-wrap", className), ...props, children: [
2062
- announcement != null && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
2230
+ var import_react27 = require("react");
2231
+ var import_jsx_runtime33 = require("react/jsx-runtime");
2232
+ var TableWrap = (0, import_react27.forwardRef)(function TableWrap2({ announcement, children, className, ...props }, ref) {
2233
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { ref, className: cx("uix-table-wrap", className), ...props, children: [
2234
+ announcement != null && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
2063
2235
  children
2064
2236
  ] });
2065
2237
  });
@@ -2074,7 +2246,7 @@ function Table({
2074
2246
  children,
2075
2247
  ...props
2076
2248
  }) {
2077
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2249
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2078
2250
  "table",
2079
2251
  {
2080
2252
  className: cx(
@@ -2093,7 +2265,7 @@ function Table({
2093
2265
  );
2094
2266
  }
2095
2267
  function Th({ sortable, sortDirection, sortOrder, onSort, className, children, onClick, ...props }) {
2096
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2268
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2097
2269
  "th",
2098
2270
  {
2099
2271
  className,
@@ -2102,15 +2274,15 @@ function Th({ sortable, sortDirection, sortOrder, onSort, className, children, o
2102
2274
  "aria-sort": sortDirection && sortDirection !== "none" ? sortDirection : void 0,
2103
2275
  onClick: sortable && onSort ? void 0 : onClick,
2104
2276
  ...props,
2105
- children: sortable ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { type: "button", className: "uix-th__sortbtn", onClick: onSort, children }) : children
2277
+ children: sortable ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: "uix-th__sortbtn", onClick: onSort, children }) : children
2106
2278
  }
2107
2279
  );
2108
2280
  }
2109
2281
  function Td({ pinned, className, children, ...props }) {
2110
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className, "data-pinned": pinned || void 0, ...props, children });
2282
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("td", { className, "data-pinned": pinned || void 0, ...props, children });
2111
2283
  }
2112
2284
  function Tr({ selected, pinned, className, children, ...props }) {
2113
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2285
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2114
2286
  "tr",
2115
2287
  {
2116
2288
  className,
@@ -2121,53 +2293,50 @@ function Tr({ selected, pinned, className, children, ...props }) {
2121
2293
  }
2122
2294
  );
2123
2295
  }
2124
- function BulkBar({ count, children, className, ...props }) {
2125
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cx("uix-bulkbar", className), role: "toolbar", "aria-label": "Bulk actions", ...props, children: [
2126
- count != null && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "uix-bulkbar__count", children: [
2127
- count,
2128
- " selected"
2129
- ] }),
2130
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "uix-bulkbar__spacer" }),
2296
+ function BulkBar({ count, children, label = "Bulk actions", selectedLabel = (n) => `${n} selected`, className, ...props }) {
2297
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: cx("uix-bulkbar", className), role: "toolbar", "aria-label": label, ...props, children: [
2298
+ count != null && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "uix-bulkbar__count", children: selectedLabel(count) }),
2299
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "uix-bulkbar__spacer" }),
2131
2300
  children
2132
2301
  ] });
2133
2302
  }
2134
2303
  function RowActions({ children, className, ...props }) {
2135
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: cx("uix-table__actions", className), ...props, children });
2304
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("td", { className: cx("uix-table__actions", className), ...props, children });
2136
2305
  }
2137
2306
  function RowAction({ children, className, type = "button", ...props }) {
2138
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { type, className: cx("uix-rowact", className), ...props, children });
2307
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type, className: cx("uix-rowact", className), ...props, children });
2139
2308
  }
2140
- function ExpandToggle({ expanded, controls, className, type = "button", ...props }) {
2141
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
2309
+ function ExpandToggle({ expanded, controls, expandLabel = "Expand row", collapseLabel = "Collapse row", className, type = "button", ...props }) {
2310
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2142
2311
  "button",
2143
2312
  {
2144
2313
  type,
2145
2314
  className: cx("uix-table__expand", className),
2146
2315
  "aria-expanded": expanded,
2147
2316
  "aria-controls": controls,
2148
- "aria-label": expanded ? "Collapse row" : "Expand row",
2317
+ "aria-label": expanded ? collapseLabel : expandLabel,
2149
2318
  ...props,
2150
- 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" }) })
2319
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.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_runtime33.jsx)("path", { d: "M6 4l4 4-4 4" }) })
2151
2320
  }
2152
2321
  );
2153
2322
  }
2154
2323
  function CellStrong({ children, className, ...props }) {
2155
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cx("uix-cell-strong", className), ...props, children });
2324
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: cx("uix-cell-strong", className), ...props, children });
2156
2325
  }
2157
2326
  function CellSub({ children, className, ...props }) {
2158
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cx("uix-cell-sub", className), ...props, children });
2327
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: cx("uix-cell-sub", className), ...props, children });
2159
2328
  }
2160
2329
  function Mark({ children, className, ...props }) {
2161
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("mark", { className: cx("uix-mark", className), ...props, children });
2330
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("mark", { className: cx("uix-mark", className), ...props, children });
2162
2331
  }
2163
2332
  function Highlighted({ text, query }) {
2164
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: highlightSegments(text, query).map(
2165
- (seg, i) => seg.match ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("mark", { className: "uix-mark", children: seg.text }, i) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: seg.text }, i)
2333
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_jsx_runtime33.Fragment, { children: highlightSegments(text, query).map(
2334
+ (seg, i) => seg.match ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("mark", { className: "uix-mark", children: seg.text }, i) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: seg.text }, i)
2166
2335
  ) });
2167
2336
  }
2168
2337
 
2169
2338
  // src/components/Pagination.tsx
2170
- var import_jsx_runtime33 = require("react/jsx-runtime");
2339
+ var import_jsx_runtime34 = require("react/jsx-runtime");
2171
2340
  function getPageNumbers(page, total) {
2172
2341
  if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
2173
2342
  const pages = [1];
@@ -2179,21 +2348,27 @@ function getPageNumbers(page, total) {
2179
2348
  pages.push(total);
2180
2349
  return pages;
2181
2350
  }
2182
- function Pagination({ page, pageCount, onChange, className, ...props }) {
2351
+ var DEFAULT_PAGINATION_LABELS = {
2352
+ region: "Pagination",
2353
+ previous: "Previous page",
2354
+ next: "Next page"
2355
+ };
2356
+ function Pagination({ page, pageCount, onChange, labels: labelOverrides, className, ...props }) {
2357
+ const labels = { ...DEFAULT_PAGINATION_LABELS, ...labelOverrides };
2183
2358
  const pages = getPageNumbers(page, pageCount);
2184
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("nav", { "aria-label": "Pagination", className: cx("uix-pagination", className), ...props, children: [
2185
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2359
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("nav", { "aria-label": labels.region, className: cx("uix-pagination", className), ...props, children: [
2360
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2186
2361
  "button",
2187
2362
  {
2188
2363
  className: "uix-pagination__btn",
2189
2364
  onClick: () => onChange(page - 1),
2190
2365
  disabled: page <= 1,
2191
- "aria-label": "Previous page",
2366
+ "aria-label": labels.previous,
2192
2367
  children: "\u2039"
2193
2368
  }
2194
2369
  ),
2195
2370
  pages.map(
2196
- (p, i) => p === "ellipsis" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "uix-pagination__ellipsis", children: "\u2026" }, `e${i}`) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2371
+ (p, i) => p === "ellipsis" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "uix-pagination__ellipsis", children: "\u2026" }, `e${i}`) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2197
2372
  "button",
2198
2373
  {
2199
2374
  className: "uix-pagination__btn",
@@ -2204,13 +2379,13 @@ function Pagination({ page, pageCount, onChange, className, ...props }) {
2204
2379
  p
2205
2380
  )
2206
2381
  ),
2207
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2382
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2208
2383
  "button",
2209
2384
  {
2210
2385
  className: "uix-pagination__btn",
2211
2386
  onClick: () => onChange(page + 1),
2212
2387
  disabled: page >= pageCount,
2213
- "aria-label": "Next page",
2388
+ "aria-label": labels.next,
2214
2389
  children: "\u203A"
2215
2390
  }
2216
2391
  )
@@ -2218,15 +2393,15 @@ function Pagination({ page, pageCount, onChange, className, ...props }) {
2218
2393
  }
2219
2394
 
2220
2395
  // src/components/StatusPill.tsx
2221
- var import_jsx_runtime34 = require("react/jsx-runtime");
2396
+ var import_jsx_runtime35 = require("react/jsx-runtime");
2222
2397
  function StatusPill({ tone = "neutral", treatment = "filled", dot, children, className, ...props }) {
2223
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
2398
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
2224
2399
  "span",
2225
2400
  {
2226
2401
  className: cx("uix-pill", `uix-pill--${tone}`, treatment === "outline" && "uix-pill--outline", className),
2227
2402
  ...props,
2228
2403
  children: [
2229
- dot && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "uix-pill__dot", "aria-hidden": "true" }),
2404
+ dot && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "uix-pill__dot", "aria-hidden": "true" }),
2230
2405
  children
2231
2406
  ]
2232
2407
  }
@@ -2234,11 +2409,11 @@ function StatusPill({ tone = "neutral", treatment = "filled", dot, children, cla
2234
2409
  }
2235
2410
 
2236
2411
  // src/components/Progress.tsx
2237
- var import_jsx_runtime35 = require("react/jsx-runtime");
2412
+ var import_jsx_runtime36 = require("react/jsx-runtime");
2238
2413
  function Progress({ value = 0, max = 100, indeterminate, label, className, ...props }) {
2239
2414
  const clamped = Math.max(0, Math.min(max || 100, value));
2240
2415
  const pct = clamped / (max || 100) * 100;
2241
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
2416
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2242
2417
  "div",
2243
2418
  {
2244
2419
  role: "progressbar",
@@ -2248,33 +2423,34 @@ function Progress({ value = 0, max = 100, indeterminate, label, className, ...pr
2248
2423
  "aria-label": label,
2249
2424
  className: cx("uix-progress", indeterminate && "uix-progress--indeterminate", className),
2250
2425
  ...props,
2251
- children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "uix-progress__bar", style: indeterminate ? void 0 : { width: `${pct}%` } })
2426
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "uix-progress__bar", style: indeterminate ? void 0 : { width: `${pct}%` } })
2252
2427
  }
2253
2428
  );
2254
2429
  }
2255
2430
 
2256
2431
  // src/components/Meter.tsx
2257
- var import_jsx_runtime36 = require("react/jsx-runtime");
2432
+ var import_jsx_runtime37 = require("react/jsx-runtime");
2258
2433
  var toneText = {
2259
2434
  warning: "warning",
2260
2435
  danger: "critical",
2261
2436
  attention: "needs attention",
2262
2437
  overdue: "overdue"
2263
2438
  };
2264
- function Meter({ value = 0, tone, label, className, ...props }) {
2439
+ function Meter({ value = 0, tone, label, toneLabels, className, ...props }) {
2440
+ const spoken = { ...toneText, ...toneLabels };
2265
2441
  const pct = Math.max(0, Math.min(100, value));
2266
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2442
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2267
2443
  "div",
2268
2444
  {
2269
2445
  role: "meter",
2270
2446
  "aria-valuenow": pct,
2271
2447
  "aria-valuemin": 0,
2272
2448
  "aria-valuemax": 100,
2273
- "aria-valuetext": tone && tone !== "success" ? `${pct}%, ${toneText[tone]}` : void 0,
2449
+ "aria-valuetext": tone && tone !== "success" ? `${pct}%, ${spoken[tone]}` : void 0,
2274
2450
  "aria-label": label,
2275
2451
  className: cx("uix-meter", className),
2276
2452
  ...props,
2277
- children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2453
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2278
2454
  "div",
2279
2455
  {
2280
2456
  className: "uix-meter__fill",
@@ -2287,34 +2463,75 @@ function Meter({ value = 0, tone, label, className, ...props }) {
2287
2463
  }
2288
2464
 
2289
2465
  // src/components/Stat.tsx
2290
- var import_jsx_runtime37 = require("react/jsx-runtime");
2291
- function Stat({ label, value, icon, meta, trend, className, ...props }) {
2292
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: cx("uix-stat", className), ...props, children: [
2293
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "uix-stat__label", children: [
2294
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: label }),
2295
- icon
2466
+ var import_react28 = require("react");
2467
+ var import_jsx_runtime38 = require("react/jsx-runtime");
2468
+ var Chevron2 = () => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "uix-stat__chevron", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("path", { d: "m6 9 6 6 6-6" }) }) });
2469
+ var Stat = (0, import_react28.forwardRef)(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, className, onClick, ...props }, ref) {
2470
+ const id = (0, import_react28.useId)();
2471
+ const interactive = onActivate != null;
2472
+ const classes = cx(
2473
+ "uix-stat",
2474
+ tone !== "neutral" && `uix-stat--${tone}`,
2475
+ size === "compact" && "uix-stat--compact",
2476
+ interactive && "uix-stat--interactive",
2477
+ className
2478
+ );
2479
+ const Row = interactive ? "span" : "div";
2480
+ const body = /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
2481
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Row, { className: "uix-stat__label", children: [
2482
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { id: interactive ? `${id}-label` : void 0, children: label }),
2483
+ icon,
2484
+ interactive && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Chevron2, {})
2296
2485
  ] }),
2297
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "uix-stat__value", children: value }),
2298
- (meta != null || trend != null) && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "uix-stat__meta", children: [
2299
- trend != null && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`), children: [
2300
- /* @__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" }) }),
2301
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "uix-visually-hidden", children: trend.direction === "up" ? "up" : "down" }),
2486
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Row, { className: "uix-stat__value", id: interactive ? `${id}-value` : void 0, children: value }),
2487
+ (meta != null || trend != null) && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(Row, { className: "uix-stat__meta", id: interactive ? `${id}-meta` : void 0, children: [
2488
+ trend != null && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`), children: [
2489
+ /* @__PURE__ */ (0, import_jsx_runtime38.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_runtime38.jsx)("path", { d: "M12 19V5m-6 6 6-6 6 6" }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("path", { d: "M12 5v14m6-6-6 6-6-6" }) }),
2490
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "uix-visually-hidden", children: trend.direction === "up" ? trendLabels?.up ?? "up" : trendLabels?.down ?? "down" }),
2302
2491
  trend.label
2303
2492
  ] }),
2304
2493
  meta
2305
2494
  ] })
2306
2495
  ] });
2307
- }
2496
+ if (!interactive) {
2497
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { ref, className: classes, onClick, ...props, children: body });
2498
+ }
2499
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2500
+ "button",
2501
+ {
2502
+ type: "button",
2503
+ ...props,
2504
+ ref,
2505
+ className: classes,
2506
+ "aria-haspopup": "dialog",
2507
+ "aria-expanded": expanded,
2508
+ "aria-labelledby": `${id}-label ${id}-sep ${id}-value${activateLabel ? ` ${id}-action` : ""}`,
2509
+ "aria-describedby": meta != null || trend != null ? `${id}-meta` : void 0,
2510
+ onClick: (e) => {
2511
+ onClick?.(e);
2512
+ if (!e.defaultPrevented) onActivate();
2513
+ },
2514
+ children: [
2515
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { id: `${id}-sep`, className: "uix-visually-hidden", children: ":" }),
2516
+ activateLabel && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { id: `${id}-action`, className: "uix-visually-hidden", children: [
2517
+ ", ",
2518
+ activateLabel
2519
+ ] }),
2520
+ body
2521
+ ]
2522
+ }
2523
+ );
2524
+ });
2308
2525
 
2309
2526
  // src/components/Tooltip.tsx
2310
- var import_react26 = require("react");
2311
- var import_jsx_runtime38 = require("react/jsx-runtime");
2527
+ var import_react29 = require("react");
2528
+ var import_jsx_runtime39 = require("react/jsx-runtime");
2312
2529
  function Tooltip({ label, placement = "top", className, children, ...props }) {
2313
- const triggerRef = (0, import_react26.useRef)(null);
2314
- const bubbleRef = (0, import_react26.useRef)(null);
2315
- const closeTimer = (0, import_react26.useRef)(null);
2316
- const [open, setOpen] = (0, import_react26.useState)(false);
2317
- const id = (0, import_react26.useId)();
2530
+ const triggerRef = (0, import_react29.useRef)(null);
2531
+ const bubbleRef = (0, import_react29.useRef)(null);
2532
+ const closeTimer = (0, import_react29.useRef)(null);
2533
+ const [open, setOpen] = (0, import_react29.useState)(false);
2534
+ const id = (0, import_react29.useId)();
2318
2535
  useAnchoredPosition(triggerRef, bubbleRef, { open, placement, offset: 6 });
2319
2536
  const cancelClose = () => {
2320
2537
  if (closeTimer.current != null) {
@@ -2348,7 +2565,7 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2348
2565
  cancelClose();
2349
2566
  closeTimer.current = window.setTimeout(hide, 100);
2350
2567
  };
2351
- (0, import_react26.useEffect)(() => {
2568
+ (0, import_react29.useEffect)(() => {
2352
2569
  if (!open) return;
2353
2570
  const onKey = (e) => {
2354
2571
  if (e.key === "Escape") hide();
@@ -2356,7 +2573,7 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2356
2573
  document.addEventListener("keydown", onKey);
2357
2574
  return () => document.removeEventListener("keydown", onKey);
2358
2575
  }, [open]);
2359
- (0, import_react26.useEffect)(() => () => {
2576
+ (0, import_react29.useEffect)(() => () => {
2360
2577
  if (closeTimer.current != null) clearTimeout(closeTimer.current);
2361
2578
  const b = bubbleRef.current;
2362
2579
  if (b && b.matches(":popover-open")) {
@@ -2367,11 +2584,11 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2367
2584
  }
2368
2585
  }, []);
2369
2586
  const bubbleAttr = { popover: "manual" };
2370
- const single = (0, import_react26.isValidElement)(children);
2371
- const child = single ? (0, import_react26.cloneElement)(children, {
2587
+ const single = (0, import_react29.isValidElement)(children);
2588
+ const child = single ? (0, import_react29.cloneElement)(children, {
2372
2589
  "aria-describedby": [children.props["aria-describedby"], id].filter(Boolean).join(" ")
2373
2590
  }) : children;
2374
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2591
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
2375
2592
  "span",
2376
2593
  {
2377
2594
  ref: triggerRef,
@@ -2388,7 +2605,7 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2388
2605
  ...props,
2389
2606
  children: [
2390
2607
  child,
2391
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2608
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2392
2609
  "span",
2393
2610
  {
2394
2611
  ref: bubbleRef,
@@ -2407,45 +2624,45 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
2407
2624
  }
2408
2625
 
2409
2626
  // src/components/States.tsx
2410
- var import_jsx_runtime39 = require("react/jsx-runtime");
2627
+ var import_jsx_runtime40 = require("react/jsx-runtime");
2411
2628
  function EmptyState({ icon, title, children, action, variant = "section", className, ...props }) {
2412
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cx("uix-empty", `uix-empty--${variant}`, className), ...props, children: [
2413
- icon != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-empty__icon", children: icon }),
2414
- title != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-empty__title", children: title }),
2629
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: cx("uix-empty", `uix-empty--${variant}`, className), ...props, children: [
2630
+ icon != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uix-empty__icon", children: icon }),
2631
+ title != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uix-empty__title", children: title }),
2415
2632
  children,
2416
2633
  action
2417
2634
  ] });
2418
2635
  }
2419
2636
  function ErrorState({ icon, title, detail, action, variant = "section", className, ...props }) {
2420
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cx("uix-empty", "uix-empty--danger", `uix-empty--${variant}`, className), role: "alert", ...props, children: [
2421
- icon != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-empty__icon uix-empty__icon--danger", children: icon }),
2422
- title != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-empty__title", children: title }),
2423
- detail != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { children: detail }),
2637
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: cx("uix-empty", "uix-empty--danger", `uix-empty--${variant}`, className), role: "alert", ...props, children: [
2638
+ icon != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uix-empty__icon uix-empty__icon--danger", children: icon }),
2639
+ title != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uix-empty__title", children: title }),
2640
+ detail != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { children: detail }),
2424
2641
  action
2425
2642
  ] });
2426
2643
  }
2427
2644
  function ForbiddenState({ icon, title, detail, action, variant = "section", className, ...props }) {
2428
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cx("uix-empty", "uix-empty--warning", `uix-empty--${variant}`, className), ...props, children: [
2429
- icon != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-empty__icon uix-empty__icon--warning", children: icon }),
2430
- title != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-empty__title", children: title }),
2431
- detail != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { children: detail }),
2645
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: cx("uix-empty", "uix-empty--warning", `uix-empty--${variant}`, className), ...props, children: [
2646
+ icon != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uix-empty__icon uix-empty__icon--warning", children: icon }),
2647
+ title != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uix-empty__title", children: title }),
2648
+ detail != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { children: detail }),
2432
2649
  action
2433
2650
  ] });
2434
2651
  }
2435
2652
  function NotFoundState({ icon, title, detail, action, variant = "section", className, ...props }) {
2436
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cx("uix-empty", `uix-empty--${variant}`, className), ...props, children: [
2437
- icon != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-empty__icon", children: icon }),
2438
- title != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-empty__title", children: title }),
2439
- detail != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { children: detail }),
2653
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: cx("uix-empty", `uix-empty--${variant}`, className), ...props, children: [
2654
+ icon != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uix-empty__icon", children: icon }),
2655
+ title != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uix-empty__title", children: title }),
2656
+ detail != null && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { children: detail }),
2440
2657
  action
2441
2658
  ] });
2442
2659
  }
2443
2660
  function FilteredEmptyState(props) {
2444
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(EmptyState, { "data-filtered": "true", ...props });
2661
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(EmptyState, { "data-filtered": "true", ...props });
2445
2662
  }
2446
2663
  function Skeleton({ variant = "block", width, height, className, style, ...props }) {
2447
2664
  const dims = { width, height, ...style };
2448
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2665
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2449
2666
  "div",
2450
2667
  {
2451
2668
  className: cx(
@@ -2462,15 +2679,15 @@ function Skeleton({ variant = "block", width, height, className, style, ...props
2462
2679
  function LoadingState({ rows = 3, density = "comfortable", label, className, ...props }) {
2463
2680
  return (
2464
2681
  // no aria-busy: busy=true tells AT the region isn't ready and suppresses the announcement (UIX-A11Y-4)
2465
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cx("uix-stack", density === "compact" && "uix-stack--compact", className), role: "status", ...props, children: [
2466
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "uix-visually-hidden", children: label ?? "Loading" }),
2467
- Array.from({ length: rows }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Skeleton, { variant: "text", width: `${92 - i % 3 * 14}%` }, i))
2682
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: cx("uix-stack", density === "compact" && "uix-stack--compact", className), role: "status", ...props, children: [
2683
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "uix-visually-hidden", children: label ?? "Loading" }),
2684
+ Array.from({ length: rows }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Skeleton, { variant: "text", width: `${92 - i % 3 * 14}%` }, i))
2468
2685
  ] })
2469
2686
  );
2470
2687
  }
2471
2688
 
2472
2689
  // src/components/RelativeTime.tsx
2473
- var import_react27 = require("react");
2690
+ var import_react30 = require("react");
2474
2691
 
2475
2692
  // src/relative-time-model.ts
2476
2693
  function parseDateValue(value) {
@@ -2518,7 +2735,7 @@ function subscribeRelativeClock(interval, listener) {
2518
2735
  }
2519
2736
 
2520
2737
  // src/components/RelativeTime.tsx
2521
- var import_jsx_runtime40 = require("react/jsx-runtime");
2738
+ var import_jsx_runtime41 = require("react/jsx-runtime");
2522
2739
  function RelativeTime({
2523
2740
  value,
2524
2741
  now,
@@ -2533,13 +2750,13 @@ function RelativeTime({
2533
2750
  }) {
2534
2751
  const interval = refreshInterval === false ? 0 : Math.max(0, refreshInterval);
2535
2752
  const fixedNow = now == null ? void 0 : new Date(now).getTime();
2536
- const subscribe = (0, import_react27.useCallback)((listener) => fixedNow == null ? subscribeRelativeClock(interval, listener) : () => {
2753
+ const subscribe = (0, import_react30.useCallback)((listener) => fixedNow == null ? subscribeRelativeClock(interval, listener) : () => {
2537
2754
  }, [fixedNow, interval]);
2538
- const getSnapshot = (0, import_react27.useCallback)(() => fixedNow ?? readRelativeClock(interval), [fixedNow, interval]);
2539
- const getServerSnapshot = (0, import_react27.useCallback)(() => fixedNow ?? Date.now(), [fixedNow]);
2540
- const clock = (0, import_react27.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
2541
- const date = (0, import_react27.useMemo)(() => parseDateValue(value), [value]);
2542
- if (!date) return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("time", { "data-invalid": "true", suppressHydrationWarning: true, ...props, children: invalidLabel });
2755
+ const getSnapshot = (0, import_react30.useCallback)(() => fixedNow ?? readRelativeClock(interval), [fixedNow, interval]);
2756
+ const getServerSnapshot = (0, import_react30.useCallback)(() => fixedNow ?? Date.now(), [fixedNow]);
2757
+ const clock = (0, import_react30.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
2758
+ const date = (0, import_react30.useMemo)(() => parseDateValue(value), [value]);
2759
+ if (!date) return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("time", { "data-invalid": "true", suppressHydrationWarning: true, ...props, children: invalidLabel });
2543
2760
  const current = new Date(clock);
2544
2761
  const content = formatter ? formatter({ date, now: current, locale, timeZone }) : (() => {
2545
2762
  const relative = relativeTimeValue(date, current);
@@ -2549,11 +2766,11 @@ function RelativeTime({
2549
2766
  return new Intl.RelativeTimeFormat(locale, { numeric }).format(relative.value, relative.unit);
2550
2767
  })();
2551
2768
  const absolute = new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short", timeZone }).format(date);
2552
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("time", { dateTime: date.toISOString(), title: title ?? absolute, suppressHydrationWarning: true, ...props, children: content });
2769
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("time", { dateTime: date.toISOString(), title: title ?? absolute, suppressHydrationWarning: true, ...props, children: content });
2553
2770
  }
2554
2771
 
2555
2772
  // src/components/AsyncOperationStatus.tsx
2556
- var import_jsx_runtime41 = require("react/jsx-runtime");
2773
+ var import_jsx_runtime42 = require("react/jsx-runtime");
2557
2774
  var tones = {
2558
2775
  queued: "neutral",
2559
2776
  running: "info",
@@ -2561,54 +2778,54 @@ var tones = {
2561
2778
  failed: "danger"
2562
2779
  };
2563
2780
  function AsyncOperationStatus({ state, title, statusLabel, description, progress, progressLabel, action, className, ...props }) {
2564
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: cx("uix-operation", className), role: state === "failed" ? "alert" : "status", "aria-live": "polite", ...props, children: [
2565
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uix-operation__head", children: [
2566
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: title }),
2567
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StatusPill, { tone: tones[state], children: statusLabel })
2781
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: cx("uix-operation", className), role: state === "failed" ? "alert" : "status", "aria-live": "polite", ...props, children: [
2782
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "uix-operation__head", children: [
2783
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: title }),
2784
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(StatusPill, { tone: tones[state], children: statusLabel })
2568
2785
  ] }),
2569
- description != null && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uix-operation__description", children: description }),
2570
- progress != null && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Progress, { value: progress, "aria-label": progressLabel }),
2571
- action != null && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uix-operation__action", children: action })
2786
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "uix-operation__description", children: description }),
2787
+ progress != null && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(Progress, { value: progress, "aria-label": progressLabel }),
2788
+ action != null && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "uix-operation__action", children: action })
2572
2789
  ] });
2573
2790
  }
2574
2791
 
2575
2792
  // src/components/Label.tsx
2576
- var import_jsx_runtime42 = require("react/jsx-runtime");
2793
+ var import_jsx_runtime43 = require("react/jsx-runtime");
2577
2794
  function Label({ color, dot, children, className, style, ...props }) {
2578
2795
  const merged = color ? { "--label-color": color, ...style } : style;
2579
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: cx("uix-label", className), style: merged, ...props, children: [
2580
- dot && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "uix-label__dot", "aria-hidden": "true" }),
2796
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: cx("uix-label", className), style: merged, ...props, children: [
2797
+ dot && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-label__dot", "aria-hidden": "true" }),
2581
2798
  children
2582
2799
  ] });
2583
2800
  }
2584
2801
 
2585
2802
  // src/components/Avatar.tsx
2586
- var import_jsx_runtime43 = require("react/jsx-runtime");
2587
- function Avatar({ size = "md", src, alt, children, status, className, ...props }) {
2588
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: cx("uix-avatar", size !== "md" && `uix-avatar--${size}`, className), ...props, children: [
2589
- src ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("img", { src, alt: alt ?? "" }) : children,
2590
- status && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-avatar__status", "aria-hidden": "true" }),
2591
- status && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-visually-hidden", children: "online" })
2803
+ var import_jsx_runtime44 = require("react/jsx-runtime");
2804
+ function Avatar({ size = "md", src, alt, children, status, onlineLabel = "online", className, ...props }) {
2805
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: cx("uix-avatar", size !== "md" && `uix-avatar--${size}`, className), ...props, children: [
2806
+ src ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("img", { src, alt: alt ?? "" }) : children,
2807
+ status && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-avatar__status", "aria-hidden": "true" }),
2808
+ status && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-visually-hidden", children: onlineLabel })
2592
2809
  ] });
2593
2810
  }
2594
2811
  function AvatarGroup({ children, className, ...props }) {
2595
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: cx("uix-avatar-group", className), ...props, children });
2812
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: cx("uix-avatar-group", className), ...props, children });
2596
2813
  }
2597
2814
  function UserChip({ avatar, name, sub, className, children, ...props }) {
2598
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: cx("uix-user-chip", className), ...props, children: [
2815
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: cx("uix-user-chip", className), ...props, children: [
2599
2816
  avatar,
2600
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { children: [
2601
- name != null && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-user-chip__name", children: name }),
2602
- sub != null && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-user-chip__sub", style: { display: "block" }, children: sub })
2817
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { children: [
2818
+ name != null && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-user-chip__name", children: name }),
2819
+ sub != null && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-user-chip__sub", style: { display: "block" }, children: sub })
2603
2820
  ] }),
2604
2821
  children
2605
2822
  ] });
2606
2823
  }
2607
2824
 
2608
2825
  // src/components/Comments.tsx
2609
- var import_jsx_runtime44 = require("react/jsx-runtime");
2826
+ var import_jsx_runtime45 = require("react/jsx-runtime");
2610
2827
  function Comments({ children, className, ...props }) {
2611
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { role: "log", className: cx("uix-comments", className), ...props, children });
2828
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { role: "log", className: cx("uix-comments", className), ...props, children });
2612
2829
  }
2613
2830
  function Comment({
2614
2831
  avatar,
@@ -2624,23 +2841,23 @@ function Comment({
2624
2841
  }) {
2625
2842
  const system = variant === "system";
2626
2843
  const byline = author ?? (system ? systemLabel : void 0);
2627
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
2844
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2628
2845
  "div",
2629
2846
  {
2630
2847
  className: cx("uix-comment", system && "uix-comment--system", className),
2631
2848
  "data-variant": system ? "system" : void 0,
2632
2849
  ...props,
2633
2850
  children: [
2634
- avatar ?? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { "aria-hidden": "true" }),
2635
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "uix-comment__body", children: [
2636
- (byline != null || meta != null) && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "uix-comment__meta", children: [
2637
- byline != null && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-comment__author", children: byline }),
2851
+ avatar ?? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { "aria-hidden": "true" }),
2852
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "uix-comment__body", children: [
2853
+ (byline != null || meta != null) && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "uix-comment__meta", children: [
2854
+ byline != null && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "uix-comment__author", children: byline }),
2638
2855
  byline != null && meta != null ? " \xB7 " : null,
2639
2856
  meta
2640
2857
  ] }),
2641
- replyTo != null && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("blockquote", { className: "uix-comment__reply", children: [
2642
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-comment__reply-label", children: replyToLabel }),
2643
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-comment__reply-body", children: replyTo })
2858
+ replyTo != null && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("blockquote", { className: "uix-comment__reply", children: [
2859
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "uix-comment__reply-label", children: replyToLabel }),
2860
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "uix-comment__reply-body", children: replyTo })
2644
2861
  ] }),
2645
2862
  children
2646
2863
  ] })
@@ -2650,7 +2867,7 @@ function Comment({
2650
2867
  }
2651
2868
 
2652
2869
  // src/components/SaveStatus.tsx
2653
- var import_jsx_runtime45 = require("react/jsx-runtime");
2870
+ var import_jsx_runtime46 = require("react/jsx-runtime");
2654
2871
  var DEFAULT_SAVE_STATUS_LABELS = {
2655
2872
  saving: "Saving\u2026",
2656
2873
  saved: "Saved",
@@ -2660,34 +2877,34 @@ var DEFAULT_SAVE_STATUS_LABELS = {
2660
2877
  function SaveStatus({ state, labels, onRetry, className, ...props }) {
2661
2878
  const text = { ...DEFAULT_SAVE_STATUS_LABELS, ...labels };
2662
2879
  const message = state === "idle" ? "" : text[state];
2663
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: cx("uix-save-status", className), "data-state": state, ...props, children: [
2664
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "uix-save-status__icon", "aria-hidden": "true" }),
2665
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "uix-save-status__text", role: "status", "aria-live": "polite", children: message }),
2666
- state === "failed" && onRetry && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", className: "uix-btn uix-btn--link uix-btn--sm uix-save-status__retry", onClick: onRetry, children: text.retry })
2880
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: cx("uix-save-status", className), "data-state": state, ...props, children: [
2881
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "uix-save-status__icon", "aria-hidden": "true" }),
2882
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "uix-save-status__text", role: "status", "aria-live": "polite", children: message }),
2883
+ state === "failed" && onRetry && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: "uix-btn uix-btn--link uix-btn--sm uix-save-status__retry", onClick: onRetry, children: text.retry })
2667
2884
  ] });
2668
2885
  }
2669
2886
 
2670
2887
  // src/components/Composer.tsx
2671
- var import_react28 = require("react");
2672
- var import_jsx_runtime46 = require("react/jsx-runtime");
2888
+ var import_react31 = require("react");
2889
+ var import_jsx_runtime47 = require("react/jsx-runtime");
2673
2890
  function Composer({ children, className, label = "Add a comment", ...props }) {
2674
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: cx("uix-composer", className), ...props, children: import_react28.Children.map(children, (child) => {
2675
- if (!(0, import_react28.isValidElement)(child) || child.type !== "textarea") return child;
2891
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: cx("uix-composer", className), ...props, children: import_react31.Children.map(children, (child) => {
2892
+ if (!(0, import_react31.isValidElement)(child) || child.type !== "textarea") return child;
2676
2893
  const p = child.props;
2677
- return p["aria-label"] || p["aria-labelledby"] || p.id ? child : (0, import_react28.cloneElement)(child, { "aria-label": label });
2894
+ return p["aria-label"] || p["aria-labelledby"] || p.id ? child : (0, import_react31.cloneElement)(child, { "aria-label": label });
2678
2895
  }) });
2679
2896
  }
2680
2897
  function ComposerBar({ children, className, ...props }) {
2681
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: cx("uix-composer__bar", className), ...props, children });
2898
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: cx("uix-composer__bar", className), ...props, children });
2682
2899
  }
2683
2900
 
2684
2901
  // src/components/Segmented.tsx
2685
- var import_react29 = require("react");
2686
- var import_jsx_runtime47 = require("react/jsx-runtime");
2687
- var SegmentedCtx = (0, import_react29.createContext)({});
2902
+ var import_react32 = require("react");
2903
+ var import_jsx_runtime48 = require("react/jsx-runtime");
2904
+ var SegmentedCtx = (0, import_react32.createContext)({});
2688
2905
  function Segmented({ value, onChange, children, className, ...props }) {
2689
- const contextValue = (0, import_react29.useMemo)(() => ({ value, onChange }), [value, onChange]);
2690
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(SegmentedCtx.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { role: "group", className: cx("uix-segmented", className), ...props, children }) });
2906
+ const contextValue = (0, import_react32.useMemo)(() => ({ value, onChange }), [value, onChange]);
2907
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SegmentedCtx.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { role: "group", className: cx("uix-segmented", className), ...props, children }) });
2691
2908
  }
2692
2909
  function SegmentedOption({
2693
2910
  value,
@@ -2696,9 +2913,9 @@ function SegmentedOption({
2696
2913
  onClick,
2697
2914
  ...props
2698
2915
  }) {
2699
- const ctx = (0, import_react29.useContext)(SegmentedCtx);
2916
+ const ctx = (0, import_react32.useContext)(SegmentedCtx);
2700
2917
  const selected = ctx.value === value;
2701
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
2918
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2702
2919
  "button",
2703
2920
  {
2704
2921
  type: "button",
@@ -2715,81 +2932,81 @@ function SegmentedOption({
2715
2932
  }
2716
2933
 
2717
2934
  // src/components/TableControls.tsx
2718
- var import_react30 = require("react");
2719
- var import_jsx_runtime48 = require("react/jsx-runtime");
2935
+ var import_react33 = require("react");
2936
+ var import_jsx_runtime49 = require("react/jsx-runtime");
2720
2937
  function ViewMenu({ density, densityLabel, densityOptions, onDensityChange, zebra, freeze, columns, columnsLabel, onColumnVisibilityChange }) {
2721
- const densityLabelId = (0, import_react30.useId)();
2722
- const zebraLabelId = (0, import_react30.useId)();
2723
- const freezeLabelId = (0, import_react30.useId)();
2724
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-view-menu", children: [
2725
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-view-menu__group", children: [
2726
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { id: densityLabelId, className: "uix-view-menu__label", children: densityLabel }),
2727
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Segmented, { value: density, onChange: onDensityChange, "aria-labelledby": densityLabelId, children: densityOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SegmentedOption, { value: option.value, children: option.label }, option.value)) })
2938
+ const densityLabelId = (0, import_react33.useId)();
2939
+ const zebraLabelId = (0, import_react33.useId)();
2940
+ const freezeLabelId = (0, import_react33.useId)();
2941
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-view-menu", children: [
2942
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-view-menu__group", children: [
2943
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { id: densityLabelId, className: "uix-view-menu__label", children: densityLabel }),
2944
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Segmented, { value: density, onChange: onDensityChange, "aria-labelledby": densityLabelId, children: densityOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(SegmentedOption, { value: option.value, children: option.label }, option.value)) })
2728
2945
  ] }),
2729
- (zebra || freeze) && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-view-menu__group", children: [
2730
- zebra && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-view-menu__row", children: [
2731
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { id: zebraLabelId, children: zebra.label }),
2732
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Switch, { checked: zebra.checked, "aria-labelledby": zebraLabelId, onChange: (event) => zebra.onChange(event.currentTarget.checked) })
2946
+ (zebra || freeze) && /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-view-menu__group", children: [
2947
+ zebra && /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-view-menu__row", children: [
2948
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { id: zebraLabelId, children: zebra.label }),
2949
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Switch, { checked: zebra.checked, "aria-labelledby": zebraLabelId, onChange: (event) => zebra.onChange(event.currentTarget.checked) })
2733
2950
  ] }),
2734
- freeze && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-view-menu__row", children: [
2735
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { id: freezeLabelId, children: freeze.label }),
2736
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Switch, { checked: freeze.checked, "aria-labelledby": freezeLabelId, onChange: (event) => freeze.onChange(event.currentTarget.checked) })
2951
+ freeze && /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-view-menu__row", children: [
2952
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { id: freezeLabelId, children: freeze.label }),
2953
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Switch, { checked: freeze.checked, "aria-labelledby": freezeLabelId, onChange: (event) => freeze.onChange(event.currentTarget.checked) })
2737
2954
  ] })
2738
2955
  ] }),
2739
- columns && columns.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-view-menu__group", children: [
2740
- columnsLabel != null && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "uix-view-menu__label", children: columnsLabel }),
2741
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "uix-view-menu__cols", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Checkbox, { label: column.label, checked: column.visible, disabled: column.disabled, onChange: (event) => onColumnVisibilityChange?.(column.id, event.currentTarget.checked) }, column.id)) })
2956
+ columns && columns.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-view-menu__group", children: [
2957
+ columnsLabel != null && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "uix-view-menu__label", children: columnsLabel }),
2958
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "uix-view-menu__cols", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Checkbox, { label: column.label, checked: column.visible, disabled: column.disabled, onChange: (event) => onColumnVisibilityChange?.(column.id, event.currentTarget.checked) }, column.id)) })
2742
2959
  ] })
2743
2960
  ] });
2744
2961
  }
2745
2962
  function FilterPopover({ label, type = "text", value, onValueChange, options, applyLabel, clearLabel, onApply, onClear, placeholder }) {
2746
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-filter-popover", children: [
2747
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "uix-label", children: [
2748
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { children: label }),
2749
- type === "select" || type === "enum" || type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("select", { className: "uix-select", value, onChange: (event) => onValueChange(event.currentTarget.value), children: options?.map((option) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: option.value, children: option.label }, option.value)) }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Input, { type, value, placeholder, onChange: (event) => onValueChange(event.currentTarget.value) })
2963
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-filter-popover", children: [
2964
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "uix-label", children: [
2965
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { children: label }),
2966
+ type === "select" || type === "enum" || type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("select", { className: "uix-select", value, onChange: (event) => onValueChange(event.currentTarget.value), children: options?.map((option) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("option", { value: option.value, children: option.label }, option.value)) }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Input, { type, value, placeholder, onChange: (event) => onValueChange(event.currentTarget.value) })
2750
2967
  ] }),
2751
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "uix-filter-popover__actions", children: [
2752
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Button, { type: "button", onClick: onClear, children: clearLabel }),
2753
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Button, { type: "button", variant: "primary", onClick: onApply, children: applyLabel })
2968
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-filter-popover__actions", children: [
2969
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Button, { type: "button", onClick: onClear, children: clearLabel }),
2970
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Button, { type: "button", variant: "primary", onClick: onApply, children: applyLabel })
2754
2971
  ] })
2755
2972
  ] });
2756
2973
  }
2757
2974
  function SavedViewMenu({ items, onSelect, onPinChange, pinLabel, unpinLabel, emptyLabel, actions, footer }) {
2758
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("ul", { className: "uix-menu uix-saved-views", children: [
2759
- items.length === 0 && emptyLabel != null && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("li", { className: "uix-menu__label", children: emptyLabel }),
2760
- items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("li", { className: "uix-saved-views__row", children: [
2761
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("button", { type: "button", className: "uix-menu__item", "data-active": item.active || void 0, onClick: () => onSelect(item.id), children: item.label }),
2762
- onPinChange && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("button", { type: "button", className: "uix-saved-views__pin", "aria-label": item.pinned ? unpinLabel : pinLabel, "data-on": item.pinned || void 0, onClick: () => onPinChange(item.id, !item.pinned), children: "\u2605" }),
2975
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("ul", { className: "uix-menu uix-saved-views", children: [
2976
+ items.length === 0 && emptyLabel != null && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("li", { className: "uix-menu__label", children: emptyLabel }),
2977
+ items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { className: "uix-saved-views__row", children: [
2978
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("button", { type: "button", className: "uix-menu__item", "data-active": item.active || void 0, onClick: () => onSelect(item.id), children: item.label }),
2979
+ onPinChange && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("button", { type: "button", className: "uix-saved-views__pin", "aria-label": item.pinned ? unpinLabel : pinLabel, "data-on": item.pinned || void 0, onClick: () => onPinChange(item.id, !item.pinned), children: "\u2605" }),
2763
2980
  actions?.(item)
2764
2981
  ] }, item.id)),
2765
- footer != null && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("li", { className: "uix-saved-views__footer", children: footer })
2982
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("li", { className: "uix-saved-views__footer", children: footer })
2766
2983
  ] });
2767
2984
  }
2768
2985
 
2769
2986
  // src/components/Timeline.tsx
2770
- var import_jsx_runtime49 = require("react/jsx-runtime");
2987
+ var import_jsx_runtime50 = require("react/jsx-runtime");
2771
2988
  function Timeline({ children, className, ...props }) {
2772
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ol", { className: cx("uix-timeline", className), ...props, children });
2989
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("ol", { className: cx("uix-timeline", className), ...props, children });
2773
2990
  }
2774
2991
  function TimelineItem({ node, meta, children, className, ...props }) {
2775
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { className: cx("uix-timeline__item", className), ...props, children: [
2776
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-timeline__rail", "aria-hidden": "true", children: [
2777
- node ?? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "uix-timeline__node" }),
2778
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "uix-timeline__line" })
2992
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("li", { className: cx("uix-timeline__item", className), ...props, children: [
2993
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "uix-timeline__rail", "aria-hidden": "true", children: [
2994
+ node ?? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "uix-timeline__node" }),
2995
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "uix-timeline__line" })
2779
2996
  ] }),
2780
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "uix-timeline__body", children: [
2781
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "uix-timeline__meta", children: meta }),
2997
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "uix-timeline__body", children: [
2998
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uix-timeline__meta", children: meta }),
2782
2999
  children
2783
3000
  ] })
2784
3001
  ] });
2785
3002
  }
2786
3003
 
2787
3004
  // src/components/Pipeline.tsx
2788
- var import_react31 = require("react");
2789
- var import_jsx_runtime50 = require("react/jsx-runtime");
3005
+ var import_react34 = require("react");
3006
+ var import_jsx_runtime51 = require("react/jsx-runtime");
2790
3007
  function Pipeline({ detailed = false, children, className, tabIndex, ...props }) {
2791
- 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;
2792
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3008
+ const stages = detailed ? import_react34.Children.map(children, (child) => (0, import_react34.isValidElement)(child) && child.type === PipelineStage ? (0, import_react34.cloneElement)(child, { detailed: child.props.detailed ?? true }) : child) : children;
3009
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
2793
3010
  "ol",
2794
3011
  {
2795
3012
  className: cx("uix-pipeline", detailed && "uix-pipeline--detailed", className),
@@ -2814,7 +3031,7 @@ var DEFAULT_STATE_LABELS = {
2814
3031
  function PipelineStage({
2815
3032
  label,
2816
3033
  state = "pending",
2817
- stateLabel: stateLabel2,
3034
+ stateLabel,
2818
3035
  description,
2819
3036
  meta,
2820
3037
  marker,
@@ -2824,22 +3041,22 @@ function PipelineStage({
2824
3041
  ...props
2825
3042
  }) {
2826
3043
  const current = currentProp ?? (state === "active" || state === "current" || state === "running");
2827
- const resolvedStateLabel = stateLabel2 ?? DEFAULT_STATE_LABELS[state];
3044
+ const resolvedStateLabel = stateLabel ?? DEFAULT_STATE_LABELS[state];
2828
3045
  const showDetails = detailed || description != null || meta != null || marker != null;
2829
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3046
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
2830
3047
  "li",
2831
3048
  {
2832
3049
  className: cx("uix-pipeline__stage", className),
2833
3050
  "data-state": state,
2834
3051
  "aria-current": current ? "step" : void 0,
2835
3052
  ...props,
2836
- children: showDetails ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_jsx_runtime50.Fragment, { children: [
2837
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "uix-pipeline__marker", "aria-hidden": "true", children: marker }),
2838
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "uix-pipeline__content", children: [
2839
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uix-pipeline__eyebrow", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "uix-pipeline__state", children: resolvedStateLabel }) }),
2840
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uix-pipeline__title", children: label }),
2841
- description != null && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uix-pipeline__description", children: description }),
2842
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uix-pipeline__meta", children: meta })
3053
+ children: showDetails ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
3054
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "uix-pipeline__marker", "aria-hidden": "true", children: marker }),
3055
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "uix-pipeline__content", children: [
3056
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-pipeline__eyebrow", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "uix-pipeline__state", children: resolvedStateLabel }) }),
3057
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-pipeline__title", children: label }),
3058
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-pipeline__description", children: description }),
3059
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-pipeline__meta", children: meta })
2843
3060
  ] })
2844
3061
  ] }) : label
2845
3062
  }
@@ -2847,9 +3064,9 @@ function PipelineStage({
2847
3064
  }
2848
3065
 
2849
3066
  // src/components/Flow.tsx
2850
- var import_jsx_runtime51 = require("react/jsx-runtime");
3067
+ var import_jsx_runtime52 = require("react/jsx-runtime");
2851
3068
  function Flow({ variant = "linear", panel = false, children, className, role = "group", ...props }) {
2852
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3069
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
2853
3070
  "div",
2854
3071
  {
2855
3072
  className: cx("uix-flow", `uix-flow--${variant}`, panel && "uix-flow--panel", className),
@@ -2869,7 +3086,7 @@ var FLOW_STATE_LABELS = {
2869
3086
  function FlowNode({
2870
3087
  title,
2871
3088
  state = "pending",
2872
- stateLabel: stateLabel2,
3089
+ stateLabel,
2873
3090
  eyebrow,
2874
3091
  meta,
2875
3092
  icon,
@@ -2878,34 +3095,34 @@ function FlowNode({
2878
3095
  className,
2879
3096
  ...props
2880
3097
  }) {
2881
- const resolvedStateLabel = stateLabel2 ?? FLOW_STATE_LABELS[state];
2882
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: cx("uix-node", `uix-node--${state}`, icon == null && "uix-node--no-icon", wide && "uix-node--wide", className), ...props, children: [
2883
- icon != null && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "uix-node__icon", "aria-hidden": "true", children: icon }),
2884
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "uix-node__body", children: [
2885
- eyebrow != null && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-node__eyebrow", children: eyebrow }),
2886
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-node__title", children: title }),
2887
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-node__meta", children: meta }),
2888
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-node__status", children: resolvedStateLabel })
3098
+ const resolvedStateLabel = stateLabel ?? FLOW_STATE_LABELS[state];
3099
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: cx("uix-node", `uix-node--${state}`, icon == null && "uix-node--no-icon", wide && "uix-node--wide", className), ...props, children: [
3100
+ icon != null && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "uix-node__icon", "aria-hidden": "true", children: icon }),
3101
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uix-node__body", children: [
3102
+ eyebrow != null && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uix-node__eyebrow", children: eyebrow }),
3103
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uix-node__title", children: title }),
3104
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uix-node__meta", children: meta }),
3105
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uix-node__status", children: resolvedStateLabel })
2889
3106
  ] }),
2890
- footer != null && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "uix-node__footer", children: footer })
3107
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uix-node__footer", children: footer })
2891
3108
  ] });
2892
3109
  }
2893
3110
 
2894
3111
  // src/components/Prose.tsx
2895
- var import_jsx_runtime52 = require("react/jsx-runtime");
3112
+ var import_jsx_runtime53 = require("react/jsx-runtime");
2896
3113
  function Prose({ children, className, ...props }) {
2897
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: cx("uix-prose", className), ...props, children });
3114
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: cx("uix-prose", className), ...props, children });
2898
3115
  }
2899
3116
  function Note({ tone, icon, children, className, ...props }) {
2900
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: cx("uix-note", tone && `uix-note--${tone}`, className), ...props, children: [
2901
- icon != null && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uix-note__icon", children: icon }),
2902
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uix-note__body", children })
3117
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: cx("uix-note", tone && `uix-note--${tone}`, className), ...props, children: [
3118
+ icon != null && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uix-note__icon", children: icon }),
3119
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uix-note__body", children })
2903
3120
  ] });
2904
3121
  }
2905
3122
 
2906
3123
  // src/components/Popover.tsx
2907
- var import_react32 = require("react");
2908
- var import_jsx_runtime53 = require("react/jsx-runtime");
3124
+ var import_react35 = require("react");
3125
+ var import_jsx_runtime54 = require("react/jsx-runtime");
2909
3126
  function Popover({
2910
3127
  popover = "auto",
2911
3128
  anchor,
@@ -2915,15 +3132,15 @@ function Popover({
2915
3132
  children,
2916
3133
  ...props
2917
3134
  }) {
2918
- const ref = (0, import_react32.useRef)(null);
2919
- const [open, setOpen] = (0, import_react32.useState)(false);
3135
+ const ref = (0, import_react35.useRef)(null);
3136
+ const [open, setOpen] = (0, import_react35.useState)(false);
2920
3137
  const popoverAttr = { popover };
2921
3138
  const reposition = useAnchoredPosition(anchor ?? null, ref, {
2922
3139
  open: open && !!anchor,
2923
3140
  placement,
2924
3141
  offset
2925
3142
  });
2926
- (0, import_react32.useEffect)(() => {
3143
+ (0, import_react35.useEffect)(() => {
2927
3144
  const el = ref.current;
2928
3145
  if (!el || !anchor) return;
2929
3146
  const sync = () => {
@@ -2934,32 +3151,32 @@ function Popover({
2934
3151
  el.addEventListener("toggle", sync);
2935
3152
  return () => el.removeEventListener("toggle", sync);
2936
3153
  }, [anchor, reposition]);
2937
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { ref, className: cx("uix-popover", className), ...popoverAttr, ...props, children });
3154
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { ref, className: cx("uix-popover", className), ...popoverAttr, ...props, children });
2938
3155
  }
2939
3156
 
2940
3157
  // src/components/CommandPalette.tsx
2941
- var import_react33 = require("react");
2942
- var import_jsx_runtime54 = require("react/jsx-runtime");
2943
- var CmdkContext = (0, import_react33.createContext)(null);
2944
- function CommandPalette({ inputProps, children, className, ...props }) {
2945
- const listId = (0, import_react33.useId)();
2946
- const [activeId, setActiveId] = (0, import_react33.useState)(null);
2947
- const [count, setCount] = (0, import_react33.useState)(0);
2948
- const [announced, setAnnounced] = (0, import_react33.useState)("");
2949
- const setActive = (0, import_react33.useCallback)((id, active) => {
3158
+ var import_react36 = require("react");
3159
+ var import_jsx_runtime55 = require("react/jsx-runtime");
3160
+ var CmdkContext = (0, import_react36.createContext)(null);
3161
+ function CommandPalette({ inputProps, children, inputLabel = "Command palette", className, ...props }) {
3162
+ const listId = (0, import_react36.useId)();
3163
+ const [activeId, setActiveId] = (0, import_react36.useState)(null);
3164
+ const [count, setCount] = (0, import_react36.useState)(0);
3165
+ const [announced, setAnnounced] = (0, import_react36.useState)("");
3166
+ const setActive = (0, import_react36.useCallback)((id, active) => {
2950
3167
  setActiveId((cur) => active ? id : cur === id ? null : cur);
2951
3168
  }, []);
2952
- const registerItem = (0, import_react33.useCallback)(() => {
3169
+ const registerItem = (0, import_react36.useCallback)(() => {
2953
3170
  setCount((c) => c + 1);
2954
3171
  return () => setCount((c) => c - 1);
2955
3172
  }, []);
2956
- (0, import_react33.useEffect)(() => {
3173
+ (0, import_react36.useEffect)(() => {
2957
3174
  const t = window.setTimeout(() => setAnnounced(`${count} result${count === 1 ? "" : "s"}`), 150);
2958
3175
  return () => clearTimeout(t);
2959
3176
  }, [count]);
2960
- const ctx = (0, import_react33.useMemo)(() => ({ listId, setActive, registerItem }), [listId, setActive, registerItem]);
2961
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(CmdkContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: cx("uix-cmdk", className), ...props, children: [
2962
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3177
+ const ctx = (0, import_react36.useMemo)(() => ({ listId, setActive, registerItem }), [listId, setActive, registerItem]);
3178
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(CmdkContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: cx("uix-cmdk", className), ...props, children: [
3179
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
2963
3180
  "input",
2964
3181
  {
2965
3182
  className: "uix-cmdk__input",
@@ -2968,32 +3185,32 @@ function CommandPalette({ inputProps, children, className, ...props }) {
2968
3185
  "aria-autocomplete": "list",
2969
3186
  "aria-controls": listId,
2970
3187
  "aria-activedescendant": activeId ?? void 0,
2971
- "aria-label": "Command palette",
3188
+ "aria-label": inputLabel,
2972
3189
  ...inputProps
2973
3190
  }
2974
3191
  ),
2975
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uix-cmdk__list", role: "listbox", id: listId, children }),
2976
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uix-visually-hidden", role: "status", children: announced })
3192
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-cmdk__list", role: "listbox", id: listId, children }),
3193
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "uix-visually-hidden", role: "status", children: announced })
2977
3194
  ] }) });
2978
3195
  }
2979
3196
  function CommandGroup({ label, children }) {
2980
- const labelId = (0, import_react33.useId)();
2981
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { role: "group", "aria-labelledby": label != null ? labelId : void 0, children: [
2982
- label != null && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uix-cmdk__group", id: labelId, children: label }),
3197
+ const labelId = (0, import_react36.useId)();
3198
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { role: "group", "aria-labelledby": label != null ? labelId : void 0, children: [
3199
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-cmdk__group", id: labelId, children: label }),
2983
3200
  children
2984
3201
  ] });
2985
3202
  }
2986
3203
  function CommandItem({ icon, shortcut, active, children, className, id, ...props }) {
2987
- const ctx = (0, import_react33.useContext)(CmdkContext);
2988
- const autoId = (0, import_react33.useId)();
3204
+ const ctx = (0, import_react36.useContext)(CmdkContext);
3205
+ const autoId = (0, import_react36.useId)();
2989
3206
  const itemId = id ?? autoId;
2990
- (0, import_react33.useEffect)(() => ctx?.registerItem(), [ctx]);
2991
- (0, import_react33.useEffect)(() => {
3207
+ (0, import_react36.useEffect)(() => ctx?.registerItem(), [ctx]);
3208
+ (0, import_react36.useEffect)(() => {
2992
3209
  if (!ctx || !active) return;
2993
3210
  ctx.setActive(itemId, true);
2994
3211
  return () => ctx.setActive(itemId, false);
2995
3212
  }, [ctx, itemId, active]);
2996
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
3213
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
2997
3214
  "div",
2998
3215
  {
2999
3216
  className: cx("uix-cmdk__item", className),
@@ -3004,7 +3221,7 @@ function CommandItem({ icon, shortcut, active, children, className, id, ...props
3004
3221
  ...props,
3005
3222
  children: [
3006
3223
  icon,
3007
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { children }),
3224
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { children }),
3008
3225
  shortcut
3009
3226
  ]
3010
3227
  }
@@ -3012,16 +3229,16 @@ function CommandItem({ icon, shortcut, active, children, className, id, ...props
3012
3229
  }
3013
3230
 
3014
3231
  // src/components/Inbox.tsx
3015
- var import_react34 = require("react");
3016
- var import_jsx_runtime55 = require("react/jsx-runtime");
3232
+ var import_react37 = require("react");
3233
+ var import_jsx_runtime56 = require("react/jsx-runtime");
3017
3234
  function Inbox({ view, children, className, ...props }) {
3018
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: cx("uix-inbox", className), "data-view": view, ...props, children });
3235
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: cx("uix-inbox", className), "data-view": view, ...props, children });
3019
3236
  }
3020
- var InboxListCtx = (0, import_react34.createContext)({});
3021
- function InboxList({ children, className, ...props }) {
3022
- const listRef = (0, import_react34.useRef)(null);
3023
- const [activeId, setActiveId] = (0, import_react34.useState)(void 0);
3024
- const ctx = (0, import_react34.useMemo)(() => ({ activeId }), [activeId]);
3237
+ var InboxListCtx = (0, import_react37.createContext)({});
3238
+ function InboxList({ children, listLabel = "Inbox", className, ...props }) {
3239
+ const listRef = (0, import_react37.useRef)(null);
3240
+ const [activeId, setActiveId] = (0, import_react37.useState)(void 0);
3241
+ const ctx = (0, import_react37.useMemo)(() => ({ activeId }), [activeId]);
3025
3242
  const onKeyDown = (e) => {
3026
3243
  const opts = Array.from(listRef.current?.querySelectorAll('[role="option"]') ?? []);
3027
3244
  if (opts.length === 0) return;
@@ -3056,14 +3273,14 @@ function InboxList({ children, className, ...props }) {
3056
3273
  setActiveId(el.id);
3057
3274
  el.scrollIntoView({ block: "nearest" });
3058
3275
  };
3059
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(InboxListCtx.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
3276
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(InboxListCtx.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
3060
3277
  "div",
3061
3278
  {
3062
3279
  ref: listRef,
3063
3280
  className: cx("uix-inbox__list", className),
3064
3281
  role: "listbox",
3065
3282
  tabIndex: 0,
3066
- "aria-label": "Inbox",
3283
+ "aria-label": listLabel,
3067
3284
  "aria-activedescendant": activeId,
3068
3285
  onKeyDown,
3069
3286
  ...props,
@@ -3082,10 +3299,10 @@ function InboxItem({
3082
3299
  id,
3083
3300
  ...props
3084
3301
  }) {
3085
- const autoId = (0, import_react34.useId)();
3302
+ const autoId = (0, import_react37.useId)();
3086
3303
  const itemId = id ?? autoId;
3087
- const { activeId } = (0, import_react34.useContext)(InboxListCtx);
3088
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
3304
+ const { activeId } = (0, import_react37.useContext)(InboxListCtx);
3305
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
3089
3306
  "div",
3090
3307
  {
3091
3308
  role: "option",
@@ -3097,35 +3314,35 @@ function InboxItem({
3097
3314
  ...props,
3098
3315
  children: [
3099
3316
  leading,
3100
- subject != null && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-inbox__subject", children: subject }),
3101
- preview != null && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uix-inbox__preview", children: preview }),
3317
+ subject != null && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uix-inbox__subject", children: subject }),
3318
+ preview != null && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uix-inbox__preview", children: preview }),
3102
3319
  children
3103
3320
  ]
3104
3321
  }
3105
3322
  );
3106
3323
  }
3107
3324
  function InboxDetail({ children, className, ...props }) {
3108
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: cx("uix-inbox__detail", className), ...props, children });
3325
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: cx("uix-inbox__detail", className), ...props, children });
3109
3326
  }
3110
3327
 
3111
3328
  // src/components/Kanban.tsx
3112
- var import_react35 = require("react");
3113
- var import_jsx_runtime56 = require("react/jsx-runtime");
3329
+ var import_react38 = require("react");
3330
+ var import_jsx_runtime57 = require("react/jsx-runtime");
3114
3331
  function Kanban({ announcement, children, className, ...props }) {
3115
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: cx("uix-kanban", className), ...props, children: [
3116
- announcement != null && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
3332
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: cx("uix-kanban", className), ...props, children: [
3333
+ announcement != null && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
3117
3334
  children
3118
3335
  ] });
3119
3336
  }
3120
3337
  function KanbanColumn({ title, count, children, className, ...props }) {
3121
- const headId = (0, import_react35.useId)();
3338
+ const headId = (0, import_react38.useId)();
3122
3339
  const hasHead = title != null || count != null;
3123
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: cx("uix-kanban__col", className), ...props, children: [
3124
- hasHead && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "uix-kanban__head", id: headId, children: [
3340
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: cx("uix-kanban__col", className), ...props, children: [
3341
+ hasHead && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "uix-kanban__head", id: headId, children: [
3125
3342
  title,
3126
- count != null && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "uix-kanban__count", children: count })
3343
+ count != null && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "uix-kanban__count", children: count })
3127
3344
  ] }),
3128
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uix-kanban__body", role: "list", "aria-labelledby": hasHead ? headId : void 0, children })
3345
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uix-kanban__body", role: "list", "aria-labelledby": hasHead ? headId : void 0, children })
3129
3346
  ] });
3130
3347
  }
3131
3348
  var MOVE_KEYS = {
@@ -3144,7 +3361,7 @@ function KanbanCard({ title, meta, children, className, onMove, onKeyDown, ...pr
3144
3361
  onMove(dir);
3145
3362
  }
3146
3363
  };
3147
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
3364
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
3148
3365
  "div",
3149
3366
  {
3150
3367
  role: "listitem",
@@ -3153,8 +3370,8 @@ function KanbanCard({ title, meta, children, className, onMove, onKeyDown, ...pr
3153
3370
  onKeyDown: handleKeyDown,
3154
3371
  ...props,
3155
3372
  children: [
3156
- title && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uix-kanban__card-title", children: title }),
3157
- meta && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uix-kanban__card-meta", children: meta }),
3373
+ title && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uix-kanban__card-title", children: title }),
3374
+ meta && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uix-kanban__card-meta", children: meta }),
3158
3375
  children
3159
3376
  ]
3160
3377
  }
@@ -3162,7 +3379,7 @@ function KanbanCard({ title, meta, children, className, onMove, onKeyDown, ...pr
3162
3379
  }
3163
3380
 
3164
3381
  // src/components/Tree.tsx
3165
- var import_react36 = require("react");
3382
+ var import_react39 = require("react");
3166
3383
 
3167
3384
  // src/tree-model.ts
3168
3385
  function flattenTree(nodes, expanded, level = 1) {
@@ -3220,12 +3437,12 @@ function treeNav(flat, currentId, key) {
3220
3437
  }
3221
3438
 
3222
3439
  // src/components/Tree.tsx
3223
- var import_jsx_runtime57 = require("react/jsx-runtime");
3224
- var ChevronIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("svg", { viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("path", { d: "M2 4l4 4 4-4" }) });
3225
- function TreeNode({ node, expanded, selected, selectable, tabbableId, onToggle, onSelect, onFocusNode, level = 1 }) {
3440
+ var import_jsx_runtime58 = require("react/jsx-runtime");
3441
+ var ChevronIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("svg", { viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("path", { d: "M2 4l4 4 4-4" }) });
3442
+ function TreeNode({ node, expanded, selected, selectable, tabbableId, onToggle, onSelect, onFocusNode, level = 1, rowToggles = true }) {
3226
3443
  const hasChildren = Array.isArray(node.children) && node.children.length > 0;
3227
3444
  const isExpanded = expanded.has(node.id);
3228
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
3445
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
3229
3446
  "li",
3230
3447
  {
3231
3448
  role: "treeitem",
@@ -3240,17 +3457,36 @@ function TreeNode({ node, expanded, selected, selectable, tabbableId, onToggle,
3240
3457
  },
3241
3458
  onClick: (e) => {
3242
3459
  e.stopPropagation();
3243
- if (hasChildren) onToggle(node.id);
3460
+ if (hasChildren && rowToggles) onToggle(node.id);
3244
3461
  onSelect?.(node.id);
3245
3462
  onFocusNode(node.id);
3246
3463
  },
3247
3464
  children: [
3248
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "uix-tree__row", children: [
3249
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "uix-tree__toggle", children: hasChildren && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ChevronIcon2, {}) }),
3250
- node.icon && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { "aria-hidden": "true", children: node.icon }),
3251
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "uix-tree__label", children: node.label })
3465
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "uix-tree__row", children: [
3466
+ hasChildren ? (
3467
+ // TENSOR RX-125 (UIX-09): the chevron is its own pointer target, so a
3468
+ // branch can be expanded without selecting it. Keyboard users toggle with
3469
+ // the arrow keys on the treeitem, so it stays out of the tab order.
3470
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
3471
+ "button",
3472
+ {
3473
+ type: "button",
3474
+ tabIndex: -1,
3475
+ "aria-hidden": "true",
3476
+ className: "uix-tree__toggle",
3477
+ onClick: (e) => {
3478
+ e.stopPropagation();
3479
+ onToggle(node.id);
3480
+ onFocusNode(node.id);
3481
+ },
3482
+ children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(ChevronIcon2, {})
3483
+ }
3484
+ )
3485
+ ) : /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-tree__toggle" }),
3486
+ node.icon && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { "aria-hidden": "true", children: node.icon }),
3487
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-tree__label", children: node.label })
3252
3488
  ] }),
3253
- hasChildren && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("ul", { role: "group", className: "uix-tree__group", children: node.children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
3489
+ hasChildren && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("ul", { role: "group", className: "uix-tree__group", children: node.children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
3254
3490
  TreeNode,
3255
3491
  {
3256
3492
  node: child,
@@ -3261,7 +3497,8 @@ function TreeNode({ node, expanded, selected, selectable, tabbableId, onToggle,
3261
3497
  onToggle,
3262
3498
  onSelect,
3263
3499
  onFocusNode,
3264
- level: level + 1
3500
+ level: level + 1,
3501
+ rowToggles
3265
3502
  },
3266
3503
  child.id
3267
3504
  )) })
@@ -3279,15 +3516,17 @@ function Tree({
3279
3516
  virtualize,
3280
3517
  rowHeight = 32,
3281
3518
  maxHeight = 384,
3519
+ toggleOnRowClick,
3282
3520
  className,
3283
3521
  ...props
3284
3522
  }) {
3285
- const [internalExpanded, setInternalExpanded] = (0, import_react36.useState)(defaultExpanded ?? /* @__PURE__ */ new Set());
3523
+ const [internalExpanded, setInternalExpanded] = (0, import_react39.useState)(defaultExpanded ?? /* @__PURE__ */ new Set());
3286
3524
  const expanded = controlledExpanded ?? internalExpanded;
3287
- const rootRef = (0, import_react36.useRef)(null);
3288
- const [focusedId, setFocusedId] = (0, import_react36.useState)(void 0);
3525
+ const rootRef = (0, import_react39.useRef)(null);
3526
+ const [focusedId, setFocusedId] = (0, import_react39.useState)(void 0);
3289
3527
  const selectable = selected !== void 0 || onSelect != null;
3290
- const handleToggle = (0, import_react36.useCallback)((id) => {
3528
+ const rowToggles = toggleOnRowClick ?? !selectable;
3529
+ const handleToggle = (0, import_react39.useCallback)((id) => {
3291
3530
  if (!controlledExpanded) {
3292
3531
  setInternalExpanded((prev) => {
3293
3532
  const next = new Set(prev);
@@ -3298,11 +3537,11 @@ function Tree({
3298
3537
  }
3299
3538
  onToggle?.(id);
3300
3539
  }, [controlledExpanded, onToggle]);
3301
- const flat = (0, import_react36.useMemo)(() => flattenTree(nodes, expanded), [nodes, expanded]);
3540
+ const flat = (0, import_react39.useMemo)(() => flattenTree(nodes, expanded), [nodes, expanded]);
3302
3541
  const useVirtual = virtualize ?? shouldVirtualize(flat.length);
3303
3542
  const tabbableId = focusedId ?? selected ?? nodes[0]?.id;
3304
3543
  if (useVirtual) {
3305
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
3544
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
3306
3545
  VirtualTreeView,
3307
3546
  {
3308
3547
  flat,
@@ -3315,6 +3554,7 @@ function Tree({
3315
3554
  onSelect,
3316
3555
  focusedId,
3317
3556
  setFocusedId,
3557
+ rowToggles,
3318
3558
  className,
3319
3559
  ...props
3320
3560
  }
@@ -3379,7 +3619,7 @@ function Tree({
3379
3619
  break;
3380
3620
  }
3381
3621
  };
3382
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("ul", { ref: rootRef, className: cx("uix-tree", className), role: "tree", onKeyDown, ...props, children: nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
3622
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("ul", { ref: rootRef, className: cx("uix-tree", className), role: "tree", onKeyDown, ...props, children: nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
3383
3623
  TreeNode,
3384
3624
  {
3385
3625
  node,
@@ -3390,7 +3630,8 @@ function Tree({
3390
3630
  onToggle: handleToggle,
3391
3631
  onSelect,
3392
3632
  onFocusNode: setFocusedId,
3393
- level: 1
3633
+ level: 1,
3634
+ rowToggles
3394
3635
  },
3395
3636
  node.id
3396
3637
  )) });
@@ -3406,17 +3647,18 @@ function VirtualTreeView({
3406
3647
  onSelect,
3407
3648
  focusedId,
3408
3649
  setFocusedId,
3650
+ rowToggles,
3409
3651
  className,
3410
3652
  ...props
3411
3653
  }) {
3412
- const scrollRef = (0, import_react36.useRef)(null);
3413
- const [scrollTop, setScrollTop] = (0, import_react36.useState)(0);
3414
- const pendingFocus = (0, import_react36.useRef)(false);
3415
- const hadFocus = (0, import_react36.useRef)(false);
3654
+ const scrollRef = (0, import_react39.useRef)(null);
3655
+ const [scrollTop, setScrollTop] = (0, import_react39.useState)(0);
3656
+ const pendingFocus = (0, import_react39.useRef)(false);
3657
+ const hadFocus = (0, import_react39.useRef)(false);
3416
3658
  const win = virtualWindow(scrollTop, maxHeight, rowHeight, flat.length);
3417
3659
  const rows = flat.slice(win.start, win.end);
3418
3660
  const windowHasTabbable = tabbableId != null && rows.some((f) => f.node.id === tabbableId);
3419
- (0, import_react36.useEffect)(() => {
3661
+ (0, import_react39.useEffect)(() => {
3420
3662
  if (!pendingFocus.current || focusedId == null) return;
3421
3663
  const el = scrollRef.current?.querySelector(`[role="treeitem"][data-id="${CSS.escape(focusedId)}"]`);
3422
3664
  if (el) {
@@ -3424,7 +3666,7 @@ function VirtualTreeView({
3424
3666
  pendingFocus.current = false;
3425
3667
  }
3426
3668
  }, [focusedId, win.start, win.end]);
3427
- (0, import_react36.useEffect)(() => {
3669
+ (0, import_react39.useEffect)(() => {
3428
3670
  if (!hadFocus.current || pendingFocus.current) return;
3429
3671
  const active = document.activeElement;
3430
3672
  if (active === document.body || active == null) scrollRef.current?.focus({ preventScroll: true });
@@ -3459,7 +3701,7 @@ function VirtualTreeView({
3459
3701
  }
3460
3702
  if (act.focusId !== void 0) moveTo(act.focusId);
3461
3703
  };
3462
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
3704
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
3463
3705
  "ul",
3464
3706
  {
3465
3707
  ref: scrollRef,
@@ -3477,10 +3719,13 @@ function VirtualTreeView({
3477
3719
  },
3478
3720
  ...props,
3479
3721
  children: [
3480
- win.padTop > 0 && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("li", { role: "presentation", "aria-hidden": "true", style: { height: win.padTop } }),
3722
+ win.padTop > 0 && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("li", { role: "presentation", "aria-hidden": "true", style: { height: win.padTop } }),
3481
3723
  rows.map((f, i) => {
3482
- const rowStyle = { height: rowHeight, paddingLeft: `calc(${f.level - 1} * var(--uix-space-5))` };
3483
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
3724
+ const rowStyle = {
3725
+ height: rowHeight,
3726
+ paddingLeft: `calc(${Math.min(f.level - 1, 4)} * var(--uix-space-5) + ${Math.max(0, f.level - 5)} * var(--uix-space-1))`
3727
+ };
3728
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
3484
3729
  "li",
3485
3730
  {
3486
3731
  role: "treeitem",
@@ -3497,27 +3742,46 @@ function VirtualTreeView({
3497
3742
  },
3498
3743
  onClick: (e) => {
3499
3744
  e.stopPropagation();
3500
- if (f.hasChildren) onToggle(f.node.id);
3745
+ if (f.hasChildren && rowToggles) onToggle(f.node.id);
3501
3746
  onSelect?.(f.node.id);
3502
3747
  setFocusedId(f.node.id);
3503
3748
  },
3504
- children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "uix-tree__row", style: rowStyle, children: [
3505
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "uix-tree__toggle", children: f.hasChildren && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ChevronIcon2, {}) }),
3506
- f.node.icon && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { "aria-hidden": "true", children: f.node.icon }),
3507
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "uix-tree__label", children: f.node.label })
3749
+ children: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "uix-tree__row", style: rowStyle, children: [
3750
+ f.hasChildren ? (
3751
+ // TENSOR RX-125 (UIX-09): the chevron is its own pointer target, so a
3752
+ // branch can be expanded without selecting it. Keyboard users toggle with
3753
+ // the arrow keys on the treeitem, so it stays out of the tab order.
3754
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
3755
+ "button",
3756
+ {
3757
+ type: "button",
3758
+ tabIndex: -1,
3759
+ "aria-hidden": "true",
3760
+ className: "uix-tree__toggle",
3761
+ onClick: (e) => {
3762
+ e.stopPropagation();
3763
+ onToggle(f.node.id);
3764
+ setFocusedId(f.node.id);
3765
+ },
3766
+ children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(ChevronIcon2, {})
3767
+ }
3768
+ )
3769
+ ) : /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-tree__toggle" }),
3770
+ f.node.icon && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { "aria-hidden": "true", children: f.node.icon }),
3771
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-tree__label", children: f.node.label })
3508
3772
  ] })
3509
3773
  },
3510
3774
  f.node.id
3511
3775
  );
3512
3776
  }),
3513
- win.padBottom > 0 && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("li", { role: "presentation", "aria-hidden": "true", style: { height: win.padBottom } })
3777
+ win.padBottom > 0 && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("li", { role: "presentation", "aria-hidden": "true", style: { height: win.padBottom } })
3514
3778
  ]
3515
3779
  }
3516
3780
  );
3517
3781
  }
3518
3782
 
3519
3783
  // src/components/EditorialHome.tsx
3520
- var import_jsx_runtime58 = require("react/jsx-runtime");
3784
+ var import_jsx_runtime59 = require("react/jsx-runtime");
3521
3785
  function PageIntro({
3522
3786
  kicker,
3523
3787
  title,
@@ -3530,39 +3794,39 @@ function PageIntro({
3530
3794
  children,
3531
3795
  ...props
3532
3796
  }) {
3533
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("section", { className: cx("uix-page-intro", className), ...props, children: [
3534
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { children: [
3535
- kicker != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-page-kicker", children: kicker }),
3536
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h1", { className: "uix-page-title", children: title }),
3537
- lede != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-page-lede", children: lede })
3797
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("section", { className: cx("uix-page-intro", className), ...props, children: [
3798
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { children: [
3799
+ kicker != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-page-kicker", children: kicker }),
3800
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h1", { className: "uix-page-title", children: title }),
3801
+ lede != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-page-lede", children: lede })
3538
3802
  ] }),
3539
- search != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { children: [
3540
- searchLabel != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-intro-search__label", children: searchLabel }),
3803
+ search != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { children: [
3804
+ searchLabel != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-intro-search__label", children: searchLabel }),
3541
3805
  search
3542
3806
  ] }),
3543
- shortcuts != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "uix-shortcut-grid", "aria-label": shortcutsLabel, children: shortcuts }),
3807
+ shortcuts != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "uix-shortcut-grid", "aria-label": shortcutsLabel, children: shortcuts }),
3544
3808
  children
3545
3809
  ] });
3546
3810
  }
3547
3811
  function SectionHead({ title, titleId, action, className, ...props }) {
3548
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: cx("uix-section-head", className), ...props, children: [
3549
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h2", { className: "uix-section-title", id: titleId, children: title }),
3812
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: cx("uix-section-head", className), ...props, children: [
3813
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h2", { className: "uix-section-title", id: titleId, children: title }),
3550
3814
  action
3551
3815
  ] });
3552
3816
  }
3553
3817
  function NoticeQueue({ icon, title, summary, meta, position, actions, className, ...props }) {
3554
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("section", { className: cx("uix-notice", className), ...props, children: [
3818
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("section", { className: cx("uix-notice", className), ...props, children: [
3555
3819
  icon,
3556
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "uix-notice__content", "aria-live": "polite", children: [
3557
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("p", { className: "uix-notice__copy", children: [
3558
- title != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("strong", { children: title }),
3820
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-notice__content", "aria-live": "polite", children: [
3821
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("p", { className: "uix-notice__copy", children: [
3822
+ title != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("strong", { children: title }),
3559
3823
  title != null && summary != null && " ",
3560
3824
  summary
3561
3825
  ] }),
3562
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-notice__meta", children: meta })
3826
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-notice__meta", children: meta })
3563
3827
  ] }),
3564
- (position != null || actions != null) && /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "uix-notice__actions", children: [
3565
- position != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-notice__position", children: position }),
3828
+ (position != null || actions != null) && /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-notice__actions", children: [
3829
+ position != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-notice__position", children: position }),
3566
3830
  actions
3567
3831
  ] })
3568
3832
  ] });
@@ -3580,8 +3844,8 @@ function FeaturedStage({
3580
3844
  className,
3581
3845
  ...props
3582
3846
  }) {
3583
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("article", { className: cx("uix-featured__stage", className), ...props, children: [
3584
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
3847
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("article", { className: cx("uix-featured__stage", className), ...props, children: [
3848
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
3585
3849
  "div",
3586
3850
  {
3587
3851
  className: "uix-featured__visual",
@@ -3591,32 +3855,32 @@ function FeaturedStage({
3591
3855
  children: visual
3592
3856
  }
3593
3857
  ),
3594
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "uix-featured__content", "aria-live": "polite", children: [
3595
- (eyebrow != null || ordinal != null) && /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("p", { className: "uix-featured__eyebrow", children: [
3596
- ordinal != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-featured__now", children: ordinal }),
3858
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-featured__content", "aria-live": "polite", children: [
3859
+ (eyebrow != null || ordinal != null) && /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("p", { className: "uix-featured__eyebrow", children: [
3860
+ ordinal != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-featured__now", children: ordinal }),
3597
3861
  eyebrow
3598
3862
  ] }),
3599
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h2", { className: "uix-featured__title", id: titleId, children: title }),
3600
- description != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-featured__description", children: description }),
3601
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-featured__meta", children: meta }),
3863
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h2", { className: "uix-featured__title", id: titleId, children: title }),
3864
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-featured__description", children: description }),
3865
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-featured__meta", children: meta }),
3602
3866
  action
3603
3867
  ] })
3604
3868
  ] });
3605
3869
  }
3606
3870
  function FeaturedRundown({ eyebrow, title, titleId, meta, children, className, ...props }) {
3607
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("aside", { className: cx("uix-rundown", className), ...props, children: [
3608
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "uix-rundown__head", children: [
3609
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { children: [
3610
- eyebrow != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-rundown__eyebrow", children: eyebrow }),
3611
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h2", { className: "uix-rundown__title", id: titleId, children: title })
3871
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("aside", { className: cx("uix-rundown", className), ...props, children: [
3872
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-rundown__head", children: [
3873
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { children: [
3874
+ eyebrow != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-rundown__eyebrow", children: eyebrow }),
3875
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h2", { className: "uix-rundown__title", id: titleId, children: title })
3612
3876
  ] }),
3613
3877
  meta
3614
3878
  ] }),
3615
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "uix-rundown__items", children })
3879
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "uix-rundown__items", children })
3616
3880
  ] });
3617
3881
  }
3618
3882
  function FeaturedRundownItem({ number, topic, title, selected = false, className, ...props }) {
3619
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
3883
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
3620
3884
  "button",
3621
3885
  {
3622
3886
  type: "button",
@@ -3625,63 +3889,63 @@ function FeaturedRundownItem({ number, topic, title, selected = false, className
3625
3889
  "data-selected": selected ? "true" : "false",
3626
3890
  ...props,
3627
3891
  children: [
3628
- number != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-rundown__number", children: number }),
3629
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { children: [
3630
- topic != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-rundown__topic", children: topic }),
3631
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-rundown__item-title", children: title })
3892
+ number != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-rundown__number", children: number }),
3893
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { children: [
3894
+ topic != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-rundown__topic", children: topic }),
3895
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-rundown__item-title", children: title })
3632
3896
  ] })
3633
3897
  ]
3634
3898
  }
3635
3899
  );
3636
3900
  }
3637
3901
  function NewsLead({ meta, title, summary, className, ...props }) {
3638
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("article", { className: cx("uix-news-lead", className), ...props, children: [
3639
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-news-lead__meta", children: meta }),
3640
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h3", { className: "uix-news-lead__title", children: title }),
3641
- summary != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-news-lead__summary", children: summary })
3902
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("article", { className: cx("uix-news-lead", className), ...props, children: [
3903
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-news-lead__meta", children: meta }),
3904
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h3", { className: "uix-news-lead__title", children: title }),
3905
+ summary != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-news-lead__summary", children: summary })
3642
3906
  ] });
3643
3907
  }
3644
3908
  function ContentList({ children, className, ...props }) {
3645
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("ul", { className: cx("uix-content-list", className), ...props, children });
3909
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("ul", { className: cx("uix-content-list", className), ...props, children });
3646
3910
  }
3647
3911
  function ContentListItem({ title, meta, trailing, className, ...props }) {
3648
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("li", { className: cx("uix-content-list__item", className), ...props, children: [
3649
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { children: [
3650
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-content-list__title", children: title }),
3651
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-content-list__meta", children: meta })
3912
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("li", { className: cx("uix-content-list__item", className), ...props, children: [
3913
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { children: [
3914
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-content-list__title", children: title }),
3915
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-content-list__meta", children: meta })
3652
3916
  ] }),
3653
3917
  trailing
3654
3918
  ] });
3655
3919
  }
3656
3920
  function ResourceGrid({ children, className, ...props }) {
3657
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: cx("uix-resource-grid", className), ...props, children });
3921
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: cx("uix-resource-grid", className), ...props, children });
3658
3922
  }
3659
3923
  function StatLine({ items, children, className, ...props }) {
3660
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: cx("uix-stat-line", className), ...props, children: [
3661
- items?.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "uix-stat-line__item", children: [
3662
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-stat-line__value", children: item.value }),
3663
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-stat-line__label", children: item.label })
3924
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: cx("uix-stat-line", className), ...props, children: [
3925
+ items?.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-stat-line__item", children: [
3926
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-stat-line__value", children: item.value }),
3927
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-stat-line__label", children: item.label })
3664
3928
  ] }, item.id ?? i)),
3665
3929
  children
3666
3930
  ] });
3667
3931
  }
3668
3932
  function EventRow({ month, day, title, meta, className, ...props }) {
3669
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: cx("uix-event-row", className), ...props, children: [
3670
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "uix-event-date", children: [
3671
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-event-date__month", children: month }),
3672
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-event-date__day", children: day })
3933
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: cx("uix-event-row", className), ...props, children: [
3934
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-event-date", children: [
3935
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-event-date__month", children: month }),
3936
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-event-date__day", children: day })
3673
3937
  ] }),
3674
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { children: [
3675
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-event-row__title", children: title }),
3676
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "uix-event-row__meta", children: meta })
3938
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { children: [
3939
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-event-row__title", children: title }),
3940
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "uix-event-row__meta", children: meta })
3677
3941
  ] })
3678
3942
  ] });
3679
3943
  }
3680
3944
  function StatusRow({ indicator, name, meta, className, ...props }) {
3681
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: cx("uix-status-row", className), ...props, children: [
3945
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: cx("uix-status-row", className), ...props, children: [
3682
3946
  indicator,
3683
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-status-row__name", children: name }),
3684
- meta != null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "uix-list-meta", children: meta })
3947
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-status-row__name", children: name }),
3948
+ meta != null && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-list-meta", children: meta })
3685
3949
  ] });
3686
3950
  }
3687
3951
 
@@ -3777,8 +4041,47 @@ function summarizeRule(value, labels = {}) {
3777
4041
  return `When ${formatGroup(value.when) || "no conditions"}, then ${actions || "no actions"}.`;
3778
4042
  }
3779
4043
 
4044
+ // src/fill-label.ts
4045
+ function fillLabel(template, values) {
4046
+ return template.replace(
4047
+ /\{(\w+)\}/g,
4048
+ (match, key) => Object.prototype.hasOwnProperty.call(values, key) ? String(values[key]) : match
4049
+ );
4050
+ }
4051
+
3780
4052
  // src/components/RuleBuilder.tsx
3781
- var import_jsx_runtime59 = require("react/jsx-runtime");
4053
+ var import_jsx_runtime60 = require("react/jsx-runtime");
4054
+ var DEFAULT_RULE_BUILDER_LABELS = {
4055
+ region: "Rule builder",
4056
+ summary: "Rule summary",
4057
+ when: "When",
4058
+ group: "Group",
4059
+ match: "Match",
4060
+ all: "all (AND)",
4061
+ any: "any (OR)",
4062
+ field: "Field",
4063
+ operator: "Operator",
4064
+ valueFor: "Value for {field}",
4065
+ itemGroup: "group",
4066
+ itemCondition: "condition",
4067
+ itemAction: "action",
4068
+ moveUp: "Up",
4069
+ moveUpNamed: "Move {item} up",
4070
+ moveDown: "Down",
4071
+ moveDownNamed: "Move {item} down",
4072
+ remove: "Remove",
4073
+ removeNamed: "Remove {item}",
4074
+ then: "Then",
4075
+ actionType: "Action type",
4076
+ valid: "Rule is valid.",
4077
+ issuesOne: "{count} validation issue",
4078
+ issuesMany: "{count} validation issues",
4079
+ summaryIssuesOne: "Rule has {count} validation issue.",
4080
+ summaryIssuesMany: "Rule has {count} validation issues.",
4081
+ addCondition: "Add condition",
4082
+ addGroup: "Add group",
4083
+ addAction: "Add action"
4084
+ };
3782
4085
  var ruleId = 0;
3783
4086
  var nextId = (prefix) => `${prefix}-${Date.now().toString(36)}-${(++ruleId).toString(36)}`;
3784
4087
  function defaultCondition(fields, operators) {
@@ -3794,39 +4097,40 @@ function RuleGroupEditor({ group, depth, root, fields, operators, maxDepth, disa
3794
4097
  combinator: "and",
3795
4098
  conditions: [defaultCondition(fields, operators)]
3796
4099
  }, maxDepth));
3797
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("fieldset", { className: "uix-rule-builder__group", "data-depth": depth, children: [
3798
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("legend", { className: "uix-rule-builder__group-heading", children: [
3799
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { children: depth === 1 ? "When" : "Group" }),
3800
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("label", { children: [
3801
- "Match",
3802
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("select", { className: "uix-select uix-select--sm", value: group.combinator, disabled, onChange: (event) => updateNode(group.id, (node) => ({ ...node, combinator: event.currentTarget.value })), children: [
3803
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("option", { value: "and", children: "all (AND)" }),
3804
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("option", { value: "or", children: "any (OR)" })
4100
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("fieldset", { className: "uix-rule-builder__group", "data-depth": depth, children: [
4101
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("legend", { className: "uix-rule-builder__group-heading", children: [
4102
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { children: depth === 1 ? labels.when : labels.group }),
4103
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("label", { children: [
4104
+ labels.match,
4105
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("select", { className: "uix-select uix-select--sm", value: group.combinator, disabled, onChange: (event) => updateNode(group.id, (node) => ({ ...node, combinator: event.currentTarget.value })), children: [
4106
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("option", { value: "and", children: labels.all }),
4107
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("option", { value: "or", children: labels.any })
3805
4108
  ] })
3806
4109
  ] })
3807
4110
  ] }),
3808
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "uix-rule-builder__rows", children: group.conditions.map((node, index) => isRuleGroup(node) ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-rule-builder__nested", children: [
3809
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(RuleGroupEditor, { ...{ group: node, depth: depth + 1, root, fields, operators, maxDepth, disabled, onRootChange, labels } }),
3810
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(RowControls, { label: "group", first: index === 0, last: index === group.conditions.length - 1, disabled, onUp: () => onRootChange(moveRuleNode(root, node.id, -1)), onDown: () => onRootChange(moveRuleNode(root, node.id, 1)), onRemove: () => onRootChange(removeRuleNode(root, node.id)) })
3811
- ] }, node.id) : /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
4111
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "uix-rule-builder__rows", children: group.conditions.map((node, index) => isRuleGroup(node) ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "uix-rule-builder__nested", children: [
4112
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(RuleGroupEditor, { ...{ group: node, depth: depth + 1, root, fields, operators, maxDepth, disabled, onRootChange, labels } }),
4113
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(RowControls, { labels, label: labels.itemGroup, first: index === 0, last: index === group.conditions.length - 1, disabled, onUp: () => onRootChange(moveRuleNode(root, node.id, -1)), onDown: () => onRootChange(moveRuleNode(root, node.id, 1)), onRemove: () => onRootChange(removeRuleNode(root, node.id)) })
4114
+ ] }, node.id) : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
3812
4115
  ConditionRow,
3813
4116
  {
4117
+ labels,
3814
4118
  condition: node,
3815
4119
  fields,
3816
4120
  operators,
3817
4121
  disabled,
3818
4122
  onChange: (condition) => updateNode(node.id, () => condition),
3819
- controls: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(RowControls, { label: "condition", first: index === 0, last: index === group.conditions.length - 1, disabled, onUp: () => onRootChange(moveRuleNode(root, node.id, -1)), onDown: () => onRootChange(moveRuleNode(root, node.id, 1)), onRemove: () => onRootChange(removeRuleNode(root, node.id)) })
4123
+ controls: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(RowControls, { labels, label: labels.itemCondition, first: index === 0, last: index === group.conditions.length - 1, disabled, onUp: () => onRootChange(moveRuleNode(root, node.id, -1)), onDown: () => onRootChange(moveRuleNode(root, node.id, 1)), onRemove: () => onRootChange(removeRuleNode(root, node.id)) })
3820
4124
  },
3821
4125
  node.id
3822
4126
  )) }),
3823
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-rule-builder__add", children: [
3824
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", onClick: addCondition, disabled: disabled || fields.length === 0 || operators.length === 0, children: labels.addCondition }),
3825
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: addGroup, disabled: disabled || depth >= maxDepth, children: labels.addGroup })
4127
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "uix-rule-builder__add", children: [
4128
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", onClick: addCondition, disabled: disabled || fields.length === 0 || operators.length === 0, children: labels.addCondition }),
4129
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: addGroup, disabled: disabled || depth >= maxDepth, children: labels.addGroup })
3826
4130
  ] })
3827
4131
  ] });
3828
4132
  }
3829
- function ConditionRow({ condition, fields, operators, disabled, onChange, controls }) {
4133
+ function ConditionRow({ labels, condition, fields, operators, disabled, onChange, controls }) {
3830
4134
  const field = fields.find((item) => item.id === condition.field);
3831
4135
  const availableOperators = field?.operators?.length ? operators.filter((item) => field.operators.includes(item.id)) : operators;
3832
4136
  const operator = operators.find((item) => item.id === condition.operator);
@@ -3835,24 +4139,24 @@ function ConditionRow({ condition, fields, operators, disabled, onChange, contro
3835
4139
  const nextOperator = operators.find((item) => nextField?.operators?.includes(item.id)) ?? availableOperators[0] ?? operators[0];
3836
4140
  onChange({ ...condition, field: id, operator: nextOperator?.id ?? "" });
3837
4141
  };
3838
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-rule-builder__condition", children: [
3839
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("label", { children: [
3840
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-visually-hidden", children: "Field" }),
3841
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("select", { className: "uix-select", value: condition.field, onChange: (event) => setField(event.currentTarget.value), disabled, children: fields.map((item) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("option", { value: item.id, children: item.label }, item.id)) })
4142
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "uix-rule-builder__condition", children: [
4143
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("label", { children: [
4144
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "uix-visually-hidden", children: labels.field }),
4145
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("select", { className: "uix-select", value: condition.field, onChange: (event) => setField(event.currentTarget.value), disabled, children: fields.map((item) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("option", { value: item.id, children: item.label }, item.id)) })
3842
4146
  ] }),
3843
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("label", { children: [
3844
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "uix-visually-hidden", children: "Operator" }),
3845
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("select", { className: "uix-select", value: condition.operator, onChange: (event) => onChange({ ...condition, operator: event.currentTarget.value }), disabled, children: availableOperators.map((item) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("option", { value: item.id, children: item.label }, item.id)) })
4147
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("label", { children: [
4148
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "uix-visually-hidden", children: labels.operator }),
4149
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("select", { className: "uix-select", value: condition.operator, onChange: (event) => onChange({ ...condition, operator: event.currentTarget.value }), disabled, children: availableOperators.map((item) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("option", { value: item.id, children: item.label }, item.id)) })
3846
4150
  ] }),
3847
- operator?.requiresValue !== false && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "uix-rule-builder__value", children: field?.renderValueEditor?.({ condition, onChange: (value) => onChange({ ...condition, value }), disabled }) ?? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("input", { className: "uix-input", value: typeof condition.value === "string" || typeof condition.value === "number" ? condition.value : condition.value == null ? "" : JSON.stringify(condition.value), onChange: (event) => onChange({ ...condition, value: event.currentTarget.value }), disabled, "aria-label": `Value for ${field?.label ?? "condition"}` }) }),
4151
+ operator?.requiresValue !== false && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "uix-rule-builder__value", children: field?.renderValueEditor?.({ condition, onChange: (value) => onChange({ ...condition, value }), disabled }) ?? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("input", { className: "uix-input", value: typeof condition.value === "string" || typeof condition.value === "number" ? condition.value : condition.value == null ? "" : JSON.stringify(condition.value), onChange: (event) => onChange({ ...condition, value: event.currentTarget.value }), disabled, "aria-label": fillLabel(labels.valueFor, { field: field?.label ?? labels.itemCondition }) }) }),
3848
4152
  controls
3849
4153
  ] });
3850
4154
  }
3851
- function RowControls({ label, first, last, disabled, onUp, onDown, onRemove }) {
3852
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "uix-rule-builder__row-actions", children: [
3853
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onUp, disabled: disabled || first, "aria-label": `Move ${label} up`, children: "Up" }),
3854
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onDown, disabled: disabled || last, "aria-label": `Move ${label} down`, children: "Down" }),
3855
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onRemove, disabled, "aria-label": `Remove ${label}`, children: "Remove" })
4155
+ function RowControls({ labels, label, first, last, disabled, onUp, onDown, onRemove }) {
4156
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "uix-rule-builder__row-actions", children: [
4157
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onUp, disabled: disabled || first, "aria-label": fillLabel(labels.moveUpNamed, { item: label }), children: labels.moveUp }),
4158
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onDown, disabled: disabled || last, "aria-label": fillLabel(labels.moveDownNamed, { item: label }), children: labels.moveDown }),
4159
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onRemove, disabled, "aria-label": fillLabel(labels.removeNamed, { item: label }), children: labels.remove })
3856
4160
  ] });
3857
4161
  }
3858
4162
  function RuleBuilder({
@@ -3865,38 +4169,42 @@ function RuleBuilder({
3865
4169
  readOnly = false,
3866
4170
  validate,
3867
4171
  className,
3868
- addConditionLabel = "Add condition",
3869
- addGroupLabel = "Add group",
3870
- addActionLabel = "Add action"
4172
+ addConditionLabel,
4173
+ addGroupLabel,
4174
+ addActionLabel,
4175
+ labels: labelOverrides
3871
4176
  }) {
4177
+ const labels = {
4178
+ ...DEFAULT_RULE_BUILDER_LABELS,
4179
+ ...addConditionLabel != null ? { addCondition: addConditionLabel } : {},
4180
+ ...addGroupLabel != null ? { addGroup: addGroupLabel } : {},
4181
+ ...addActionLabel != null ? { addAction: addActionLabel } : {},
4182
+ ...labelOverrides
4183
+ };
4184
+ const issuesText = (template1, templateN) => fillLabel(issues.length === 1 ? template1 : templateN, { count: issues.length });
3872
4185
  const issues = [...validateRuleDefinition(value, maxDepth), ...validate?.(value) ?? []];
3873
4186
  const fieldLabels = Object.fromEntries(fields.map((field) => [field.id, field.label]));
3874
4187
  const operatorLabels = Object.fromEntries(operators.map((operator) => [operator.id, operator.label]));
3875
4188
  const actionLabels = Object.fromEntries(actions.map((action) => [action.id, action.label]));
3876
- if (readOnly) return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("section", { className: cx("uix-rule-builder uix-rule-builder--summary", className), "aria-label": "Rule summary", children: [
3877
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { children: summarizeRule(value, { fields: fieldLabels, operators: operatorLabels, actions: actionLabels }) }),
3878
- issues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("p", { className: "uix-rule-builder__invalid", children: [
3879
- "Rule has ",
3880
- issues.length,
3881
- " validation issue",
3882
- issues.length === 1 ? "" : "s",
3883
- "."
3884
- ] })
4189
+ if (readOnly) return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("section", { className: cx("uix-rule-builder uix-rule-builder--summary", className), "aria-label": labels.summary, children: [
4190
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { children: summarizeRule(value, { fields: fieldLabels, operators: operatorLabels, actions: actionLabels }) }),
4191
+ issues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "uix-rule-builder__invalid", children: issuesText(labels.summaryIssuesOne, labels.summaryIssuesMany) })
3885
4192
  ] });
3886
4193
  const updateActions = (next) => onChange({ ...value, then: next });
3887
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("section", { className: cx("uix-rule-builder", className), "aria-label": "Rule builder", children: [
3888
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(RuleGroupEditor, { group: value.when, depth: 1, root: value.when, fields, operators, maxDepth, disabled: readOnly, onRootChange: (when) => onChange({ ...value, when }), labels: { addCondition: addConditionLabel, addGroup: addGroupLabel } }),
3889
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("fieldset", { className: "uix-rule-builder__actions", children: [
3890
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("legend", { children: "Then" }),
4194
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("section", { className: cx("uix-rule-builder", className), "aria-label": labels.region, children: [
4195
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(RuleGroupEditor, { group: value.when, depth: 1, root: value.when, fields, operators, maxDepth, disabled: readOnly, onRootChange: (when) => onChange({ ...value, when }), labels }),
4196
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("fieldset", { className: "uix-rule-builder__actions", children: [
4197
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("legend", { children: labels.then }),
3891
4198
  value.then.map((action, index) => {
3892
4199
  const definition = actions.find((item) => item.id === action.type);
3893
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "uix-rule-builder__action", children: [
3894
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("select", { className: "uix-select", value: action.type, onChange: (event) => updateActions(value.then.map((item) => item.id === action.id ? { ...item, type: event.currentTarget.value } : item)), "aria-label": "Action type", children: actions.map((item) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("option", { value: item.id, children: item.label }, item.id)) }),
4200
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "uix-rule-builder__action", children: [
4201
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("select", { className: "uix-select", value: action.type, onChange: (event) => updateActions(value.then.map((item) => item.id === action.id ? { ...item, type: event.currentTarget.value } : item)), "aria-label": labels.actionType, children: actions.map((item) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("option", { value: item.id, children: item.label }, item.id)) }),
3895
4202
  definition?.renderParameters?.(action, (parameters) => updateActions(value.then.map((item) => item.id === action.id ? { ...item, parameters } : item)), false),
3896
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
4203
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
3897
4204
  RowControls,
3898
4205
  {
3899
- label: "action",
4206
+ labels,
4207
+ label: labels.itemAction,
3900
4208
  first: index === 0,
3901
4209
  last: index === value.then.length - 1,
3902
4210
  disabled: false,
@@ -3915,22 +4223,40 @@ function RuleBuilder({
3915
4223
  )
3916
4224
  ] }, action.id);
3917
4225
  }),
3918
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", disabled: actions.length === 0, onClick: () => updateActions([...value.then, { id: nextId("action"), type: actions[0]?.id ?? "", parameters: {} }]), children: addActionLabel })
4226
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", disabled: actions.length === 0, onClick: () => updateActions([...value.then, { id: nextId("action"), type: actions[0]?.id ?? "", parameters: {} }]), children: labels.addAction })
3919
4227
  ] }),
3920
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "uix-rule-builder__validation", "aria-live": "polite", children: issues.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { children: "Rule is valid." }) : /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_jsx_runtime59.Fragment, { children: [
3921
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("strong", { children: [
3922
- issues.length,
3923
- " validation issue",
3924
- issues.length === 1 ? "" : "s"
3925
- ] }),
3926
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("ul", { children: issues.map((issue, index) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("li", { children: issue.message }, `${issue.path}-${index}`)) })
4228
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "uix-rule-builder__validation", "aria-live": "polite", children: issues.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { children: labels.valid }) : /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
4229
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("strong", { children: issuesText(labels.issuesOne, labels.issuesMany) }),
4230
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("ul", { children: issues.map((issue, index) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("li", { children: issue.message }, `${issue.path}-${index}`)) })
3927
4231
  ] }) })
3928
4232
  ] });
3929
4233
  }
3930
4234
 
3931
4235
  // src/components/BuilderCanvas.tsx
3932
- var import_react37 = require("react");
3933
- var import_jsx_runtime60 = require("react/jsx-runtime");
4236
+ var import_react40 = require("react");
4237
+ var import_jsx_runtime61 = require("react/jsx-runtime");
4238
+ var DEFAULT_BUILDER_CANVAS_LABELS = {
4239
+ region: "Builder canvas",
4240
+ palette: "Item palette",
4241
+ paletteHeading: "Palette",
4242
+ paletteEmpty: "No item types available.",
4243
+ add: "Add",
4244
+ addFirst: "Add {label}",
4245
+ canvasHeading: "Canvas",
4246
+ loading: "Loading canvas\u2026",
4247
+ retry: "Try again",
4248
+ moveUp: "Up",
4249
+ moveUpNamed: "Move {label} up",
4250
+ moveDown: "Down",
4251
+ moveDownNamed: "Move {label} down",
4252
+ remove: "Remove",
4253
+ removeNamed: "Remove {label}",
4254
+ properties: "Item properties",
4255
+ propertiesHeading: "Properties",
4256
+ propertiesEmpty: "Select a canvas item to edit its properties.",
4257
+ type: "Type",
4258
+ label: "Label"
4259
+ };
3934
4260
  function BuilderCanvas({
3935
4261
  items,
3936
4262
  onItemsChange,
@@ -3943,15 +4269,17 @@ function BuilderCanvas({
3943
4269
  error,
3944
4270
  onRetry,
3945
4271
  emptyMessage = "Add an item from the palette to begin.",
3946
- className
4272
+ className,
4273
+ labels: labelOverrides
3947
4274
  }) {
3948
- const [internalSelectedId, setInternalSelectedId] = (0, import_react37.useState)();
3949
- const [draggedId, setDraggedId] = (0, import_react37.useState)();
3950
- const propertyHeadingRef = (0, import_react37.useRef)(null);
3951
- const shouldFocusProperties = (0, import_react37.useRef)(false);
4275
+ const labels = { ...DEFAULT_BUILDER_CANVAS_LABELS, ...labelOverrides };
4276
+ const [internalSelectedId, setInternalSelectedId] = (0, import_react40.useState)();
4277
+ const [draggedId, setDraggedId] = (0, import_react40.useState)();
4278
+ const propertyHeadingRef = (0, import_react40.useRef)(null);
4279
+ const shouldFocusProperties = (0, import_react40.useRef)(false);
3952
4280
  const selectedId = controlledSelectedId ?? internalSelectedId;
3953
4281
  const selected = items.find((item) => item.id === selectedId);
3954
- (0, import_react37.useEffect)(() => {
4282
+ (0, import_react40.useEffect)(() => {
3955
4283
  if (shouldFocusProperties.current && selected) {
3956
4284
  propertyHeadingRef.current?.focus();
3957
4285
  shouldFocusProperties.current = false;
@@ -3985,27 +4313,24 @@ function BuilderCanvas({
3985
4313
  if (from >= 0 && to >= 0) onItemsChange(reorder(items, from, to));
3986
4314
  setDraggedId(void 0);
3987
4315
  };
3988
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("section", { className: cx("uix-builder-canvas", className), "aria-label": "Builder canvas", children: [
3989
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("aside", { className: "uix-builder-canvas__palette", "aria-label": "Item palette", children: [
3990
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h3", { children: "Palette" }),
3991
- palette.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { children: "No item types available." }) : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("ul", { children: palette.map((item) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("button", { type: "button", onClick: () => add(item), children: [
3992
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("strong", { children: item.label }),
3993
- item.description && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { children: item.description }),
3994
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { "aria-hidden": "true", children: "Add" })
4316
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("section", { className: cx("uix-builder-canvas", className), "aria-label": labels.region, children: [
4317
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("aside", { className: "uix-builder-canvas__palette", "aria-label": labels.palette, children: [
4318
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("h3", { children: labels.paletteHeading }),
4319
+ palette.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { children: labels.paletteEmpty }) : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("ul", { children: palette.map((item) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("button", { type: "button", onClick: () => add(item), children: [
4320
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("strong", { children: item.label }),
4321
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { children: item.description }),
4322
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { "aria-hidden": "true", children: labels.add })
3995
4323
  ] }) }, item.id)) })
3996
4324
  ] }),
3997
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "uix-builder-canvas__workspace", children: [
3998
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h3", { children: "Canvas" }),
3999
- loading ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "uix-builder-canvas__state", role: "status", children: "Loading canvas\u2026" }) : error ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "uix-builder-canvas__state", role: "alert", children: [
4000
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { children: error }),
4001
- onRetry && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: "Try again" })
4002
- ] }) : items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "uix-builder-canvas__state", children: [
4003
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { children: emptyMessage }),
4004
- palette[0] && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("button", { type: "button", className: "uix-btn uix-btn--primary", onClick: () => add(palette[0]), children: [
4005
- "Add ",
4006
- palette[0].label
4007
- ] })
4008
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("ol", { className: "uix-builder-canvas__items", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
4325
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "uix-builder-canvas__workspace", children: [
4326
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("h3", { children: labels.canvasHeading }),
4327
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "uix-builder-canvas__state", role: "status", children: labels.loading }) : error ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "uix-builder-canvas__state", role: "alert", children: [
4328
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { children: error }),
4329
+ onRetry && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: labels.retry })
4330
+ ] }) : items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "uix-builder-canvas__state", children: [
4331
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { children: emptyMessage }),
4332
+ palette[0] && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary", onClick: () => add(palette[0]), children: fillLabel(labels.addFirst, { label: palette[0].label }) })
4333
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("ol", { className: "uix-builder-canvas__items", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
4009
4334
  "li",
4010
4335
  {
4011
4336
  draggable: true,
@@ -4015,34 +4340,34 @@ function BuilderCanvas({
4015
4340
  onDrop: (event) => drop(event, item.id),
4016
4341
  className: cx("uix-builder-canvas__item", selectedId === item.id && "uix-builder-canvas__item--selected"),
4017
4342
  children: [
4018
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", className: "uix-builder-canvas__item-main", "aria-pressed": selectedId === item.id, onClick: () => select(item.id), children: renderItem?.(item, selectedId === item.id) ?? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
4019
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("strong", { children: item.label }),
4020
- item.description && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { children: item.description })
4343
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", className: "uix-builder-canvas__item-main", "aria-pressed": selectedId === item.id, onClick: () => select(item.id), children: renderItem?.(item, selectedId === item.id) ?? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
4344
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("strong", { children: item.label }),
4345
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { children: item.description })
4021
4346
  ] }) }),
4022
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "uix-builder-canvas__item-actions", children: [
4023
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", onClick: () => move(item.id, -1), disabled: index === 0, "aria-label": `Move ${item.label} up`, children: "Up" }),
4024
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", onClick: () => move(item.id, 1), disabled: index === items.length - 1, "aria-label": `Move ${item.label} down`, children: "Down" }),
4025
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("button", { type: "button", onClick: () => remove(item.id), "aria-label": `Remove ${item.label}`, children: "Remove" })
4347
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "uix-builder-canvas__item-actions", children: [
4348
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", onClick: () => move(item.id, -1), disabled: index === 0, "aria-label": fillLabel(labels.moveUpNamed, { label: item.label }), children: labels.moveUp }),
4349
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", onClick: () => move(item.id, 1), disabled: index === items.length - 1, "aria-label": fillLabel(labels.moveDownNamed, { label: item.label }), children: labels.moveDown }),
4350
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", onClick: () => remove(item.id), "aria-label": fillLabel(labels.removeNamed, { label: item.label }), children: labels.remove })
4026
4351
  ] })
4027
4352
  ]
4028
4353
  },
4029
4354
  item.id
4030
4355
  )) })
4031
4356
  ] }),
4032
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("aside", { className: "uix-builder-canvas__properties", "aria-label": "Item properties", children: [
4033
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h3", { ref: propertyHeadingRef, tabIndex: -1, children: "Properties" }),
4034
- !selected ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { children: "Select a canvas item to edit its properties." }) : renderProperties?.(selected, (updated) => onItemsChange(items.map((item) => item.id === updated.id ? updated : item))) ?? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("dl", { children: [
4035
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("dt", { children: "Type" }),
4036
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("dd", { children: selected.type }),
4037
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("dt", { children: "Label" }),
4038
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("dd", { children: selected.label })
4357
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("aside", { className: "uix-builder-canvas__properties", "aria-label": labels.properties, children: [
4358
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("h3", { ref: propertyHeadingRef, tabIndex: -1, children: labels.propertiesHeading }),
4359
+ !selected ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { children: labels.propertiesEmpty }) : renderProperties?.(selected, (updated) => onItemsChange(items.map((item) => item.id === updated.id ? updated : item))) ?? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("dl", { children: [
4360
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("dt", { children: labels.type }),
4361
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("dd", { children: selected.type }),
4362
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("dt", { children: labels.label }),
4363
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("dd", { children: selected.label })
4039
4364
  ] })
4040
4365
  ] })
4041
4366
  ] });
4042
4367
  }
4043
4368
 
4044
4369
  // src/components/SchedulingCalendar.tsx
4045
- var import_react38 = require("react");
4370
+ var import_react41 = require("react");
4046
4371
 
4047
4372
  // src/calendar-model.ts
4048
4373
  function fromDateKey(value) {
@@ -4123,8 +4448,24 @@ function isDateUnavailable(date, options) {
4123
4448
  }
4124
4449
 
4125
4450
  // src/components/SchedulingCalendar.tsx
4126
- var import_jsx_runtime61 = require("react/jsx-runtime");
4127
- var stateLabel = { scheduled: "Scheduled", conflicted: "Conflicted", "in-progress": "In progress", "blackout-violation": "Blackout violation" };
4451
+ var import_jsx_runtime62 = require("react/jsx-runtime");
4452
+ var DEFAULT_SCHEDULING_CALENDAR_LABELS = {
4453
+ region: "Scheduling calendar in {timeZone}",
4454
+ previous: "Previous",
4455
+ next: "Next",
4456
+ viewGroup: "Calendar view",
4457
+ viewMonth: "Month",
4458
+ viewWeek: "Week",
4459
+ viewAgenda: "Agenda",
4460
+ loading: "Loading schedule\u2026",
4461
+ retry: "Try again",
4462
+ agenda: "Schedule agenda",
4463
+ agendaEmpty: "No scheduled entries match the current filters.",
4464
+ grid: "{view} schedule",
4465
+ entry: "{title}, {state}, {start} to {end}",
4466
+ legend: "Schedule state legend",
4467
+ states: { scheduled: "Scheduled", conflicted: "Conflicted", "in-progress": "In progress", "blackout-violation": "Blackout violation" }
4468
+ };
4128
4469
  var stateTone = (state) => state === "scheduled" ? "info" : state === "in-progress" ? "success" : "danger";
4129
4470
  var dateLabel = (date, locale) => new Intl.DateTimeFormat(locale, { dateStyle: "full", timeZone: "UTC" }).format(/* @__PURE__ */ new Date(`${date}T00:00:00Z`));
4130
4471
  var EMPTY_OVERLAYS = [];
@@ -4143,21 +4484,29 @@ function SchedulingCalendar({
4143
4484
  loading,
4144
4485
  error,
4145
4486
  onRetry,
4146
- className
4487
+ className,
4488
+ labels: labelOverrides
4147
4489
  }) {
4148
- const [internalView, setInternalView] = (0, import_react38.useState)("month");
4490
+ const labels = {
4491
+ ...DEFAULT_SCHEDULING_CALENDAR_LABELS,
4492
+ ...labelOverrides,
4493
+ states: { ...DEFAULT_SCHEDULING_CALENDAR_LABELS.states, ...labelOverrides?.states }
4494
+ };
4495
+ const stateLabel = labels.states;
4496
+ const viewLabel = { month: labels.viewMonth, week: labels.viewWeek, agenda: labels.viewAgenda };
4497
+ const [internalView, setInternalView] = (0, import_react41.useState)("month");
4149
4498
  const view = controlledView ?? internalView;
4150
- const [activeDate, setActiveDate] = (0, import_react38.useState)(anchorDate);
4151
- const gridRef = (0, import_react38.useRef)(null);
4152
- const visibleEntries = (0, import_react38.useMemo)(() => entries.filter((entry) => filter?.(entry) ?? true), [entries, filter]);
4153
- const entrySpans = (0, import_react38.useMemo)(() => new Map(visibleEntries.map((entry) => [entry.id, zonedDateSpan(entry.start, entry.end, timeZone)])), [visibleEntries, timeZone]);
4154
- 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]);
4155
- const monthDays = (0, import_react38.useMemo)(() => buildMonthGrid(startOfMonth(anchorDate)), [anchorDate]);
4499
+ const [activeDate, setActiveDate] = (0, import_react41.useState)(anchorDate);
4500
+ const gridRef = (0, import_react41.useRef)(null);
4501
+ const visibleEntries = (0, import_react41.useMemo)(() => entries.filter((entry) => filter?.(entry) ?? true), [entries, filter]);
4502
+ const entrySpans = (0, import_react41.useMemo)(() => new Map(visibleEntries.map((entry) => [entry.id, zonedDateSpan(entry.start, entry.end, timeZone)])), [visibleEntries, timeZone]);
4503
+ const overlaySpans = (0, import_react41.useMemo)(() => new Map(overlays.map((overlay) => [overlay.id, { start: overlay.start.slice(0, 10), end: overlay.end.slice(0, 10) }])), [overlays]);
4504
+ const monthDays = (0, import_react41.useMemo)(() => buildMonthGrid(startOfMonth(anchorDate)), [anchorDate]);
4156
4505
  const weekday = ((/* @__PURE__ */ new Date(`${anchorDate}T00:00:00Z`)).getUTCDay() + 6) % 7;
4157
4506
  const weekStart = addCalendarDays(anchorDate, -weekday);
4158
- const weekDays = (0, import_react38.useMemo)(() => Array.from({ length: 7 }, (_, index) => addCalendarDays(weekStart, index)), [weekStart]);
4159
- const days = (0, import_react38.useMemo)(() => view === "month" ? monthDays.map((day) => day.date) : weekDays, [view, monthDays, weekDays]);
4160
- (0, import_react38.useEffect)(() => {
4507
+ const weekDays = (0, import_react41.useMemo)(() => Array.from({ length: 7 }, (_, index) => addCalendarDays(weekStart, index)), [weekStart]);
4508
+ const days = (0, import_react41.useMemo)(() => view === "month" ? monthDays.map((day) => day.date) : weekDays, [view, monthDays, weekDays]);
4509
+ (0, import_react41.useEffect)(() => {
4161
4510
  if (view !== "agenda" && !days.includes(activeDate)) setActiveDate(days[0]);
4162
4511
  }, [activeDate, days, view]);
4163
4512
  const setView = (next) => {
@@ -4191,60 +4540,73 @@ function SchedulingCalendar({
4191
4540
  return date >= span.start && date <= span.end;
4192
4541
  });
4193
4542
  const formatInstant = (instant) => new Intl.DateTimeFormat(locale, { timeZone, dateStyle: "medium", timeStyle: "short" }).format(new Date(instant));
4194
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("section", { className: cx("uix-scheduling-calendar", className), "aria-label": `Scheduling calendar in ${timeZone}`, children: [
4195
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "uix-scheduling-calendar__header", children: [
4196
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { children: [
4197
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(-1), disabled: !onAnchorDateChange, children: "Previous" }),
4198
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(1), disabled: !onAnchorDateChange, children: "Next" })
4543
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("section", { className: cx("uix-scheduling-calendar", className), "aria-label": fillLabel(labels.region, { timeZone }), children: [
4544
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "uix-scheduling-calendar__header", children: [
4545
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { children: [
4546
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(-1), disabled: !onAnchorDateChange, children: labels.previous }),
4547
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(1), disabled: !onAnchorDateChange, children: labels.next })
4199
4548
  ] }),
4200
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("strong", { children: view === "month" ? new Intl.DateTimeFormat(locale, { month: "long", year: "numeric", timeZone: "UTC" }).format(/* @__PURE__ */ new Date(`${anchorDate}T00:00:00Z`)) : `${dateLabel(weekStart, locale)} \u2013 ${dateLabel(weekDays[weekDays.length - 1], locale)}` }),
4201
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "uix-segmented", role: "group", "aria-label": "Calendar view", children: ["month", "week", "agenda"].map((option) => /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("button", { type: "button", className: "uix-segmented__option", "aria-pressed": view === option, "data-selected": view === option || void 0, onClick: () => setView(option), children: [
4202
- option[0].toUpperCase(),
4203
- option.slice(1)
4204
- ] }, option)) })
4549
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("strong", { children: view === "month" ? new Intl.DateTimeFormat(locale, { month: "long", year: "numeric", timeZone: "UTC" }).format(/* @__PURE__ */ new Date(`${anchorDate}T00:00:00Z`)) : `${dateLabel(weekStart, locale)} \u2013 ${dateLabel(weekDays[weekDays.length - 1], locale)}` }),
4550
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "uix-segmented", role: "group", "aria-label": labels.viewGroup, children: ["month", "week", "agenda"].map((option) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("button", { type: "button", className: "uix-segmented__option", "aria-pressed": view === option, "data-selected": view === option || void 0, onClick: () => setView(option), children: viewLabel[option] }, option)) })
4205
4551
  ] }),
4206
- loading ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "uix-scheduling-calendar__state", role: "status", children: "Loading schedule\u2026" }) : error ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "uix-scheduling-calendar__state", role: "alert", children: [
4207
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { children: error }),
4208
- onRetry && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: "Try again" })
4209
- ] }) : view === "agenda" ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "uix-scheduling-calendar__agenda", role: "region", "aria-label": "Schedule agenda", children: visibleEntries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { children: "No scheduled entries match the current filters." }) : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("ol", { children: [...visibleEntries].sort((a, b) => a.start.localeCompare(b.start)).map((entry) => {
4552
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "uix-scheduling-calendar__state", role: "status", children: labels.loading }) : error ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "uix-scheduling-calendar__state", role: "alert", children: [
4553
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { children: error }),
4554
+ onRetry && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: labels.retry })
4555
+ ] }) : view === "agenda" ? /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "uix-scheduling-calendar__agenda", role: "region", "aria-label": labels.agenda, children: visibleEntries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { children: labels.agendaEmpty }) : /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("ol", { children: [...visibleEntries].sort((a, b) => a.start.localeCompare(b.start)).map((entry) => {
4210
4556
  const state = entry.state ?? "scheduled";
4211
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("button", { type: "button", onClick: () => onSelectEntry?.(entry), children: [
4212
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { children: [
4213
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("strong", { children: renderEntry?.(entry) ?? entry.title }),
4214
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { children: [
4557
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("button", { type: "button", onClick: () => onSelectEntry?.(entry), children: [
4558
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { children: [
4559
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("strong", { children: renderEntry?.(entry) ?? entry.title }),
4560
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { children: [
4215
4561
  formatInstant(entry.start),
4216
4562
  " \u2013 ",
4217
4563
  formatInstant(entry.end)
4218
4564
  ] }),
4219
- entry.meta && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { children: entry.meta })
4565
+ entry.meta && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: entry.meta })
4220
4566
  ] }),
4221
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StatusPill, { tone: stateTone(state), children: stateLabel[state] })
4567
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(StatusPill, { tone: stateTone(state), children: stateLabel[state] })
4222
4568
  ] }) }, entry.id);
4223
- }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { ref: gridRef, className: cx("uix-scheduling-calendar__grid", view === "week" && "uix-scheduling-calendar__grid--week"), role: "group", "aria-label": `${view} schedule`, children: days.map((date, index) => {
4569
+ }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { ref: gridRef, className: cx("uix-scheduling-calendar__grid", view === "week" && "uix-scheduling-calendar__grid--week"), role: "group", "aria-label": fillLabel(labels.grid, { view: viewLabel[view] }), children: days.map((date, index) => {
4224
4570
  const dayEntries = entriesFor(date);
4225
4571
  const dayOverlays = overlaysFor(date);
4226
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "uix-scheduling-calendar__day", "data-outside": view === "month" && !monthDays[index].inMonth || void 0, children: [
4227
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("button", { type: "button", className: "uix-scheduling-calendar__date", "data-calendar-date": date, tabIndex: activeDate === date ? 0 : -1, onFocus: () => setActiveDate(date), onKeyDown: (event) => onDayKeyDown(event, date), "aria-label": dateLabel(date, locale), children: Number(date.slice(-2)) }),
4228
- dayOverlays.map((overlay) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "uix-scheduling-calendar__overlay", "data-kind": overlay.kind, children: overlay.label }, overlay.id)),
4229
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "uix-scheduling-calendar__entries", children: dayEntries.map((entry) => {
4572
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "uix-scheduling-calendar__day", "data-outside": view === "month" && !monthDays[index].inMonth || void 0, children: [
4573
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("button", { type: "button", className: "uix-scheduling-calendar__date", "data-calendar-date": date, tabIndex: activeDate === date ? 0 : -1, onFocus: () => setActiveDate(date), onKeyDown: (event) => onDayKeyDown(event, date), "aria-label": dateLabel(date, locale), children: Number(date.slice(-2)) }),
4574
+ dayOverlays.map((overlay) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "uix-scheduling-calendar__overlay", "data-kind": overlay.kind, children: overlay.label }, overlay.id)),
4575
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "uix-scheduling-calendar__entries", children: dayEntries.map((entry) => {
4230
4576
  const span = entrySpans.get(entry.id);
4231
4577
  const state = entry.state ?? "scheduled";
4232
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("button", { type: "button", className: "uix-scheduling-calendar__entry", "data-state": state, "data-range-start": date === span.start || void 0, "data-range-end": date === span.end || void 0, onClick: () => onSelectEntry?.(entry), "aria-label": `${entry.title}, ${stateLabel[state]}, ${formatInstant(entry.start)} to ${formatInstant(entry.end)}`, children: [
4233
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { children: renderEntry?.(entry) ?? entry.title }),
4234
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "uix-visually-hidden", children: stateLabel[state] })
4578
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("button", { type: "button", className: "uix-scheduling-calendar__entry", "data-state": state, "data-range-start": date === span.start || void 0, "data-range-end": date === span.end || void 0, onClick: () => onSelectEntry?.(entry), "aria-label": fillLabel(labels.entry, { title: entry.title, state: stateLabel[state], start: formatInstant(entry.start), end: formatInstant(entry.end) }), children: [
4579
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: renderEntry?.(entry) ?? entry.title }),
4580
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "uix-visually-hidden", children: stateLabel[state] })
4235
4581
  ] }, entry.id);
4236
4582
  }) })
4237
4583
  ] }, date);
4238
4584
  }) }),
4239
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "uix-scheduling-calendar__legend", "aria-label": "Schedule state legend", children: ["scheduled", "conflicted", "in-progress", "blackout-violation"].map((state) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { "data-state": state, children: stateLabel[state] }, state)) })
4585
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "uix-scheduling-calendar__legend", "aria-label": labels.legend, children: ["scheduled", "conflicted", "in-progress", "blackout-violation"].map((state) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { "data-state": state, children: stateLabel[state] }, state)) })
4240
4586
  ] });
4241
4587
  }
4242
4588
 
4243
4589
  // src/components/DateRangePicker.tsx
4244
- var import_react39 = require("react");
4245
- var import_jsx_runtime62 = require("react/jsx-runtime");
4590
+ var import_react42 = require("react");
4591
+ var import_jsx_runtime63 = require("react/jsx-runtime");
4592
+ var DEFAULT_DATE_RANGE_PICKER_LABELS = {
4593
+ previous: "Previous",
4594
+ previousMonth: "Show previous month",
4595
+ next: "Next",
4596
+ nextMonth: "Show next month",
4597
+ noneSelected: "No date range selected.",
4598
+ startSelected: "Start date {start} selected. Choose an end date.",
4599
+ rangeSelected: "{start} to {end} selected.",
4600
+ rangeStart: "start of selected range",
4601
+ rangeEnd: "end of selected range",
4602
+ inRange: "in selected range"
4603
+ };
4246
4604
  var monthLabel = (date, locale) => new Intl.DateTimeFormat(locale, { month: "long", year: "numeric", timeZone: "UTC" }).format(/* @__PURE__ */ new Date(`${date}T00:00:00Z`));
4247
4605
  var dateLabel2 = (date, locale) => new Intl.DateTimeFormat(locale, { dateStyle: "full", timeZone: "UTC" }).format(/* @__PURE__ */ new Date(`${date}T00:00:00Z`));
4606
+ var weekdayNames = (locale) => {
4607
+ const fmt = new Intl.DateTimeFormat(locale, { weekday: "short", timeZone: "UTC" });
4608
+ return Array.from({ length: 7 }, (_, i) => fmt.format(new Date(Date.UTC(2024, 0, 1 + i))));
4609
+ };
4248
4610
  function DateRangePicker({
4249
4611
  value,
4250
4612
  onChange,
@@ -4259,27 +4621,30 @@ function DateRangePicker({
4259
4621
  invalid,
4260
4622
  invalidMessage = "The selected date range is invalid.",
4261
4623
  disabled,
4262
- className
4624
+ className,
4625
+ labels: labelOverrides
4263
4626
  }) {
4264
- const id = (0, import_react39.useId)();
4265
- const [internalMonth, setInternalMonth] = (0, import_react39.useState)(() => startOfMonth(controlledMonth ?? value.start ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)));
4627
+ const id = (0, import_react42.useId)();
4628
+ const labels = { ...DEFAULT_DATE_RANGE_PICKER_LABELS, ...labelOverrides };
4629
+ const weekdays = (0, import_react42.useMemo)(() => weekdayNames(locale), [locale]);
4630
+ const [internalMonth, setInternalMonth] = (0, import_react42.useState)(() => startOfMonth(controlledMonth ?? value.start ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)));
4266
4631
  const visibleMonth = startOfMonth(controlledMonth ?? internalMonth);
4267
- const [activeDate, setActiveDate] = (0, import_react39.useState)(value.end ?? value.start ?? visibleMonth);
4268
- const rootRef = (0, import_react39.useRef)(null);
4269
- const pendingFocus = (0, import_react39.useRef)(false);
4632
+ const [activeDate, setActiveDate] = (0, import_react42.useState)(value.end ?? value.start ?? visibleMonth);
4633
+ const rootRef = (0, import_react42.useRef)(null);
4634
+ const pendingFocus = (0, import_react42.useRef)(false);
4270
4635
  const count = Math.max(1, Math.min(3, months));
4271
- const calendars = (0, import_react39.useMemo)(() => Array.from({ length: count }, (_, index) => {
4636
+ const calendars = (0, import_react42.useMemo)(() => Array.from({ length: count }, (_, index) => {
4272
4637
  const month = startOfMonth(addCalendarMonths(visibleMonth, index));
4273
4638
  return { month, days: buildMonthGrid(month).filter((day) => day.inMonth) };
4274
4639
  }), [visibleMonth, count]);
4275
4640
  const rangeInvalid = invalid || !!value.start && !!value.end && value.start > value.end;
4276
- (0, import_react39.useEffect)(() => {
4641
+ (0, import_react42.useEffect)(() => {
4277
4642
  const first = calendars[0]?.days[0]?.date;
4278
4643
  const finalDays = calendars[calendars.length - 1]?.days;
4279
4644
  const last = finalDays?.[finalDays.length - 1]?.date;
4280
4645
  if (first && last && (activeDate < first || activeDate > last)) setActiveDate(first);
4281
4646
  }, [activeDate, calendars]);
4282
- (0, import_react39.useEffect)(() => {
4647
+ (0, import_react42.useEffect)(() => {
4283
4648
  if (!pendingFocus.current) return;
4284
4649
  rootRef.current?.querySelector(`[data-date="${activeDate}"]`)?.focus();
4285
4650
  pendingFocus.current = false;
@@ -4316,24 +4681,24 @@ function DateRangePicker({
4316
4681
  focusDate(addCalendarMonths(date, event.key === "PageUp" ? -1 : 1));
4317
4682
  }
4318
4683
  };
4319
- const announcement = !value.start ? "No date range selected." : !value.end ? `Start date ${dateLabel2(value.start, locale)} selected. Choose an end date.` : `${dateLabel2(value.start, locale)} to ${dateLabel2(value.end, locale)} selected.`;
4320
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("section", { className: cx("uix-date-range-picker", rangeInvalid && "uix-date-range-picker--invalid", className), "aria-labelledby": `${id}-label`, children: [
4321
- /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "uix-date-range-picker__header", children: [
4322
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("h3", { id: `${id}-label`, children: label }),
4323
- /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { children: [
4324
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => setMonth(addCalendarMonths(visibleMonth, -1)), "aria-label": "Show previous month", children: "Previous" }),
4325
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => setMonth(addCalendarMonths(visibleMonth, 1)), "aria-label": "Show next month", children: "Next" })
4684
+ const announcement = !value.start ? labels.noneSelected : !value.end ? labels.startSelected.replace("{start}", dateLabel2(value.start, locale)) : labels.rangeSelected.replace("{start}", dateLabel2(value.start, locale)).replace("{end}", dateLabel2(value.end, locale));
4685
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("section", { className: cx("uix-date-range-picker", rangeInvalid && "uix-date-range-picker--invalid", className), "aria-labelledby": `${id}-label`, children: [
4686
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uix-date-range-picker__header", children: [
4687
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h3", { id: `${id}-label`, children: label }),
4688
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { children: [
4689
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => setMonth(addCalendarMonths(visibleMonth, -1)), "aria-label": labels.previousMonth, children: labels.previous }),
4690
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => setMonth(addCalendarMonths(visibleMonth, 1)), "aria-label": labels.nextMonth, children: labels.next })
4326
4691
  ] })
4327
4692
  ] }),
4328
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { ref: rootRef, className: "uix-date-range-picker__months", children: calendars.map(({ month, days }) => /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "uix-date-range-picker__month", children: [
4329
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("h4", { children: monthLabel(month, locale) }),
4330
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "uix-date-range-picker__weekdays", "aria-hidden": "true", children: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].map((day) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { children: day }, day)) }),
4331
- /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "uix-date-range-picker__grid", role: "group", "aria-label": monthLabel(month, locale), children: [
4332
- Array.from({ length: ((/* @__PURE__ */ new Date(`${month}T00:00:00Z`)).getUTCDay() + 6) % 7 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { "aria-hidden": "true" }, `blank-${index}`)),
4693
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { ref: rootRef, className: "uix-date-range-picker__months", children: calendars.map(({ month, days }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uix-date-range-picker__month", children: [
4694
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h4", { children: monthLabel(month, locale) }),
4695
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "uix-date-range-picker__weekdays", "aria-hidden": "true", children: weekdays.map((day, index) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { children: day }, index)) }),
4696
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uix-date-range-picker__grid", role: "group", "aria-label": monthLabel(month, locale), children: [
4697
+ Array.from({ length: ((/* @__PURE__ */ new Date(`${month}T00:00:00Z`)).getUTCDay() + 6) % 7 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { "aria-hidden": "true" }, `blank-${index}`)),
4333
4698
  days.map((day) => {
4334
4699
  const unavailable = disabled || isDateUnavailable(day.date, { min, max, isDisabled: isDateDisabled });
4335
4700
  const edge = day.date === value.start ? "start" : day.date === value.end ? "end" : void 0;
4336
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
4701
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
4337
4702
  "button",
4338
4703
  {
4339
4704
  type: "button",
@@ -4341,7 +4706,7 @@ function DateRangePicker({
4341
4706
  "data-range-edge": edge,
4342
4707
  "data-in-range": isDateInRange(day.date, value) || void 0,
4343
4708
  "aria-pressed": edge != null || isDateInRange(day.date, value),
4344
- "aria-label": `${dateLabel2(day.date, locale)}${edge ? `, ${edge} of selected range` : isDateInRange(day.date, value) ? ", in selected range" : ""}`,
4709
+ "aria-label": `${dateLabel2(day.date, locale)}${edge ? `, ${edge === "start" ? labels.rangeStart : labels.rangeEnd}` : isDateInRange(day.date, value) ? `, ${labels.inRange}` : ""}`,
4345
4710
  tabIndex: activeDate === day.date ? 0 : -1,
4346
4711
  disabled: unavailable,
4347
4712
  onFocus: () => setActiveDate(day.date),
@@ -4354,13 +4719,13 @@ function DateRangePicker({
4354
4719
  })
4355
4720
  ] })
4356
4721
  ] }, month)) }),
4357
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: "uix-date-range-picker__selection", "aria-live": "polite", children: announcement }),
4358
- rangeInvalid && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: "uix-field__error", role: "alert", children: invalidMessage })
4722
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "uix-date-range-picker__selection", "aria-live": "polite", children: announcement }),
4723
+ rangeInvalid && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "uix-field__error", role: "alert", children: invalidMessage })
4359
4724
  ] });
4360
4725
  }
4361
4726
 
4362
4727
  // src/components/RelationshipGraph.tsx
4363
- var import_react41 = require("react");
4728
+ var import_react44 = require("react");
4364
4729
 
4365
4730
  // src/relationship-graph-model.ts
4366
4731
  function boundRelationshipGraph(nodes, edges, maxNodes = 40) {
@@ -4841,10 +5206,10 @@ function layeredNeighbor(layout, currentId, key) {
4841
5206
  }
4842
5207
 
4843
5208
  // src/components/RelationshipGraphLayered.tsx
4844
- var import_react40 = require("react");
5209
+ var import_react43 = require("react");
4845
5210
 
4846
5211
  // src/components/RelationshipGraphList.tsx
4847
- var import_jsx_runtime63 = require("react/jsx-runtime");
5212
+ var import_jsx_runtime64 = require("react/jsx-runtime");
4848
5213
  function EquivalentRelationshipList({
4849
5214
  nodes,
4850
5215
  edges,
@@ -4855,19 +5220,19 @@ function EquivalentRelationshipList({
4855
5220
  onOpenDetails
4856
5221
  }) {
4857
5222
  const labelById = new Map(nodes.map((node) => [node.id, node.label]));
4858
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uix-relationship-graph__list", role: "region", "aria-label": labels.list, children: [
4859
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h3", { children: labels.listHeading }),
4860
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("ul", { children: nodes.map((node) => {
5223
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "uix-relationship-graph__list", role: "region", "aria-label": labels.list, children: [
5224
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("h3", { children: labels.listHeading }),
5225
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("ul", { children: nodes.map((node) => {
4861
5226
  const neighbors = relationshipNeighbors(node.id, edges).map((id) => labelById.get(id) ?? id);
4862
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("li", { "data-selected": selectedId === node.id || void 0, children: [
4863
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("button", { type: "button", onClick: () => onSelect(node.id), "aria-pressed": selectedId === node.id, children: [
4864
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("strong", { children: node.label }),
4865
- node.type && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { children: node.type }),
4866
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { children: neighbors.length ? labels.connectedTo(neighbors.join(", ")) : labels.noConnections })
5227
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("li", { "data-selected": selectedId === node.id || void 0, children: [
5228
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("button", { type: "button", onClick: () => onSelect(node.id), "aria-pressed": selectedId === node.id, children: [
5229
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("strong", { children: node.label }),
5230
+ node.type && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { children: node.type }),
5231
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { children: neighbors.length ? labels.connectedTo(neighbors.join(", ")) : labels.noConnections })
4867
5232
  ] }),
4868
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "uix-relationship-graph__list-actions", children: [
4869
- onExpandNeighbors && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("button", { type: "button", onClick: () => onExpandNeighbors(node), children: labels.expandNeighbors }),
4870
- onOpenDetails && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("button", { type: "button", onClick: () => onOpenDetails(node), children: labels.openDetails })
5233
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "uix-relationship-graph__list-actions", children: [
5234
+ onExpandNeighbors && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => onExpandNeighbors(node), children: labels.expandNeighbors }),
5235
+ onOpenDetails && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => onOpenDetails(node), children: labels.openDetails })
4871
5236
  ] })
4872
5237
  ] }, node.id);
4873
5238
  }) })
@@ -4875,7 +5240,7 @@ function EquivalentRelationshipList({
4875
5240
  }
4876
5241
 
4877
5242
  // src/components/RelationshipGraphLayered.tsx
4878
- var import_jsx_runtime64 = require("react/jsx-runtime");
5243
+ var import_jsx_runtime65 = require("react/jsx-runtime");
4879
5244
  var EMPTY_IDS = /* @__PURE__ */ new Set();
4880
5245
  var MIN_ZOOM = 0.4;
4881
5246
  var MAX_ZOOM = 1.5;
@@ -4928,11 +5293,11 @@ function LayeredRelationshipGraph({
4928
5293
  focusId,
4929
5294
  onFocusChange
4930
5295
  }) {
4931
- const hintId = (0, import_react40.useId)();
4932
- const bounded = (0, import_react40.useMemo)(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
4933
- const [localExpanded, setLocalExpanded] = (0, import_react40.useState)(EMPTY_IDS);
5296
+ const hintId = (0, import_react43.useId)();
5297
+ const bounded = (0, import_react43.useMemo)(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
5298
+ const [localExpanded, setLocalExpanded] = (0, import_react43.useState)(EMPTY_IDS);
4934
5299
  const expanded = expandedClusterIds ?? localExpanded;
4935
- const layout = (0, import_react40.useMemo)(
5300
+ const layout = (0, import_react43.useMemo)(
4936
5301
  () => layoutLayeredGraph(bounded.nodes, bounded.edges, {
4937
5302
  ...rootId !== void 0 ? { rootId } : {},
4938
5303
  ...clusterThreshold !== void 0 ? { clusterThreshold } : {},
@@ -4941,29 +5306,29 @@ function LayeredRelationshipGraph({
4941
5306
  }),
4942
5307
  [bounded, rootId, clusterThreshold, expanded, density]
4943
5308
  );
4944
- const itemById = (0, import_react40.useMemo)(() => new Map(layout.items.map((item) => [item.id, item])), [layout]);
4945
- const viewportRef = (0, import_react40.useRef)(null);
4946
- const itemRefs = (0, import_react40.useRef)(/* @__PURE__ */ new Map());
4947
- const [size, setSize] = (0, import_react40.useState)({ width: 0, height: 0 });
4948
- const [view, setView] = (0, import_react40.useState)({ x: 0, y: 0, zoom: 1 });
4949
- const [animate, setAnimate] = (0, import_react40.useState)(false);
4950
- const [localFocus, setLocalFocus] = (0, import_react40.useState)(void 0);
4951
- const [hoverId, setHoverId] = (0, import_react40.useState)(void 0);
4952
- const viewRef = (0, import_react40.useRef)(view);
5309
+ const itemById = (0, import_react43.useMemo)(() => new Map(layout.items.map((item) => [item.id, item])), [layout]);
5310
+ const viewportRef = (0, import_react43.useRef)(null);
5311
+ const itemRefs = (0, import_react43.useRef)(/* @__PURE__ */ new Map());
5312
+ const [size, setSize] = (0, import_react43.useState)({ width: 0, height: 0 });
5313
+ const [view, setView] = (0, import_react43.useState)({ x: 0, y: 0, zoom: 1 });
5314
+ const [animate, setAnimate] = (0, import_react43.useState)(false);
5315
+ const [localFocus, setLocalFocus] = (0, import_react43.useState)(void 0);
5316
+ const [hoverId, setHoverId] = (0, import_react43.useState)(void 0);
5317
+ const viewRef = (0, import_react43.useRef)(view);
4953
5318
  viewRef.current = view;
4954
- const layoutRef = (0, import_react40.useRef)(layout);
5319
+ const layoutRef = (0, import_react43.useRef)(layout);
4955
5320
  layoutRef.current = layout;
4956
- const pendingFocus = (0, import_react40.useRef)(void 0);
4957
- const initialisedFor = (0, import_react40.useRef)(void 0);
5321
+ const pendingFocus = (0, import_react43.useRef)(void 0);
5322
+ const initialisedFor = (0, import_react43.useRef)(void 0);
4958
5323
  const rootItemId = layout.rootId !== void 0 ? layout.itemOf[layout.rootId] : layout.items[0]?.id;
4959
5324
  const requestedFocus = focusId !== void 0 ? layout.itemOf[focusId] ?? focusId : localFocus;
4960
5325
  const focusedId = requestedFocus !== void 0 && itemById.has(requestedFocus) ? requestedFocus : rootItemId;
4961
5326
  const selectedItemId = selectedId !== void 0 ? layout.itemOf[selectedId] : void 0;
4962
- const activeIds = (0, import_react40.useMemo)(
5327
+ const activeIds = (0, import_react43.useMemo)(
4963
5328
  () => new Set([hoverId, selectedItemId].filter((id) => id !== void 0)),
4964
5329
  [hoverId, selectedItemId]
4965
5330
  );
4966
- (0, import_react40.useEffect)(() => {
5331
+ (0, import_react43.useEffect)(() => {
4967
5332
  const element = viewportRef.current;
4968
5333
  if (!element) return;
4969
5334
  const measure = () => setSize({ width: element.clientWidth, height: element.clientHeight });
@@ -4973,18 +5338,18 @@ function LayeredRelationshipGraph({
4973
5338
  observer.observe(element);
4974
5339
  return () => observer.disconnect();
4975
5340
  }, []);
4976
- (0, import_react40.useEffect)(() => {
5341
+ (0, import_react43.useEffect)(() => {
4977
5342
  if (size.width === 0) return;
4978
5343
  const key = `${layout.rootId ?? ""}`;
4979
5344
  if (initialisedFor.current === key) return;
4980
5345
  initialisedFor.current = key;
4981
5346
  setView(initialView(layout, size));
4982
5347
  }, [layout, size]);
4983
- const moveView = (0, import_react40.useCallback)((next, smooth) => {
5348
+ const moveView = (0, import_react43.useCallback)((next, smooth) => {
4984
5349
  setAnimate(smooth);
4985
5350
  setView(next);
4986
5351
  }, []);
4987
- const ensureVisible = (0, import_react40.useCallback)((id, smooth) => {
5352
+ const ensureVisible = (0, import_react43.useCallback)((id, smooth) => {
4988
5353
  const element = viewportRef.current;
4989
5354
  const item = layoutRef.current.items.find((candidate) => candidate.id === id);
4990
5355
  if (!element || !item) return;
@@ -5003,7 +5368,7 @@ function LayeredRelationshipGraph({
5003
5368
  else if (bottom > heightPx - FOCUS_MARGIN) nextY -= bottom - (heightPx - FOCUS_MARGIN);
5004
5369
  if (nextX !== x || nextY !== y) moveView({ x: nextX, y: nextY, zoom }, smooth);
5005
5370
  }, [moveView]);
5006
- const focusItem = (0, import_react40.useCallback)((id) => {
5371
+ const focusItem = (0, import_react43.useCallback)((id) => {
5007
5372
  setLocalFocus(id);
5008
5373
  onFocusChange?.(id);
5009
5374
  requestAnimationFrame(() => {
@@ -5011,7 +5376,7 @@ function LayeredRelationshipGraph({
5011
5376
  ensureVisible(id, true);
5012
5377
  });
5013
5378
  }, [ensureVisible, onFocusChange]);
5014
- (0, import_react40.useEffect)(() => {
5379
+ (0, import_react43.useEffect)(() => {
5015
5380
  const wanted = pendingFocus.current;
5016
5381
  if (wanted !== void 0 && itemById.has(wanted)) {
5017
5382
  pendingFocus.current = void 0;
@@ -5021,8 +5386,8 @@ function LayeredRelationshipGraph({
5021
5386
  const controlledTarget = focusId !== void 0 ? layout.itemOf[focusId] ?? focusId : void 0;
5022
5387
  const controlledPresent = controlledTarget !== void 0 && itemById.has(controlledTarget);
5023
5388
  const controlledKey = `${controlledTarget ?? ""}|${controlledPresent}`;
5024
- const lastControlledKey = (0, import_react40.useRef)(controlledKey);
5025
- (0, import_react40.useEffect)(() => {
5389
+ const lastControlledKey = (0, import_react43.useRef)(controlledKey);
5390
+ (0, import_react43.useEffect)(() => {
5026
5391
  if (lastControlledKey.current === controlledKey) return;
5027
5392
  lastControlledKey.current = controlledKey;
5028
5393
  if (!controlledPresent || controlledTarget === void 0) return;
@@ -5031,7 +5396,7 @@ function LayeredRelationshipGraph({
5031
5396
  ensureVisible(controlledTarget, true);
5032
5397
  });
5033
5398
  }, [controlledKey, controlledTarget, controlledPresent, ensureVisible]);
5034
- (0, import_react40.useEffect)(() => {
5399
+ (0, import_react43.useEffect)(() => {
5035
5400
  const element = viewportRef.current;
5036
5401
  if (!element) return;
5037
5402
  const onWheel = (event) => {
@@ -5049,8 +5414,8 @@ function LayeredRelationshipGraph({
5049
5414
  element.addEventListener("wheel", onWheel, { passive: false });
5050
5415
  return () => element.removeEventListener("wheel", onWheel);
5051
5416
  }, []);
5052
- const pointers = (0, import_react40.useRef)(/* @__PURE__ */ new Map());
5053
- const pinchDistance = (0, import_react40.useRef)(void 0);
5417
+ const pointers = (0, import_react43.useRef)(/* @__PURE__ */ new Map());
5418
+ const pinchDistance = (0, import_react43.useRef)(void 0);
5054
5419
  const onPointerDown = (event) => {
5055
5420
  if (event.target.closest("button")) return;
5056
5421
  event.currentTarget.setPointerCapture?.(event.pointerId);
@@ -5148,21 +5513,21 @@ function LayeredRelationshipGraph({
5148
5513
  height: layout.height,
5149
5514
  transform: `translate(${view.x}px, ${view.y}px) scale(${view.zoom})`
5150
5515
  };
5151
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("section", { className: cx("uix-relationship-graph", "uix-relationship-graph--layered", density === "compact" && "uix-relationship-graph--compact", className), "aria-label": labels.graph, children: [
5152
- /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "uix-relationship-graph__toolbar", role: "group", "aria-label": labels.controls, children: [
5153
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => zoomBy(ZOOM_STEP), disabled: view.zoom >= MAX_ZOOM, children: labels.zoomIn }),
5154
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => zoomBy(1 / ZOOM_STEP), disabled: view.zoom <= MIN_ZOOM, children: labels.zoomOut }),
5155
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => moveView(fitView(layout, size), true), children: labels.fit }),
5156
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => moveView(initialView(layout, size), true), children: labels.reset }),
5157
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => panBy(PAN_STEP, 0), "aria-label": labels.panLeft, children: labels.left }),
5158
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => panBy(0, PAN_STEP), "aria-label": labels.panUp, children: labels.up }),
5159
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => panBy(0, -PAN_STEP), "aria-label": labels.panDown, children: labels.down }),
5160
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", onClick: () => panBy(-PAN_STEP, 0), "aria-label": labels.panRight, children: labels.right }),
5161
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { "aria-live": "polite", children: labels.zoomLevel(Math.round(view.zoom * 100)) })
5516
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("section", { className: cx("uix-relationship-graph", "uix-relationship-graph--layered", density === "compact" && "uix-relationship-graph--compact", className), "aria-label": labels.graph, children: [
5517
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: "uix-relationship-graph__toolbar", role: "group", "aria-label": labels.controls, children: [
5518
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => zoomBy(ZOOM_STEP), disabled: view.zoom >= MAX_ZOOM, children: labels.zoomIn }),
5519
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => zoomBy(1 / ZOOM_STEP), disabled: view.zoom <= MIN_ZOOM, children: labels.zoomOut }),
5520
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => moveView(fitView(layout, size), true), children: labels.fit }),
5521
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => moveView(initialView(layout, size), true), children: labels.reset }),
5522
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => panBy(PAN_STEP, 0), "aria-label": labels.panLeft, children: labels.left }),
5523
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => panBy(0, PAN_STEP), "aria-label": labels.panUp, children: labels.up }),
5524
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => panBy(0, -PAN_STEP), "aria-label": labels.panDown, children: labels.down }),
5525
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => panBy(-PAN_STEP, 0), "aria-label": labels.panRight, children: labels.right }),
5526
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { "aria-live": "polite", children: labels.zoomLevel(Math.round(view.zoom * 100)) })
5162
5527
  ] }),
5163
- bounded.omittedNodeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("p", { className: "uix-relationship-graph__bounded", role: "status", children: labels.bounded(bounded.nodes.length, bounded.omittedNodeCount) }),
5164
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("p", { id: hintId, className: "uix-visually-hidden", children: labels.keyboardHint }),
5165
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5528
+ bounded.omittedNodeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { className: "uix-relationship-graph__bounded", role: "status", children: labels.bounded(bounded.nodes.length, bounded.omittedNodeCount) }),
5529
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { id: hintId, className: "uix-visually-hidden", children: labels.keyboardHint }),
5530
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5166
5531
  "div",
5167
5532
  {
5168
5533
  ref: viewportRef,
@@ -5172,11 +5537,11 @@ function LayeredRelationshipGraph({
5172
5537
  onPointerMove,
5173
5538
  onPointerUp: onPointerEnd,
5174
5539
  onPointerCancel: onPointerEnd,
5175
- children: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "uix-relationship-graph__stage", style: stageStyle, "data-animate": animate || void 0, onTransitionEnd: () => setAnimate(false), children: [
5176
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("svg", { className: "uix-relationship-graph__edges", width: layout.width, height: layout.height, "aria-hidden": "true", focusable: "false", children: layout.edges.map((edge) => {
5540
+ children: /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: "uix-relationship-graph__stage", style: stageStyle, "data-animate": animate || void 0, onTransitionEnd: () => setAnimate(false), children: [
5541
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("svg", { className: "uix-relationship-graph__edges", width: layout.width, height: layout.height, "aria-hidden": "true", focusable: "false", children: layout.edges.map((edge) => {
5177
5542
  const active = activeIds.has(edge.source) || activeIds.has(edge.target) || edge.edgeIds.some((id) => highlightedEdgeIds.has(id));
5178
5543
  const angle = edge.arrowAngle * 180 / Math.PI;
5179
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
5544
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
5180
5545
  "g",
5181
5546
  {
5182
5547
  className: "uix-relationship-graph__link",
@@ -5186,15 +5551,15 @@ function LayeredRelationshipGraph({
5186
5551
  "data-conflicted": edge.edgeIds.some((id) => conflictedEdgeIds.has(id)) || void 0,
5187
5552
  "data-dimmed": dimmedNodeIds.has(edge.source) && dimmedNodeIds.has(edge.target) || void 0,
5188
5553
  children: [
5189
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("path", { d: edge.path }),
5190
- edge.arrow !== "none" && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("polygon", { points: arrowPoints, transform: `translate(${edge.arrowX} ${edge.arrowY}) rotate(${angle})` }),
5191
- showLabel(edge) && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("text", { x: edge.labelX, y: edge.labelY, textAnchor: "middle", dominantBaseline: "middle", children: (edge.kind === "cycle" ? [...edge.labelLines, labels.cycle] : edge.labelLines).map((line, index, lines) => /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("tspan", { x: edge.labelX, dy: index === 0 ? `${-(lines.length - 1) * 0.55}em` : "1.1em", children: line }, index)) })
5554
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("path", { d: edge.path }),
5555
+ edge.arrow !== "none" && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("polygon", { points: arrowPoints, transform: `translate(${edge.arrowX} ${edge.arrowY}) rotate(${angle})` }),
5556
+ showLabel(edge) && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("text", { x: edge.labelX, y: edge.labelY, textAnchor: "middle", dominantBaseline: "middle", children: (edge.kind === "cycle" ? [...edge.labelLines, labels.cycle] : edge.labelLines).map((line, index, lines) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("tspan", { x: edge.labelX, dy: index === 0 ? `${-(lines.length - 1) * 0.55}em` : "1.1em", children: line }, index)) })
5192
5557
  ]
5193
5558
  },
5194
5559
  edge.id
5195
5560
  );
5196
5561
  }) }),
5197
- layout.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5562
+ layout.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5198
5563
  "div",
5199
5564
  {
5200
5565
  className: "uix-relationship-graph__column",
@@ -5204,17 +5569,17 @@ function LayeredRelationshipGraph({
5204
5569
  },
5205
5570
  column.depth
5206
5571
  )),
5207
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { role: "group", "aria-roledescription": labels.roleDescription, "aria-label": labels.graphSummary(bounded.nodes.length, bounded.edges.length), "aria-describedby": hintId, children: layout.items.map((item) => {
5572
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { role: "group", "aria-roledescription": labels.roleDescription, "aria-label": labels.graphSummary(bounded.nodes.length, bounded.edges.length), "aria-describedby": hintId, children: layout.items.map((item) => {
5208
5573
  const selected = item.id === selectedItemId;
5209
5574
  const dimmed = item.node ? dimmedNodeIds.has(item.node.id) : item.cluster.members.every((member) => dimmedNodeIds.has(member.id));
5210
- const body = item.cluster ? renderCluster?.(item.cluster) ?? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(import_jsx_runtime64.Fragment, { children: [
5211
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "uix-relationship-graph__item-label", children: labels.cluster(item.cluster.members.length, item.cluster.type, item.cluster.edgeLabel) }),
5212
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "uix-relationship-graph__item-meta", children: labels.expandCluster })
5213
- ] }) : renderNode?.(item.node, { selected, dimmed }) ?? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(import_jsx_runtime64.Fragment, { children: [
5214
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "uix-relationship-graph__item-label", children: item.node.label }),
5215
- (item.node.type || item.node.description) && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "uix-relationship-graph__item-meta", children: [item.node.type, item.node.description].filter(Boolean).join(" \xB7 ") })
5575
+ const body = item.cluster ? renderCluster?.(item.cluster) ?? /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(import_jsx_runtime65.Fragment, { children: [
5576
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "uix-relationship-graph__item-label", children: labels.cluster(item.cluster.members.length, item.cluster.type, item.cluster.edgeLabel) }),
5577
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "uix-relationship-graph__item-meta", children: labels.expandCluster })
5578
+ ] }) : renderNode?.(item.node, { selected, dimmed }) ?? /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(import_jsx_runtime65.Fragment, { children: [
5579
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "uix-relationship-graph__item-label", children: item.node.label }),
5580
+ (item.node.type || item.node.description) && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "uix-relationship-graph__item-meta", children: [item.node.type, item.node.description].filter(Boolean).join(" \xB7 ") })
5216
5581
  ] });
5217
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
5582
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
5218
5583
  "button",
5219
5584
  {
5220
5585
  ref: (element) => {
@@ -5245,7 +5610,7 @@ function LayeredRelationshipGraph({
5245
5610
  onPointerLeave: () => setHoverId((current) => current === item.id ? void 0 : current),
5246
5611
  children: [
5247
5612
  body,
5248
- item.inCycle && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "uix-relationship-graph__item-flag", "aria-hidden": "true", children: labels.cycle })
5613
+ item.inCycle && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "uix-relationship-graph__item-flag", "aria-hidden": "true", children: labels.cycle })
5249
5614
  ]
5250
5615
  },
5251
5616
  item.id
@@ -5253,7 +5618,7 @@ function LayeredRelationshipGraph({
5253
5618
  }) }),
5254
5619
  layout.items.filter((item) => item.expandedGroup).map((item) => {
5255
5620
  const group = item.expandedGroup;
5256
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5621
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5257
5622
  "button",
5258
5623
  {
5259
5624
  type: "button",
@@ -5269,8 +5634,8 @@ function LayeredRelationshipGraph({
5269
5634
  ] })
5270
5635
  }
5271
5636
  ),
5272
- legend.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("li", { "data-type": entry.id, children: entry.label }, entry.id)) }),
5273
- showList && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5637
+ legend.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("li", { "data-type": entry.id, children: entry.label }, entry.id)) }),
5638
+ showList && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5274
5639
  EquivalentRelationshipList,
5275
5640
  {
5276
5641
  nodes: bounded.nodes,
@@ -5289,7 +5654,7 @@ function LayeredRelationshipGraph({
5289
5654
  }
5290
5655
 
5291
5656
  // src/components/RelationshipGraph.tsx
5292
- var import_jsx_runtime65 = require("react/jsx-runtime");
5657
+ var import_jsx_runtime66 = require("react/jsx-runtime");
5293
5658
  var DEFAULT_RELATIONSHIP_GRAPH_LABELS = {
5294
5659
  graph: "Relationship graph",
5295
5660
  controls: "Graph view controls",
@@ -5351,21 +5716,21 @@ function radialViewBox(nodes) {
5351
5716
  return `${round(minX)} ${round(minY)} ${width} ${height}`;
5352
5717
  }
5353
5718
  function RelationshipGraph(props) {
5354
- const labels = (0, import_react41.useMemo)(() => ({ ...DEFAULT_RELATIONSHIP_GRAPH_LABELS, ...props.labels }), [props.labels]);
5719
+ const labels = (0, import_react44.useMemo)(() => ({ ...DEFAULT_RELATIONSHIP_GRAPH_LABELS, ...props.labels }), [props.labels]);
5355
5720
  const stateClass = cx("uix-relationship-graph uix-relationship-graph--state", props.className);
5356
- if (props.loading) return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: stateClass, role: "status", children: labels.loading });
5721
+ if (props.loading) return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: stateClass, role: "status", children: labels.loading });
5357
5722
  if (props.error) {
5358
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: stateClass, role: "alert", children: [
5359
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { children: props.error }),
5360
- props.onRetry && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: props.onRetry, children: labels.retry })
5723
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: stateClass, role: "alert", children: [
5724
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { children: props.error }),
5725
+ props.onRetry && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: props.onRetry, children: labels.retry })
5361
5726
  ] });
5362
5727
  }
5363
- if (props.nodes.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: stateClass, children: [
5364
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { children: labels.emptyTitle }),
5365
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { children: labels.emptyHint })
5728
+ if (props.nodes.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: stateClass, children: [
5729
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { children: labels.emptyTitle }),
5730
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { children: labels.emptyHint })
5366
5731
  ] });
5367
- if (props.layout === "layered") return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(LayeredRelationshipGraph, { ...props, labels });
5368
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(RadialRelationshipGraph, { ...props, labels });
5732
+ if (props.layout === "layered") return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(LayeredRelationshipGraph, { ...props, labels });
5733
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(RadialRelationshipGraph, { ...props, labels });
5369
5734
  }
5370
5735
  function RadialRelationshipGraph({
5371
5736
  nodes,
@@ -5385,13 +5750,17 @@ function RadialRelationshipGraph({
5385
5750
  labels,
5386
5751
  showList = true
5387
5752
  }) {
5388
- const bounded = (0, import_react41.useMemo)(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
5389
- const positioned = (0, import_react41.useMemo)(() => layoutRelationshipGraph(bounded.nodes, bounded.edges, selectedId), [bounded, selectedId]);
5390
- const positionedById = (0, import_react41.useMemo)(() => new Map(positioned.map((node) => [node.id, node])), [positioned]);
5391
- const [zoom, setZoom] = (0, import_react41.useState)(1);
5392
- const [pan, setPan] = (0, import_react41.useState)({ x: 0, y: 0 });
5393
- const [focusedId, setFocusedId] = (0, import_react41.useState)(selectedId ?? positioned[0]?.id);
5394
- const svgRef = (0, import_react41.useRef)(null);
5753
+ const bounded = (0, import_react44.useMemo)(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
5754
+ const positioned = (0, import_react44.useMemo)(() => layoutRelationshipGraph(bounded.nodes, bounded.edges, selectedId), [bounded, selectedId]);
5755
+ const typeColor = (0, import_react44.useMemo)(
5756
+ () => new Map(legend.map((item, index) => [item.id, `var(--uix-chart-${index % 8 + 1})`])),
5757
+ [legend]
5758
+ );
5759
+ const positionedById = (0, import_react44.useMemo)(() => new Map(positioned.map((node) => [node.id, node])), [positioned]);
5760
+ const [zoom, setZoom] = (0, import_react44.useState)(1);
5761
+ const [pan, setPan] = (0, import_react44.useState)({ x: 0, y: 0 });
5762
+ const [focusedId, setFocusedId] = (0, import_react44.useState)(selectedId ?? positioned[0]?.id);
5763
+ const svgRef = (0, import_react44.useRef)(null);
5395
5764
  const select = (id) => {
5396
5765
  const node = bounded.nodes.find((item) => item.id === id);
5397
5766
  if (node) onSelect?.(node);
@@ -5414,25 +5783,25 @@ function RadialRelationshipGraph({
5414
5783
  setZoom(1);
5415
5784
  setPan({ x: 0, y: 0 });
5416
5785
  };
5417
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("section", { className: cx("uix-relationship-graph", `uix-relationship-graph--${density}`, className), "aria-label": labels.graph, children: [
5418
- /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: "uix-relationship-graph__toolbar", "aria-label": labels.controls, children: [
5419
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => setPan((value) => ({ ...value, x: value.x - 24 })), "aria-label": labels.panLeft, children: labels.left }),
5420
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => setPan((value) => ({ ...value, y: value.y - 24 })), "aria-label": labels.panUp, children: labels.up }),
5421
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => setPan((value) => ({ ...value, y: value.y + 24 })), "aria-label": labels.panDown, children: labels.down }),
5422
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => setPan((value) => ({ ...value, x: value.x + 24 })), "aria-label": labels.panRight, children: labels.right }),
5423
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => setZoom((value) => Math.min(2, Number((value + 0.2).toFixed(1)))), "aria-label": labels.zoomIn, children: labels.zoomIn }),
5424
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: () => setZoom((value) => Math.max(0.5, Number((value - 0.2).toFixed(1)))), "aria-label": labels.zoomOut, children: labels.zoomOut }),
5425
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("button", { type: "button", onClick: reset, children: labels.reset }),
5426
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { "aria-live": "polite", children: labels.zoomLevel(Math.round(zoom * 100)) })
5786
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("section", { className: cx("uix-relationship-graph", `uix-relationship-graph--${density}`, className), "aria-label": labels.graph, children: [
5787
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "uix-relationship-graph__toolbar", "aria-label": labels.controls, children: [
5788
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", onClick: () => setPan((value) => ({ ...value, x: value.x - 24 })), "aria-label": labels.panLeft, children: labels.left }),
5789
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", onClick: () => setPan((value) => ({ ...value, y: value.y - 24 })), "aria-label": labels.panUp, children: labels.up }),
5790
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", onClick: () => setPan((value) => ({ ...value, y: value.y + 24 })), "aria-label": labels.panDown, children: labels.down }),
5791
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", onClick: () => setPan((value) => ({ ...value, x: value.x + 24 })), "aria-label": labels.panRight, children: labels.right }),
5792
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", onClick: () => setZoom((value) => Math.min(2, Number((value + 0.2).toFixed(1)))), "aria-label": labels.zoomIn, children: labels.zoomIn }),
5793
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", onClick: () => setZoom((value) => Math.max(0.5, Number((value - 0.2).toFixed(1)))), "aria-label": labels.zoomOut, children: labels.zoomOut }),
5794
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", onClick: reset, children: labels.reset }),
5795
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { "aria-live": "polite", children: labels.zoomLevel(Math.round(zoom * 100)) })
5427
5796
  ] }),
5428
- bounded.omittedNodeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("p", { className: "uix-relationship-graph__bounded", role: "status", children: labels.bounded(bounded.nodes.length, bounded.omittedNodeCount) }),
5429
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "uix-relationship-graph__visual", children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("svg", { ref: svgRef, viewBox: radialViewBox(positioned), role: "group", "aria-label": labels.graphSummary(bounded.nodes.length, bounded.edges.length), children: /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("g", { transform: `translate(${pan.x} ${pan.y}) scale(${zoom})`, children: [
5797
+ bounded.omittedNodeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "uix-relationship-graph__bounded", role: "status", children: labels.bounded(bounded.nodes.length, bounded.omittedNodeCount) }),
5798
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "uix-relationship-graph__visual", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("svg", { ref: svgRef, viewBox: radialViewBox(positioned), role: "group", "aria-label": labels.graphSummary(bounded.nodes.length, bounded.edges.length), children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("g", { transform: `translate(${pan.x} ${pan.y}) scale(${zoom})`, children: [
5430
5799
  bounded.edges.map((edge) => {
5431
5800
  const source = positionedById.get(edge.source);
5432
5801
  const target = positionedById.get(edge.target);
5433
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("line", { x1: source.x * RADIAL_SCALE_X, y1: source.y * RADIAL_SCALE_Y, x2: target.x * RADIAL_SCALE_X, y2: target.y * RADIAL_SCALE_Y, className: "uix-relationship-graph__edge", "data-highlighted": highlightedEdgeIds.has(edge.id) || void 0, "data-conflicted": conflictedEdgeIds.has(edge.id) || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("title", { children: edge.label ?? edge.type ?? labels.relationship }) }, edge.id);
5802
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("line", { x1: source.x * RADIAL_SCALE_X, y1: source.y * RADIAL_SCALE_Y, x2: target.x * RADIAL_SCALE_X, y2: target.y * RADIAL_SCALE_Y, className: "uix-relationship-graph__edge", "data-typed": edge.type != null && typeColor.has(edge.type) || void 0, style: edge.type != null && typeColor.has(edge.type) ? { "--uix-graph-type-color": typeColor.get(edge.type) } : void 0, "data-highlighted": highlightedEdgeIds.has(edge.id) || void 0, "data-conflicted": conflictedEdgeIds.has(edge.id) || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("title", { children: edge.label ?? edge.type ?? labels.relationship }) }, edge.id);
5434
5803
  }),
5435
- positioned.map((node) => /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
5804
+ positioned.map((node) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
5436
5805
  "g",
5437
5806
  {
5438
5807
  transform: `translate(${node.x * RADIAL_SCALE_X} ${node.y * RADIAL_SCALE_Y})`,
@@ -5448,22 +5817,63 @@ function RadialRelationshipGraph({
5448
5817
  onKeyDown: (event) => onNodeKeyDown(event, node.id),
5449
5818
  onClick: () => select(node.id),
5450
5819
  children: [
5451
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("title", { children: node.label }),
5452
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("rect", { x: -RADIAL_NODE_HALF_W, y: -RADIAL_NODE_HALF_H, width: RADIAL_NODE_HALF_W * 2, height: RADIAL_NODE_HALF_H * 2, rx: "8" }),
5453
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("text", { textAnchor: "middle", dominantBaseline: "middle", children: node.label.length > 16 ? `${node.label.slice(0, 15)}\u2026` : node.label })
5820
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("title", { children: node.label }),
5821
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("rect", { x: -RADIAL_NODE_HALF_W, y: -RADIAL_NODE_HALF_H, width: RADIAL_NODE_HALF_W * 2, height: RADIAL_NODE_HALF_H * 2, rx: "8" }),
5822
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("text", { textAnchor: "middle", dominantBaseline: "middle", children: node.label.length > 16 ? `${node.label.slice(0, 15)}\u2026` : node.label })
5454
5823
  ]
5455
5824
  },
5456
5825
  node.id
5457
5826
  ))
5458
5827
  ] }) }) }),
5459
- legend.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((item) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("li", { "data-type": item.id, children: item.label }, item.id)) }),
5460
- showList && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(EquivalentRelationshipList, { nodes: bounded.nodes, edges: bounded.edges, selectedId, labels, onSelect: select, onExpandNeighbors, onOpenDetails })
5828
+ legend.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((item) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("li", { "data-type": item.id, style: { "--uix-graph-type-color": typeColor.get(item.id) }, children: item.label }, item.id)) }),
5829
+ showList && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(EquivalentRelationshipList, { nodes: bounded.nodes, edges: bounded.edges, selectedId, labels, onSelect: select, onExpandNeighbors, onOpenDetails })
5461
5830
  ] });
5462
5831
  }
5463
5832
 
5464
5833
  // src/components/MatchReview.tsx
5465
- var import_react42 = require("react");
5466
- var import_jsx_runtime66 = require("react/jsx-runtime");
5834
+ var import_react45 = require("react");
5835
+ var import_jsx_runtime67 = require("react/jsx-runtime");
5836
+ var DEFAULT_MATCH_REVIEW_LABELS = {
5837
+ region: "Match review",
5838
+ loading: "Loading match candidates\u2026",
5839
+ retry: "Try again",
5840
+ empty: "No candidate matches found.",
5841
+ emptyDetail: "Choose another record source or continue without a match.",
5842
+ pendingOf: "{pending} pending of {total}",
5843
+ bulk: "Bulk candidate actions",
5844
+ selectedCount: "{count} selected",
5845
+ applying: "Applying\u2026",
5846
+ acceptSelected: "Accept selected",
5847
+ dismissSelected: "Dismiss selected",
5848
+ caption: "Candidate matches and available decisions",
5849
+ select: "Select",
5850
+ confidence: "Confidence",
5851
+ status: "Status",
5852
+ actions: "Actions",
5853
+ selectCandidate: "Select candidate {id}",
5854
+ notScored: "Not scored",
5855
+ resolved: "Resolved",
5856
+ pending: "Pending",
5857
+ decisionAccepted: "Accepted",
5858
+ decisionDismissed: "Dismissed",
5859
+ decisionSplit: "Split",
5860
+ decisionOther: "Other match",
5861
+ accept: "Accept",
5862
+ dismiss: "Dismiss",
5863
+ split: "Split",
5864
+ pickOther: "Pick other",
5865
+ acceptingOne: "Accepting {count} candidate\u2026",
5866
+ acceptingMany: "Accepting {count} candidates\u2026",
5867
+ dismissingOne: "Dismissing {count} candidate\u2026",
5868
+ dismissingMany: "Dismissing {count} candidates\u2026",
5869
+ acceptedOne: "{count} candidate accepted",
5870
+ acceptedMany: "{count} candidates accepted",
5871
+ dismissedOne: "{count} candidate dismissed",
5872
+ dismissedMany: "{count} candidates dismissed",
5873
+ failedSuffix: "; {count} failed",
5874
+ bulkAcceptFailed: "Bulk accept failed. Try again.",
5875
+ bulkDismissFailed: "Bulk dismiss failed. Try again."
5876
+ };
5467
5877
  var valueText = (value) => value == null ? "\u2014" : typeof value === "string" ? value : JSON.stringify(value);
5468
5878
  function MatchReview({
5469
5879
  incoming,
@@ -5477,13 +5887,18 @@ function MatchReview({
5477
5887
  loading,
5478
5888
  error,
5479
5889
  onRetry,
5480
- className
5890
+ className,
5891
+ labels: labelOverrides
5481
5892
  }) {
5482
- const [internalSelection, setInternalSelection] = (0, import_react42.useState)(/* @__PURE__ */ new Set());
5483
- const [announcement, setAnnouncement] = (0, import_react42.useState)("");
5484
- const [bulkPending, setBulkPending] = (0, import_react42.useState)(false);
5893
+ const labels = { ...DEFAULT_MATCH_REVIEW_LABELS, ...labelOverrides };
5894
+ const plural = (n, one, many) => fillLabel(n === 1 ? one : many, { count: n });
5895
+ const decisionLabel = { accepted: labels.decisionAccepted, dismissed: labels.decisionDismissed, split: labels.decisionSplit, other: labels.decisionOther };
5896
+ const actionLabel = { accept: labels.accept, dismiss: labels.dismiss, split: labels.split, "pick-other": labels.pickOther };
5897
+ const [internalSelection, setInternalSelection] = (0, import_react45.useState)(/* @__PURE__ */ new Set());
5898
+ const [announcement, setAnnouncement] = (0, import_react45.useState)("");
5899
+ const [bulkPending, setBulkPending] = (0, import_react45.useState)(false);
5485
5900
  const selection = selectedIds ?? internalSelection;
5486
- const pending = (0, import_react42.useMemo)(() => candidates.filter((candidate) => candidate.status !== "resolved"), [candidates]);
5901
+ const pending = (0, import_react45.useMemo)(() => candidates.filter((candidate) => candidate.status !== "resolved"), [candidates]);
5487
5902
  const setSelection = (next) => {
5488
5903
  if (selectedIds === void 0) setInternalSelection(next);
5489
5904
  onSelectionChange?.(next);
@@ -5498,87 +5913,81 @@ function MatchReview({
5498
5913
  if (!onBulkDecision || selection.size === 0 || bulkPending) return;
5499
5914
  const ids = [...selection];
5500
5915
  setBulkPending(true);
5501
- setAnnouncement(`${action === "accept" ? "Accepting" : "Dismissing"} ${ids.length} candidate${ids.length === 1 ? "" : "s"}\u2026`);
5916
+ setAnnouncement(action === "accept" ? plural(ids.length, labels.acceptingOne, labels.acceptingMany) : plural(ids.length, labels.dismissingOne, labels.dismissingMany));
5502
5917
  try {
5503
5918
  const result = await onBulkDecision(ids, action);
5504
5919
  const succeeded = result?.succeeded ?? ids.length;
5505
5920
  const failed = result?.failed ?? 0;
5506
- setAnnouncement(`${succeeded} candidate${succeeded === 1 ? "" : "s"} ${action === "accept" ? "accepted" : "dismissed"}${failed ? `; ${failed} failed` : ""}.`);
5921
+ const done = action === "accept" ? plural(succeeded, labels.acceptedOne, labels.acceptedMany) : plural(succeeded, labels.dismissedOne, labels.dismissedMany);
5922
+ setAnnouncement(`${done}${failed ? fillLabel(labels.failedSuffix, { count: failed }) : ""}.`);
5507
5923
  if (!failed) setSelection(/* @__PURE__ */ new Set());
5508
5924
  } catch {
5509
- setAnnouncement(`Bulk ${action} failed. Try again.`);
5925
+ setAnnouncement(action === "accept" ? labels.bulkAcceptFailed : labels.bulkDismissFailed);
5510
5926
  } finally {
5511
5927
  setBulkPending(false);
5512
5928
  }
5513
5929
  };
5514
- if (loading) return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: cx("uix-match-review uix-match-review--state", className), role: "status", children: "Loading match candidates\u2026" });
5515
- if (error) return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: cx("uix-match-review uix-match-review--state", className), role: "alert", children: [
5516
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { children: error }),
5517
- onRetry && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: "Try again" })
5930
+ if (loading) return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: cx("uix-match-review uix-match-review--state", className), role: "status", children: labels.loading });
5931
+ if (error) return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: cx("uix-match-review uix-match-review--state", className), role: "alert", children: [
5932
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("p", { children: error }),
5933
+ onRetry && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: labels.retry })
5518
5934
  ] });
5519
- if (candidates.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: cx("uix-match-review uix-match-review--state", className), children: [
5520
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { children: "No candidate matches found." }),
5521
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { children: "Choose another record source or continue without a match." })
5935
+ if (candidates.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: cx("uix-match-review uix-match-review--state", className), children: [
5936
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("p", { children: labels.empty }),
5937
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("p", { children: labels.emptyDetail })
5522
5938
  ] });
5523
- return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("section", { className: cx("uix-match-review", className), "aria-label": "Match review", children: [
5524
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "uix-match-review__summary", children: [
5525
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { children: [
5526
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("strong", { children: incomingLabel }),
5527
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { children: [
5528
- pending.length,
5529
- " pending of ",
5530
- candidates.length
5531
- ] })
5939
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("section", { className: cx("uix-match-review", className), "aria-label": labels.region, children: [
5940
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "uix-match-review__summary", children: [
5941
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { children: [
5942
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("strong", { children: incomingLabel }),
5943
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { children: fillLabel(labels.pendingOf, { pending: pending.length, total: candidates.length }) })
5532
5944
  ] }),
5533
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "uix-match-review__incoming", children: fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { children: [
5534
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("b", { children: field.label }),
5945
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "uix-match-review__incoming", children: fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { children: [
5946
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("b", { children: field.label }),
5535
5947
  field.render?.(incoming[field.id], incoming) ?? valueText(incoming[field.id])
5536
5948
  ] }, field.id)) })
5537
5949
  ] }),
5538
- onBulkDecision && /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "uix-match-review__bulk", "aria-label": "Bulk candidate actions", children: [
5539
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { children: [
5540
- selection.size,
5541
- " selected"
5542
- ] }),
5543
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", disabled: selection.size === 0 || bulkPending, onClick: () => void runBulk("accept"), children: bulkPending ? "Applying\u2026" : "Accept selected" }),
5544
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", disabled: selection.size === 0 || bulkPending, onClick: () => void runBulk("dismiss"), children: bulkPending ? "Applying\u2026" : "Dismiss selected" })
5950
+ onBulkDecision && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "uix-match-review__bulk", "aria-label": labels.bulk, children: [
5951
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { children: fillLabel(labels.selectedCount, { count: selection.size }) }),
5952
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", disabled: selection.size === 0 || bulkPending, onClick: () => void runBulk("accept"), children: bulkPending ? labels.applying : labels.acceptSelected }),
5953
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", disabled: selection.size === 0 || bulkPending, onClick: () => void runBulk("dismiss"), children: bulkPending ? labels.applying : labels.dismissSelected })
5545
5954
  ] }),
5546
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "uix-match-review__table-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("table", { className: "uix-table uix-match-review__table", children: [
5547
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("caption", { className: "uix-visually-hidden", children: "Candidate matches and available decisions" }),
5548
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("tr", { children: [
5549
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { scope: "col", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "uix-visually-hidden", children: "Select" }) }),
5550
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { scope: "col", children: "Confidence" }),
5551
- fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { scope: "col", children: field.label }, field.id)),
5552
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { scope: "col", children: "Status" }),
5553
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("th", { scope: "col", children: "Actions" })
5955
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "uix-match-review__table-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("table", { className: "uix-table uix-match-review__table", children: [
5956
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("caption", { className: "uix-visually-hidden", children: labels.caption }),
5957
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("tr", { children: [
5958
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { scope: "col", children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "uix-visually-hidden", children: labels.select }) }),
5959
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { scope: "col", children: labels.confidence }),
5960
+ fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { scope: "col", children: field.label }, field.id)),
5961
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { scope: "col", children: labels.status }),
5962
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { scope: "col", children: labels.actions })
5554
5963
  ] }) }),
5555
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("tbody", { children: candidates.map((candidate) => {
5964
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("tbody", { children: candidates.map((candidate) => {
5556
5965
  const resolved = candidate.status === "resolved";
5557
- return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("tr", { "data-status": candidate.status ?? "pending", children: [
5558
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("input", { type: "checkbox", checked: selection.has(candidate.id), onChange: () => toggle(candidate.id), "aria-label": `Select candidate ${candidate.id}` }) }),
5559
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "uix-match-review__confidence", children: candidate.confidence == null ? "Not scored" : `${Math.round(candidate.confidence * 100)}%` }) }),
5560
- fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { children: field.render?.(candidate.record[field.id], candidate.record) ?? valueText(candidate.record[field.id]) }, field.id)),
5561
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(StatusPill, { tone: resolved ? "success" : "warning", children: resolved ? candidate.decision ?? "Resolved" : "Pending" }) }),
5562
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "uix-match-review__actions", children: ["accept", "dismiss", "split", "pick-other"].map((action) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
5966
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("tr", { "data-status": candidate.status ?? "pending", children: [
5967
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("input", { type: "checkbox", checked: selection.has(candidate.id), onChange: () => toggle(candidate.id), "aria-label": fillLabel(labels.selectCandidate, { id: candidate.id }) }) }),
5968
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "uix-match-review__confidence", children: candidate.confidence == null ? labels.notScored : `${Math.round(candidate.confidence * 100)}%` }) }),
5969
+ fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: field.render?.(candidate.record[field.id], candidate.record) ?? valueText(candidate.record[field.id]) }, field.id)),
5970
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(StatusPill, { tone: resolved ? "success" : "warning", children: resolved ? candidate.decision ? decisionLabel[candidate.decision] : labels.resolved : labels.pending }) }),
5971
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "uix-match-review__actions", children: ["accept", "dismiss", "split", "pick-other"].map((action) => /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
5563
5972
  "button",
5564
5973
  {
5565
5974
  type: "button",
5566
5975
  className: "uix-btn uix-btn--ghost uix-btn--sm",
5567
5976
  disabled: resolved,
5568
5977
  onClick: () => onDecision(candidate.id, action),
5569
- children: action === "pick-other" ? "Pick other" : `${action[0].toUpperCase()}${action.slice(1)}`
5978
+ children: actionLabel[action]
5570
5979
  },
5571
5980
  action
5572
5981
  )) }) })
5573
5982
  ] }, candidate.id);
5574
5983
  }) })
5575
5984
  ] }) }),
5576
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "uix-visually-hidden", "aria-live": "polite", children: announcement })
5985
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("p", { className: "uix-visually-hidden", "aria-live": "polite", children: announcement })
5577
5986
  ] });
5578
5987
  }
5579
5988
 
5580
5989
  // src/components/MetricInput.tsx
5581
- var import_react43 = require("react");
5990
+ var import_react46 = require("react");
5582
5991
 
5583
5992
  // src/metric-model.ts
5584
5993
  function decimals(value) {
@@ -5603,7 +6012,7 @@ function parseMetricValue(value) {
5603
6012
  }
5604
6013
 
5605
6014
  // src/components/MetricInput.tsx
5606
- var import_jsx_runtime67 = require("react/jsx-runtime");
6015
+ var import_jsx_runtime68 = require("react/jsx-runtime");
5607
6016
  var defaultMetricFormat = (input) => input == null ? "" : String(input);
5608
6017
  function MetricInput({
5609
6018
  value,
@@ -5622,11 +6031,11 @@ function MetricInput({
5622
6031
  className,
5623
6032
  id: providedId
5624
6033
  }) {
5625
- const generatedId = (0, import_react43.useId)();
6034
+ const generatedId = (0, import_react46.useId)();
5626
6035
  const id = providedId ?? generatedId;
5627
6036
  const errorId = `${id}-error`;
5628
- const [text, setText] = (0, import_react43.useState)(() => format(value));
5629
- (0, import_react43.useEffect)(() => setText(format(value)), [value, format]);
6037
+ const [text, setText] = (0, import_react46.useState)(() => format(value));
6038
+ (0, import_react46.useEffect)(() => setText(format(value)), [value, format]);
5630
6039
  const commit = (input) => {
5631
6040
  const parsed = parse(input);
5632
6041
  if (input.trim() === "" || parsed !== null) {
@@ -5652,10 +6061,10 @@ function MetricInput({
5652
6061
  const parsed = parse(event.currentTarget.value);
5653
6062
  setText(parsed === null && event.currentTarget.value.trim() !== "" ? format(value) : format(parsed));
5654
6063
  };
5655
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: cx("uix-metric-input", invalid && "uix-metric-input--invalid", className), children: [
5656
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("label", { className: "uix-field__label", htmlFor: id, children: label }),
5657
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "uix-metric-input__control", children: [
5658
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
6064
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: cx("uix-metric-input", invalid && "uix-metric-input--invalid", className), children: [
6065
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("label", { className: "uix-field__label", htmlFor: id, children: label }),
6066
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "uix-metric-input__control", children: [
6067
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
5659
6068
  Input,
5660
6069
  {
5661
6070
  id,
@@ -5674,22 +6083,22 @@ function MetricInput({
5674
6083
  readOnly
5675
6084
  }
5676
6085
  ),
5677
- unit && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "uix-metric-input__unit", "aria-hidden": "true", children: unit }),
5678
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: "uix-metric-input__steps", children: [
5679
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("button", { type: "button", className: "uix-metric-input__step", onClick: () => stepBy(1), disabled: disabled || readOnly, "aria-label": `Increase ${label}`, children: "+" }),
5680
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("button", { type: "button", className: "uix-metric-input__step", onClick: () => stepBy(-1), disabled: disabled || readOnly, "aria-label": `Decrease ${label}`, children: "\u2212" })
6086
+ unit && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "uix-metric-input__unit", "aria-hidden": "true", children: unit }),
6087
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "uix-metric-input__steps", children: [
6088
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("button", { type: "button", className: "uix-metric-input__step", onClick: () => stepBy(1), disabled: disabled || readOnly, "aria-label": `Increase ${label}`, children: "+" }),
6089
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("button", { type: "button", className: "uix-metric-input__step", onClick: () => stepBy(-1), disabled: disabled || readOnly, "aria-label": `Decrease ${label}`, children: "\u2212" })
5681
6090
  ] })
5682
6091
  ] }),
5683
- unit && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: "uix-visually-hidden", children: [
6092
+ unit && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "uix-visually-hidden", children: [
5684
6093
  "Unit: ",
5685
6094
  unit
5686
6095
  ] }),
5687
- invalid && errorMessage && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { id: errorId, className: "uix-field__error", children: errorMessage })
6096
+ invalid && errorMessage && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { id: errorId, className: "uix-field__error", children: errorMessage })
5688
6097
  ] });
5689
6098
  }
5690
6099
 
5691
6100
  // src/components/LicensePositionBar.tsx
5692
- var import_jsx_runtime68 = require("react/jsx-runtime");
6101
+ var import_jsx_runtime69 = require("react/jsx-runtime");
5693
6102
  var defaultCapacityFormat = (value) => new Intl.NumberFormat().format(value);
5694
6103
  function LicensePositionBar({
5695
6104
  consumed,
@@ -5710,18 +6119,18 @@ function LicensePositionBar({
5710
6119
  const percent = safeEntitled === 0 ? safeConsumed > 0 ? 100 : 0 : safeConsumed / safeEntitled * 100;
5711
6120
  const format = (value) => `${formatValue(value)}${unit ? ` ${unit}` : ""}`;
5712
6121
  const summary = `${consumedLabel}: ${format(safeConsumed)}. ${entitledLabel}: ${format(safeEntitled)}. ${over > 0 ? `${format(over)} ${overLabel}` : `${format(available)} ${availableLabel}`}.`;
5713
- return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: cx("uix-license-position", over > 0 && "uix-license-position--over", className), ...props, children: [
5714
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "uix-license-position__header", children: [
5715
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "uix-license-position__value", children: [
6122
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: cx("uix-license-position", over > 0 && "uix-license-position--over", className), ...props, children: [
6123
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "uix-license-position__header", children: [
6124
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "uix-license-position__value", children: [
5716
6125
  format(safeConsumed),
5717
6126
  " / ",
5718
6127
  format(safeEntitled)
5719
6128
  ] }),
5720
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(StatusPill, { tone: over > 0 ? "danger" : percent >= 80 ? "warning" : "success", children: over > 0 ? `${format(over)} ${overLabel}` : `${format(available)} ${availableLabel}` })
6129
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatusPill, { tone: over > 0 ? "danger" : percent >= 80 ? "warning" : "success", children: over > 0 ? `${format(over)} ${overLabel}` : `${format(available)} ${availableLabel}` })
5721
6130
  ] }),
5722
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "uix-license-position__track", children: [
5723
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Meter, { value: Math.min(100, percent), tone: over > 0 ? "danger" : percent >= 80 ? "warning" : "success", "aria-label": summary, "aria-valuetext": summary }),
5724
- over > 0 && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6131
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "uix-license-position__track", children: [
6132
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Meter, { value: Math.min(100, percent), tone: over > 0 ? "danger" : percent >= 80 ? "warning" : "success", "aria-label": summary, "aria-valuetext": summary }),
6133
+ over > 0 && /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
5725
6134
  "span",
5726
6135
  {
5727
6136
  className: "uix-license-position__overflow",
@@ -5730,12 +6139,12 @@ function LicensePositionBar({
5730
6139
  }
5731
6140
  )
5732
6141
  ] }),
5733
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "uix-visually-hidden", children: summary })
6142
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "uix-visually-hidden", children: summary })
5734
6143
  ] });
5735
6144
  }
5736
6145
 
5737
6146
  // src/components/BrandProfiles.tsx
5738
- var import_react45 = require("react");
6147
+ var import_react48 = require("react");
5739
6148
 
5740
6149
  // src/color-model.ts
5741
6150
  var clamp2 = (value, min, max) => Math.min(max, Math.max(min, value));
@@ -5804,8 +6213,24 @@ function meetsContrast(background, foreground, minimum = 4.5) {
5804
6213
  }
5805
6214
 
5806
6215
  // src/components/ColorPicker.tsx
5807
- var import_react44 = require("react");
5808
- var import_jsx_runtime69 = require("react/jsx-runtime");
6216
+ var import_react47 = require("react");
6217
+ var import_jsx_runtime70 = require("react/jsx-runtime");
6218
+ var DEFAULT_COLOR_PICKER_LABELS = {
6219
+ trigger: "{label}: {color}",
6220
+ sample: "Aa",
6221
+ hue: "Hue",
6222
+ saturation: "Saturation",
6223
+ brightness: "Brightness",
6224
+ hex: "Hex",
6225
+ set: "Set",
6226
+ presets: "Presets",
6227
+ recent: "Recent",
6228
+ usePreset: "Use preset {color}",
6229
+ useRecent: "Use recent color {color}",
6230
+ contrastPasses: "Contrast {ratio}:1 \u2014 passes WCAG AA ({minimum}:1)",
6231
+ contrastFails: "Contrast {ratio}:1 \u2014 does not meet WCAG AA ({minimum}:1)",
6232
+ done: "Done"
6233
+ };
5809
6234
  var EMPTY_COLORS = [];
5810
6235
  function ColorPicker({
5811
6236
  value,
@@ -5816,19 +6241,21 @@ function ColorPicker({
5816
6241
  minimumContrast = 4.5,
5817
6242
  label = "Choose color",
5818
6243
  disabled,
5819
- className
6244
+ className,
6245
+ labels: labelOverrides
5820
6246
  }) {
5821
- const id = (0, import_react44.useId)();
5822
- const triggerRef = (0, import_react44.useRef)(null);
5823
- const dialogRef = (0, import_react44.useRef)(null);
5824
- const [open, setOpen] = (0, import_react44.useState)(false);
6247
+ const labels = { ...DEFAULT_COLOR_PICKER_LABELS, ...labelOverrides };
6248
+ const id = (0, import_react47.useId)();
6249
+ const triggerRef = (0, import_react47.useRef)(null);
6250
+ const dialogRef = (0, import_react47.useRef)(null);
6251
+ const [open, setOpen] = (0, import_react47.useState)(false);
5825
6252
  const normalized = normalizeHex(value) ?? "#000000";
5826
- const [hexText, setHexText] = (0, import_react44.useState)(normalized);
5827
- const hsv = (0, import_react44.useMemo)(() => rgbToHsv(hexToRgb(normalized)), [normalized]);
6253
+ const [hexText, setHexText] = (0, import_react47.useState)(normalized);
6254
+ const hsv = (0, import_react47.useMemo)(() => rgbToHsv(hexToRgb(normalized)), [normalized]);
5828
6255
  const ratio = contrastRatio(normalized, foreground) ?? 0;
5829
6256
  const passes = ratio >= minimumContrast;
5830
- (0, import_react44.useEffect)(() => setHexText(normalized), [normalized]);
5831
- (0, import_react44.useEffect)(() => {
6257
+ (0, import_react47.useEffect)(() => setHexText(normalized), [normalized]);
6258
+ (0, import_react47.useEffect)(() => {
5832
6259
  if (!open) return;
5833
6260
  const dialog = dialogRef.current;
5834
6261
  dialog?.querySelector("input,button")?.focus();
@@ -5871,25 +6298,25 @@ function ColorPicker({
5871
6298
  if (next) onChange(next);
5872
6299
  };
5873
6300
  const sampleStyle = { backgroundColor: normalized };
5874
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: cx("uix-color-picker", className), children: [
5875
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(
6301
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: cx("uix-color-picker", className), children: [
6302
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
5876
6303
  "button",
5877
6304
  {
5878
6305
  ref: triggerRef,
5879
6306
  type: "button",
5880
6307
  className: "uix-color-picker__trigger",
5881
- "aria-label": `${label}: ${normalized}`,
6308
+ "aria-label": fillLabel(labels.trigger, { label, color: normalized }),
5882
6309
  "aria-expanded": open,
5883
6310
  "aria-controls": `${id}-dialog`,
5884
6311
  onClick: () => setOpen((current) => !current),
5885
6312
  disabled,
5886
6313
  children: [
5887
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "uix-color-picker__swatch", style: sampleStyle, "aria-hidden": "true" }),
5888
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { children: normalized })
6314
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "uix-color-picker__swatch", style: sampleStyle, "aria-hidden": "true" }),
6315
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { children: normalized })
5889
6316
  ]
5890
6317
  }
5891
6318
  ),
5892
- open && /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(
6319
+ open && /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
5893
6320
  "div",
5894
6321
  {
5895
6322
  ref: dialogRef,
@@ -5900,57 +6327,55 @@ function ColorPicker({
5900
6327
  className: "uix-color-picker__popover",
5901
6328
  onKeyDown: onDialogKeyDown,
5902
6329
  children: [
5903
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "uix-color-picker__preview", style: sampleStyle, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { color: foreground }, children: "Aa" }) }),
5904
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("label", { className: "uix-color-picker__range", children: [
5905
- "Hue ",
5906
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { children: [
6330
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "uix-color-picker__preview", style: sampleStyle, children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { style: { color: foreground }, children: labels.sample }) }),
6331
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-color-picker__range", children: [
6332
+ labels.hue,
6333
+ " ",
6334
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
5907
6335
  Math.round(hsv.h),
5908
6336
  "\xB0"
5909
6337
  ] }),
5910
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("input", { type: "range", min: "0", max: "359", value: Math.round(hsv.h), onChange: (event) => updateHsv({ h: Number(event.currentTarget.value) }) })
6338
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { type: "range", min: "0", max: "359", value: Math.round(hsv.h), onChange: (event) => updateHsv({ h: Number(event.currentTarget.value) }) })
5911
6339
  ] }),
5912
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("label", { className: "uix-color-picker__range", children: [
5913
- "Saturation ",
5914
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { children: [
6340
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-color-picker__range", children: [
6341
+ labels.saturation,
6342
+ " ",
6343
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
5915
6344
  Math.round(hsv.s * 100),
5916
6345
  "%"
5917
6346
  ] }),
5918
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("input", { type: "range", min: "0", max: "100", value: Math.round(hsv.s * 100), onChange: (event) => updateHsv({ s: Number(event.currentTarget.value) / 100 }) })
6347
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { type: "range", min: "0", max: "100", value: Math.round(hsv.s * 100), onChange: (event) => updateHsv({ s: Number(event.currentTarget.value) / 100 }) })
5919
6348
  ] }),
5920
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("label", { className: "uix-color-picker__range", children: [
5921
- "Brightness ",
5922
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { children: [
6349
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-color-picker__range", children: [
6350
+ labels.brightness,
6351
+ " ",
6352
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
5923
6353
  Math.round(hsv.v * 100),
5924
6354
  "%"
5925
6355
  ] }),
5926
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("input", { type: "range", min: "0", max: "100", value: Math.round(hsv.v * 100), onChange: (event) => updateHsv({ v: Number(event.currentTarget.value) / 100 }) })
6356
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { type: "range", min: "0", max: "100", value: Math.round(hsv.v * 100), onChange: (event) => updateHsv({ v: Number(event.currentTarget.value) / 100 }) })
5927
6357
  ] }),
5928
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("label", { className: "uix-color-picker__hex", children: [
5929
- "Hex",
5930
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "uix-color-picker__hex-row", children: [
5931
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("input", { className: "uix-input", value: hexText, onChange: (event) => setHexText(event.currentTarget.value), onBlur: commitHex, onKeyDown: (event) => {
6358
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-color-picker__hex", children: [
6359
+ labels.hex,
6360
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "uix-color-picker__hex-row", children: [
6361
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { className: "uix-input", value: hexText, onChange: (event) => setHexText(event.currentTarget.value), onBlur: commitHex, onKeyDown: (event) => {
5932
6362
  if (event.key === "Enter") commitHex();
5933
6363
  }, "aria-invalid": !normalizeHex(hexText) }),
5934
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", onClick: commitHex, disabled: !normalizeHex(hexText), children: "Set" })
6364
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", onClick: commitHex, disabled: !normalizeHex(hexText), children: labels.set })
5935
6365
  ] })
5936
6366
  ] }),
5937
- (presets.length > 0 || recent.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "uix-color-picker__palettes", children: [
5938
- presets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("fieldset", { children: [
5939
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("legend", { children: "Presets" }),
5940
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { children: presets.map((color) => /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("button", { type: "button", className: "uix-color-picker__preset", style: { backgroundColor: normalizeHex(color) ?? color }, onClick: () => choose(color), "aria-label": `Use preset ${color}` }, color)) })
6367
+ (presets.length > 0 || recent.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "uix-color-picker__palettes", children: [
6368
+ presets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("fieldset", { children: [
6369
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("legend", { children: labels.presets }),
6370
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { children: presets.map((color) => /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("button", { type: "button", className: "uix-color-picker__preset", style: { backgroundColor: normalizeHex(color) ?? color }, onClick: () => choose(color), "aria-label": fillLabel(labels.usePreset, { color }) }, color)) })
5941
6371
  ] }),
5942
- recent.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("fieldset", { children: [
5943
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("legend", { children: "Recent" }),
5944
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { children: recent.map((color) => /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("button", { type: "button", className: "uix-color-picker__preset", style: { backgroundColor: normalizeHex(color) ?? color }, onClick: () => choose(color), "aria-label": `Use recent color ${color}` }, color)) })
6372
+ recent.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("fieldset", { children: [
6373
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("legend", { children: labels.recent }),
6374
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { children: recent.map((color) => /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("button", { type: "button", className: "uix-color-picker__preset", style: { backgroundColor: normalizeHex(color) ?? color }, onClick: () => choose(color), "aria-label": fillLabel(labels.useRecent, { color }) }, color)) })
5945
6375
  ] })
5946
6376
  ] }),
5947
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("p", { className: cx("uix-color-picker__contrast", passes ? "uix-color-picker__contrast--pass" : "uix-color-picker__contrast--fail"), role: "status", "aria-live": "polite", children: [
5948
- "Contrast ",
5949
- ratio.toFixed(2),
5950
- ":1 \u2014 ",
5951
- passes ? `passes WCAG AA (${minimumContrast}:1)` : `does not meet WCAG AA (${minimumContrast}:1)`
5952
- ] }),
5953
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary uix-btn--sm", onClick: close, children: "Done" })
6377
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("p", { className: cx("uix-color-picker__contrast", passes ? "uix-color-picker__contrast--pass" : "uix-color-picker__contrast--fail"), role: "status", "aria-live": "polite", children: fillLabel(passes ? labels.contrastPasses : labels.contrastFails, { ratio: ratio.toFixed(2), minimum: minimumContrast }) }),
6378
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary uix-btn--sm", onClick: close, children: labels.done })
5954
6379
  ]
5955
6380
  }
5956
6381
  )
@@ -5958,7 +6383,7 @@ function ColorPicker({
5958
6383
  }
5959
6384
 
5960
6385
  // src/components/BrandProfiles.tsx
5961
- var import_jsx_runtime70 = require("react/jsx-runtime");
6386
+ var import_jsx_runtime71 = require("react/jsx-runtime");
5962
6387
  var PROFILE_PROPERTIES = {
5963
6388
  brand: "--uix-brand",
5964
6389
  brandForeground: "--uix-brand-fg",
@@ -6016,6 +6441,27 @@ function restoreBrandProfile(snapshot, target) {
6016
6441
  if (snapshot.logoAlt) element.dataset.uixBrandLogoAlt = snapshot.logoAlt;
6017
6442
  else delete element.dataset.uixBrandLogoAlt;
6018
6443
  }
6444
+ var DEFAULT_BRAND_PROFILE_EDITOR_LABELS = {
6445
+ region: "Brand profile editor",
6446
+ profile: "Profile",
6447
+ name: "Name",
6448
+ brand: "Brand",
6449
+ brandColor: "Brand color",
6450
+ onBrand: "On brand",
6451
+ onBrandColor: "Brand foreground color",
6452
+ bodyFont: "Body font",
6453
+ headingFont: "Heading font",
6454
+ logoFile: "Logo file",
6455
+ apply: "Apply profile",
6456
+ applied: "{name} applied.",
6457
+ preview: "Live preview of {name}",
6458
+ logoPlaceholder: "Logo",
6459
+ previewTitleFallback: "Brand preview",
6460
+ previewHeading: "Readable, serializable branding",
6461
+ previewBody: "Accent, links, rings, and muted states continue through the existing UIx token chain.",
6462
+ previewPrimary: "Primary action",
6463
+ previewLink: "Preview link"
6464
+ };
6019
6465
  function BrandProfileEditor({
6020
6466
  value,
6021
6467
  onChange,
@@ -6025,14 +6471,16 @@ function BrandProfileEditor({
6025
6471
  applyTarget,
6026
6472
  onLogoFile,
6027
6473
  colorPresets = EMPTY_COLORS2,
6028
- className
6474
+ className,
6475
+ labels: labelOverrides
6029
6476
  }) {
6030
- const [announcement, setAnnouncement] = (0, import_react45.useState)("");
6477
+ const labels = { ...DEFAULT_BRAND_PROFILE_EDITOR_LABELS, ...labelOverrides };
6478
+ const [announcement, setAnnouncement] = (0, import_react48.useState)("");
6031
6479
  const update = (patch) => onChange({ ...value, ...patch });
6032
6480
  const apply = () => {
6033
6481
  if (applyTarget !== null) applyBrandProfile(value, applyTarget);
6034
6482
  onApply?.(value);
6035
- setAnnouncement(`${value.name} applied.`);
6483
+ setAnnouncement(fillLabel(labels.applied, { name: value.name }));
6036
6484
  };
6037
6485
  const onFile = (event) => {
6038
6486
  const file = event.currentTarget.files?.[0];
@@ -6044,54 +6492,54 @@ function BrandProfileEditor({
6044
6492
  ...value.typography?.sans ? { "--uix-font-sans": value.typography.sans } : {},
6045
6493
  ...value.typography?.heading ? { "--uix-font-heading": value.typography.heading } : {}
6046
6494
  };
6047
- return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("section", { className: cx("uix-brand-profiles", className), "aria-label": "Brand profile editor", children: [
6048
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "uix-brand-profiles__form", children: [
6049
- profiles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-field__label", children: [
6050
- "Profile",
6051
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("select", { className: "uix-select", value: value.id, onChange: (event) => {
6495
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("section", { className: cx("uix-brand-profiles", className), "aria-label": labels.region, children: [
6496
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "uix-brand-profiles__form", children: [
6497
+ profiles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("label", { className: "uix-field__label", children: [
6498
+ labels.profile,
6499
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("select", { className: "uix-select", value: value.id, onChange: (event) => {
6052
6500
  const selected = profiles.find((profile) => profile.id === event.currentTarget.value);
6053
6501
  if (selected) onSelectProfile?.(selected);
6054
- }, children: profiles.map((profile) => /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("option", { value: profile.id, children: profile.name }, profile.id)) })
6502
+ }, children: profiles.map((profile) => /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("option", { value: profile.id, children: profile.name }, profile.id)) })
6055
6503
  ] }),
6056
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-field__label", children: [
6057
- "Name",
6058
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { className: "uix-input", value: value.name, onChange: (event) => update({ name: event.currentTarget.value }) })
6504
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("label", { className: "uix-field__label", children: [
6505
+ labels.name,
6506
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("input", { className: "uix-input", value: value.name, onChange: (event) => update({ name: event.currentTarget.value }) })
6059
6507
  ] }),
6060
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "uix-brand-profiles__colors", children: [
6061
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { children: [
6062
- "Brand",
6063
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(ColorPicker, { label: "Brand color", value: value.brand, foreground: value.brandForeground, presets: colorPresets, onChange: (brand) => update({ brand }) })
6508
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "uix-brand-profiles__colors", children: [
6509
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("label", { children: [
6510
+ labels.brand,
6511
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ColorPicker, { label: labels.brandColor, value: value.brand, foreground: value.brandForeground, presets: colorPresets, onChange: (brand) => update({ brand }) })
6064
6512
  ] }),
6065
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { children: [
6066
- "On brand",
6067
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(ColorPicker, { label: "Brand foreground color", value: value.brandForeground, foreground: value.brand, presets: colorPresets, onChange: (brandForeground) => update({ brandForeground }) })
6513
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("label", { children: [
6514
+ labels.onBrand,
6515
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ColorPicker, { label: labels.onBrandColor, value: value.brandForeground, foreground: value.brand, presets: colorPresets, onChange: (brandForeground) => update({ brandForeground }) })
6068
6516
  ] })
6069
6517
  ] }),
6070
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-field__label", children: [
6071
- "Body font",
6072
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { className: "uix-input", value: value.typography?.sans ?? "", onChange: (event) => update({ typography: { ...value.typography, sans: event.currentTarget.value || void 0 } }) })
6518
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("label", { className: "uix-field__label", children: [
6519
+ labels.bodyFont,
6520
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("input", { className: "uix-input", value: value.typography?.sans ?? "", onChange: (event) => update({ typography: { ...value.typography, sans: event.currentTarget.value || void 0 } }) })
6073
6521
  ] }),
6074
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-field__label", children: [
6075
- "Heading font",
6076
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { className: "uix-input", value: value.typography?.heading ?? "", onChange: (event) => update({ typography: { ...value.typography, heading: event.currentTarget.value || void 0 } }) })
6522
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("label", { className: "uix-field__label", children: [
6523
+ labels.headingFont,
6524
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("input", { className: "uix-input", value: value.typography?.heading ?? "", onChange: (event) => update({ typography: { ...value.typography, heading: event.currentTarget.value || void 0 } }) })
6077
6525
  ] }),
6078
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: "uix-file-upload uix-brand-profiles__upload", children: [
6079
- "Logo file",
6080
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { type: "file", accept: "image/*", onChange: onFile })
6526
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("label", { className: "uix-file-upload uix-brand-profiles__upload", children: [
6527
+ labels.logoFile,
6528
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("input", { type: "file", accept: "image/*", onChange: onFile })
6081
6529
  ] }),
6082
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary", onClick: apply, children: "Apply profile" }),
6083
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "uix-visually-hidden", "aria-live": "polite", children: announcement })
6530
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary", onClick: apply, children: labels.apply }),
6531
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "uix-visually-hidden", "aria-live": "polite", children: announcement })
6084
6532
  ] }),
6085
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "uix-brand-profiles__preview", style: previewStyle, "aria-label": `Live preview of ${value.name}`, children: [
6086
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "uix-brand-profiles__preview-header", children: [
6087
- value.logo ? /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("img", { src: value.logo.src, alt: value.logo.alt }) : /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "uix-brand-profiles__logo-placeholder", children: "Logo" }),
6088
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("strong", { children: value.name || "Brand preview" })
6533
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "uix-brand-profiles__preview", style: previewStyle, "aria-label": fillLabel(labels.preview, { name: value.name }), children: [
6534
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "uix-brand-profiles__preview-header", children: [
6535
+ value.logo ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("img", { src: value.logo.src, alt: value.logo.alt }) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "uix-brand-profiles__logo-placeholder", children: labels.logoPlaceholder }),
6536
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("strong", { children: value.name || labels.previewTitleFallback })
6089
6537
  ] }),
6090
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "uix-brand-profiles__preview-body", children: [
6091
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("h3", { children: "Readable, serializable branding" }),
6092
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("p", { children: "Accent, links, rings, and muted states continue through the existing UIx token chain." }),
6093
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary", children: "Primary action" }),
6094
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("a", { href: "#brand-profile-preview", children: "Preview link" })
6538
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "uix-brand-profiles__preview-body", children: [
6539
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("h3", { children: labels.previewHeading }),
6540
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("p", { children: labels.previewBody }),
6541
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary", children: labels.previewPrimary }),
6542
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("a", { href: "#brand-profile-preview", children: labels.previewLink })
6095
6543
  ] })
6096
6544
  ] })
6097
6545
  ] });
@@ -6099,7 +6547,7 @@ function BrandProfileEditor({
6099
6547
  var BrandProfiles = BrandProfileEditor;
6100
6548
 
6101
6549
  // src/components/DiffViewer.tsx
6102
- var import_react46 = require("react");
6550
+ var import_react49 = require("react");
6103
6551
 
6104
6552
  // src/diff-model.ts
6105
6553
  function isJsonObject(value) {
@@ -6150,15 +6598,34 @@ function summarizeDiff(entries, resolutions = {}) {
6150
6598
  }
6151
6599
 
6152
6600
  // src/components/DiffViewer.tsx
6153
- var import_jsx_runtime71 = require("react/jsx-runtime");
6154
- var GROUPS = [
6155
- { kind: "conflicted", label: "Conflicted" },
6156
- { kind: "changed", label: "Changed" },
6157
- { kind: "added", label: "Added" },
6158
- { kind: "removed", label: "Removed" }
6159
- ];
6160
- var DEFAULT_LABELS = {};
6161
- var renderValue = (value) => value === void 0 ? "Not present" : JSON.stringify(value, null, 2);
6601
+ var import_jsx_runtime72 = require("react/jsx-runtime");
6602
+ var DEFAULT_DIFF_VIEWER_LABELS = {
6603
+ base: "Base",
6604
+ current: "Current",
6605
+ incoming: "Incoming",
6606
+ region: "Configuration differences",
6607
+ summary: "Difference summary",
6608
+ noDifferences: "No differences",
6609
+ noDifferencesDetail: "Base, current, and incoming values are aligned.",
6610
+ conflicted: "Conflicted",
6611
+ changed: "Changed",
6612
+ added: "Added",
6613
+ removed: "Removed",
6614
+ resolved: "resolved",
6615
+ pending: "pending",
6616
+ valueFor: "{version} value for {path}",
6617
+ resolve: "Resolve {path}",
6618
+ acceptIncoming: "Accept incoming",
6619
+ keepCurrent: "Keep current",
6620
+ markPending: "Mark pending",
6621
+ resolutionAccept: "accepted",
6622
+ resolutionSkip: "kept",
6623
+ resolutionPending: "pending",
6624
+ notPresent: "Not present",
6625
+ progress: "{resolved} of {total} differences resolved."
6626
+ };
6627
+ var GROUPS = ["conflicted", "changed", "added", "removed"];
6628
+ var renderValue = (value, notPresent) => value === void 0 ? notPresent : JSON.stringify(value, null, 2);
6162
6629
  function DiffViewer({
6163
6630
  base,
6164
6631
  current,
@@ -6166,73 +6633,72 @@ function DiffViewer({
6166
6633
  entries: providedEntries,
6167
6634
  resolutions: controlledResolutions,
6168
6635
  onResolutionChange,
6169
- labels = DEFAULT_LABELS,
6636
+ labels: labelOverrides,
6170
6637
  className
6171
6638
  }) {
6172
- const id = (0, import_react46.useId)();
6173
- const entries = (0, import_react46.useMemo)(() => providedEntries ?? buildThreeWayDiff(base, current, incoming), [providedEntries, base, current, incoming]);
6174
- const [internalResolutions, setInternalResolutions] = (0, import_react46.useState)({});
6639
+ const labels = { ...DEFAULT_DIFF_VIEWER_LABELS, ...labelOverrides };
6640
+ const resolutionLabel = { accept: labels.resolutionAccept, skip: labels.resolutionSkip, pending: labels.resolutionPending };
6641
+ const id = (0, import_react49.useId)();
6642
+ const entries = (0, import_react49.useMemo)(() => providedEntries ?? buildThreeWayDiff(base, current, incoming), [providedEntries, base, current, incoming]);
6643
+ const [internalResolutions, setInternalResolutions] = (0, import_react49.useState)({});
6175
6644
  const resolutions = controlledResolutions ?? internalResolutions;
6176
6645
  const summary = summarizeDiff(entries, resolutions);
6177
6646
  const resolve2 = (path, resolution) => {
6178
6647
  if (controlledResolutions === void 0) setInternalResolutions((currentState) => ({ ...currentState, [path]: resolution }));
6179
6648
  onResolutionChange?.(path, resolution);
6180
6649
  };
6181
- if (entries.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("section", { className: cx("uix-diff-viewer uix-diff-viewer--empty", className), "aria-label": "Configuration differences", children: [
6182
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("h3", { children: "No differences" }),
6183
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("p", { children: "Base, current, and incoming values are aligned." })
6650
+ if (entries.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("section", { className: cx("uix-diff-viewer uix-diff-viewer--empty", className), "aria-label": labels.region, children: [
6651
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("h3", { children: labels.noDifferences }),
6652
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("p", { children: labels.noDifferencesDetail })
6184
6653
  ] });
6185
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("section", { className: cx("uix-diff-viewer", className), "aria-label": "Configuration differences", children: [
6186
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "uix-diff-viewer__summary", "aria-label": "Difference summary", children: [
6187
- GROUPS.map((group) => /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { children: [
6188
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("b", { children: summary[group.kind] }),
6654
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("section", { className: cx("uix-diff-viewer", className), "aria-label": labels.region, children: [
6655
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "uix-diff-viewer__summary", "aria-label": labels.summary, children: [
6656
+ GROUPS.map((kind) => /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { children: [
6657
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("b", { children: summary[kind] }),
6658
+ " ",
6659
+ labels[kind].toLowerCase()
6660
+ ] }, kind)),
6661
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { children: [
6662
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("b", { children: summary.resolved }),
6189
6663
  " ",
6190
- group.label.toLowerCase()
6191
- ] }, group.kind)),
6192
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { children: [
6193
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("b", { children: summary.resolved }),
6194
- " resolved"
6664
+ labels.resolved
6195
6665
  ] }),
6196
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { children: [
6197
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("b", { children: summary.pending }),
6198
- " pending"
6666
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { children: [
6667
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("b", { children: summary.pending }),
6668
+ " ",
6669
+ labels.pending
6199
6670
  ] })
6200
6671
  ] }),
6201
- GROUPS.map((group) => {
6202
- const grouped = entries.filter((entry) => entry.kind === group.kind);
6672
+ GROUPS.map((kind) => {
6673
+ const grouped = entries.filter((entry) => entry.kind === kind);
6203
6674
  if (!grouped.length) return null;
6204
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("section", { className: "uix-diff-viewer__group", "aria-labelledby": `${id}-${group.kind}`, children: [
6205
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("h3", { id: `${id}-${group.kind}`, children: [
6206
- group.label,
6675
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("section", { className: "uix-diff-viewer__group", "aria-labelledby": `${id}-${kind}`, children: [
6676
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("h3", { id: `${id}-${kind}`, children: [
6677
+ labels[kind],
6207
6678
  " ",
6208
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { children: grouped.length })
6679
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { children: grouped.length })
6209
6680
  ] }),
6210
6681
  grouped.map((entry) => {
6211
6682
  const resolution = resolutions[entry.path] ?? "pending";
6212
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("details", { className: "uix-diff-viewer__entry", "data-kind": entry.kind, open: entry.kind === "conflicted", children: [
6213
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("summary", { children: [
6214
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("code", { children: entry.path }),
6215
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(StatusPill, { tone: resolution === "pending" ? "warning" : "success", children: resolution })
6683
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("details", { className: "uix-diff-viewer__entry", "data-kind": entry.kind, open: entry.kind === "conflicted", children: [
6684
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("summary", { children: [
6685
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("code", { children: entry.path }),
6686
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(StatusPill, { tone: resolution === "pending" ? "warning" : "success", children: resolutionLabel[resolution] })
6216
6687
  ] }),
6217
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("div", { className: "uix-diff-viewer__versions", children: ["base", "current", "incoming"].map((version) => /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { role: "region", "aria-label": `${labels[version] ?? `${version[0].toUpperCase()}${version.slice(1)}`} value for ${entry.path}`, children: [
6218
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("strong", { children: labels[version] ?? `${version[0].toUpperCase()}${version.slice(1)}` }),
6219
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("pre", { children: renderValue(entry[version]) })
6688
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "uix-diff-viewer__versions", children: ["base", "current", "incoming"].map((version) => /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { role: "region", "aria-label": fillLabel(labels.valueFor, { version: labels[version], path: entry.path }), children: [
6689
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("strong", { children: labels[version] }),
6690
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("pre", { children: renderValue(entry[version], labels.notPresent) })
6220
6691
  ] }, version)) }),
6221
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "uix-diff-viewer__actions", "aria-label": `Resolve ${entry.path}`, children: [
6222
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary uix-btn--sm", "aria-pressed": resolution === "accept", onClick: () => resolve2(entry.path, "accept"), children: "Accept incoming" }),
6223
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", "aria-pressed": resolution === "skip", onClick: () => resolve2(entry.path, "skip"), children: "Keep current" }),
6224
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", "aria-pressed": resolution === "pending", onClick: () => resolve2(entry.path, "pending"), children: "Mark pending" })
6692
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "uix-diff-viewer__actions", "aria-label": fillLabel(labels.resolve, { path: entry.path }), children: [
6693
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "uix-btn uix-btn--primary uix-btn--sm", "aria-pressed": resolution === "accept", onClick: () => resolve2(entry.path, "accept"), children: labels.acceptIncoming }),
6694
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", "aria-pressed": resolution === "skip", onClick: () => resolve2(entry.path, "skip"), children: labels.keepCurrent }),
6695
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", "aria-pressed": resolution === "pending", onClick: () => resolve2(entry.path, "pending"), children: labels.markPending })
6225
6696
  ] })
6226
6697
  ] }, entry.path);
6227
6698
  })
6228
- ] }, group.kind);
6699
+ ] }, kind);
6229
6700
  }),
6230
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("p", { className: "uix-visually-hidden", "aria-live": "polite", children: [
6231
- summary.resolved,
6232
- " of ",
6233
- entries.length,
6234
- " differences resolved."
6235
- ] })
6701
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("p", { className: "uix-visually-hidden", "aria-live": "polite", children: fillLabel(labels.progress, { resolved: summary.resolved, total: entries.length }) })
6236
6702
  ] });
6237
6703
  }
6238
6704
  // Annotate the CommonJS export names for ESM import in node:
@@ -6267,8 +6733,18 @@ function DiffViewer({
6267
6733
  ConfirmDialog,
6268
6734
  ContentList,
6269
6735
  ContentListItem,
6736
+ CopyButton,
6737
+ DEFAULT_BRAND_PROFILE_EDITOR_LABELS,
6738
+ DEFAULT_BUILDER_CANVAS_LABELS,
6739
+ DEFAULT_COLOR_PICKER_LABELS,
6740
+ DEFAULT_DATE_RANGE_PICKER_LABELS,
6741
+ DEFAULT_DIFF_VIEWER_LABELS,
6742
+ DEFAULT_MATCH_REVIEW_LABELS,
6743
+ DEFAULT_PAGINATION_LABELS,
6270
6744
  DEFAULT_RELATIONSHIP_GRAPH_LABELS,
6745
+ DEFAULT_RULE_BUILDER_LABELS,
6271
6746
  DEFAULT_SAVE_STATUS_LABELS,
6747
+ DEFAULT_SCHEDULING_CALENDAR_LABELS,
6272
6748
  DateRangePicker,
6273
6749
  DescriptionItem,
6274
6750
  DescriptionList,