@tensor_1/react 2.10.0 → 2.12.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 +10 -1
- package/dist/ChartCore-Bt1C84ty.d.cts +22 -0
- package/dist/chart-preset.cjs +168 -0
- package/dist/chart-preset.d.cts +9 -0
- package/dist/chart-preset.d.ts +9 -0
- package/dist/chart-preset.js +35 -0
- package/dist/chart.cjs +58 -41
- package/dist/chart.d.cts +6 -21
- package/dist/chart.d.ts +2 -1
- package/dist/components/Alert.js +7 -15
- package/dist/components/AppShell.d.ts +1 -3
- package/dist/components/AppShell.js +1 -3
- package/dist/components/Avatar.js +1 -2
- package/dist/components/Button.js +16 -32
- package/dist/components/Card.d.ts +1 -3
- package/dist/components/Card.js +2 -2
- package/dist/components/Chart.d.ts +6 -21
- package/dist/components/Chart.js +5 -85
- package/dist/components/ChartCore.d.ts +33 -0
- package/dist/components/ChartCore.js +100 -0
- package/dist/components/CommandPalette.d.ts +2 -4
- package/dist/components/CommandPalette.js +13 -66
- package/dist/components/Comments.d.ts +1 -5
- package/dist/components/Comments.js +1 -1
- package/dist/components/Composer.d.ts +1 -8
- package/dist/components/Composer.js +2 -7
- package/dist/components/DetailLayout.js +1 -1
- package/dist/components/Drawer.d.ts +4 -3
- package/dist/components/Drawer.js +4 -6
- package/dist/components/Field.js +3 -6
- package/dist/components/Inbox.d.ts +3 -13
- package/dist/components/Inbox.js +3 -62
- package/dist/components/Input.d.ts +2 -13
- package/dist/components/Input.js +5 -20
- package/dist/components/Kanban.d.ts +3 -15
- package/dist/components/Kanban.js +10 -42
- package/dist/components/Meter.d.ts +1 -3
- package/dist/components/Meter.js +1 -10
- package/dist/components/Modal.d.ts +5 -3
- package/dist/components/Modal.js +4 -6
- package/dist/components/NavFavourites.js +35 -119
- package/dist/components/PageHeader.d.ts +1 -3
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/Peek.d.ts +4 -3
- package/dist/components/Peek.js +6 -9
- package/dist/components/Progress.d.ts +1 -3
- package/dist/components/Progress.js +3 -5
- package/dist/components/Radio.d.ts +1 -3
- package/dist/components/Radio.js +2 -6
- package/dist/components/Segmented.js +3 -2
- package/dist/components/Sidebar.js +2 -4
- package/dist/components/Spinner.d.ts +1 -3
- package/dist/components/Spinner.js +3 -3
- package/dist/components/Stat.js +1 -5
- package/dist/components/States.d.ts +1 -3
- package/dist/components/States.js +2 -8
- package/dist/components/Table.d.ts +2 -9
- package/dist/components/Table.js +8 -11
- package/dist/components/Tabs.d.ts +1 -13
- package/dist/components/Tabs.js +4 -78
- package/dist/components/Timeline.d.ts +3 -3
- package/dist/components/Timeline.js +3 -3
- package/dist/components/Toast.js +5 -42
- package/dist/components/Tooltip.d.ts +1 -3
- package/dist/components/Tooltip.js +5 -44
- package/dist/components/Tree.d.ts +0 -2
- package/dist/components/Tree.js +4 -26
- package/dist/hooks/useDialog.d.ts +1 -1
- package/dist/hooks/useDialog.js +2 -17
- package/dist/hooks/useTable.d.ts +0 -5
- package/dist/hooks/useTable.js +12 -27
- package/dist/hooks/useVirtualRows.d.ts +27 -0
- package/dist/hooks/useVirtualRows.js +50 -0
- package/dist/index.cjs +291 -760
- package/dist/index.d.cts +61 -127
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -3
- package/dist/table-engine.js +8 -6
- package/dist/tree-model.d.ts +0 -4
- package/dist/tree-model.js +0 -8
- package/package.json +16 -2
package/dist/components/Input.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
3
|
import { cx } from "../cx.js";
|
|
4
4
|
const Input = forwardRef(
|
|
5
5
|
({ size = "md", invalid, valid, className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
@@ -14,22 +14,7 @@ const Input = forwardRef(
|
|
|
14
14
|
)
|
|
15
15
|
);
|
|
16
16
|
Input.displayName = "Input";
|
|
17
|
-
function InputGroup({
|
|
18
|
-
children,
|
|
19
|
-
leadingIcon,
|
|
20
|
-
trailingIcon,
|
|
21
|
-
className,
|
|
22
|
-
id,
|
|
23
|
-
"aria-describedby": describedBy,
|
|
24
|
-
"aria-invalid": invalid,
|
|
25
|
-
"aria-required": required
|
|
26
|
-
}) {
|
|
27
|
-
const control = isValidElement(children) && (id ?? describedBy ?? invalid ?? required) != null ? cloneElement(children, {
|
|
28
|
-
id: children.props.id ?? id,
|
|
29
|
-
"aria-describedby": children.props["aria-describedby"] ?? describedBy,
|
|
30
|
-
"aria-invalid": children.props["aria-invalid"] ?? invalid,
|
|
31
|
-
"aria-required": children.props["aria-required"] ?? required
|
|
32
|
-
}) : children;
|
|
17
|
+
function InputGroup({ children, leadingIcon, trailingIcon, className }) {
|
|
33
18
|
return /* @__PURE__ */ jsxs(
|
|
34
19
|
"div",
|
|
35
20
|
{
|
|
@@ -40,9 +25,9 @@ function InputGroup({
|
|
|
40
25
|
className
|
|
41
26
|
),
|
|
42
27
|
children: [
|
|
43
|
-
leadingIcon && /* @__PURE__ */ jsx("span", { className: "uix-input-group__icon",
|
|
44
|
-
|
|
45
|
-
trailingIcon && /* @__PURE__ */ jsx("span", { className: "uix-input-group__icon uix-input-group__icon--trailing",
|
|
28
|
+
leadingIcon && /* @__PURE__ */ jsx("span", { className: "uix-input-group__icon", children: leadingIcon }),
|
|
29
|
+
children,
|
|
30
|
+
trailingIcon && /* @__PURE__ */ jsx("span", { className: "uix-input-group__icon uix-input-group__icon--trailing", children: trailingIcon })
|
|
46
31
|
]
|
|
47
32
|
}
|
|
48
33
|
);
|
|
@@ -2,32 +2,20 @@ import * as react from 'react';
|
|
|
2
2
|
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
interface KanbanProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
-
/**
|
|
6
|
-
* Polite live-region text for keyboard moves (UIX-A11Y-2). `onMove` implementations
|
|
7
|
-
* should set it, e.g. "Card X moved to Doing, position 2 of 4".
|
|
8
|
-
*/
|
|
9
|
-
announcement?: string;
|
|
10
5
|
children?: ReactNode;
|
|
11
6
|
}
|
|
12
|
-
declare function Kanban({
|
|
7
|
+
declare function Kanban({ children, className, ...props }: KanbanProps): react.JSX.Element;
|
|
13
8
|
interface KanbanColumnProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
14
9
|
title?: ReactNode;
|
|
15
10
|
count?: number;
|
|
16
11
|
children?: ReactNode;
|
|
17
12
|
}
|
|
18
13
|
declare function KanbanColumn({ title, count, children, className, ...props }: KanbanColumnProps): react.JSX.Element;
|
|
19
|
-
type KanbanMoveDirection = 'up' | 'down' | 'left' | 'right';
|
|
20
14
|
interface KanbanCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
21
15
|
title?: ReactNode;
|
|
22
16
|
meta?: ReactNode;
|
|
23
|
-
/**
|
|
24
|
-
* Keyboard move contract (UIX-A11Y-2): when provided, Alt+Arrow on the focused card
|
|
25
|
-
* calls it — the same accelerator convention as NavFavourites row moves. Pair with
|
|
26
|
-
* the board-level `announcement` so SR users hear the result.
|
|
27
|
-
*/
|
|
28
|
-
onMove?: (dir: KanbanMoveDirection) => void;
|
|
29
17
|
children?: ReactNode;
|
|
30
18
|
}
|
|
31
|
-
declare function KanbanCard({ title, meta, children, className,
|
|
19
|
+
declare function KanbanCard({ title, meta, children, className, ...props }: KanbanCardProps): react.JSX.Element;
|
|
32
20
|
|
|
33
|
-
export { Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type
|
|
21
|
+
export { Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type KanbanProps };
|
|
@@ -1,55 +1,23 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useId } from "react";
|
|
4
2
|
import { cx } from "../cx.js";
|
|
5
|
-
function Kanban({
|
|
6
|
-
return /* @__PURE__ */
|
|
7
|
-
announcement != null && /* @__PURE__ */ jsx("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
|
|
8
|
-
children
|
|
9
|
-
] });
|
|
3
|
+
function Kanban({ children, className, ...props }) {
|
|
4
|
+
return /* @__PURE__ */ jsx("div", { className: cx("uix-kanban", className), ...props, children });
|
|
10
5
|
}
|
|
11
6
|
function KanbanColumn({ title, count, children, className, ...props }) {
|
|
12
|
-
const headId = useId();
|
|
13
|
-
const hasHead = title != null || count != null;
|
|
14
7
|
return /* @__PURE__ */ jsxs("div", { className: cx("uix-kanban__col", className), ...props, children: [
|
|
15
|
-
|
|
8
|
+
(title != null || count != null) && /* @__PURE__ */ jsxs("div", { className: "uix-kanban__head", children: [
|
|
16
9
|
title,
|
|
17
10
|
count != null && /* @__PURE__ */ jsx("span", { className: "uix-kanban__count", children: count })
|
|
18
11
|
] }),
|
|
19
|
-
/* @__PURE__ */ jsx("div", { className: "uix-kanban__body",
|
|
12
|
+
/* @__PURE__ */ jsx("div", { className: "uix-kanban__body", children })
|
|
20
13
|
] });
|
|
21
14
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
28
|
-
function KanbanCard({ title, meta, children, className, onMove, onKeyDown, ...props }) {
|
|
29
|
-
const handleKeyDown = (e) => {
|
|
30
|
-
onKeyDown?.(e);
|
|
31
|
-
if (!onMove || !e.altKey || e.defaultPrevented) return;
|
|
32
|
-
const dir = MOVE_KEYS[e.key];
|
|
33
|
-
if (dir) {
|
|
34
|
-
e.preventDefault();
|
|
35
|
-
onMove(dir);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
return /* @__PURE__ */ jsxs(
|
|
39
|
-
"div",
|
|
40
|
-
{
|
|
41
|
-
role: "listitem",
|
|
42
|
-
tabIndex: 0,
|
|
43
|
-
className: cx("uix-kanban__card", className),
|
|
44
|
-
onKeyDown: handleKeyDown,
|
|
45
|
-
...props,
|
|
46
|
-
children: [
|
|
47
|
-
title && /* @__PURE__ */ jsx("div", { className: "uix-kanban__card-title", children: title }),
|
|
48
|
-
meta && /* @__PURE__ */ jsx("div", { className: "uix-kanban__card-meta", children: meta }),
|
|
49
|
-
children
|
|
50
|
-
]
|
|
51
|
-
}
|
|
52
|
-
);
|
|
15
|
+
function KanbanCard({ title, meta, children, className, ...props }) {
|
|
16
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("uix-kanban__card", className), ...props, children: [
|
|
17
|
+
title && /* @__PURE__ */ jsx("div", { className: "uix-kanban__card-title", children: title }),
|
|
18
|
+
meta && /* @__PURE__ */ jsx("div", { className: "uix-kanban__card-meta", children: meta }),
|
|
19
|
+
children
|
|
20
|
+
] });
|
|
53
21
|
}
|
|
54
22
|
export {
|
|
55
23
|
Kanban,
|
|
@@ -8,10 +8,8 @@ interface MeterProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
8
8
|
value?: number;
|
|
9
9
|
/** Threshold tone applied via `data-tone` on the fill element. `success` is the implicit default (no attribute). */
|
|
10
10
|
tone?: MeterTone;
|
|
11
|
-
/** Accessible name — rendered as `aria-label` (an explicit `aria-label` prop wins). */
|
|
12
|
-
label?: string;
|
|
13
11
|
}
|
|
14
12
|
/** Horizontal utilization / threshold bar backed by `.uix-meter`. */
|
|
15
|
-
declare function Meter({ value, tone,
|
|
13
|
+
declare function Meter({ value, tone, className, ...props }: MeterProps): react.JSX.Element;
|
|
16
14
|
|
|
17
15
|
export { Meter, type MeterProps, type MeterTone };
|
package/dist/components/Meter.js
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import { jsx } from "react/jsx-runtime";
|
|
3
2
|
import { cx } from "../cx.js";
|
|
4
|
-
|
|
5
|
-
warning: "warning",
|
|
6
|
-
danger: "critical",
|
|
7
|
-
attention: "needs attention",
|
|
8
|
-
overdue: "overdue"
|
|
9
|
-
};
|
|
10
|
-
function Meter({ value = 0, tone, label, className, ...props }) {
|
|
3
|
+
function Meter({ value = 0, tone, className, ...props }) {
|
|
11
4
|
const pct = Math.max(0, Math.min(100, value));
|
|
12
5
|
return /* @__PURE__ */ jsx(
|
|
13
6
|
"div",
|
|
@@ -16,8 +9,6 @@ function Meter({ value = 0, tone, label, className, ...props }) {
|
|
|
16
9
|
"aria-valuenow": pct,
|
|
17
10
|
"aria-valuemin": 0,
|
|
18
11
|
"aria-valuemax": 100,
|
|
19
|
-
"aria-valuetext": tone && tone !== "success" ? `${pct}%, ${toneText[tone]}` : void 0,
|
|
20
|
-
"aria-label": label,
|
|
21
12
|
className: cx("uix-meter", className),
|
|
22
13
|
...props,
|
|
23
14
|
children: /* @__PURE__ */ jsx(
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ReactNode, CSSProperties } from 'react';
|
|
3
3
|
|
|
4
|
-
interface ModalProps
|
|
4
|
+
interface ModalProps {
|
|
5
5
|
open: boolean;
|
|
6
6
|
onClose?: () => void;
|
|
7
7
|
title?: ReactNode;
|
|
8
8
|
children?: ReactNode;
|
|
9
9
|
footer?: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: CSSProperties;
|
|
10
12
|
}
|
|
11
|
-
declare function Modal({ open, onClose, title, children, footer, className,
|
|
13
|
+
declare function Modal({ open, onClose, title, children, footer, className, style }: ModalProps): react.JSX.Element;
|
|
12
14
|
|
|
13
15
|
export { Modal, type ModalProps };
|
package/dist/components/Modal.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useId } from "react";
|
|
4
3
|
import { cx } from "../cx.js";
|
|
5
4
|
import { useDialog } from "../hooks/useDialog.js";
|
|
6
5
|
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
|
-
function Modal({ open, onClose, title, children, footer, className,
|
|
8
|
-
const ref = useDialog(open
|
|
9
|
-
|
|
10
|
-
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-dialog", className), "aria-labelledby": title ? titleId : void 0, ...rest, children: [
|
|
6
|
+
function Modal({ open, onClose, title, children, footer, className, style }) {
|
|
7
|
+
const ref = useDialog(open);
|
|
8
|
+
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-dialog", className), style, onClose, children: [
|
|
11
9
|
(title != null || onClose) && /* @__PURE__ */ jsxs("div", { className: "uix-dialog__header", children: [
|
|
12
|
-
title && /* @__PURE__ */ jsx("
|
|
10
|
+
title && /* @__PURE__ */ jsx("div", { className: "uix-dialog__title", children: title }),
|
|
13
11
|
onClose && /* @__PURE__ */ jsx("button", { className: "uix-dialog__close", onClick: onClose, "aria-label": "Close dialog", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
14
12
|
] }),
|
|
15
13
|
children != null && /* @__PURE__ */ jsx("div", { className: "uix-dialog__body", children }),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import { memo, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
const ChevronDownIcon = () => /* @__PURE__ */ jsx(
|
|
6
6
|
"svg",
|
|
@@ -14,7 +14,7 @@ const ChevronDownIcon = () => /* @__PURE__ */ jsx(
|
|
|
14
14
|
strokeLinecap: "round",
|
|
15
15
|
strokeLinejoin: "round",
|
|
16
16
|
"aria-hidden": "true",
|
|
17
|
-
|
|
17
|
+
className: "uix-favourites__chevron",
|
|
18
18
|
children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
|
|
19
19
|
}
|
|
20
20
|
);
|
|
@@ -30,7 +30,7 @@ const ChevronRightIcon = () => /* @__PURE__ */ jsx(
|
|
|
30
30
|
strokeLinecap: "round",
|
|
31
31
|
strokeLinejoin: "round",
|
|
32
32
|
"aria-hidden": "true",
|
|
33
|
-
|
|
33
|
+
className: "uix-favourites__chevron",
|
|
34
34
|
children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
|
|
35
35
|
}
|
|
36
36
|
);
|
|
@@ -53,7 +53,6 @@ const MoreIcon = () => /* @__PURE__ */ jsxs(
|
|
|
53
53
|
]
|
|
54
54
|
}
|
|
55
55
|
);
|
|
56
|
-
const MUTED = "color-mix(in srgb, var(--uix-text) 50%, transparent)";
|
|
57
56
|
function NavFavourites({
|
|
58
57
|
items,
|
|
59
58
|
collapsed = false,
|
|
@@ -67,10 +66,9 @@ function NavFavourites({
|
|
|
67
66
|
const regionId = useId();
|
|
68
67
|
const headerRef = useRef(null);
|
|
69
68
|
const regionRef = useRef(null);
|
|
70
|
-
const [announcement, setAnnouncement] = useState("");
|
|
71
69
|
const focusAfterRef = useRef(null);
|
|
72
70
|
const triggerRefs = useRef(/* @__PURE__ */ new Map());
|
|
73
|
-
const order = items.map((
|
|
71
|
+
const order = useMemo(() => items.map((item) => item.id), [items]);
|
|
74
72
|
useEffect(() => {
|
|
75
73
|
const id = focusAfterRef.current;
|
|
76
74
|
if (!id) return;
|
|
@@ -78,7 +76,7 @@ function NavFavourites({
|
|
|
78
76
|
const el = triggerRefs.current.get(id);
|
|
79
77
|
if (el) el.focus();
|
|
80
78
|
else headerRef.current?.focus();
|
|
81
|
-
}, [order
|
|
79
|
+
}, [order]);
|
|
82
80
|
const handleToggle = () => {
|
|
83
81
|
if (!collapsed) {
|
|
84
82
|
const active = document.activeElement;
|
|
@@ -88,7 +86,7 @@ function NavFavourites({
|
|
|
88
86
|
}
|
|
89
87
|
onToggleCollapsed?.();
|
|
90
88
|
};
|
|
91
|
-
const move = (id, dir) => {
|
|
89
|
+
const move = useCallback((id, dir) => {
|
|
92
90
|
const idx = order.indexOf(id);
|
|
93
91
|
const next = idx + dir;
|
|
94
92
|
if (idx < 0 || next < 0 || next >= order.length) return;
|
|
@@ -97,18 +95,19 @@ function NavFavourites({
|
|
|
97
95
|
if (it === void 0) return;
|
|
98
96
|
reordered.splice(next, 0, it);
|
|
99
97
|
focusAfterRef.current = id;
|
|
100
|
-
const moved = items.find((i) => i.id === id);
|
|
101
|
-
if (moved) setAnnouncement(`${moved.label} moved to position ${next + 1} of ${order.length}`);
|
|
102
98
|
onReorder(reordered);
|
|
103
|
-
};
|
|
104
|
-
const remove = (id) => {
|
|
99
|
+
}, [onReorder, order]);
|
|
100
|
+
const remove = useCallback((id) => {
|
|
105
101
|
const idx = order.indexOf(id);
|
|
106
102
|
const neighbour = order[idx + 1] ?? order[idx - 1] ?? null;
|
|
107
103
|
focusAfterRef.current = neighbour;
|
|
108
104
|
onRemove(id);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
}, [onRemove, order]);
|
|
106
|
+
const registerTrigger = useCallback((id, element) => {
|
|
107
|
+
if (element) triggerRefs.current.set(id, element);
|
|
108
|
+
else triggerRefs.current.delete(id);
|
|
109
|
+
}, []);
|
|
110
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("uix-favourites", className), children: [
|
|
112
111
|
/* @__PURE__ */ jsxs(
|
|
113
112
|
"button",
|
|
114
113
|
{
|
|
@@ -117,18 +116,7 @@ function NavFavourites({
|
|
|
117
116
|
"aria-expanded": !collapsed,
|
|
118
117
|
"aria-controls": regionId,
|
|
119
118
|
onClick: handleToggle,
|
|
120
|
-
className: "uix-text-eyebrow",
|
|
121
|
-
style: {
|
|
122
|
-
display: "flex",
|
|
123
|
-
width: "100%",
|
|
124
|
-
alignItems: "center",
|
|
125
|
-
gap: "6px",
|
|
126
|
-
padding: "8px 4px 4px",
|
|
127
|
-
border: 0,
|
|
128
|
-
background: "transparent",
|
|
129
|
-
cursor: "pointer",
|
|
130
|
-
color: "inherit"
|
|
131
|
-
},
|
|
119
|
+
className: "uix-favourites__heading uix-text-eyebrow",
|
|
132
120
|
children: [
|
|
133
121
|
collapsed ? /* @__PURE__ */ jsx(ChevronRightIcon, {}) : /* @__PURE__ */ jsx(ChevronDownIcon, {}),
|
|
134
122
|
labels.heading
|
|
@@ -141,20 +129,12 @@ function NavFavourites({
|
|
|
141
129
|
ref: regionRef,
|
|
142
130
|
id: regionId,
|
|
143
131
|
hidden: collapsed,
|
|
144
|
-
|
|
145
|
-
display: "flex",
|
|
146
|
-
flexDirection: "column",
|
|
147
|
-
gap: "1px",
|
|
148
|
-
listStyle: "none",
|
|
149
|
-
margin: 0,
|
|
150
|
-
padding: 0
|
|
151
|
-
},
|
|
132
|
+
className: "uix-favourites__list",
|
|
152
133
|
children: items.length === 0 ? /* @__PURE__ */ jsx(
|
|
153
134
|
"li",
|
|
154
135
|
{
|
|
155
|
-
className: "uix-text-meta",
|
|
136
|
+
className: "uix-favourites__empty uix-text-meta",
|
|
156
137
|
"data-empty-reason": emptyReason,
|
|
157
|
-
style: { padding: "6px 8px", color: MUTED },
|
|
158
138
|
children: labels.empty
|
|
159
139
|
}
|
|
160
140
|
) : items.map((item, idx) => /* @__PURE__ */ jsx(
|
|
@@ -164,10 +144,9 @@ function NavFavourites({
|
|
|
164
144
|
isFirst: idx === 0,
|
|
165
145
|
isLast: idx === items.length - 1,
|
|
166
146
|
labels,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
registerTrigger: (el) => triggerRefs.current.set(item.id, el)
|
|
147
|
+
onMove: move,
|
|
148
|
+
onRemove: remove,
|
|
149
|
+
registerTrigger
|
|
171
150
|
},
|
|
172
151
|
item.id
|
|
173
152
|
))
|
|
@@ -175,26 +154,24 @@ function NavFavourites({
|
|
|
175
154
|
)
|
|
176
155
|
] });
|
|
177
156
|
}
|
|
178
|
-
|
|
157
|
+
const FavouriteRow = memo(function FavouriteRow2({
|
|
179
158
|
item,
|
|
180
159
|
isFirst,
|
|
181
160
|
isLast,
|
|
182
161
|
labels,
|
|
183
|
-
|
|
184
|
-
onMoveDown,
|
|
162
|
+
onMove,
|
|
185
163
|
onRemove,
|
|
186
164
|
registerTrigger
|
|
187
165
|
}) {
|
|
188
166
|
const [open, setOpen] = useState(false);
|
|
189
|
-
const [revealed, setRevealed] = useState(false);
|
|
190
167
|
const menuId = useId();
|
|
191
168
|
const triggerRef = useRef(null);
|
|
192
169
|
const itemRefs = useRef([]);
|
|
193
170
|
const optionsTemplate = labels.options ?? "{label} favourite options";
|
|
194
171
|
const actions = [
|
|
195
|
-
...isFirst ? [] : [{ label: labels.moveUp, onSelect:
|
|
196
|
-
...isLast ? [] : [{ label: labels.moveDown, onSelect:
|
|
197
|
-
{ label: labels.remove.replace("{label}", item.label), onSelect: onRemove }
|
|
172
|
+
...isFirst ? [] : [{ label: labels.moveUp, onSelect: () => onMove(item.id, -1) }],
|
|
173
|
+
...isLast ? [] : [{ label: labels.moveDown, onSelect: () => onMove(item.id, 1) }],
|
|
174
|
+
{ label: labels.remove.replace("{label}", item.label), onSelect: () => onRemove(item.id) }
|
|
198
175
|
];
|
|
199
176
|
useEffect(() => {
|
|
200
177
|
if (open) itemRefs.current[0]?.focus();
|
|
@@ -212,12 +189,6 @@ function FavouriteRow({
|
|
|
212
189
|
} else if (e.key === "ArrowUp") {
|
|
213
190
|
e.preventDefault();
|
|
214
191
|
menuItems[(currentIdx - 1 + menuItems.length) % menuItems.length]?.focus();
|
|
215
|
-
} else if (e.key === "Home") {
|
|
216
|
-
e.preventDefault();
|
|
217
|
-
menuItems[0]?.focus();
|
|
218
|
-
} else if (e.key === "End") {
|
|
219
|
-
e.preventDefault();
|
|
220
|
-
menuItems[menuItems.length - 1]?.focus();
|
|
221
192
|
} else if (e.key === "Escape") {
|
|
222
193
|
e.preventDefault();
|
|
223
194
|
closeAndReturnFocus();
|
|
@@ -229,34 +200,27 @@ function FavouriteRow({
|
|
|
229
200
|
if (!e.altKey) return;
|
|
230
201
|
if (e.key === "ArrowUp" && !isFirst) {
|
|
231
202
|
e.preventDefault();
|
|
232
|
-
|
|
203
|
+
onMove(item.id, -1);
|
|
233
204
|
} else if (e.key === "ArrowDown" && !isLast) {
|
|
234
205
|
e.preventDefault();
|
|
235
|
-
|
|
206
|
+
onMove(item.id, 1);
|
|
236
207
|
}
|
|
237
208
|
};
|
|
238
|
-
const triggerVisible = revealed || open;
|
|
239
209
|
return (
|
|
240
210
|
// biome-ignore lint/a11y/noStaticElementInteractions: keyboard accelerators on the row; the focusable controls inside carry their own semantics.
|
|
241
211
|
/* @__PURE__ */ jsxs(
|
|
242
212
|
"li",
|
|
243
213
|
{
|
|
244
|
-
|
|
214
|
+
className: "uix-favourites__row",
|
|
245
215
|
onKeyDown: onRowKeyDown,
|
|
246
|
-
onMouseEnter: () => setRevealed(true),
|
|
247
|
-
onMouseLeave: () => setRevealed(false),
|
|
248
|
-
onFocus: () => setRevealed(true),
|
|
249
|
-
onBlur: (e) => {
|
|
250
|
-
if (!e.currentTarget.contains(e.relatedTarget)) setRevealed(false);
|
|
251
|
-
},
|
|
252
216
|
children: [
|
|
253
|
-
/* @__PURE__ */ jsx("div", {
|
|
217
|
+
/* @__PURE__ */ jsx("div", { className: "uix-favourites__link", children: item.link }),
|
|
254
218
|
/* @__PURE__ */ jsx(
|
|
255
219
|
"button",
|
|
256
220
|
{
|
|
257
221
|
ref: (el) => {
|
|
258
222
|
triggerRef.current = el;
|
|
259
|
-
registerTrigger(el);
|
|
223
|
+
registerTrigger(item.id, el);
|
|
260
224
|
},
|
|
261
225
|
type: "button",
|
|
262
226
|
"aria-haspopup": "menu",
|
|
@@ -264,22 +228,7 @@ function FavouriteRow({
|
|
|
264
228
|
"aria-controls": open ? menuId : void 0,
|
|
265
229
|
"aria-label": optionsTemplate.replace("{label}", item.label),
|
|
266
230
|
onClick: () => setOpen((v) => !v),
|
|
267
|
-
|
|
268
|
-
marginLeft: "auto",
|
|
269
|
-
display: "inline-flex",
|
|
270
|
-
height: "20px",
|
|
271
|
-
width: "20px",
|
|
272
|
-
flexShrink: 0,
|
|
273
|
-
alignItems: "center",
|
|
274
|
-
justifyContent: "center",
|
|
275
|
-
border: 0,
|
|
276
|
-
borderRadius: "2px",
|
|
277
|
-
background: "transparent",
|
|
278
|
-
cursor: "pointer",
|
|
279
|
-
color: MUTED,
|
|
280
|
-
opacity: triggerVisible ? 1 : 0,
|
|
281
|
-
transition: "opacity var(--uix-dur-fast) var(--uix-ease-out)"
|
|
282
|
-
},
|
|
231
|
+
className: "uix-favourites__menu-trigger",
|
|
283
232
|
children: /* @__PURE__ */ jsx(MoreIcon, {})
|
|
284
233
|
}
|
|
285
234
|
),
|
|
@@ -290,7 +239,7 @@ function FavouriteRow({
|
|
|
290
239
|
"aria-hidden": "true",
|
|
291
240
|
role: "presentation",
|
|
292
241
|
onClick: () => setOpen(false),
|
|
293
|
-
|
|
242
|
+
className: "uix-favourites__backdrop"
|
|
294
243
|
}
|
|
295
244
|
),
|
|
296
245
|
/* @__PURE__ */ jsx(
|
|
@@ -298,23 +247,8 @@ function FavouriteRow({
|
|
|
298
247
|
{
|
|
299
248
|
id: menuId,
|
|
300
249
|
role: "menu",
|
|
301
|
-
"aria-label": optionsTemplate.replace("{label}", item.label),
|
|
302
250
|
onKeyDown: onMenuKeyDown,
|
|
303
|
-
|
|
304
|
-
position: "absolute",
|
|
305
|
-
right: 0,
|
|
306
|
-
top: "calc(100% + 2px)",
|
|
307
|
-
zIndex: 50,
|
|
308
|
-
minWidth: "160px",
|
|
309
|
-
overflow: "hidden",
|
|
310
|
-
margin: 0,
|
|
311
|
-
padding: "4px 0",
|
|
312
|
-
listStyle: "none",
|
|
313
|
-
borderRadius: "6px",
|
|
314
|
-
border: "1px solid var(--uix-border)",
|
|
315
|
-
background: "var(--uix-surface)",
|
|
316
|
-
boxShadow: "var(--uix-shadow-popover)"
|
|
317
|
-
},
|
|
251
|
+
className: "uix-favourites__menu",
|
|
318
252
|
children: actions.map((action, i) => /* @__PURE__ */ jsx("li", { role: "presentation", children: /* @__PURE__ */ jsx(
|
|
319
253
|
"button",
|
|
320
254
|
{
|
|
@@ -328,25 +262,7 @@ function FavouriteRow({
|
|
|
328
262
|
setOpen(false);
|
|
329
263
|
action.onSelect();
|
|
330
264
|
},
|
|
331
|
-
|
|
332
|
-
display: "flex",
|
|
333
|
-
width: "100%",
|
|
334
|
-
alignItems: "center",
|
|
335
|
-
padding: "6px 12px",
|
|
336
|
-
border: 0,
|
|
337
|
-
background: "transparent",
|
|
338
|
-
cursor: "pointer",
|
|
339
|
-
textAlign: "left",
|
|
340
|
-
fontSize: "13px",
|
|
341
|
-
color: "color-mix(in srgb, var(--uix-text) 85%, transparent)",
|
|
342
|
-
transition: "background-color var(--uix-dur-fast) var(--uix-ease-out)"
|
|
343
|
-
},
|
|
344
|
-
onMouseEnter: (e) => {
|
|
345
|
-
e.currentTarget.style.background = "var(--uix-bg-hover)";
|
|
346
|
-
},
|
|
347
|
-
onMouseLeave: (e) => {
|
|
348
|
-
e.currentTarget.style.background = "transparent";
|
|
349
|
-
},
|
|
265
|
+
className: "uix-favourites__menu-item",
|
|
350
266
|
children: action.label
|
|
351
267
|
}
|
|
352
268
|
) }, action.label))
|
|
@@ -357,7 +273,7 @@ function FavouriteRow({
|
|
|
357
273
|
}
|
|
358
274
|
)
|
|
359
275
|
);
|
|
360
|
-
}
|
|
276
|
+
});
|
|
361
277
|
export {
|
|
362
278
|
NavFavourites
|
|
363
279
|
};
|
|
@@ -4,8 +4,6 @@ import { HTMLAttributes, ReactNode } from 'react';
|
|
|
4
4
|
interface PageHeaderProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
|
|
5
5
|
eyebrow?: ReactNode;
|
|
6
6
|
title: ReactNode;
|
|
7
|
-
/** Heading level for the title — drop to `h2` when the page already owns an `h1` (UIX-A11Y-4). */
|
|
8
|
-
as?: 'h1' | 'h2';
|
|
9
7
|
/** Supporting copy under the title. */
|
|
10
8
|
subtitle?: ReactNode;
|
|
11
9
|
/** Right-aligned action area (buttons, menus). */
|
|
@@ -15,6 +13,6 @@ interface PageHeaderProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
|
|
|
15
13
|
* Page header — eyebrow / title / subtitle + actions row, over `.uix-page-header`.
|
|
16
14
|
* The hairline + breathing room below come from the component CSS.
|
|
17
15
|
*/
|
|
18
|
-
declare function PageHeader({ eyebrow, title, subtitle, actions,
|
|
16
|
+
declare function PageHeader({ eyebrow, title, subtitle, actions, className, ...props }: PageHeaderProps): react.JSX.Element;
|
|
19
17
|
|
|
20
18
|
export { PageHeader, type PageHeaderProps };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from "../cx.js";
|
|
3
|
-
function PageHeader({ eyebrow, title, subtitle, actions,
|
|
3
|
+
function PageHeader({ eyebrow, title, subtitle, actions, className, ...props }) {
|
|
4
4
|
return /* @__PURE__ */ jsxs("header", { className: cx("uix-page-header", className), ...props, children: [
|
|
5
5
|
/* @__PURE__ */ jsxs("div", { className: "uix-page-header__titles", children: [
|
|
6
6
|
eyebrow != null && /* @__PURE__ */ jsx("div", { className: "uix-page-header__eyebrow", children: eyebrow }),
|
|
7
|
-
/* @__PURE__ */ jsx(
|
|
7
|
+
/* @__PURE__ */ jsx("h1", { className: "uix-page-header__title", children: title }),
|
|
8
8
|
subtitle != null && /* @__PURE__ */ jsx("p", { className: "uix-page-header__subtitle", children: subtitle })
|
|
9
9
|
] }),
|
|
10
10
|
actions != null && /* @__PURE__ */ jsx("div", { className: "uix-page-header__actions", children: actions })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
-
interface PeekProps
|
|
4
|
+
interface PeekProps {
|
|
5
5
|
open: boolean;
|
|
6
6
|
onClose?: () => void;
|
|
7
7
|
title?: ReactNode;
|
|
@@ -10,7 +10,8 @@ interface PeekProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title'> {
|
|
|
10
10
|
onNavPrev?: () => void;
|
|
11
11
|
onNavNext?: () => void;
|
|
12
12
|
hint?: string;
|
|
13
|
+
className?: string;
|
|
13
14
|
}
|
|
14
|
-
declare function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className
|
|
15
|
+
declare function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className }: PeekProps): react.JSX.Element;
|
|
15
16
|
|
|
16
17
|
export { Peek, type PeekProps };
|
package/dist/components/Peek.js
CHANGED
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useId } from "react";
|
|
4
3
|
import { cx } from "../cx.js";
|
|
5
4
|
import { useDialog } from "../hooks/useDialog.js";
|
|
6
5
|
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
6
|
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
7
|
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
|
|
10
|
-
const ref = useDialog(open
|
|
8
|
+
function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className }) {
|
|
9
|
+
const ref = useDialog(open);
|
|
11
10
|
const hasNav = onNavPrev != null || onNavNext != null;
|
|
12
|
-
const titleId = useId();
|
|
13
11
|
const onBackdropClick = (e) => {
|
|
14
|
-
onClick?.(e);
|
|
15
12
|
if (!onClose || e.target !== e.currentTarget) return;
|
|
16
13
|
const r = e.currentTarget.getBoundingClientRect();
|
|
17
14
|
if (r.width === 0) return;
|
|
18
15
|
const outside = e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom;
|
|
19
16
|
if (outside) onClose();
|
|
20
17
|
};
|
|
21
|
-
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-peek", className),
|
|
18
|
+
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-peek", className), onClose, onClick: onBackdropClick, children: [
|
|
22
19
|
/* @__PURE__ */ jsxs("div", { className: "uix-peek__header", children: [
|
|
23
20
|
hasNav && /* @__PURE__ */ jsxs("div", { className: "uix-peek__nav", children: [
|
|
24
|
-
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick:
|
|
25
|
-
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick:
|
|
21
|
+
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: onNavPrev, disabled: !onNavPrev, "aria-label": "Previous record", children: /* @__PURE__ */ jsx(ChevronUp, {}) }),
|
|
22
|
+
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: onNavNext, disabled: !onNavNext, "aria-label": "Next record", children: /* @__PURE__ */ jsx(ChevronDown, {}) })
|
|
26
23
|
] }),
|
|
27
|
-
title && /* @__PURE__ */ jsx("
|
|
24
|
+
title && /* @__PURE__ */ jsx("div", { className: "uix-peek__title", children: title }),
|
|
28
25
|
hint && /* @__PURE__ */ jsx("span", { className: "uix-peek__hint", children: hint }),
|
|
29
26
|
onClose && /* @__PURE__ */ jsx("button", { className: "uix-peek__close", onClick: onClose, "aria-label": "Close preview", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
30
27
|
] }),
|
|
@@ -8,9 +8,7 @@ interface ProgressProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
8
8
|
max?: number;
|
|
9
9
|
/** Continuous slide animation when the amount of work is unknown. */
|
|
10
10
|
indeterminate?: boolean;
|
|
11
|
-
/** Accessible name — rendered as `aria-label` (an explicit `aria-label` prop wins). */
|
|
12
|
-
label?: string;
|
|
13
11
|
}
|
|
14
|
-
declare function Progress({ value, max, indeterminate,
|
|
12
|
+
declare function Progress({ value, max, indeterminate, className, ...props }: ProgressProps): react.JSX.Element;
|
|
15
13
|
|
|
16
14
|
export { Progress, type ProgressProps };
|