@tensor_1/react 2.20.0 → 2.22.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 (65) hide show
  1. package/dist/{ChartCore-Do6gRBN3.d.cts → ChartCore-DzWe10bN.d.cts} +16 -1
  2. package/dist/chart-preset.cjs +25 -13
  3. package/dist/chart-preset.d.cts +2 -2
  4. package/dist/chart-preset.d.ts +1 -1
  5. package/dist/chart-preset.js +2 -1
  6. package/dist/chart.cjs +25 -13
  7. package/dist/chart.d.cts +2 -2
  8. package/dist/chart.d.ts +1 -1
  9. package/dist/chart.js +2 -1
  10. package/dist/components/AppShell.d.ts +5 -1
  11. package/dist/components/AppShell.js +4 -2
  12. package/dist/components/Avatar.d.ts +4 -2
  13. package/dist/components/Avatar.js +2 -2
  14. package/dist/components/BrandProfiles.d.ts +29 -2
  15. package/dist/components/BrandProfiles.js +45 -20
  16. package/dist/components/BuilderCanvas.d.ts +27 -2
  17. package/dist/components/BuilderCanvas.js +45 -22
  18. package/dist/components/Chart.d.ts +1 -1
  19. package/dist/components/Chart.js +2 -1
  20. package/dist/components/ChartCore.d.ts +17 -2
  21. package/dist/components/ChartCore.js +24 -13
  22. package/dist/components/ColorPicker.d.ts +24 -2
  23. package/dist/components/ColorPicker.js +38 -20
  24. package/dist/components/CommandPalette.d.ts +3 -1
  25. package/dist/components/CommandPalette.js +2 -2
  26. package/dist/components/DateRangePicker.d.ts +21 -2
  27. package/dist/components/DateRangePicker.js +26 -6
  28. package/dist/components/DetailPage.d.ts +22 -3
  29. package/dist/components/DetailPage.js +33 -3
  30. package/dist/components/DiffViewer.d.ts +34 -3
  31. package/dist/components/DiffViewer.js +60 -40
  32. package/dist/components/Drawer.d.ts +3 -1
  33. package/dist/components/Drawer.js +2 -2
  34. package/dist/components/Inbox.d.ts +3 -1
  35. package/dist/components/Inbox.js +2 -2
  36. package/dist/components/MatchReview.d.ts +49 -2
  37. package/dist/components/MatchReview.js +72 -30
  38. package/dist/components/Meter.d.ts +3 -1
  39. package/dist/components/Meter.js +3 -2
  40. package/dist/components/Pagination.d.ts +10 -2
  41. package/dist/components/Pagination.js +11 -4
  42. package/dist/components/Peek.d.ts +7 -1
  43. package/dist/components/Peek.js +4 -4
  44. package/dist/components/RelationshipGraph.js +6 -2
  45. package/dist/components/RuleBuilder.d.ts +42 -2
  46. package/dist/components/RuleBuilder.js +71 -37
  47. package/dist/components/SchedulingCalendar.d.ts +25 -2
  48. package/dist/components/SchedulingCalendar.js +38 -15
  49. package/dist/components/Stat.d.ts +5 -0
  50. package/dist/components/Stat.js +2 -2
  51. package/dist/components/Table.d.ts +11 -3
  52. package/dist/components/Table.js +5 -8
  53. package/dist/components/Tabs.d.ts +8 -1
  54. package/dist/components/Tabs.js +4 -5
  55. package/dist/components/Toast.d.ts +6 -2
  56. package/dist/components/Toast.js +4 -4
  57. package/dist/components/Tree.d.ts +9 -1
  58. package/dist/components/Tree.js +55 -8
  59. package/dist/fill-label.d.ts +7 -0
  60. package/dist/fill-label.js +9 -0
  61. package/dist/index.cjs +765 -463
  62. package/dist/index.d.cts +341 -28
  63. package/dist/index.d.ts +10 -10
  64. package/dist/index.js +18 -9
  65. package/package.json +1 -1
@@ -11,16 +11,22 @@ function getPageNumbers(page, total) {
11
11
  pages.push(total);
12
12
  return pages;
13
13
  }
