@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
@@ -3,6 +3,48 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useMemo, useState } from "react";
4
4
  import { cx } from "../cx.js";
5
5
  import { StatusPill } from "./StatusPill.js";
6
+ import { fillLabel } from "../fill-label.js";
7
+ const DEFAULT_MATCH_REVIEW_LABELS = {
8
+ region: "Match review",
9
+ loading: "Loading match candidates\u2026",
10
+ retry: "Try again",
11
+ empty: "No candidate matches found.",
12
+ emptyDetail: "Choose another record source or continue without a match.",
13
+ pendingOf: "{pending} pending of {total}",
14
+ bulk: "Bulk candidate actions",
15
+ selectedCount: "{count} selected",
16
+ applying: "Applying\u2026",
17
+ acceptSelected: "Accept selected",
18
+ dismissSelected: "Dismiss selected",
19
+ caption: "Candidate matches and available decisions",
20
+ select: "Select",
21
+ confidence: "Confidence",
22
+ status: "Status",
23
+ actions: "Actions",
24
+ selectCandidate: "Select candidate {id}",
25
+ notScored: "Not scored",
26
+ resolved: "Resolved",
27
+ pending: "Pending",
28
+ decisionAccepted: "Accepted",
29
+ decisionDismissed: "Dismissed",
30
+ decisionSplit: "Split",
31
+ decisionOther: "Other match",
32
+ accept: "Accept",
33
+ dismiss: "Dismiss",
34
+ split: "Split",
35
+ pickOther: "Pick other",
36
+ acceptingOne: "Accepting {count} candidate\u2026",
37
+ acceptingMany: "Accepting {count} candidates\u2026",
38
+ dismissingOne: "Dismissing {count} candidate\u2026",
39
+ dismissingMany: "Dismissing {count} candidates\u2026",
40
+ acceptedOne: "{count} candidate accepted",
41
+ acceptedMany: "{count} candidates accepted",
42
+ dismissedOne: "{count} candidate dismissed",
43
+ dismissedMany: "{count} candidates dismissed",
44
+ failedSuffix: "; {count} failed",
45
+ bulkAcceptFailed: "Bulk accept failed. Try again.",
46
+ bulkDismissFailed: "Bulk dismiss failed. Try again."
47
+ };
6
48
  const valueText = (value) => value == null ? "\u2014" : typeof value === "string" ? value : JSON.stringify(value);
