@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.
- package/README.md +14 -0
- package/dist/{ChartCore-Do6gRBN3.d.cts → ChartCore-DzWe10bN.d.cts} +16 -1
- package/dist/chart-preset.cjs +25 -13
- package/dist/chart-preset.d.cts +2 -2
- package/dist/chart-preset.d.ts +1 -1
- package/dist/chart-preset.js +2 -1
- package/dist/chart.cjs +25 -13
- package/dist/chart.d.cts +2 -2
- package/dist/chart.d.ts +1 -1
- package/dist/chart.js +2 -1
- package/dist/components/AppShell.d.ts +5 -1
- package/dist/components/AppShell.js +4 -2
- package/dist/components/Avatar.d.ts +3 -1
- package/dist/components/Avatar.js +2 -2
- package/dist/components/BrandProfiles.d.ts +29 -2
- package/dist/components/BrandProfiles.js +45 -20
- package/dist/components/BuilderCanvas.d.ts +27 -2
- package/dist/components/BuilderCanvas.js +45 -22
- package/dist/components/Chart.d.ts +1 -1
- package/dist/components/Chart.js +2 -1
- package/dist/components/ChartCore.d.ts +17 -2
- package/dist/components/ChartCore.js +24 -13
- package/dist/components/ColorPicker.d.ts +24 -2
- package/dist/components/ColorPicker.js +38 -20
- package/dist/components/CommandPalette.d.ts +3 -1
- package/dist/components/CommandPalette.js +2 -2
- package/dist/components/CopyButton.d.ts +25 -0
- package/dist/components/CopyButton.js +52 -0
- package/dist/components/DateRangePicker.d.ts +21 -2
- package/dist/components/DateRangePicker.js +26 -6
- package/dist/components/DetailPage.d.ts +22 -3
- package/dist/components/DetailPage.js +33 -3
- package/dist/components/DiffViewer.d.ts +34 -3
- package/dist/components/DiffViewer.js +60 -40
- package/dist/components/Drawer.d.ts +3 -1
- package/dist/components/Drawer.js +2 -2
- package/dist/components/Inbox.d.ts +3 -1
- package/dist/components/Inbox.js +2 -2
- package/dist/components/MatchReview.d.ts +49 -2
- package/dist/components/MatchReview.js +72 -30
- package/dist/components/Meter.d.ts +3 -1
- package/dist/components/Meter.js +3 -2
- package/dist/components/Pagination.d.ts +10 -2
- package/dist/components/Pagination.js +11 -4
- package/dist/components/Peek.d.ts +7 -1
- package/dist/components/Peek.js +4 -4
- package/dist/components/RelationshipGraph.js +6 -2
- package/dist/components/RuleBuilder.d.ts +42 -2
- package/dist/components/RuleBuilder.js +71 -37
- package/dist/components/SchedulingCalendar.d.ts +25 -2
- package/dist/components/SchedulingCalendar.js +38 -15
- package/dist/components/Stat.d.ts +24 -3
- package/dist/components/Stat.js +51 -10
- package/dist/components/Table.d.ts +11 -3
- package/dist/components/Table.js +5 -8
- package/dist/components/Tabs.d.ts +14 -1
- package/dist/components/Tabs.js +88 -19
- package/dist/components/Toast.d.ts +6 -2
- package/dist/components/Toast.js +4 -4
- package/dist/components/Tree.d.ts +9 -1
- package/dist/components/Tree.js +55 -8
- package/dist/copy-model.d.ts +12 -0
- package/dist/copy-model.js +12 -0
- package/dist/fill-label.d.ts +7 -0
- package/dist/fill-label.js +9 -0
- package/dist/index.cjs +1480 -1004
- package/dist/index.d.cts +387 -30
- package/dist/index.d.ts +11 -10
- package/dist/index.js +20 -9
- 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(
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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:
|
|
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:
|
|
60
|
-
/* @__PURE__ */ jsx("p", { children:
|
|
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":
|
|
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__ */
|
|
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":
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
|
|
80
|
-
|
|
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:
|
|
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:
|
|
89
|
-
/* @__PURE__ */ jsx("th", { scope: "col", children:
|
|
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:
|
|
92
|
-
/* @__PURE__ */ jsx("th", { scope: "col", children:
|
|
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":
|
|
98
|
-
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("span", { className: "uix-match-review__confidence", children: candidate.confidence == null ?
|
|
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
|
|
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
|
|
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 };
|
package/dist/components/Meter.js
CHANGED
|
@@ -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}%, ${
|
|
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
|
-
|
|
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":
|
|
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":
|
|
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":
|
|
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 };
|
package/dist/components/Peek.js
CHANGED
|
@@ -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":
|
|
25
|
-
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: () => onNavNext?.(), "aria-disabled": onNavNext ? void 0 : true, "aria-label":
|
|
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":
|
|
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 ?
|
|
62
|
+
/* @__PURE__ */ jsx("span", { children: depth === 1 ? labels.when : labels.group }),
|
|
31
63
|
/* @__PURE__ */ jsxs("label", { children: [
|
|
32
|
-
|
|
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:
|
|
35
|
-
/* @__PURE__ */ jsx("option", { value: "or", children:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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":
|
|
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":
|
|
85
|
-
/* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onDown, disabled: disabled || last, "aria-label":
|
|
86
|
-
/* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: onRemove, disabled, "aria-label":
|
|
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
|
|
100
|
-
addGroupLabel
|
|
101
|
-
addActionLabel
|
|
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":
|
|
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__ */
|
|
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":
|
|
119
|
-
/* @__PURE__ */ jsx(RuleGroupEditor, { group: value.when, depth: 1, root: value.when, fields, operators, maxDepth, disabled: readOnly, onRootChange: (when) => onChange({ ...value, when }), labels
|
|
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:
|
|
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":
|
|
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
|
-
|
|
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:
|
|
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:
|
|
152
|
-
/* @__PURE__ */
|
|
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
|
};
|