14
- function Pagination({ page, pageCount, onChange, className, ...props }) {
14
+ const DEFAULT_PAGINATION_LABELS = {
15
+ region: "Pagination",
16
+ previous: "Previous page",
17
+ next: "Next page"
18
+ };
19
+ function Pagination({ page, pageCount, onChange, labels: labelOverrides, className, ...props }) {
20
+ const labels = { ...DEFAULT_PAGINATION_LABELS, ...labelOverrides };
15
21
  const pages = getPageNumbers(page, pageCount);
16
- return /* @__PURE__ */ jsxs("nav", { "aria-label": "Pagination", className: cx("uix-pagination", className), ...props, children: [
22
+ return /* @__PURE__ */ jsxs("nav", { "aria-label": labels.region, className: cx("uix-pagination", className), ...props, children: [
17
23
  /* @__PURE__ */ jsx(
18
24
  "button",
19
25
  {
20
26
  className: "uix-pagination__btn",
21
27
  onClick: () => onChange(page - 1),
22
28
  disabled: page <= 1,
23
- "aria-label": "Previous page",
29
+ "aria-label": labels.previous,
24
30
  children: "\u2039"
25
31
  }
26
32
  ),
@@ -42,12 +48,13 @@ function Pagination({ page, pageCount, onChange, className, ...props }) {
42
48
  className: "uix-pagination__btn",
43
49
  onClick: () => onChange(page + 1),
44
50
  disabled: page >= pageCount,
45
- "aria-label": "Next page",
51
+ "aria-label": labels.next,
46
52
  children: "\u203A"
47
53
  }
48
54
  )
49
55
  ] });
50
56
  }
51
57
  export {
58
+ DEFAULT_PAGINATION_LABELS,
52
59
  Pagination
53
60
  };
@@ -2,6 +2,12 @@ import * as react from 'react';
2
2
  import { HTMLAttributes, ReactNode } from 'react';
3
3
 
4
4
  interface PeekProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title'> {
5
+ /** TENSOR RX-125 (UIX-04): translatable; English default. */
6
+ previousLabel?: string;
7
+ /** TENSOR RX-125 (UIX-04): translatable; English default. */
8
+ nextLabel?: string;
9
+ /** TENSOR RX-125 (UIX-04): translatable; English default. */
10
+ closeLabel?: string;
5
11
  open: boolean;
6
12
  onClose?: () => void;
7
13
  title?: ReactNode;
@@ -11,6 +17,6 @@ interface PeekProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title'> {
11
17
  onNavNext?: () => void;
12
18
  hint?: string;
13
19
  }
14
- declare function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className, onClick, ...rest }: PeekProps): react.JSX.Element;
20
+ declare function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, previousLabel, nextLabel, closeLabel, className, onClick, ...rest }: PeekProps): react.JSX.Element;
15
21
 
16
22
  export { Peek, type PeekProps };
@@ -6,7 +6,7 @@ import { useDialog } from "../hooks/useDialog.js";
6
6
  const CloseIcon = () => /* @__PURE__ */ 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__ */ jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) });
7
7
  const ChevronUp = () => /* @__PURE__ */ 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__ */ jsx("path", { d: "M2 8l4-4 4 4" }) });
8
8
  const ChevronDown = () => /* @__PURE__ */ 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__ */ jsx("path", { d: "M2 4l4 4 4-4" }) });
9
- function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className, onClick, ...rest }) {
9
+ function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, previousLabel = "Previous record", nextLabel = "Next record", closeLabel = "Close preview", className, onClick, ...rest }) {
10
10
  const ref = useDialog(open, onClose);
11
11
  const hasNav = onNavPrev != null || onNavNext != null;
12
12
  const titleId = useId();
@@ -21,12 +21,12 @@ function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hi
21
21
  return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-peek", className), "aria-labelledby": title ? titleId : void 0, ...rest, onClick: onBackdropClick, children: [
22
22
  /* @__PURE__ */ jsxs("div", { className: "uix-peek__header", children: [
23
23
  hasNav && /* @__PURE__ */ jsxs("div", { className: "uix-peek__nav", children: [
24
- /* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: () => onNavPrev?.(), "aria-disabled": onNavPrev ? void 0 : true, "aria-label": "Previous record", children: /* @__PURE__ */ jsx(ChevronUp, {}) }),
25
- /* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: () => onNavNext?.(), "aria-disabled": onNavNext ? void 0 : true, "aria-label": "Next record", children: /* @__PURE__ */ jsx(ChevronDown, {}) })
24
+ /* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: () => onNavPrev?.(), "aria-disabled": onNavPrev ? void 0 : true, "aria-label": previousLabel, children: /* @__PURE__ */ jsx(ChevronUp, {}) }),
25
+ /* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: () => onNavNext?.(), "aria-disabled": onNavNext ? void 0 : true, "aria-label": nextLabel, children: /* @__PURE__ */ jsx(ChevronDown, {}) })
26
26
  ] }),
27
27
  title && /* @__PURE__ */ jsx("h2", { className: "uix-peek__title", id: titleId, children: title }),
28
28
  hint && /* @__PURE__ */ jsx("span", { className: "uix-peek__hint", children: hint }),
29
- onClose && /* @__PURE__ */ jsx("button", { className: "uix-peek__close", onClick: onClose, "aria-label": "Close preview", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
29
+ onClose && /* @__PURE__ */ jsx("button", { className: "uix-peek__close", onClick: onClose, "aria-label": closeLabel, children: /* @__PURE__ */ jsx(CloseIcon, {}) })
30
30
  ] }),
31
31
  children != null && /* @__PURE__ */ jsx("div", { className: "uix-peek__body", children }),
32
32
  footer != null && /* @__PURE__ */ jsx("div", { className: "uix-peek__footer", children: footer })
@@ -102,6 +102,10 @@ function RadialRelationshipGraph({
102
102
  }) {
103
103
  const bounded = useMemo(() => boundRelationshipGraph(nodes, edges, maxNodes), [nodes, edges, maxNodes]);
104
104
  const positioned = useMemo(() => layoutRelationshipGraph(bounded.nodes, bounded.edges, selectedId), [bounded, selectedId]);
105
+ const typeColor = useMemo(
106
+ () => new Map(legend.map((item, index) => [item.id, `var(--uix-chart-${index % 8 + 1})`])),
107
+ [legend]
108
+ );
105
109
  const positionedById = useMemo(() => new Map(positioned.map((node) => [node.id, node])), [positioned]);
106
110
  const [zoom, setZoom] = useState(1);
107
111
  const [pan, setPan] = useState({ x: 0, y: 0 });
@@ -145,7 +149,7 @@ function RadialRelationshipGraph({
145
149
  bounded.edges.map((edge) => {
146
150
  const source = positionedById.get(edge.source);
147
151
  const target = positionedById.get(edge.target);
148
- return /* @__PURE__ */ 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__ */ jsx("title", { children: edge.label ?? edge.type ?? labels.relationship }) }, edge.id);
152
+ return /* @__PURE__ */ 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__ */ jsx("title", { children: edge.label ?? edge.type ?? labels.relationship }) }, edge.id);
149
153
  }),
