@tensor_1/react 2.47.0 → 2.49.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 +540 -2
- package/dist/{SchedulingCalendar-B6TakO2h.d.ts → SchedulingCalendar-WWyFL3Eo.d.ts} +51 -2
- package/dist/announce.d.ts +10 -0
- package/dist/announce.js +30 -0
- package/dist/chart-analytic.cjs +33 -25
- package/dist/chart-preset.cjs +23 -15
- package/dist/chart.cjs +23 -15
- package/dist/combobox-model.d.ts +10 -1
- package/dist/combobox-model.js +15 -0
- package/dist/command-palette-model.d.ts +44 -0
- package/dist/command-palette-model.js +36 -0
- package/dist/components/AccountMenu.d.ts +44 -0
- package/dist/components/AccountMenu.js +43 -0
- package/dist/components/AppShell.d.ts +45 -2
- package/dist/components/AppShell.js +116 -5
- package/dist/components/AuditLog.d.ts +128 -0
- package/dist/components/AuditLog.js +196 -0
- package/dist/components/BrandProfiles.js +4 -3
- package/dist/components/Breadcrumbs.d.ts +9 -2
- package/dist/components/Breadcrumbs.js +3 -2
- package/dist/components/Button.d.ts +12 -5
- package/dist/components/Button.js +7 -3
- package/dist/components/Card.d.ts +18 -1
- package/dist/components/Card.js +5 -1
- package/dist/components/ChangeHighlight.d.ts +30 -0
- package/dist/components/ChangeHighlight.js +21 -0
- package/dist/components/ChartCore.js +2 -1
- package/dist/components/Checkbox.d.ts +27 -1
- package/dist/components/Checkbox.js +31 -2
- package/dist/components/Chip.d.ts +7 -3
- package/dist/components/Chip.js +2 -2
- package/dist/components/CodeDisplay.d.ts +65 -0
- package/dist/components/CodeDisplay.js +124 -0
- package/dist/components/Combobox.d.ts +27 -6
- package/dist/components/Combobox.js +195 -58
- package/dist/components/CommandPalette.d.ts +36 -1
- package/dist/components/CommandPalette.js +254 -2
- package/dist/components/ContactCard.d.ts +66 -0
- package/dist/components/ContactCard.js +74 -0
- package/dist/components/Count.d.ts +24 -0
- package/dist/components/Count.js +32 -0
- package/dist/components/DashboardCanvas.js +14 -0
- package/dist/components/DataWorkspace.d.ts +167 -0
- package/dist/components/DataWorkspace.js +380 -0
- package/dist/components/DateFieldParts.d.ts +2 -1
- package/dist/components/DateFieldParts.js +7 -0
- package/dist/components/DatePicker.d.ts +9 -2
- package/dist/components/DatePicker.js +67 -28
- package/dist/components/DateRangePicker.d.ts +12 -2
- package/dist/components/DateRangePicker.js +13 -12
- package/dist/components/DetailPage.d.ts +7 -1
- package/dist/components/DetailPage.js +2 -1
- package/dist/components/Dialogs.d.ts +71 -10
- package/dist/components/Dialogs.js +130 -30
- package/dist/components/DiffViewer.d.ts +23 -3
- package/dist/components/DiffViewer.js +26 -12
- package/dist/components/DiscardPrompt.js +16 -0
- package/dist/components/DisplayPreferences.d.ts +83 -0
- package/dist/components/DisplayPreferences.js +185 -0
- package/dist/components/EditorialHome.d.ts +23 -3
- package/dist/components/EditorialHome.js +16 -11
- package/dist/components/EntityPicker.d.ts +20 -3
- package/dist/components/EntityPicker.js +32 -13
- package/dist/components/FilterEditor.d.ts +18 -4
- package/dist/components/FilterEditor.js +141 -19
- package/dist/components/FocusOnMount.d.ts +282 -0
- package/dist/components/FocusOnMount.js +12 -0
- package/dist/components/InfoTip.js +11 -12
- package/dist/components/InlineEdit.d.ts +87 -20
- package/dist/components/InlineEdit.js +197 -54
- package/dist/components/Input.d.ts +12 -2
- package/dist/components/Input.js +5 -3
- package/dist/components/Kanban.d.ts +14 -3
- package/dist/components/Kanban.js +9 -4
- package/dist/components/Kbd.d.ts +6 -1
- package/dist/components/Kbd.js +6 -6
- package/dist/components/Lightbox.d.ts +41 -5
- package/dist/components/Lightbox.js +95 -9
- package/dist/components/MatchReview.d.ts +40 -1
- package/dist/components/MatchReview.js +130 -4
- package/dist/components/MetricInput.js +3 -2
- package/dist/components/Modal.d.ts +2 -1
- package/dist/components/Modal.js +13 -4
- package/dist/components/MotionList.d.ts +303 -0
- package/dist/components/MotionList.js +175 -0
- package/dist/components/NavFavourites.d.ts +5 -0
- package/dist/components/NavFavourites.js +7 -7
- package/dist/components/OtpInput.d.ts +33 -0
- package/dist/components/OtpInput.js +123 -0
- package/dist/components/PageHeader.d.ts +7 -1
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/Pagination.js +6 -5
- package/dist/components/PasswordInput.d.ts +34 -0
- package/dist/components/PasswordInput.js +101 -0
- package/dist/components/Peek.js +3 -3
- package/dist/components/Popover.js +11 -0
- package/dist/components/PrintLayout.d.ts +63 -0
- package/dist/components/PrintLayout.js +114 -0
- package/dist/components/QrCode.d.ts +47 -0
- package/dist/components/QrCode.js +55 -0
- package/dist/components/QrScanner.d.ts +95 -0
- package/dist/components/QrScanner.js +266 -0
- package/dist/components/RelationshipGraph.d.ts +32 -1
- package/dist/components/RelationshipGraph.js +22 -6
- package/dist/components/RelationshipGraphLayered.d.ts +1 -1
- package/dist/components/RelationshipGraphLayered.js +268 -118
- package/dist/components/RelationshipGraphList.js +33 -6
- package/dist/components/RuleBuilder.js +39 -7
- package/dist/components/SchedulingAgenda.d.ts +3 -1
- package/dist/components/SchedulingCalendar.d.ts +3 -1
- package/dist/components/SchedulingCalendar.js +43 -4
- package/dist/components/SchedulingResourceDay.d.ts +57 -0
- package/dist/components/SchedulingResourceDay.js +287 -0
- package/dist/components/SchedulingTimeGrid.d.ts +3 -1
- package/dist/components/SchedulingTimeline.d.ts +3 -1
- package/dist/components/SearchSuggest.d.ts +23 -3
- package/dist/components/SearchSuggest.js +56 -18
- package/dist/components/Segmented.d.ts +39 -4
- package/dist/components/Segmented.js +39 -5
- package/dist/components/Select.d.ts +3 -2
- package/dist/components/Select.js +7 -1
- package/dist/components/ShortcutHint.d.ts +11 -10
- package/dist/components/ShortcutHint.js +44 -38
- package/dist/components/Sidebar.d.ts +36 -4
- package/dist/components/Sidebar.js +37 -12
- package/dist/components/SortableList.d.ts +45 -0
- package/dist/components/SortableList.js +147 -0
- package/dist/components/Stat.d.ts +28 -3
- package/dist/components/Stat.js +13 -3
- package/dist/components/States.d.ts +33 -1
- package/dist/components/States.js +43 -1
- package/dist/components/StatusPill.d.ts +14 -3
- package/dist/components/StatusPill.js +11 -3
- package/dist/components/Steps.js +2 -1
- package/dist/components/Table.d.ts +9 -2
- package/dist/components/Table.js +4 -2
- package/dist/components/TableControls.js +18 -58
- package/dist/components/TableOverflowProbe.d.ts +12 -0
- package/dist/components/TableOverflowProbe.js +27 -0
- package/dist/components/Tabs.d.ts +2 -1
- package/dist/components/Tabs.js +10 -2
- package/dist/components/TagInput.d.ts +67 -0
- package/dist/components/TagInput.js +342 -0
- package/dist/components/Textarea.d.ts +5 -0
- package/dist/components/Textarea.js +2 -2
- package/dist/components/TimePicker.d.ts +80 -0
- package/dist/components/TimePicker.js +347 -0
- package/dist/components/Toast.d.ts +1 -1
- package/dist/components/Toast.js +109 -4
- package/dist/components/Tooltip.d.ts +8 -4
- package/dist/components/Tooltip.js +86 -28
- package/dist/components/Tree.d.ts +8 -0
- package/dist/components/Tree.js +11 -5
- package/dist/display-preferences-model.d.ts +53 -0
- package/dist/display-preferences-model.js +64 -0
- package/dist/emoji.cjs +143 -49
- package/dist/filter-model.d.ts +59 -3
- package/dist/filter-model.js +67 -2
- package/dist/hooks/useAnchoredPosition.js +14 -2
- package/dist/hooks/useChangeHighlight.d.ts +33 -0
- package/dist/hooks/useChangeHighlight.js +44 -0
- package/dist/hooks/useDeferredReorder.d.ts +32 -0
- package/dist/hooks/useDeferredReorder.js +47 -0
- package/dist/hooks/useDialog.d.ts +5 -0
- package/dist/hooks/useDialog.js +17 -3
- package/dist/hooks/useKeyboardGrab.d.ts +58 -0
- package/dist/hooks/useKeyboardGrab.js +118 -0
- package/dist/hooks/useOptimisticValue.d.ts +51 -0
- package/dist/hooks/useOptimisticValue.js +61 -0
- package/dist/hooks/useReducedMotion.d.ts +4 -1
- package/dist/hooks/useReducedMotion.js +7 -1
- package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
- package/dist/hooks/useResolvedFilterLabels.js +34 -0
- package/dist/hooks/useSlidingIndicator.d.ts +18 -0
- package/dist/hooks/useSlidingIndicator.js +80 -0
- package/dist/hooks/useVirtualRows.d.ts +21 -2
- package/dist/hooks/useVirtualRows.js +30 -3
- package/dist/icons/Icon.d.ts +1 -1
- package/dist/index.cjs +19687 -13423
- package/dist/index.d.cts +3419 -651
- package/dist/index.d.ts +48 -18
- package/dist/index.js +153 -9
- package/dist/labels-context.d.ts +93 -3
- package/dist/motion.d.ts +11 -0
- package/dist/motion.js +35 -0
- package/dist/overlay-stack.d.ts +6 -0
- package/dist/overlay-stack.js +13 -0
- package/dist/qr-model.d.ts +65 -0
- package/dist/qr-model.js +323 -0
- package/dist/relationship-graph-model.d.ts +92 -3
- package/dist/relationship-graph-model.js +134 -15
- package/dist/reorder.d.ts +30 -0
- package/dist/reorder.js +74 -0
- package/dist/rich-text.cjs +46 -4
- package/dist/scheduling-resource-model.d.ts +76 -0
- package/dist/scheduling-resource-model.js +74 -0
- package/dist/search-suggest-model.js +3 -1
- package/dist/shell-context.d.ts +11 -0
- package/dist/shell-context.js +7 -0
- package/dist/time-field-model.d.ts +46 -0
- package/dist/time-field-model.js +152 -0
- package/dist/toast-store.d.ts +22 -3
- package/dist/toast-store.js +26 -9
- package/package.json +2 -1
|
@@ -1,63 +1,121 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { cloneElement, isValidElement, useEffect, useId, useRef, useState } from "react";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cloneElement, isValidElement, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
import { useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
6
|
-
import { KbdCombo,
|
|
6
|
+
import { KbdCombo, isKeyShortcut, spokenKeys, useKbdPlatform } from "./Kbd.js";
|
|
7
|
+
import { markKeyOpened, tokenMs, watchInputModality } from "../motion.js";
|
|
8
|
+
const group = { open: 0, lastClosed: -Infinity, current: null };
|
|
9
|
+
const useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
|
|
7
10
|
function Tooltip({ label, content, placement = "top", shortcut, className, children, ...props }) {
|
|
8
11
|
const triggerRef = useRef(null);
|
|
9
12
|
const bubbleRef = useRef(null);
|
|
10
13
|
const closeTimer = useRef(null);
|
|
14
|
+
const openTimer = useRef(null);
|
|
15
|
+
const shown = useRef(false);
|
|
11
16
|
const [open, setOpen] = useState(false);
|
|
12
17
|
const id = useId();
|
|
13
18
|
const platform = useKbdPlatform();
|
|
14
19
|
const childShortcut = isValidElement(children) ? children.props.shortcut : void 0;
|
|
15
20
|
const own = shortcut ?? (isKeyShortcut(childShortcut) ? childShortcut : void 0);
|
|
16
21
|
const keys = own && own.length > 0 ? own : null;
|
|
17
|
-
const keyshortcuts = keys ? ariaKeyShortcuts(keys, platform) : void 0;
|
|
18
22
|
useAnchoredPosition(triggerRef, bubbleRef, { open, placement, offset: 6 });
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
watchInputModality();
|
|
25
|
+
}, []);
|
|
19
26
|
const cancelClose = () => {
|
|
20
27
|
if (closeTimer.current != null) {
|
|
21
28
|
clearTimeout(closeTimer.current);
|
|
22
29
|
closeTimer.current = null;
|
|
23
30
|
}
|
|
24
31
|
};
|
|
25
|
-
const
|
|
26
|
-
|
|
32
|
+
const cancelOpen = () => {
|
|
33
|
+
if (openTimer.current != null) {
|
|
34
|
+
clearTimeout(openTimer.current);
|
|
35
|
+
openTimer.current = null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const reveal = (instant) => {
|
|
39
|
+
cancelOpen();
|
|
40
|
+
if (group.current && group.current !== self) group.current.current(true);
|
|
41
|
+
group.current = self;
|
|
27
42
|
const b = bubbleRef.current;
|
|
28
43
|
if (b && !b.matches(":popover-open")) {
|
|
44
|
+
b.toggleAttribute("data-uix-instant", instant);
|
|
45
|
+
markKeyOpened(b);
|
|
29
46
|
try {
|
|
30
47
|
b.showPopover();
|
|
31
48
|
} catch {
|
|
32
49
|
}
|
|
33
50
|
}
|
|
51
|
+
if (!shown.current) {
|
|
52
|
+
shown.current = true;
|
|
53
|
+
group.open += 1;
|
|
54
|
+
}
|
|
34
55
|
setOpen(true);
|
|
35
56
|
};
|
|
36
|
-
const
|
|
57
|
+
const show = (via) => {
|
|
58
|
+
cancelClose();
|
|
59
|
+
if (shown.current) return;
|
|
60
|
+
const warm = group.open > 0 || performance.now() - group.lastClosed < tokenMs("--uix-delay-tooltip-skip", 300);
|
|
61
|
+
if (via === "focus" || warm) {
|
|
62
|
+
reveal(via === "pointer");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (openTimer.current == null) openTimer.current = window.setTimeout(() => reveal(false), tokenMs("--uix-delay-tooltip", 400));
|
|
66
|
+
};
|
|
67
|
+
const hide = (instant = false) => {
|
|
37
68
|
cancelClose();
|
|
69
|
+
cancelOpen();
|
|
38
70
|
const b = bubbleRef.current;
|
|
39
71
|
if (b && b.matches(":popover-open")) {
|
|
72
|
+
b.toggleAttribute("data-uix-instant", instant);
|
|
40
73
|
try {
|
|
41
74
|
b.hidePopover();
|
|
42
75
|
} catch {
|
|
43
76
|
}
|
|
44
77
|
}
|
|
78
|
+
if (shown.current) {
|
|
79
|
+
shown.current = false;
|
|
80
|
+
group.open -= 1;
|
|
81
|
+
group.lastClosed = performance.now();
|
|
82
|
+
}
|
|
83
|
+
if (group.current === self) group.current = null;
|
|
45
84
|
setOpen(false);
|
|
46
85
|
};
|
|
86
|
+
const self = useRef(hide);
|
|
87
|
+
self.current = hide;
|
|
47
88
|
const scheduleHide = () => {
|
|
48
89
|
cancelClose();
|
|
49
|
-
closeTimer.current = window.setTimeout(
|
|
90
|
+
closeTimer.current = window.setTimeout(() => {
|
|
91
|
+
closeTimer.current = null;
|
|
92
|
+
try {
|
|
93
|
+
if (triggerRef.current?.matches(":hover")) return;
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
hide();
|
|
97
|
+
}, 100);
|
|
50
98
|
};
|
|
51
|
-
|
|
52
|
-
if (!open) return;
|
|
99
|
+
useIsomorphicLayoutEffect(() => {
|
|
100
|
+
if (!open) return void 0;
|
|
53
101
|
const onKey = (e) => {
|
|
54
|
-
if (e.key
|
|
102
|
+
if (e.key !== "Escape") return;
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
e.stopPropagation();
|
|
105
|
+
hide();
|
|
55
106
|
};
|
|
56
|
-
document.addEventListener("keydown", onKey);
|
|
57
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
107
|
+
document.addEventListener("keydown", onKey, true);
|
|
108
|
+
return () => document.removeEventListener("keydown", onKey, true);
|
|
58
109
|
}, [open]);
|
|
59
110
|
useEffect(() => () => {
|
|
60
111
|
if (closeTimer.current != null) clearTimeout(closeTimer.current);
|
|
112
|
+
if (openTimer.current != null) clearTimeout(openTimer.current);
|
|
113
|
+
if (shown.current) {
|
|
114
|
+
shown.current = false;
|
|
115
|
+
group.open -= 1;
|
|
116
|
+
group.lastClosed = performance.now();
|
|
117
|
+
}
|
|
118
|
+
if (group.current === self) group.current = null;
|
|
61
119
|
const b = bubbleRef.current;
|
|
62
120
|
if (b && b.matches(":popover-open")) {
|
|
63
121
|
try {
|
|
@@ -67,30 +125,27 @@ function Tooltip({ label, content, placement = "top", shortcut, className, child
|
|
|
67
125
|
}
|
|
68
126
|
}, []);
|
|
69
127
|
const bubbleAttr = { popover: "manual" };
|
|
128
|
+
const text = content ?? label;
|
|
129
|
+
const description = keys ? [text != null ? `${id}-text` : null, `${id}-keys`].filter(Boolean).join(" ") : id;
|
|
70
130
|
const single = isValidElement(children);
|
|
71
131
|
const child = single ? cloneElement(children, {
|
|
72
|
-
"aria-describedby": [children.props["aria-describedby"],
|
|
73
|
-
...keyshortcuts ? { "aria-keyshortcuts": keyshortcuts } : {}
|
|
132
|
+
"aria-describedby": [children.props["aria-describedby"], description].filter(Boolean).join(" ")
|
|
74
133
|
}) : children;
|
|
75
134
|
return /* @__PURE__ */ jsxs(
|
|
76
135
|
"span",
|
|
77
136
|
{
|
|
78
137
|
ref: triggerRef,
|
|
79
138
|
className: cx("uix-tooltip", className),
|
|
80
|
-
"aria-describedby": single ? void 0 :
|
|
81
|
-
"aria-keyshortcuts": single ? void 0 : keyshortcuts,
|
|
139
|
+
"aria-describedby": single ? void 0 : description,
|
|
82
140
|
tabIndex: single ? void 0 : 0,
|
|
83
|
-
onMouseEnter: show,
|
|
141
|
+
onMouseEnter: () => show("pointer"),
|
|
84
142
|
onMouseLeave: scheduleHide,
|
|
85
|
-
onFocus: show,
|
|
86
|
-
onBlur: hide,
|
|
87
|
-
onKeyDown: (e) => {
|
|
88
|
-
if (e.key === "Escape") hide();
|
|
89
|
-
},
|
|
143
|
+
onFocus: () => show("focus"),
|
|
144
|
+
onBlur: () => hide(),
|
|
90
145
|
...props,
|
|
91
146
|
children: [
|
|
92
147
|
child,
|
|
93
|
-
/* @__PURE__ */
|
|
148
|
+
/* @__PURE__ */ jsx(
|
|
94
149
|
"span",
|
|
95
150
|
{
|
|
96
151
|
ref: bubbleRef,
|
|
@@ -100,10 +155,13 @@ function Tooltip({ label, content, placement = "top", shortcut, className, child
|
|
|
100
155
|
onMouseEnter: cancelClose,
|
|
101
156
|
onMouseLeave: scheduleHide,
|
|
102
157
|
...bubbleAttr,
|
|
103
|
-
children: [
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
158
|
+
children: keys ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
159
|
+
text != null && /* @__PURE__ */ jsx("span", { id: `${id}-text`, children: text }),
|
|
160
|
+
/* @__PURE__ */ jsxs("span", { className: "uix-tooltip__shortcut", children: [
|
|
161
|
+
/* @__PURE__ */ jsx("span", { id: `${id}-keys`, className: "uix-visually-hidden", children: spokenKeys(keys, platform) }),
|
|
162
|
+
/* @__PURE__ */ jsx(KbdCombo, { keys: [...keys], platform, "aria-hidden": "true" })
|
|
163
|
+
] })
|
|
164
|
+
] }) : text
|
|
107
165
|
}
|
|
108
166
|
)
|
|
109
167
|
]
|
|
@@ -6,6 +6,12 @@ interface TreeNodeData {
|
|
|
6
6
|
label: ReactNode;
|
|
7
7
|
/** Plain-text label for keyboard typeahead when `label` is not a string (UIX-A11Y-2). */
|
|
8
8
|
typeaheadLabel?: string;
|
|
9
|
+
/**
|
|
10
|
+
* The row's accessible name when `label` is rich (an avatar, a name and a meta line) and only
|
|
11
|
+
* part of it should be spoken, e.g. the person's name (HAR-1828). By default a row is named by
|
|
12
|
+
* its own `label`, never by its children.
|
|
13
|
+
*/
|
|
14
|
+
ariaLabel?: string;
|
|
9
15
|
icon?: ReactNode;
|
|
10
16
|
children?: TreeNodeData[];
|
|
11
17
|
/**
|
|
@@ -39,6 +45,8 @@ interface TreeNodeProps {
|
|
|
39
45
|
rowToggles?: boolean;
|
|
40
46
|
/** Ids of nodes whose children are loading (`aria-busy`). */
|
|
41
47
|
busy?: ReadonlySet<string>;
|
|
48
|
+
/** Scopes the ids that name each row by its own label (HAR-1828). Set by `Tree`. */
|
|
49
|
+
treeId?: string;
|
|
42
50
|
}
|
|
43
51
|
interface TreeProps extends Omit<HTMLAttributes<HTMLUListElement>, 'onSelect' | 'onChange'> {
|
|
44
52
|
nodes: TreeNodeData[];
|
package/dist/components/Tree.js
CHANGED
|
@@ -15,13 +15,16 @@ const LOADING = "::uix-loading";
|
|
|
15
15
|
const FAILED = "::uix-error";
|
|
16
16
|
const syntheticOf = (id) => id.endsWith(LOADING) ? { parent: id.slice(0, -LOADING.length), kind: "loading" } : id.endsWith(FAILED) ? { parent: id.slice(0, -FAILED.length), kind: "error" } : null;
|
|
17
17
|
const Ring = () => /* @__PURE__ */ jsx("span", { className: "uix-spinner uix-spinner--sm", "aria-hidden": "true" });
|
|
18
|
-
|
|
18
|
+
const labelId = (treeId, nodeId) => `${treeId}-label-${encodeURIComponent(nodeId)}`;
|
|
19
|
+
const rowName = (treeId, node) => node.ariaLabel ? { "aria-label": node.ariaLabel } : { "aria-labelledby": labelId(treeId, node.id) };
|
|
20
|
+
function TreeNode({ node, expanded, selected, selectable, tabbableId, onToggle, onSelect, onFocusNode, level = 1, rowToggles = true, busy, treeId = "uix-tree" }) {
|
|
19
21
|
const hasChildren = Array.isArray(node.children) && node.children.length > 0;
|
|
20
22
|
const isExpanded = expanded.has(node.id);
|
|
21
23
|
return /* @__PURE__ */ jsxs(
|
|
22
24
|
"li",
|
|
23
25
|
{
|
|
24
26
|
role: "treeitem",
|
|
27
|
+
...rowName(treeId, node),
|
|
25
28
|
"aria-level": level,
|
|
26
29
|
"aria-expanded": hasChildren ? isExpanded : void 0,
|
|
27
30
|
"aria-selected": selectable && !syntheticOf(node.id) ? selected === node.id : void 0,
|
|
@@ -61,7 +64,7 @@ function TreeNode({ node, expanded, selected, selectable, tabbableId, onToggle,
|
|
|
61
64
|
)
|
|
62
65
|
) : /* @__PURE__ */ jsx("span", { className: "uix-tree__toggle" }),
|
|
63
66
|
node.icon && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: node.icon }),
|
|
64
|
-
/* @__PURE__ */ jsx("span", { className: "uix-tree__label", children: node.label })
|
|
67
|
+
/* @__PURE__ */ jsx("span", { id: labelId(treeId, node.id), className: "uix-tree__label", children: node.label })
|
|
65
68
|
] }),
|
|
66
69
|
hasChildren && isExpanded && /* @__PURE__ */ jsx("ul", { role: "group", className: "uix-tree__group", children: node.children.map((child) => /* @__PURE__ */ jsx(
|
|
67
70
|
TreeNode,
|
|
@@ -76,7 +79,8 @@ function TreeNode({ node, expanded, selected, selectable, tabbableId, onToggle,
|
|
|
76
79
|
onFocusNode,
|
|
77
80
|
level: level + 1,
|
|
78
81
|
rowToggles,
|
|
79
|
-
busy
|
|
82
|
+
busy,
|
|
83
|
+
treeId
|
|
80
84
|
},
|
|
81
85
|
child.id
|
|
82
86
|
)) })
|
|
@@ -317,7 +321,8 @@ function Tree({
|
|
|
317
321
|
onFocusNode: setFocusedId,
|
|
318
322
|
level: 1,
|
|
319
323
|
rowToggles,
|
|
320
|
-
busy: loading
|
|
324
|
+
busy: loading,
|
|
325
|
+
treeId
|
|
321
326
|
},
|
|
322
327
|
node.id
|
|
323
328
|
)) });
|
|
@@ -418,6 +423,7 @@ function VirtualTreeView({
|
|
|
418
423
|
"li",
|
|
419
424
|
{
|
|
420
425
|
role: "treeitem",
|
|
426
|
+
...rowName(treeId, f.node),
|
|
421
427
|
"aria-level": f.level,
|
|
422
428
|
"aria-setsize": f.setsize,
|
|
423
429
|
"aria-posinset": f.posinset,
|
|
@@ -458,7 +464,7 @@ function VirtualTreeView({
|
|
|
458
464
|
)
|
|
459
465
|
) : /* @__PURE__ */ jsx("span", { className: "uix-tree__toggle" }),
|
|
460
466
|
f.node.icon && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: f.node.icon }),
|
|
461
|
-
/* @__PURE__ */ jsx("span", { className: "uix-tree__label", children: f.node.label })
|
|
467
|
+
/* @__PURE__ */ jsx("span", { id: labelId(treeId, f.node.id), className: "uix-tree__label", children: f.node.label })
|
|
462
468
|
] })
|
|
463
469
|
},
|
|
464
470
|
f.node.id
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
type ThemePreference = 'light' | 'dark' | 'system';
|
|
2
|
+
type ContrastPreference = 'standard' | 'more' | 'system';
|
|
3
|
+
type TextScalePreference = 'sm' | 'md' | 'lg' | 'xl';
|
|
4
|
+
type MotionPreference = 'system' | 'reduce';
|
|
5
|
+
type DensityPreference = 'compact' | 'standard' | 'comfortable';
|
|
6
|
+
interface DisplayPreferenceValues {
|
|
7
|
+
theme: ThemePreference;
|
|
8
|
+
contrast: ContrastPreference;
|
|
9
|
+
textScale: TextScalePreference;
|
|
10
|
+
motion: MotionPreference;
|
|
11
|
+
density: DensityPreference;
|
|
12
|
+
}
|
|
13
|
+
/** What the system says, for the `system` choices. */
|
|
14
|
+
interface SystemDisplayPreferences {
|
|
15
|
+
dark: boolean;
|
|
16
|
+
moreContrast: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** The attributes written on <html>; `undefined` means the attribute is removed. */
|
|
19
|
+
interface DisplayAttributes {
|
|
20
|
+
'data-theme': 'light' | 'dark';
|
|
21
|
+
'data-contrast'?: 'more';
|
|
22
|
+
'data-text-scale'?: 'sm' | 'lg' | 'xl';
|
|
23
|
+
'data-motion'?: 'reduce';
|
|
24
|
+
'data-density'?: 'compact' | 'comfortable';
|
|
25
|
+
}
|
|
26
|
+
declare const DEFAULT_DISPLAY_PREFERENCES: DisplayPreferenceValues;
|
|
27
|
+
/** The default `localStorage` key. */
|
|
28
|
+
declare const DISPLAY_PREFERENCES_STORAGE_KEY = "uix-display-preferences";
|
|
29
|
+
declare const DISPLAY_PREFERENCE_OPTIONS: {
|
|
30
|
+
readonly theme: readonly ["light", "dark", "system"];
|
|
31
|
+
readonly contrast: readonly ["standard", "more", "system"];
|
|
32
|
+
readonly textScale: readonly ["sm", "md", "lg", "xl"];
|
|
33
|
+
readonly motion: readonly ["system", "reduce"];
|
|
34
|
+
readonly density: readonly ["compact", "standard", "comfortable"];
|
|
35
|
+
};
|
|
36
|
+
/** Read stored preferences; anything missing or unknown falls back to `defaults`. */
|
|
37
|
+
declare function parseDisplayPreferences(raw: string | null | undefined, defaults?: DisplayPreferenceValues): DisplayPreferenceValues;
|
|
38
|
+
/** The <html> attributes for a set of preferences, resolving `system` against the system. */
|
|
39
|
+
declare function resolveDisplayAttributes(prefs: DisplayPreferenceValues, system: SystemDisplayPreferences): DisplayAttributes;
|
|
40
|
+
/** Write (or remove) the attributes on an element, normally `document.documentElement`. */
|
|
41
|
+
declare function applyDisplayAttributes(root: Element, attributes: DisplayAttributes): void;
|
|
42
|
+
/** The system's answers from `matchMedia`; all false where there is none (SSR, tests). */
|
|
43
|
+
declare function readSystemDisplayPreferences(): SystemDisplayPreferences;
|
|
44
|
+
/**
|
|
45
|
+
* An inline script for the document head that applies the stored preferences before the first
|
|
46
|
+
* paint, so a dark or large-text page never flashes light or small (HAR-1372). Self-contained ES5;
|
|
47
|
+
* it never throws. Put it in a `<script>` before the stylesheets:
|
|
48
|
+
* <script dangerouslySetInnerHTML={{ __html: displayPreferencesScript() }} />
|
|
49
|
+
* It mirrors parseDisplayPreferences + resolveDisplayAttributes (tested to agree).
|
|
50
|
+
*/
|
|
51
|
+
declare function displayPreferencesScript(storageKey?: string, defaults?: DisplayPreferenceValues): string;
|
|
52
|
+
|
|
53
|
+
export { type ContrastPreference, DEFAULT_DISPLAY_PREFERENCES, DISPLAY_PREFERENCES_STORAGE_KEY, DISPLAY_PREFERENCE_OPTIONS, type DensityPreference, type DisplayAttributes, type DisplayPreferenceValues, type MotionPreference, type SystemDisplayPreferences, type TextScalePreference, type ThemePreference, applyDisplayAttributes, displayPreferencesScript, parseDisplayPreferences, readSystemDisplayPreferences, resolveDisplayAttributes };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const DEFAULT_DISPLAY_PREFERENCES = {
|
|
2
|
+
theme: "system",
|
|
3
|
+
contrast: "system",
|
|
4
|
+
textScale: "md",
|
|
5
|
+
motion: "system",
|
|
6
|
+
density: "standard"
|
|
7
|
+
};
|
|
8
|
+
const DISPLAY_PREFERENCES_STORAGE_KEY = "uix-display-preferences";
|
|
9
|
+
const DISPLAY_PREFERENCE_OPTIONS = {
|
|
10
|
+
theme: ["light", "dark", "system"],
|
|
11
|
+
contrast: ["standard", "more", "system"],
|
|
12
|
+
textScale: ["sm", "md", "lg", "xl"],
|
|
13
|
+
motion: ["system", "reduce"],
|
|
14
|
+
density: ["compact", "standard", "comfortable"]
|
|
15
|
+
};
|
|
16
|
+
function parseDisplayPreferences(raw, defaults = DEFAULT_DISPLAY_PREFERENCES) {
|
|
17
|
+
let stored = {};
|
|
18
|
+
try {
|
|
19
|
+
stored = raw ? JSON.parse(raw) ?? {} : {};
|
|
20
|
+
} catch {
|
|
21
|
+
stored = {};
|
|
22
|
+
}
|
|
23
|
+
if (typeof stored !== "object") stored = {};
|
|
24
|
+
const pick = (key) => {
|
|
25
|
+
const value = stored[key];
|
|
26
|
+
return DISPLAY_PREFERENCE_OPTIONS[key].includes(value) ? value : defaults[key];
|
|
27
|
+
};
|
|
28
|
+
return { theme: pick("theme"), contrast: pick("contrast"), textScale: pick("textScale"), motion: pick("motion"), density: pick("density") };
|
|
29
|
+
}
|
|
30
|
+
function resolveDisplayAttributes(prefs, system) {
|
|
31
|
+
const theme = prefs.theme === "system" ? system.dark ? "dark" : "light" : prefs.theme;
|
|
32
|
+
const more = prefs.contrast === "more" || prefs.contrast === "system" && system.moreContrast;
|
|
33
|
+
return {
|
|
34
|
+
"data-theme": theme,
|
|
35
|
+
"data-contrast": more ? "more" : void 0,
|
|
36
|
+
"data-text-scale": prefs.textScale === "md" ? void 0 : prefs.textScale,
|
|
37
|
+
"data-motion": prefs.motion === "reduce" ? "reduce" : void 0,
|
|
38
|
+
"data-density": prefs.density === "standard" ? void 0 : prefs.density
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function applyDisplayAttributes(root, attributes) {
|
|
42
|
+
for (const name of ["data-theme", "data-contrast", "data-text-scale", "data-motion", "data-density"]) {
|
|
43
|
+
const value = attributes[name];
|
|
44
|
+
if (value == null) root.removeAttribute(name);
|
|
45
|
+
else if (root.getAttribute(name) !== value) root.setAttribute(name, value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function readSystemDisplayPreferences() {
|
|
49
|
+
const mm = (query) => typeof matchMedia === "function" && matchMedia(query).matches;
|
|
50
|
+
return { dark: mm("(prefers-color-scheme: dark)"), moreContrast: mm("(prefers-contrast: more)") };
|
|
51
|
+
}
|
|
52
|
+
function displayPreferencesScript(storageKey = DISPLAY_PREFERENCES_STORAGE_KEY, defaults = DEFAULT_DISPLAY_PREFERENCES) {
|
|
53
|
+
return `(function(){try{var d=document.documentElement,p={};try{p=JSON.parse(localStorage.getItem(${JSON.stringify(storageKey)})||'{}')||{}}catch(e){}if(typeof p!=='object')p={};var D=${JSON.stringify(defaults)},O=${JSON.stringify(DISPLAY_PREFERENCE_OPTIONS)};for(var k in O)if(O[k].indexOf(p[k])<0)p[k]=D[k];var m=function(q){return !!(window.matchMedia&&window.matchMedia(q).matches)};var s=function(n,v){if(v)d.setAttribute(n,v);else d.removeAttribute(n)};s('data-theme',p.theme==='light'||p.theme==='dark'?p.theme:(m('(prefers-color-scheme: dark)')?'dark':'light'));s('data-contrast',p.contrast==='more'||(p.contrast!=='standard'&&m('(prefers-contrast: more)'))?'more':'');s('data-text-scale',p.textScale==='sm'||p.textScale==='lg'||p.textScale==='xl'?p.textScale:'');s('data-motion',p.motion==='reduce'?'reduce':'');s('data-density',p.density==='compact'||p.density==='comfortable'?p.density:'')}catch(e){}})();`;
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
DEFAULT_DISPLAY_PREFERENCES,
|
|
57
|
+
DISPLAY_PREFERENCES_STORAGE_KEY,
|
|
58
|
+
DISPLAY_PREFERENCE_OPTIONS,
|
|
59
|
+
applyDisplayAttributes,
|
|
60
|
+
displayPreferencesScript,
|
|
61
|
+
parseDisplayPreferences,
|
|
62
|
+
readSystemDisplayPreferences,
|
|
63
|
+
resolveDisplayAttributes
|
|
64
|
+
};
|