@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.
- 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 +4 -2
- 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/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 +5 -0
- package/dist/components/Stat.js +2 -2
- package/dist/components/Table.d.ts +11 -3
- package/dist/components/Table.js +5 -8
- package/dist/components/Tabs.d.ts +8 -1
- package/dist/components/Tabs.js +4 -5
- 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/fill-label.d.ts +7 -0
- package/dist/fill-label.js +9 -0
- package/dist/index.cjs +765 -463
- package/dist/index.d.cts +341 -28
- package/dist/index.d.ts +10 -10
- package/dist/index.js +18 -9
- 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
|
-
|
|
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
|
};
|
|
@@ -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
|
-
|
|
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":
|
|
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:
|
|
78
|
-
/* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--ghost uix-btn--sm", onClick: () => movePeriod(1), disabled: !onAnchorDateChange, children:
|
|
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":
|
|
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:
|
|
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:
|
|
89
|
-
] }) : view === "agenda" ? /* @__PURE__ */ jsx("div", { className: "uix-scheduling-calendar__agenda", role: "region", "aria-label":
|
|
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":
|
|
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":
|
|
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":
|
|
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
|
}
|
package/dist/components/Stat.js
CHANGED
|
@@ -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
|
|
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). */
|