150
154
  positioned.map((node) => /* @__PURE__ */ jsxs(
151
155
  "g",
@@ -171,7 +175,7 @@ function RadialRelationshipGraph({
171
175
  node.id
172
176
  ))
173
177
  ] }) }) }),
174
- legend.length > 0 && /* @__PURE__ */ jsx("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((item) => /* @__PURE__ */ jsx("li", { "data-type": item.id, children: item.label }, item.id)) }),
178
+ legend.length > 0 && /* @__PURE__ */ jsx("ul", { className: "uix-relationship-graph__legend", "aria-label": labels.legend, children: legend.map((item) => /* @__PURE__ */ jsx("li", { "data-type": item.id, style: { "--uix-graph-type-color": typeColor.get(item.id) }, children: item.label }, item.id)) }),
175
179
  showList && /* @__PURE__ */ jsx(EquivalentRelationshipList, { nodes: bounded.nodes, edges: bounded.edges, selectedId, labels, onSelect: select, onExpandNeighbors, onOpenDetails })
176
180
  ] });
177
181
  }
@@ -25,6 +25,42 @@ interface RuleActionDefinition {
25
25
  label: string;
26
26
  renderParameters?: (action: RuleAction, onChange: (parameters: Record<string, JsonValue>) => void, disabled: boolean) => ReactNode;
27
27
  }
28
+ /**
29
+ * Every word the rule builder renders (TENSOR RX-125, UIX-12). `{item}` is one of
30
+ * `itemGroup` / `itemCondition` / `itemAction`; `{field}` a field label; `{count}` a number.
31
+ */
32
+ interface RuleBuilderLabels {
33
+ region: string;
34
+ summary: string;
35
+ when: string;
36
+ group: string;
37
+ match: string;
38
+ all: string;
39
+ any: string;
40
+ field: string;
41
+ operator: string;
42
+ valueFor: string;
43
+ itemGroup: string;
44
+ itemCondition: string;
45
+ itemAction: string;
46
+ moveUp: string;
47
+ moveUpNamed: string;
48
+ moveDown: string;
49
+ moveDownNamed: string;
50
+ remove: string;
51
+ removeNamed: string;
52
+ then: string;
53
+ actionType: string;
54
+ valid: string;
55
+ issuesOne: string;
56
+ issuesMany: string;
57
+ summaryIssuesOne: string;
58
+ summaryIssuesMany: string;
59
+ addCondition: string;
60
+ addGroup: string;
61
+ addAction: string;
62
+ }
63
+ declare const DEFAULT_RULE_BUILDER_LABELS: RuleBuilderLabels;
28
64
  interface RuleBuilderProps {
29
65
  value: RuleDefinition;
30
66
  onChange: (value: RuleDefinition) => void;
@@ -35,11 +71,15 @@ interface RuleBuilderProps {
35
71
  readOnly?: boolean;
36
72
  validate?: (value: RuleDefinition) => RuleValidationIssue[];
37
73
  className?: string;
74
+ /** @deprecated use `labels.addCondition` */
38
75
  addConditionLabel?: string;
76
+ /** @deprecated use `labels.addGroup` */
39
77
  addGroupLabel?: string;
78
+ /** @deprecated use `labels.addAction` */
40
79
  addActionLabel?: string;
80
+ labels?: Partial<RuleBuilderLabels>;
41
81
  }
42
82
  /** Declarative controlled when-conditions-to-actions editor with bounded nesting. */
43
- declare function RuleBuilder({ value, onChange, fields, operators, actions, maxDepth, readOnly, validate, className, addConditionLabel, addGroupLabel, addActionLabel, }: RuleBuilderProps): react.JSX.Element;
83
+ declare function RuleBuilder({ value, onChange, fields, operators, actions, maxDepth, readOnly, validate, className, addConditionLabel, addGroupLabel, addActionLabel, labels: labelOverrides, }: RuleBuilderProps): react.JSX.Element;
44
84
 
45
- export { type RuleActionDefinition, RuleBuilder, type RuleBuilderProps, type RuleFieldDefinition, type RuleOperatorDefinition, type RuleValueEditorProps };
85
+ export { DEFAULT_RULE_BUILDER_LABELS, type RuleActionDefinition, RuleBuilder, type RuleBuilderLabels, type RuleBuilderProps, type RuleFieldDefinition, type RuleOperatorDefinition, type RuleValueEditorProps };
@@ -10,6 +10,38 @@ import {
10
10
  summarizeRule,
11
11
  validateRuleDefinition
12
12
  } from "../rule-builder-model.js";
13
+ import { fillLabel } from "../fill-label.js";
14
+ const DEFAULT_RULE_BUILDER_LABELS = {
15
+ region: "Rule builder",
16
+ summary: "Rule summary",
17
+ when: "When",
18
+ group: "Group",
19
+ match: "Match",
20
+ all: "all (AND)",
21
+ any: "any (OR)",
22
+ field: "Field",
23
+ operator: "Operator",
24
+ valueFor: "Value for {field}",
25
+ itemGroup: "group",
26
+ itemCondition: "condition",
27
+ itemAction: "action",
28
+ moveUp: "Up",
29
+ moveUpNamed: "Move {item} up",
30
+ moveDown: "Down",
31
+ moveDownNamed: "Move {item} down",
32
+ remove: "Remove",
33
+ removeNamed: "Remove {item}",
34
+ then: "Then",
35
+ actionType: "Action type",
36
+ valid: "Rule is valid.",
37
+ issuesOne: "{count} validation issue",
38
+ issuesMany: "{count} validation issues",
39
+ summaryIssuesOne: "Rule has {count} validation issue.",
40
+ summaryIssuesMany: "Rule has {count} validation issues.",
41
+ addCondition: "Add condition",
42
+ addGroup: "Add group",
43
+ addAction: "Add action"
44
+ };
13
45
  let ruleId = 0;
14
46
  const nextId = (prefix) => `${prefix}-${Date.now().toString(36)}-${(++ruleId).toString(36)}`;
15
47
  function defaultCondition(fields, operators) {
@@ -27,27 +59,28 @@ function RuleGroupEditor({ group, depth, root, fields, operators, maxDepth, disa
27
59
  }, maxDepth));
28
60
  return /* @__PURE__ */ jsxs("fieldset", { className: "uix-rule-builder__group", "data-depth": depth, children: [
29
61
  /* @__PURE__ */ jsxs("legend", { className: "uix-rule-builder__group-heading", children: [
30
- /* @__PURE__ */ jsx("span", { children: depth === 1 ? "When" : "Group" }),
62
+ /* @__PURE__ */ jsx("span", { children: depth === 1 ? labels.when : labels.group }),
31
63
  /* @__PURE__ */ jsxs("label", { children: [
32
- "Match",
64
+ labels.match,
33
65
  /* @__PURE__ */ jsxs("select", { className: "uix-select uix-select--sm", value: group.combinator, disabled, onChange: (event) => updateNode(group.id, (node) => ({ ...node, combinator: event.currentTarget.value })), children: [
34
- /* @__PURE__ */ jsx("option", { value: "and", children: "all (AND)" }),
35
- /* @__PURE__ */ jsx("option", { value: "or", children: "any (OR)" })
66
+ /* @__PURE__ */ jsx("option", { value: "and", children: labels.all }),
67
+ /* @__PURE__ */ jsx("option", { value: "or", children: labels.any })
36
68
  ] })
37
69
  ] })
38
70
  ] }),
39
71
  /* @__PURE__ */ jsx("div", { className: "uix-rule-builder__rows", children: group.conditions.map((node, index) => isRuleGroup(node) ? /* @__PURE__ */ jsxs("div", { className: "uix-rule-builder__nested", children: [
40
72
  /* @__PURE__ */ jsx(RuleGroupEditor, { ...{ group: node, depth: depth + 1, root, fields, operators, maxDepth, disabled, onRootChange, labels } }),
41
- /* @__PURE__ */ 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)) })
73
+ /* @__PURE__ */ 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)) })
42
74
  ] }, node.id) : /* @__PURE__ */ jsx(
43
75
  ConditionRow,
44
76
  {
77
+ labels,
45
78
  condition: node,
46
79
  fields,
47
80
  operators,
48
81
  disabled,
49
82
  onChange: (condition) => updateNode(node.id, () => condition),
50
- controls: /* @__PURE__ */ 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)) })
83
+ controls: /* @__PURE__ */ 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)) })
51
84
  },