7
49
  function MatchReview({
8
50
  incoming,
@@ -16,8 +58,13 @@ function MatchReview({
16
58
  loading,
17
59
  error,
18
60
  onRetry,
19
- className
61
+ className,
62
+ labels: labelOverrides
20
63
  }) {
64
+ const labels = { ...DEFAULT_MATCH_REVIEW_LABELS, ...labelOverrides };
65
+ const plural = (n, one, many) => fillLabel(n === 1 ? one : many, { count: n });
66
+ const decisionLabel = { accepted: labels.decisionAccepted, dismissed: labels.decisionDismissed, split: labels.decisionSplit, other: labels.decisionOther };
67
+ const actionLabel = { accept: labels.accept, dismiss: labels.dismiss, split: labels.split, "pick-other": labels.pickOther };
21
68
  const [internalSelection, setInternalSelection] = useState(/* @__PURE__ */ new Set());
22
69
  const [announcement, setAnnouncement] = useState("");
23
70
  const [bulkPending, setBulkPending] = useState(false);
@@ -37,67 +84,61 @@ function MatchReview({
37
84
  if (!onBulkDecision || selection.size === 0 || bulkPending) return;
38
85
  const ids = [...selection];
39
86
  setBulkPending(true);
40
- setAnnouncement(`${action === "accept" ? "Accepting" : "Dismissing"} ${ids.length} candidate${ids.length === 1 ? "" : "s"}\u2026`);
87
+ setAnnouncement(action === "accept" ? plural(ids.length, labels.acceptingOne, labels.acceptingMany) : plural(ids.length, labels.dismissingOne, labels.dismissingMany));
41
88
  try {
42
89
  const result = await onBulkDecision(ids, action);
43
90
  const succeeded = result?.succeeded ?? ids.length;
44
91
  const failed = result?.failed ?? 0;
45
- setAnnouncement(`${succeeded} candidate${succeeded === 1 ? "" : "s"} ${action === "accept" ? "accepted" : "dismissed"}${failed ? `; ${failed} failed` : ""}.`);
92
+ const done = action === "accept" ? plural(succeeded, labels.acceptedOne, labels.acceptedMany) : plural(succeeded, labels.dismissedOne, labels.dismissedMany);
93
+ setAnnouncement(`${done}${failed ? fillLabel(labels.failedSuffix, { count: failed }) : ""}.`);
46
94
  if (!failed) setSelection(/* @__PURE__ */ new Set());
47
95
  } catch {
48
- setAnnouncement(`Bulk ${action} failed. Try again.`);
96
+ setAnnouncement(action === "accept" ? labels.bulkAcceptFailed : labels.bulkDismissFailed);
49
97
  } finally {
50
98
  setBulkPending(false);
51
99
  }
52
100
  };
53
- if (loading) return /* @__PURE__ */ jsx("div", { className: cx("uix-match-review uix-match-review--state", className), role: "status", children: "Loading match candidates\u2026" });
101
+ if (loading) return /* @__PURE__ */ jsx("div", { className: cx("uix-match-review uix-match-review--state", className), role: "status", children: labels.loading });
54
102
  if (error) return /* @__PURE__ */ jsxs("div", { className: cx("uix-match-review uix-match-review--state", className), role: "alert", children: [
55
103
  /* @__PURE__ */ jsx("p", { children: error }),
56
- onRetry && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: "Try again" })
104
+ onRetry && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--secondary", onClick: onRetry, children: labels.retry })
57
105
  ] });
58
106
  if (candidates.length === 0) return /* @__PURE__ */ jsxs("div", { className: cx("uix-match-review uix-match-review--state", className), children: [
59
- /* @__PURE__ */ jsx("p", { children: "No candidate matches found." }),
60
- /* @__PURE__ */ jsx("p", { children: "Choose another record source or continue without a match." })
107
+ /* @__PURE__ */ jsx("p", { children: labels.empty }),
108
+ /* @__PURE__ */ jsx("p", { children: labels.emptyDetail })
61
109
  ] });
62
- return /* @__PURE__ */ jsxs("section", { className: cx("uix-match-review", className), "aria-label": "Match review", children: [
110
+ return /* @__PURE__ */ jsxs("section", { className: cx("uix-match-review", className), "aria-label": labels.region, children: [
63
111
  /* @__PURE__ */ jsxs("div", { className: "uix-match-review__summary", children: [
64
112
  /* @__PURE__ */ jsxs("div", { children: [
65
113
  /* @__PURE__ */ jsx("strong", { children: incomingLabel }),
66
- /* @__PURE__ */ jsxs("span", { children: [
67
- pending.length,
68
- " pending of ",
69
- candidates.length
70
- ] })
114
+ /* @__PURE__ */ jsx("span", { children: fillLabel(labels.pendingOf, { pending: pending.length, total: candidates.length }) })
71
115
  ] }),
72
116
  /* @__PURE__ */ jsx("div", { className: "uix-match-review__incoming", children: fields.map((field) => /* @__PURE__ */ jsxs("span", { children: [
73
117
  /* @__PURE__ */ jsx("b", { children: field.label }),
74
118
  field.render?.(incoming[field.id], incoming) ?? valueText(incoming[field.id])
75
119
  ] }, field.id)) })
76
120
  ] }),
77
- onBulkDecision && /* @__PURE__ */ jsxs("div", { className: "uix-match-review__bulk", "aria-label": "Bulk candidate actions", children: [
78
- /* @__PURE__ */ jsxs("span", { children: [
79
- selection.size,
80
- " selected"
81
- ] }),
82
- /* @__PURE__ */ 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" }),
83
- /* @__PURE__ */ 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" })
121
+ onBulkDecision && /* @__PURE__ */ jsxs("div", { className: "uix-match-review__bulk", "aria-label": labels.bulk, children: [
122
+ /* @__PURE__ */ jsx("span", { children: fillLabel(labels.selectedCount, { count: selection.size }) }),
123
+ /* @__PURE__ */ 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 }),
124
+ /* @__PURE__ */ 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 })
84
125
  ] }),
85
126
  /* @__PURE__ */ jsx("div", { className: "uix-match-review__table-wrap", children: /* @__PURE__ */ jsxs("table", { className: "uix-table uix-match-review__table", children: [
86
- /* @__PURE__ */ jsx("caption", { className: "uix-visually-hidden", children: "Candidate matches and available decisions" }),
127
+ /* @__PURE__ */ jsx("caption", { className: "uix-visually-hidden", children: labels.caption }),
87
128
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
88
- /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: "Select" }) }),
89
- /* @__PURE__ */ jsx("th", { scope: "col", children: "Confidence" }),
129
+ /* @__PURE__ */ jsx("th", { scope: "col", children: /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: labels.select }) }),
130
+ /* @__PURE__ */ jsx("th", { scope: "col", children: labels.confidence }),
90
131
  fields.map((field) => /* @__PURE__ */ jsx("th", { scope: "col", children: field.label }, field.id)),
91
- /* @__PURE__ */ jsx("th", { scope: "col", children: "Status" }),
92
- /* @__PURE__ */ jsx("th", { scope: "col", children: "Actions" })
132
+ /* @__PURE__ */ jsx("th", { scope: "col", children: labels.status }),
133
+ /* @__PURE__ */ jsx("th", { scope: "col", children: labels.actions })
93
134
  ] }) }),
94
135
  /* @__PURE__ */ jsx("tbody", { children: candidates.map((candidate) => {
95
136
  const resolved = candidate.status === "resolved";
96
137
  return /* @__PURE__ */ jsxs("tr", { "data-status": candidate.status ?? "pending", children: [
97
- /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("input", { type: "checkbox", checked: selection.has(candidate.id), onChange: () => toggle(candidate.id), "aria-label": `Select candidate ${candidate.id}` }) }),
98
- /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("span", { className: "uix-match-review__confidence", children: candidate.confidence == null ? "Not scored" : `${Math.round(candidate.confidence * 100)}%` }) }),
138
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("input", { type: "checkbox", checked: selection.has(candidate.id), onChange: () => toggle(candidate.id), "aria-label": fillLabel(labels.selectCandidate, { id: candidate.id }) }) }),
139
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("span", { className: "uix-match-review__confidence", children: candidate.confidence == null ? labels.notScored : `${Math.round(candidate.confidence * 100)}%` }) }),
99
140
  fields.map((field) => /* @__PURE__ */ jsx("td", { children: field.render?.(candidate.record[field.id], candidate.record) ?? valueText(candidate.record[field.id]) }, field.id)),