52
85
  node.id
53
86
  )) }),
@@ -57,7 +90,7 @@ function RuleGroupEditor({ group, depth, root, fields, operators, maxDepth, disa
57
90
  ] })
58
91
  ] });
59
92
  }
60
- function ConditionRow({ condition, fields, operators, disabled, onChange, controls }) {
93
+ function ConditionRow({ labels, condition, fields, operators, disabled, onChange, controls }) {
61
94
  const field = fields.find((item) => item.id === condition.field);
62
95
  const availableOperators = field?.operators?.length ? operators.filter((item) => field.operators.includes(item.id)) : operators;
63
96
  const operator = operators.find((item) => item.id === condition.operator);
@@ -68,22 +101,22 @@ function ConditionRow({ condition, fields, operators, disabled, onChange, contro
68
101
  };
69
102
  return /* @__PURE__ */ jsxs("div", { className: "uix-rule-builder__condition", children: [
70
103
  /* @__PURE__ */ jsxs("label", { children: [
71
- /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: "Field" }),
104
+ /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: labels.field }),
72
105
  /* @__PURE__ */ jsx("select", { className: "uix-select", value: condition.field, onChange: (event) => setField(event.currentTarget.value), disabled, children: fields.map((item) => /* @__PURE__ */ jsx("option", { value: item.id, children: item.label }, item.id)) })
73
106
  ] }),
74
107
  /* @__PURE__ */ jsxs("label", { children: [
75
- /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: "Operator" }),
108
+ /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: labels.operator }),
76
109
  /* @__PURE__ */ jsx("select", { className: "uix-select", value: condition.operator, onChange: (event) => onChange({ ...condition, operator: event.currentTarget.value }), disabled, children: availableOperators.map((item) => /* @__PURE__ */ jsx("option", { value: item.id, children: item.label }, item.id)) })
77
110
  ] }),
78
- operator?.requiresValue !== false && /* @__PURE__ */ jsx("div", { className: "uix-rule-builder__value", children: field?.renderValueEditor?.({ condition, onChange: (value) => onChange({ ...condition, value }), disabled }) ?? /* @__PURE__ */ 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"}` }) }),
111
+ operator?.requiresValue !== false && /* @__PURE__ */ jsx("div", { className: "uix-rule-builder__value", children: field?.renderValueEditor?.({ condition, onChange: (value) => onChange({ ...condition, value }), disabled }) ?? /* @__PURE__ */ 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 }) }) }),
79
112
  controls
80
113
  ] });
81
114
  }
82
- function RowControls({ label, first, last, disabled, onUp, onDown, onRemove }) {
115
+ function RowControls({ labels, label, first, last, disabled, onUp, onDown, onRemove }) {
83
116
  return /* @__PURE__ */ jsxs("span", { className: "uix-rule-builder__row-actions", children: [
84
- /* @__PURE__ */ 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" }),
85
- /* @__PURE__ */ 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" }),
86
- /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onRemove, disabled, "aria-label": `Remove ${label}`, children: "Remove" })
117
+ /* @__PURE__ */ 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 }),
118
+ /* @__PURE__ */ 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 }),
119
+ /* @__PURE__ */ 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 })
87
120
  ] });
88
121
  }
89
122
  function RuleBuilder({
@@ -96,38 +129,42 @@ function RuleBuilder({
96
129
  readOnly = false,
97
130
  validate,
98
131
  className,
99
- addConditionLabel = "Add condition",
100
- addGroupLabel = "Add group",
101
- addActionLabel = "Add action"
132
+ addConditionLabel,
133
+ addGroupLabel,
134
+ addActionLabel,
135
+ labels: labelOverrides
102
136
  }) {
137
+ const labels = {
138
+ ...DEFAULT_RULE_BUILDER_LABELS,
139
+ ...addConditionLabel != null ? { addCondition: addConditionLabel } : {},
140
+ ...addGroupLabel != null ? { addGroup: addGroupLabel } : {},
141
+ ...addActionLabel != null ? { addAction: addActionLabel } : {},
142
+ ...labelOverrides
143
+ };
144
+ const issuesText = (template1, templateN) => fillLabel(issues.length === 1 ? template1 : templateN, { count: issues.length });
103
145
  const issues = [...validateRuleDefinition(value, maxDepth), ...validate?.(value) ?? []];
104
146
  const fieldLabels = Object.fromEntries(fields.map((field) => [field.id, field.label]));
105
147
  const operatorLabels = Object.fromEntries(operators.map((operator) => [operator.id, operator.label]));
106
148
  const actionLabels = Object.fromEntries(actions.map((action) => [action.id, action.label]));
107
- if (readOnly) return /* @__PURE__ */ jsxs("section", { className: cx("uix-rule-builder uix-rule-builder--summary", className), "aria-label": "Rule summary", children: [
149
+ if (readOnly) return /* @__PURE__ */ jsxs("section", { className: cx("uix-rule-builder uix-rule-builder--summary", className), "aria-label": labels.summary, children: [
108
150
  /* @__PURE__ */ jsx("p", { children: summarizeRule(value, { fields: fieldLabels, operators: operatorLabels, actions: actionLabels }) }),
109
- issues.length > 0 && /* @__PURE__ */ jsxs("p", { className: "uix-rule-builder__invalid", children: [
110
- "Rule has ",
111
- issues.length,
112
- " validation issue",
113
- issues.length === 1 ? "" : "s",
114
- "."
115
- ] })
151
+ issues.length > 0 && /* @__PURE__ */ jsx("p", { className: "uix-rule-builder__invalid", children: issuesText(labels.summaryIssuesOne, labels.summaryIssuesMany) })
116
152
  ] });
117
153
  const updateActions = (next) => onChange({ ...value, then: next });
118
- return /* @__PURE__ */ jsxs("section", { className: cx("uix-rule-builder", className), "aria-label": "Rule builder", children: [
119
- /* @__PURE__ */ 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 } }),
154
+ return /* @__PURE__ */ jsxs("section", { className: cx("uix-rule-builder", className), "aria-label": labels.region, children: [
155
+ /* @__PURE__ */ jsx(RuleGroupEditor, { group: value.when, depth: 1, root: value.when, fields, operators, maxDepth, disabled: readOnly, onRootChange: (when) => onChange({ ...value, when }), labels }),
120
156
  /* @__PURE__ */ jsxs("fieldset", { className: "uix-rule-builder__actions", children: [
121
- /* @__PURE__ */ jsx("legend", { children: "Then" }),
157
+ /* @__PURE__ */ jsx("legend", { children: labels.then }),
122
158
  value.then.map((action, index) => {
123
159
  const definition = actions.find((item) => item.id === action.type);
124
160
  return /* @__PURE__ */ jsxs("div", { className: "uix-rule-builder__action", children: [
125
- /* @__PURE__ */ 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__ */ jsx("option", { value: item.id, children: item.label }, item.id)) }),
161
+ /* @__PURE__ */ 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__ */ jsx("option", { value: item.id, children: item.label }, item.id)) }),
126
162
  definition?.renderParameters?.(action, (parameters) => updateActions(value.then.map((item) => item.id === action.id ? { ...item, parameters } : item)), false),
127
163
  /* @__PURE__ */ jsx(
128
164
  RowControls,
129
165
  {
130
- label: "action",
166
+ labels,
167
+ label: labels.itemAction,
131
168
  first: index === 0,
132
169
  last: index === value.then.length - 1,
133
170
  disabled: false,
@@ -146,18 +183,15 @@ function RuleBuilder({
146
183
  )
147
184
  ] }, action.id);
148
185
  }),
149
- /* @__PURE__ */ 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 })
186
+ /* @__PURE__ */ 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 })
150
187
  ] }),
151
- /* @__PURE__ */ jsx("div", { className: "uix-rule-builder__validation", "aria-live": "polite", children: issues.length === 0 ? /* @__PURE__ */ jsx("span", { children: "Rule is valid." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
152
- /* @__PURE__ */ jsxs("strong", { children: [
153
- issues.length,
154
- " validation issue",
155
- issues.length === 1 ? "" : "s"
156
- ] }),
188
+ /* @__PURE__ */ jsx("div", { className: "uix-rule-builder__validation", "aria-live": "polite", children: issues.length === 0 ? /* @__PURE__ */ jsx("span", { children: labels.valid }) : /* @__PURE__ */ jsxs(Fragment, { children: [
189
+ /* @__PURE__ */ jsx("strong", { children: issuesText(labels.issuesOne, labels.issuesMany) }),
157
190
  /* @__PURE__ */ jsx("ul", { children: issues.map((issue, index) => /* @__PURE__ */ jsx("li", { children: issue.message }, `${issue.path}-${index}`)) })
158
191
  ] }) })
159
192
  ] });
160
193
  }
161
194
  export {
195
+ DEFAULT_RULE_BUILDER_LABELS,
162
196
  RuleBuilder
163
197
  };
@@ -19,6 +19,28 @@ interface SchedulingCalendarOverlay {
19
19
  end: string;
20
20
  kind: SchedulingOverlayKind;
21
21
  }
22
+ /**
23
+ * Every word the calendar renders (TENSOR RX-125, UIX-12). `{timeZone}`, `{view}`,
24
+ * `{title}`, `{state}`, `{start}`, `{end}` are placeholders.
25
+ */
26
+ interface SchedulingCalendarLabels {
27
+ region: string;
28
+ previous: string;
29
+ next: string;
30
+ viewGroup: string;
31
+ viewMonth: string;
32
+ viewWeek: string;
33
+ viewAgenda: string;
34
+ loading: string;
35
+ retry: string;
36
+ agenda: string;
37
+ agendaEmpty: string;
38
+ grid: string;
39
+ entry: string;
40
+ legend: string;
41
+ states: Record<SchedulingEntryState, string>;
42
+ }
43
+ declare const DEFAULT_SCHEDULING_CALENDAR_LABELS: SchedulingCalendarLabels;
22
44
  interface SchedulingCalendarProps {
23
45
  entries: SchedulingCalendarEntry[];
24
46
  anchorDate: string;
@@ -35,8 +57,9 @@ interface SchedulingCalendarProps {
35
57
  error?: string;
36
58
  onRetry?: () => void;
37
59
  className?: string;
60
+ labels?: Partial<SchedulingCalendarLabels>;
38
61
  }
39
62
  /** Month/week/agenda calendar for UTC ranges rendered in an explicit IANA time zone. */
40
- declare function SchedulingCalendar({ entries, anchorDate, timeZone, view: controlledView, onViewChange, onAnchorDateChange, onSelectEntry, overlays, filter, renderEntry, locale, loading, error, onRetry, className, }: SchedulingCalendarProps): react.JSX.Element;
63
+ declare function SchedulingCalendar({ entries, anchorDate, timeZone, view: controlledView, onViewChange, onAnchorDateChange, onSelectEntry, overlays, filter, renderEntry, locale, loading, error, onRetry, className, labels: labelOverrides, }: SchedulingCalendarProps): react.JSX.Element;
41
64
 
42
- export { SchedulingCalendar, type SchedulingCalendarEntry, type SchedulingCalendarOverlay, type SchedulingCalendarProps, type SchedulingCalendarView, type SchedulingEntryState, type SchedulingOverlayKind };
65
+ export { DEFAULT_SCHEDULING_CALENDAR_LABELS, SchedulingCalendar, type SchedulingCalendarEntry, type SchedulingCalendarLabels, type SchedulingCalendarOverlay, type SchedulingCalendarProps, type SchedulingCalendarView, type SchedulingEntryState, type SchedulingOverlayKind };
@@ -4,7 +4,24 @@ import { useEffect, useMemo, useRef, useState } from "react";
4
4
  import { addCalendarDays, addCalendarMonths, buildMonthGrid, startOfMonth, zonedDateSpan } from "../calendar-model.js";
5
5
  import { cx } from "../cx.js";
6
6
  import { StatusPill } from "./StatusPill.js";
7
- const stateLabel = { scheduled: "Scheduled", conflicted: "Conflicted", "in-progress": "In progress", "blackout-violation": "Blackout violation" };
7
+ import { fillLabel } from "../fill-label.js";
8
+ const DEFAULT_SCHEDULING_CALENDAR_LABELS = {
9
+ region: "Scheduling calendar in {timeZone}",
10
+ previous: "Previous",
11
+ next: "Next",
12
+ viewGroup: "Calendar view",
13
+ viewMonth: "Month",
14
+ viewWeek: "Week",
15
+ viewAgenda: "Agenda",
16
+ loading: "Loading schedule\u2026",
17
+ retry: "Try again",
18
+ agenda: "Schedule agenda",
19
+ agendaEmpty: "No scheduled entries match the current filters.",
20
+ grid: "{view} schedule",
21
+ entry: "{title}, {state}, {start} to {end}",
22
+ legend: "Schedule state legend",
23
+ states: { scheduled: "Scheduled", conflicted: "Conflicted", "in-progress": "In progress", "blackout-violation": "Blackout violation" }
24
+ };
8
25
  const stateTone = (state) => state === "scheduled" ? "info" : state === "in-progress" ? "success" : "danger";
9
26
  const dateLabel = (date, locale) => new Intl.DateTimeFormat(locale, { dateStyle: "full", timeZone: "UTC" }).format(/* @__PURE__ */ new Date(`${date}T00:00:00Z`));
10
27
  const EMPTY_OVERLAYS = [];
@@ -23,8 +40,16 @@ function SchedulingCalendar({
23
40
  loading,
24
41
  error,
25
42
  onRetry,
26
- className
43
+ className,
44
+ labels: labelOverrides
27
45
  }) {
46
+ const labels = {
47
+ ...DEFAULT_SCHEDULING_CALENDAR_LABELS,
48
+ ...labelOverrides,
49
+ states: { ...DEFAULT_SCHEDULING_CALENDAR_LABELS.states, ...labelOverrides?.states }
50
+ };
51
+ const stateLabel = labels.states;
52
+ const viewLabel = { month: labels.viewMonth, week: labels.viewWeek, agenda: labels.viewAgenda };
28
53
  const [internalView, setInternalView] = useState("month");
29
54
  const view = controlledView ?? internalView;
30
55
  const [activeDate, setActiveDate] = useState(anchorDate);
@@ -71,22 +96,19 @@ function SchedulingCalendar({
71
96
  return date >= span.start && date <= span.end;
72
97
  });
73
98
  const formatInstant = (instant) => new Intl.DateTimeFormat(locale, { timeZone, dateStyle: "medium", timeStyle: "short" }).format(new Date(instant));
74
- return /* @__PURE__ */ jsxs("section", { className: cx("uix-scheduling-calendar", className), "aria-label": `Scheduling calendar in ${timeZone}`, children: [
99
+ return /* @__PURE__ */ jsxs("section", { className: cx("uix-scheduling-calendar", className), "aria-label": fillLabel(labels.region, { timeZone }), children: [
75
100
  /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__header", children: [
76
101
  /* @__PURE__ */ jsxs("div", { children: [
77
- /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(-1), disabled: !onAnchorDateChange, children: "Previous" }),
78
- /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(1), disabled: !onAnchorDateChange, children: "Next" })
102
+ /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(-1), disabled: !onAnchorDateChange, children: labels.previous }),
103
+ /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(1), disabled: !onAnchorDateChange, children: labels.next })
79
104
  ] }),
80
105
  /* @__PURE__ */ 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)}` }),
81
- /* @__PURE__ */ jsx("div", { className: "uix-segmented", role: "group", "aria-label": "Calendar view", children: ["month", "week", "agenda"].map((option) => /* @__PURE__ */ jsxs("button", { type: "button", className: "uix-segmented__option", "aria-pressed": view === option, "data-selected": view === option || void 0, onClick: () => setView(option), children: [
82
- option[0].toUpperCase(),
83
- option.slice(1)
84
- ] }, option)) })
106
+ /* @__PURE__ */ jsx("div", { className: "uix-segmented", role: "group", "aria-label": labels.viewGroup, children: ["month", "week", "agenda"].map((option) => /* @__PURE__ */ 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)) })
85
107
  ] }),
86
- loading ? /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__state", role: "status", children: "Loading schedule\u2026" }) : error ? /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__state", role: "alert", children: [
108
+ loading ? /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__state", role: "status", children: labels.loading }) : error ? /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__state", role: "alert", children: [
87
109
  /* @__PURE__ */ jsx("p", { children: error }),
88
- onRetry && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: "Try again" })
89
- ] }) : view === "agenda" ? /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__agenda", role: "region", "aria-label": "Schedule agenda", children: visibleEntries.length === 0 ? /* @__PURE__ */ jsx("p", { children: "No scheduled entries match the current filters." }) : /* @__PURE__ */ jsx("ol", { children: [...visibleEntries].sort((a, b) => a.start.localeCompare(b.start)).map((entry) => {
110
+ onRetry && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: labels.retry })
111
+ ] }) : view === "agenda" ? /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__agenda", role: "region", "aria-label": labels.agenda, children: visibleEntries.length === 0 ? /* @__PURE__ */ jsx("p", { children: labels.agendaEmpty }) : /* @__PURE__ */ jsx("ol", { children: [...visibleEntries].sort((a, b) => a.start.localeCompare(b.start)).map((entry) => {
90
112
  const state = entry.state ?? "scheduled";
91
113
  return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => onSelectEntry?.(entry), children: [
92
114
  /* @__PURE__ */ jsxs("span", { children: [
@@ -100,7 +122,7 @@ function SchedulingCalendar({
100
122
  ] }),
101
123
  /* @__PURE__ */ jsx(StatusPill, { tone: stateTone(state), children: stateLabel[state] })
102
124
  ] }) }, entry.id);
103
- }) }) }) : /* @__PURE__ */ 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) => {
125
+ }) }) }) : /* @__PURE__ */ 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) => {
104
126
  const dayEntries = entriesFor(date);
105
127
  const dayOverlays = overlaysFor(date);
106
128
  return /* @__PURE__ */ jsxs("div", { className: "uix-scheduling-calendar__day", "data-outside": view === "month" && !monthDays[index].inMonth || void 0, children: [
@@ -109,16 +131,17 @@ function SchedulingCalendar({
109
131
  /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__entries", children: dayEntries.map((entry) => {
110
132
  const span = entrySpans.get(entry.id);
111
133
  const state = entry.state ?? "scheduled";
112
- return /* @__PURE__ */ 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: [
134
+ return /* @__PURE__ */ 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: [
113
135
  /* @__PURE__ */ jsx("span", { children: renderEntry?.(entry) ?? entry.title }),
114
136
  /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: stateLabel[state] })
115
137
  ] }, entry.id);
116
138
  }) })
117
139
  ] }, date);
118
140
  }) }),
119
- /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__legend", "aria-label": "Schedule state legend", children: ["scheduled", "conflicted", "in-progress", "blackout-violation"].map((state) => /* @__PURE__ */ jsx("span", { "data-state": state, children: stateLabel[state] }, state)) })
141
+ /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__legend", "aria-label": labels.legend, children: ["scheduled", "conflicted", "in-progress", "blackout-violation"].map((state) => /* @__PURE__ */ jsx("span", { "data-state": state, children: stateLabel[state] }, state)) })
120
142
  ] });
121
143
  }
122
144
  export {
145
+ DEFAULT_SCHEDULING_CALENDAR_LABELS,
123
146
  SchedulingCalendar
124
147
  };
@@ -25,6 +25,11 @@ interface StatProps extends HTMLAttributes<HTMLElement> {
25
25
  onActivate?: () => void;
26
26
  /** Action word appended to the accessible name, e.g. "change" → "Priority: P1, change". */
27
27
  activateLabel?: string;
28
+ /** TENSOR RX-125 (UIX-04): the spoken trend direction; English defaults. */
29
+ trendLabels?: {
30
+ up?: string;
31
+ down?: string;
32
+ };
28
33
  /** Whether the editor this tile opens is currently open (`aria-expanded`). */
29
34
  expanded?: boolean;
30
35
  }
@@ -2,7 +2,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef, useId } from "react";
3
3
  import { cx } from "../cx.js";
4
4
  const Chevron = () => /* @__PURE__ */ jsx("span", { className: "uix-stat__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) }) });
5
- const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, className, onClick, ...props }, ref) {
5
+ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, className, onClick, ...props }, ref) {
6
6
  const id = useId();
7
7
  const interactive = onActivate != null;
8
8
  const classes = cx(
@@ -23,7 +23,7 @@ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone =
23
23
  (meta != null || trend != null) && /* @__PURE__ */ jsxs(Row, { className: "uix-stat__meta", id: interactive ? `${id}-meta` : void 0, children: [
24
24
  trend != null && /* @__PURE__ */ jsxs("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`), children: [
25
25
  /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: trend.direction === "up" ? /* @__PURE__ */ jsx("path", { d: "M12 19V5m-6 6 6-6 6 6" }) : /* @__PURE__ */ jsx("path", { d: "M12 5v14m6-6-6 6-6-6" }) }),