100
- /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(StatusPill, { tone: resolved ? "success" : "warning", children: resolved ? candidate.decision ?? "Resolved" : "Pending" }) }),
141
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(StatusPill, { tone: resolved ? "success" : "warning", children: resolved ? candidate.decision ? decisionLabel[candidate.decision] : labels.resolved : labels.pending }) }),
101
142
  /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("div", { className: "uix-match-review__actions", children: ["accept", "dismiss", "split", "pick-other"].map((action) => /* @__PURE__ */ jsx(
102
143
  "button",
103
144
  {
@@ -105,7 +146,7 @@ function MatchReview({
105
146
  className: "uix-btn uix-btn--ghost uix-btn--sm",
106
147
  disabled: resolved,
107
148
  onClick: () => onDecision(candidate.id, action),
108
- children: action === "pick-other" ? "Pick other" : `${action[0].toUpperCase()}${action.slice(1)}`
149
+ children: actionLabel[action]
109
150
  },
110
151
  action
111
152
  )) }) })
@@ -116,5 +157,6 @@ function MatchReview({
116
157
  ] });
117
158
  }
118
159
  export {
160
+ DEFAULT_MATCH_REVIEW_LABELS,
119
161
  MatchReview
120
162
  };
@@ -10,8 +10,10 @@ interface MeterProps extends HTMLAttributes<HTMLDivElement> {
10
10
  tone?: MeterTone;
11
11
  /** Accessible name — rendered as `aria-label` (an explicit `aria-label` prop wins). */
12
12
  label?: string;
13
+ /** TENSOR RX-125 (UIX-04): the spoken tone words; English defaults. */
14
+ toneLabels?: Partial<Record<Exclude<MeterTone, 'success'>, string>>;
13
15
  }
14
16
  /** Horizontal utilization / threshold bar backed by `.uix-meter`. */
15
- declare function Meter({ value, tone, label, className, ...props }: MeterProps): react.JSX.Element;
17
+ declare function Meter({ value, tone, label, toneLabels, className, ...props }: MeterProps): react.JSX.Element;
16
18
 
17
19
  export { Meter, type MeterProps, type MeterTone };
@@ -6,7 +6,8 @@ const toneText = {
6
6
  attention: "needs attention",
7
7
  overdue: "overdue"
8
8
  };
9
- function Meter({ value = 0, tone, label, className, ...props }) {
9
+ function Meter({ value = 0, tone, label, toneLabels, className, ...props }) {
10
+ const spoken = { ...toneText, ...toneLabels };
10
11
  const pct = Math.max(0, Math.min(100, value));
11
12
  return /* @__PURE__ */ jsx(
12
13
  "div",
@@ -15,7 +16,7 @@ function Meter({ value = 0, tone, label, className, ...props }) {
15
16
  "aria-valuenow": pct,
16
17
  "aria-valuemin": 0,
17
18
  "aria-valuemax": 100,
18
- "aria-valuetext": tone && tone !== "success" ? `${pct}%, ${toneText[tone]}` : void 0,
19
+ "aria-valuetext": tone && tone !== "success" ? `${pct}%, ${spoken[tone]}` : void 0,
19
20
  "aria-label": label,
20
21
  className: cx("uix-meter", className),
21
22
  ...props,
@@ -1,11 +1,19 @@
1
1
  import * as react from 'react';
2
2
  import { HTMLAttributes } from 'react';
3
3
 
4
+ /** TENSOR RX-125 (UIX-04): the pager's accessible names. */
5
+ interface PaginationLabels {
6
+ region: string;
7
+ previous: string;
8
+ next: string;
9
+ }
10
+ declare const DEFAULT_PAGINATION_LABELS: PaginationLabels;
4
11
  interface PaginationProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
5
12
  page: number;
6
13
  pageCount: number;
7
14
  onChange: (page: number) => void;
15
+ labels?: Partial<PaginationLabels>;
8
16
  }
9
- declare function Pagination({ page, pageCount, onChange, className, ...props }: PaginationProps): react.JSX.Element;
17
+ declare function Pagination({ page, pageCount, onChange, labels: labelOverrides, className, ...props }: PaginationProps): react.JSX.Element;
10
18
 
11
- export { Pagination, type PaginationProps };
19
+ export { DEFAULT_PAGINATION_LABELS, Pagination, type PaginationLabels, type PaginationProps };
@@ -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
  };