26
- /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: trend.direction === "up" ? "up" : "down" }),
26
+ /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: trend.direction === "up" ? trendLabels?.up ?? "up" : trendLabels?.down ?? "down" }),
27
27
  trend.label
28
28
  ] }),
29
29
  meta
@@ -40,12 +40,16 @@ interface TrProps extends HTMLAttributes<HTMLTableRowElement> {
40
40
  }
41
41
  declare function Tr({ selected, pinned, className, children, ...props }: TrProps): react.JSX.Element;
42
42
  interface BulkBarProps extends HTMLAttributes<HTMLDivElement> {
43
- /** number of selected rows, rendered as "N selected" */
43
+ /** number of selected rows, rendered through `selectedLabel` */
44
44
  count?: number;
45
45
  children?: ReactNode;
46
+ /** TENSOR RX-125 (UIX-04): translatable; English default. */
47
+ label?: string;
48
+ /** TENSOR RX-125 (UIX-04): translatable; English default. */
49
+ selectedLabel?: (count: number) => ReactNode;
46
50
  }
47
51
  /** Contextual action bar shown above the table when ≥1 row is selected. */
48
- declare function BulkBar({ count, children, className, ...props }: BulkBarProps): react.JSX.Element;
52
+ declare function BulkBar({ count, children, label, selectedLabel, className, ...props }: BulkBarProps): react.JSX.Element;
49
53
  interface RowActionsProps extends TdHTMLAttributes<HTMLTableCellElement> {
50
54
  children?: ReactNode;
51
55
  }
@@ -57,12 +61,16 @@ interface RowActionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
57
61
  /** A single hover-revealed row action button (icon inside). */
58
62
  declare function RowAction({ children, className, type, ...props }: RowActionProps): react.JSX.Element;
59
63
  interface ExpandToggleProps extends ButtonHTMLAttributes<HTMLButtonElement> {
64
+ /** TENSOR RX-125 (UIX-04): translatable; English default. */
65
+ expandLabel?: string;
66
+ /** TENSOR RX-125 (UIX-04): translatable; English default. */
67
+ collapseLabel?: string;
60
68
  expanded?: boolean;
61
69
  /** id of the detail row this toggle controls → `aria-controls` (UIX-A11Y-2). */
62
70
  controls?: string;
63
71
  }
64
72
  /** Chevron button that expands/collapses an inline detail row. */
65
- declare function ExpandToggle({ expanded, controls, className, type, ...props }: ExpandToggleProps): react.JSX.Element;
73
+ declare function ExpandToggle({ expanded, controls, expandLabel, collapseLabel, className, type, ...props }: ExpandToggleProps): react.JSX.Element;
66
74
  /** Emphasised primary cell text. */
67
75
  declare function CellStrong({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
68
76
  /** Secondary line under a primary cell value (muted, meta size). */