@tensor_1/react 2.15.0 → 2.17.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 +5 -0
- package/dist/ChartCore-Do6gRBN3.d.cts +44 -0
- package/dist/chart-preset.cjs +56 -12
- package/dist/chart-preset.d.cts +2 -2
- package/dist/chart-preset.d.ts +1 -1
- package/dist/chart-preset.js +4 -1
- package/dist/chart.cjs +56 -12
- package/dist/chart.d.cts +2 -2
- package/dist/chart.d.ts +1 -1
- package/dist/chart.js +4 -1
- package/dist/components/Alert.js +15 -7
- package/dist/components/AppShell.d.ts +3 -1
- package/dist/components/AppShell.js +3 -1
- package/dist/components/Avatar.js +2 -1
- package/dist/components/Button.js +32 -16
- package/dist/components/Card.d.ts +3 -1
- package/dist/components/Card.js +2 -2
- package/dist/components/Chart.d.ts +1 -1
- package/dist/components/Chart.js +4 -1
- package/dist/components/ChartCore.d.ts +24 -3
- package/dist/components/ChartCore.js +53 -12
- package/dist/components/CommandPalette.d.ts +4 -2
- package/dist/components/CommandPalette.js +66 -13
- package/dist/components/Comments.d.ts +5 -1
- package/dist/components/Comments.js +1 -1
- package/dist/components/Composer.d.ts +8 -1
- package/dist/components/Composer.js +7 -2
- package/dist/components/DetailLayout.js +1 -1
- package/dist/components/Drawer.d.ts +3 -4
- package/dist/components/Drawer.js +6 -4
- package/dist/components/Field.js +6 -3
- package/dist/components/Flow.d.ts +26 -0
- package/dist/components/Flow.js +48 -0
- package/dist/components/Inbox.d.ts +13 -3
- package/dist/components/Inbox.js +62 -3
- package/dist/components/Input.d.ts +13 -2
- package/dist/components/Input.js +20 -5
- package/dist/components/Kanban.d.ts +15 -3
- package/dist/components/Kanban.js +42 -10
- package/dist/components/Meter.d.ts +3 -1
- package/dist/components/Meter.js +9 -1
- package/dist/components/Modal.d.ts +4 -5
- package/dist/components/Modal.js +4 -4
- package/dist/components/NavFavourites.js +11 -0
- package/dist/components/PageHeader.d.ts +3 -1
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/Peek.d.ts +3 -4
- package/dist/components/Peek.js +9 -6
- package/dist/components/Pipeline.d.ts +25 -0
- package/dist/components/Pipeline.js +65 -0
- package/dist/components/Progress.d.ts +3 -1
- package/dist/components/Progress.js +5 -3
- package/dist/components/Radio.d.ts +3 -1
- package/dist/components/Radio.js +6 -2
- package/dist/components/Spinner.d.ts +3 -1
- package/dist/components/Spinner.js +3 -3
- package/dist/components/Stat.js +5 -1
- package/dist/components/States.d.ts +1 -0
- package/dist/components/States.js +7 -1
- package/dist/components/Table.d.ts +8 -1
- package/dist/components/Table.js +10 -6
- package/dist/components/Tabs.d.ts +13 -1
- package/dist/components/Tabs.js +79 -4
- package/dist/components/Timeline.d.ts +3 -3
- package/dist/components/Timeline.js +3 -3
- package/dist/components/Toast.js +42 -5
- package/dist/components/Tooltip.d.ts +3 -1
- package/dist/components/Tooltip.js +44 -5
- package/dist/components/Tree.d.ts +2 -0
- package/dist/components/Tree.js +26 -4
- package/dist/hooks/useDialog.d.ts +1 -1
- package/dist/hooks/useDialog.js +17 -2
- package/dist/hooks/useTable.d.ts +5 -0
- package/dist/hooks/useTable.js +20 -1
- package/dist/index.cjs +1191 -626
- package/dist/index.d.cts +168 -35
- package/dist/index.d.ts +4 -2
- package/dist/index.js +8 -1
- package/dist/tree-model.d.ts +4 -0
- package/dist/tree-model.js +8 -0
- package/package.json +1 -1
- package/dist/ChartCore-Bt1C84ty.d.cts +0 -22
|
@@ -2,20 +2,32 @@ 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;
|
|
5
10
|
children?: ReactNode;
|
|
6
11
|
}
|
|
7
|
-
declare function Kanban({ children, className, ...props }: KanbanProps): react.JSX.Element;
|
|
12
|
+
declare function Kanban({ announcement, children, className, ...props }: KanbanProps): react.JSX.Element;
|
|
8
13
|
interface KanbanColumnProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
9
14
|
title?: ReactNode;
|
|
10
15
|
count?: number;
|
|
11
16
|
children?: ReactNode;
|
|
12
17
|
}
|
|
13
18
|
declare function KanbanColumn({ title, count, children, className, ...props }: KanbanColumnProps): react.JSX.Element;
|
|
19
|
+
type KanbanMoveDirection = 'up' | 'down' | 'left' | 'right';
|
|
14
20
|
interface KanbanCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
15
21
|
title?: ReactNode;
|
|
16
22
|
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;
|
|
17
29
|
children?: ReactNode;
|
|
18
30
|
}
|
|
19
|
-
declare function KanbanCard({ title, meta, children, className, ...props }: KanbanCardProps): react.JSX.Element;
|
|
31
|
+
declare function KanbanCard({ title, meta, children, className, onMove, onKeyDown, ...props }: KanbanCardProps): react.JSX.Element;
|
|
20
32
|
|
|
21
|
-
export { Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type KanbanProps };
|
|
33
|
+
export { Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type KanbanMoveDirection, type KanbanProps };
|
|
@@ -1,23 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
2
4
|
import { cx } from "../cx.js";
|
|
3
|
-
function Kanban({ children, className, ...props }) {
|
|
4
|
-
return /* @__PURE__ */
|
|
5
|
+
function Kanban({ announcement, children, className, ...props }) {
|
|
6
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("uix-kanban", className), ...props, children: [
|
|
7
|
+
announcement != null && /* @__PURE__ */ jsx("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
|
|
8
|
+
children
|
|
9
|
+
] });
|
|
5
10
|
}
|
|
6
11
|
function KanbanColumn({ title, count, children, className, ...props }) {
|
|
12
|
+
const headId = useId();
|
|
13
|
+
const hasHead = title != null || count != null;
|
|
7
14
|
return /* @__PURE__ */ jsxs("div", { className: cx("uix-kanban__col", className), ...props, children: [
|
|
8
|
-
|
|
15
|
+
hasHead && /* @__PURE__ */ jsxs("div", { className: "uix-kanban__head", id: headId, children: [
|
|
9
16
|
title,
|
|
10
17
|
count != null && /* @__PURE__ */ jsx("span", { className: "uix-kanban__count", children: count })
|
|
11
18
|
] }),
|
|
12
|
-
/* @__PURE__ */ jsx("div", { className: "uix-kanban__body", children })
|
|
19
|
+
/* @__PURE__ */ jsx("div", { className: "uix-kanban__body", role: "list", "aria-labelledby": hasHead ? headId : void 0, children })
|
|
13
20
|
] });
|
|
14
21
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
const MOVE_KEYS = {
|
|
23
|
+
ArrowUp: "up",
|
|
24
|
+
ArrowDown: "down",
|
|
25
|
+
ArrowLeft: "left",
|
|
26
|
+
ArrowRight: "right"
|
|
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
|
+
);
|
|
21
53
|
}
|
|
22
54
|
export {
|
|
23
55
|
Kanban,
|
|
@@ -8,8 +8,10 @@ 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;
|
|
11
13
|
}
|
|
12
14
|
/** Horizontal utilization / threshold bar backed by `.uix-meter`. */
|
|
13
|
-
declare function Meter({ value, tone, className, ...props }: MeterProps): react.JSX.Element;
|
|
15
|
+
declare function Meter({ value, tone, label, className, ...props }: MeterProps): react.JSX.Element;
|
|
14
16
|
|
|
15
17
|
export { Meter, type MeterProps, type MeterTone };
|
package/dist/components/Meter.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from "../cx.js";
|
|
3
|
-
|
|
3
|
+
const toneText = {
|
|
4
|
+
warning: "warning",
|
|
5
|
+
danger: "critical",
|
|
6
|
+
attention: "needs attention",
|
|
7
|
+
overdue: "overdue"
|
|
8
|
+
};
|
|
9
|
+
function Meter({ value = 0, tone, label, className, ...props }) {
|
|
4
10
|
const pct = Math.max(0, Math.min(100, value));
|
|
5
11
|
return /* @__PURE__ */ jsx(
|
|
6
12
|
"div",
|
|
@@ -9,6 +15,8 @@ function Meter({ value = 0, tone, className, ...props }) {
|
|
|
9
15
|
"aria-valuenow": pct,
|
|
10
16
|
"aria-valuemin": 0,
|
|
11
17
|
"aria-valuemax": 100,
|
|
18
|
+
"aria-valuetext": tone && tone !== "success" ? `${pct}%, ${toneText[tone]}` : void 0,
|
|
19
|
+
"aria-label": label,
|
|
12
20
|
className: cx("uix-meter", className),
|
|
13
21
|
...props,
|
|
14
22
|
children: /* @__PURE__ */ jsx(
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
-
interface ModalProps {
|
|
4
|
+
interface ModalProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title'> {
|
|
5
5
|
open: boolean;
|
|
6
6
|
onClose?: () => void;
|
|
7
7
|
title?: ReactNode;
|
|
8
8
|
children?: ReactNode;
|
|
9
9
|
footer?: ReactNode;
|
|
10
|
-
|
|
11
|
-
style?: CSSProperties;
|
|
10
|
+
/** Accessible name for the close button (default "Close dialog"). */
|
|
12
11
|
closeLabel?: string;
|
|
13
12
|
role?: 'dialog' | 'alertdialog';
|
|
14
13
|
}
|
|
15
|
-
declare function Modal({ open, onClose, title, children, footer, className,
|
|
14
|
+
declare function Modal({ open, onClose, title, children, footer, className, closeLabel, role, ...rest }: ModalProps): react.JSX.Element;
|
|
16
15
|
|
|
17
16
|
export { Modal, type ModalProps };
|
package/dist/components/Modal.js
CHANGED
|
@@ -4,12 +4,12 @@ import { useId } from "react";
|
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
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
|
-
function Modal({ open, onClose, title, children, footer, className,
|
|
8
|
-
const ref = useDialog(open);
|
|
7
|
+
function Modal({ open, onClose, title, children, footer, className, closeLabel = "Close dialog", role = "dialog", ...rest }) {
|
|
8
|
+
const ref = useDialog(open, onClose);
|
|
9
9
|
const titleId = useId();
|
|
10
|
-
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-dialog", className),
|
|
10
|
+
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-dialog", className), role, "aria-labelledby": title != null ? titleId : void 0, ...rest, children: [
|
|
11
11
|
(title != null || onClose) && /* @__PURE__ */ jsxs("div", { className: "uix-dialog__header", children: [
|
|
12
|
-
title && /* @__PURE__ */ jsx("
|
|
12
|
+
title && /* @__PURE__ */ jsx("h2", { className: "uix-dialog__title", id: titleId, children: title }),
|
|
13
13
|
onClose && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-dialog__close", onClick: onClose, "aria-label": closeLabel, children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
14
14
|
] }),
|
|
15
15
|
children != null && /* @__PURE__ */ jsx("div", { className: "uix-dialog__body", children }),
|
|
@@ -66,6 +66,7 @@ function NavFavourites({
|
|
|
66
66
|
const regionId = useId();
|
|
67
67
|
const headerRef = useRef(null);
|
|
68
68
|
const regionRef = useRef(null);
|
|
69
|
+
const [announcement, setAnnouncement] = useState("");
|
|
69
70
|
const focusAfterRef = useRef(null);
|
|
70
71
|
const triggerRefs = useRef(/* @__PURE__ */ new Map());
|
|
71
72
|
const order = useMemo(() => items.map((item) => item.id), [items]);
|
|
@@ -95,6 +96,8 @@ function NavFavourites({
|
|
|
95
96
|
if (it === void 0) return;
|
|
96
97
|
reordered.splice(next, 0, it);
|
|
97
98
|
focusAfterRef.current = id;
|
|
99
|
+
const moved = items.find((i) => i.id === id);
|
|
100
|
+
if (moved) setAnnouncement(`${moved.label} moved to position ${next + 1} of ${order.length}`);
|
|
98
101
|
onReorder(reordered);
|
|
99
102
|
}, [onReorder, order]);
|
|
100
103
|
const remove = useCallback((id) => {
|
|
@@ -108,6 +111,7 @@ function NavFavourites({
|
|
|
108
111
|
else triggerRefs.current.delete(id);
|
|
109
112
|
}, []);
|
|
110
113
|
return /* @__PURE__ */ jsxs("div", { className: cx("uix-favourites", className), children: [
|
|
114
|
+
/* @__PURE__ */ jsx("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
|
|
111
115
|
/* @__PURE__ */ jsxs(
|
|
112
116
|
"button",
|
|
113
117
|
{
|
|
@@ -189,6 +193,12 @@ const FavouriteRow = memo(function FavouriteRow2({
|
|
|
189
193
|
} else if (e.key === "ArrowUp") {
|
|
190
194
|
e.preventDefault();
|
|
191
195
|
menuItems[(currentIdx - 1 + menuItems.length) % menuItems.length]?.focus();
|
|
196
|
+
} else if (e.key === "Home") {
|
|
197
|
+
e.preventDefault();
|
|
198
|
+
menuItems[0]?.focus();
|
|
199
|
+
} else if (e.key === "End") {
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
menuItems[menuItems.length - 1]?.focus();
|
|
192
202
|
} else if (e.key === "Escape") {
|
|
193
203
|
e.preventDefault();
|
|
194
204
|
closeAndReturnFocus();
|
|
@@ -247,6 +257,7 @@ const FavouriteRow = memo(function FavouriteRow2({
|
|
|
247
257
|
{
|
|
248
258
|
id: menuId,
|
|
249
259
|
role: "menu",
|
|
260
|
+
"aria-label": optionsTemplate.replace("{label}", item.label),
|
|
250
261
|
onKeyDown: onMenuKeyDown,
|
|
251
262
|
className: "uix-favourites__menu",
|
|
252
263
|
children: actions.map((action, i) => /* @__PURE__ */ jsx("li", { role: "presentation", children: /* @__PURE__ */ jsx(
|
|
@@ -4,6 +4,8 @@ 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';
|
|
7
9
|
/** Supporting copy under the title. */
|
|
8
10
|
subtitle?: ReactNode;
|
|
9
11
|
/** Right-aligned action area (buttons, menus). */
|
|
@@ -13,6 +15,6 @@ interface PageHeaderProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
|
|
|
13
15
|
* Page header — eyebrow / title / subtitle + actions row, over `.uix-page-header`.
|
|
14
16
|
* The hairline + breathing room below come from the component CSS.
|
|
15
17
|
*/
|
|
16
|
-
declare function PageHeader({ eyebrow, title, subtitle, actions, className, ...props }: PageHeaderProps): react.JSX.Element;
|
|
18
|
+
declare function PageHeader({ eyebrow, title, subtitle, actions, as: TitleTag, className, ...props }: PageHeaderProps): react.JSX.Element;
|
|
17
19
|
|
|
18
20
|
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, className, ...props }) {
|
|
3
|
+
function PageHeader({ eyebrow, title, subtitle, actions, as: TitleTag = "h1", 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(TitleTag, { 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 { ReactNode } from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
-
interface PeekProps {
|
|
4
|
+
interface PeekProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'title'> {
|
|
5
5
|
open: boolean;
|
|
6
6
|
onClose?: () => void;
|
|
7
7
|
title?: ReactNode;
|
|
@@ -10,8 +10,7 @@ interface PeekProps {
|
|
|
10
10
|
onNavPrev?: () => void;
|
|
11
11
|
onNavNext?: () => void;
|
|
12
12
|
hint?: string;
|
|
13
|
-
className?: string;
|
|
14
13
|
}
|
|
15
|
-
declare function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className }: PeekProps): react.JSX.Element;
|
|
14
|
+
declare function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className, onClick, ...rest }: PeekProps): react.JSX.Element;
|
|
16
15
|
|
|
17
16
|
export { Peek, type PeekProps };
|
package/dist/components/Peek.js
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
3
4
|
import { cx } from "../cx.js";
|
|
4
5
|
import { useDialog } from "../hooks/useDialog.js";
|
|
5
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" }) });
|
|
6
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" }) });
|
|
7
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" }) });
|
|
8
|
-
function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className }) {
|
|
9
|
-
const ref = useDialog(open);
|
|
9
|
+
function Peek({ open, onClose, title, children, footer, onNavPrev, onNavNext, hint, className, onClick, ...rest }) {
|
|
10
|
+
const ref = useDialog(open, onClose);
|
|
10
11
|
const hasNav = onNavPrev != null || onNavNext != null;
|
|
12
|
+
const titleId = useId();
|
|
11
13
|
const onBackdropClick = (e) => {
|
|
14
|
+
onClick?.(e);
|
|
12
15
|
if (!onClose || e.target !== e.currentTarget) return;
|
|
13
16
|
const r = e.currentTarget.getBoundingClientRect();
|
|
14
17
|
if (r.width === 0) return;
|
|
15
18
|
const outside = e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom;
|
|
16
19
|
if (outside) onClose();
|
|
17
20
|
};
|
|
18
|
-
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-peek", className),
|
|
21
|
+
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-peek", className), "aria-labelledby": title ? titleId : void 0, ...rest, onClick: onBackdropClick, children: [
|
|
19
22
|
/* @__PURE__ */ jsxs("div", { className: "uix-peek__header", children: [
|
|
20
23
|
hasNav && /* @__PURE__ */ jsxs("div", { className: "uix-peek__nav", children: [
|
|
21
|
-
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: onNavPrev, disabled:
|
|
22
|
-
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: onNavNext, disabled:
|
|
24
|
+
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: () => onNavPrev?.(), "aria-disabled": onNavPrev ? void 0 : true, "aria-label": "Previous record", children: /* @__PURE__ */ jsx(ChevronUp, {}) }),
|
|
25
|
+
/* @__PURE__ */ jsx("button", { className: "uix-peek__navbtn", onClick: () => onNavNext?.(), "aria-disabled": onNavNext ? void 0 : true, "aria-label": "Next record", children: /* @__PURE__ */ jsx(ChevronDown, {}) })
|
|
23
26
|
] }),
|
|
24
|
-
title && /* @__PURE__ */ jsx("
|
|
27
|
+
title && /* @__PURE__ */ jsx("h2", { className: "uix-peek__title", id: titleId, children: title }),
|
|
25
28
|
hint && /* @__PURE__ */ jsx("span", { className: "uix-peek__hint", children: hint }),
|
|
26
29
|
onClose && /* @__PURE__ */ jsx("button", { className: "uix-peek__close", onClick: onClose, "aria-label": "Close preview", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
27
30
|
] }),
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type PipelineStageState = 'pending' | 'waiting' | 'active' | 'current' | 'running' | 'done' | 'complete' | 'blocked' | 'failed' | 'error';
|
|
5
|
+
interface PipelineProps extends HTMLAttributes<HTMLOListElement> {
|
|
6
|
+
detailed?: boolean;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/** Ordered progress rail. Consumers own workflow meaning; UIx owns stage semantics and presentation. */
|
|
10
|
+
declare function Pipeline({ detailed, children, className, tabIndex, ...props }: PipelineProps): react.JSX.Element;
|
|
11
|
+
interface PipelineStageProps extends Omit<HTMLAttributes<HTMLLIElement>, 'title'> {
|
|
12
|
+
label: ReactNode;
|
|
13
|
+
state?: PipelineStageState;
|
|
14
|
+
stateLabel?: ReactNode;
|
|
15
|
+
description?: ReactNode;
|
|
16
|
+
meta?: ReactNode;
|
|
17
|
+
marker?: ReactNode;
|
|
18
|
+
detailed?: boolean;
|
|
19
|
+
/** Marks the stage as the current position independently of its operational state. */
|
|
20
|
+
current?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** One pipeline stage. `stateLabel` keeps status explicit instead of relying on colour. */
|
|
23
|
+
declare function PipelineStage({ label, state, stateLabel, description, meta, marker, detailed, current: currentProp, className, ...props }: PipelineStageProps): react.JSX.Element;
|
|
24
|
+
|
|
25
|
+
export { Pipeline, type PipelineProps, PipelineStage, type PipelineStageProps, type PipelineStageState };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Children, cloneElement, isValidElement } from "react";
|
|
3
|
+
import { cx } from "../cx.js";
|
|
4
|
+
function Pipeline({ detailed = false, children, className, tabIndex, ...props }) {
|
|
5
|
+
const stages = detailed ? Children.map(children, (child) => isValidElement(child) && child.type === PipelineStage ? cloneElement(child, { detailed: child.props.detailed ?? true }) : child) : children;
|
|
6
|
+
return /* @__PURE__ */ jsx(
|
|
7
|
+
"ol",
|
|
8
|
+
{
|
|
9
|
+
className: cx("uix-pipeline", detailed && "uix-pipeline--detailed", className),
|
|
10
|
+
tabIndex: tabIndex ?? (detailed ? 0 : void 0),
|
|
11
|
+
...props,
|
|
12
|
+
children: stages
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
const DEFAULT_STATE_LABELS = {
|
|
17
|
+
pending: "Pending",
|
|
18
|
+
waiting: "Waiting",
|
|
19
|
+
active: "Active",
|
|
20
|
+
current: "Current",
|
|
21
|
+
running: "Running",
|
|
22
|
+
done: "Done",
|
|
23
|
+
complete: "Complete",
|
|
24
|
+
blocked: "Blocked",
|
|
25
|
+
failed: "Failed",
|
|
26
|
+
error: "Error"
|
|
27
|
+
};
|
|
28
|
+
function PipelineStage({
|
|
29
|
+
label,
|
|
30
|
+
state = "pending",
|
|
31
|
+
stateLabel,
|
|
32
|
+
description,
|
|
33
|
+
meta,
|
|
34
|
+
marker,
|
|
35
|
+
detailed = false,
|
|
36
|
+
current: currentProp,
|
|
37
|
+
className,
|
|
38
|
+
...props
|
|
39
|
+
}) {
|
|
40
|
+
const current = currentProp ?? (state === "active" || state === "current" || state === "running");
|
|
41
|
+
const resolvedStateLabel = stateLabel ?? DEFAULT_STATE_LABELS[state];
|
|
42
|
+
const showDetails = detailed || description != null || meta != null || marker != null;
|
|
43
|
+
return /* @__PURE__ */ jsx(
|
|
44
|
+
"li",
|
|
45
|
+
{
|
|
46
|
+
className: cx("uix-pipeline__stage", className),
|
|
47
|
+
"data-state": state,
|
|
48
|
+
"aria-current": current ? "step" : void 0,
|
|
49
|
+
...props,
|
|
50
|
+
children: showDetails ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
51
|
+
/* @__PURE__ */ jsx("span", { className: "uix-pipeline__marker", "aria-hidden": "true", children: marker }),
|
|
52
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-pipeline__content", children: [
|
|
53
|
+
/* @__PURE__ */ jsx("div", { className: "uix-pipeline__eyebrow", children: /* @__PURE__ */ jsx("span", { className: "uix-pipeline__state", children: resolvedStateLabel }) }),
|
|
54
|
+
/* @__PURE__ */ jsx("div", { className: "uix-pipeline__title", children: label }),
|
|
55
|
+
description != null && /* @__PURE__ */ jsx("div", { className: "uix-pipeline__description", children: description }),
|
|
56
|
+
meta != null && /* @__PURE__ */ jsx("div", { className: "uix-pipeline__meta", children: meta })
|
|
57
|
+
] })
|
|
58
|
+
] }) : label
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
Pipeline,
|
|
64
|
+
PipelineStage
|
|
65
|
+
};
|
|
@@ -8,7 +8,9 @@ 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;
|
|
11
13
|
}
|
|
12
|
-
declare function Progress({ value, max, indeterminate, className, ...props }: ProgressProps): react.JSX.Element;
|
|
14
|
+
declare function Progress({ value, max, indeterminate, label, className, ...props }: ProgressProps): react.JSX.Element;
|
|
13
15
|
|
|
14
16
|
export { Progress, type ProgressProps };
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from "../cx.js";
|
|
3
|
-
function Progress({ value = 0, max = 100, indeterminate, className, ...props }) {
|
|
4
|
-
const
|
|
3
|
+
function Progress({ value = 0, max = 100, indeterminate, label, className, ...props }) {
|
|
4
|
+
const clamped = Math.max(0, Math.min(max || 100, value));
|
|
5
|
+
const pct = clamped / (max || 100) * 100;
|
|
5
6
|
return /* @__PURE__ */ jsx(
|
|
6
7
|
"div",
|
|
7
8
|
{
|
|
8
9
|
role: "progressbar",
|
|
9
10
|
"aria-valuemin": 0,
|
|
10
11
|
"aria-valuemax": max,
|
|
11
|
-
"aria-valuenow": indeterminate ? void 0 :
|
|
12
|
+
"aria-valuenow": indeterminate ? void 0 : clamped,
|
|
13
|
+
"aria-label": label,
|
|
12
14
|
className: cx("uix-progress", indeterminate && "uix-progress--indeterminate", className),
|
|
13
15
|
...props,
|
|
14
16
|
children: /* @__PURE__ */ jsx("div", { className: "uix-progress__bar", style: indeterminate ? void 0 : { width: `${pct}%` } })
|
|
@@ -8,7 +8,9 @@ declare const Radio: react.ForwardRefExoticComponent<RadioProps & react.RefAttri
|
|
|
8
8
|
interface RadioGroupProps {
|
|
9
9
|
children: ReactNode;
|
|
10
10
|
className?: string;
|
|
11
|
+
/** Group name; when set the group renders as fieldset/legend so it's announced with each radio. */
|
|
12
|
+
label?: ReactNode;
|
|
11
13
|
}
|
|
12
|
-
declare function RadioGroup({ children, className }: RadioGroupProps): react.JSX.Element;
|
|
14
|
+
declare function RadioGroup({ children, className, label }: RadioGroupProps): react.JSX.Element;
|
|
13
15
|
|
|
14
16
|
export { Radio, RadioGroup, type RadioGroupProps, type RadioProps };
|
package/dist/components/Radio.js
CHANGED
|
@@ -9,8 +9,12 @@ const Radio = forwardRef(
|
|
|
9
9
|
] })
|
|
10
10
|
);
|
|
11
11
|
Radio.displayName = "Radio";
|
|
12
|
-
function RadioGroup({ children, className }) {
|
|
13
|
-
return /* @__PURE__ */ jsx("div", { className: cx("uix-radio-group", className), children });
|
|
12
|
+
function RadioGroup({ children, className, label }) {
|
|
13
|
+
if (label == null) return /* @__PURE__ */ jsx("div", { className: cx("uix-radio-group", className), children });
|
|
14
|
+
return /* @__PURE__ */ jsxs("fieldset", { className: cx("uix-radio-group", className), children: [
|
|
15
|
+
/* @__PURE__ */ jsx("legend", { className: "uix-radio-group__legend", children: label }),
|
|
16
|
+
children
|
|
17
|
+
] });
|
|
14
18
|
}
|
|
15
19
|
export {
|
|
16
20
|
Radio,
|
|
@@ -4,7 +4,9 @@ import { HTMLAttributes } from 'react';
|
|
|
4
4
|
interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {
|
|
5
5
|
size?: 'md' | 'lg';
|
|
6
6
|
accent?: boolean;
|
|
7
|
+
/** Announced loading text (default "Loading…"). */
|
|
8
|
+
label?: string;
|
|
7
9
|
}
|
|
8
|
-
declare function Spinner({ size, accent, className, ...props }: SpinnerProps): react.JSX.Element;
|
|
10
|
+
declare function Spinner({ size, accent, label, className, ...props }: SpinnerProps): react.JSX.Element;
|
|
9
11
|
|
|
10
12
|
export { Spinner, type SpinnerProps };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from "../cx.js";
|
|
3
|
-
function Spinner({ size = "md", accent, className, ...props }) {
|
|
3
|
+
function Spinner({ size = "md", accent, label, className, ...props }) {
|
|
4
4
|
return /* @__PURE__ */ jsx(
|
|
5
5
|
"span",
|
|
6
6
|
{
|
|
7
7
|
className: cx("uix-spinner", accent && "uix-spinner--accent", size === "lg" && "uix-spinner--lg", className),
|
|
8
8
|
role: "status",
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
...props,
|
|
10
|
+
children: /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: label ?? "Loading\u2026" })
|
|
11
11
|
}
|
|
12
12
|
);
|
|
13
13
|
}
|
package/dist/components/Stat.js
CHANGED
|
@@ -8,7 +8,11 @@ function Stat({ label, value, icon, meta, trend, className, ...props }) {
|
|
|
8
8
|
] }),
|
|
9
9
|
/* @__PURE__ */ jsx("div", { className: "uix-stat__value", children: value }),
|
|
10
10
|
(meta != null || trend != null) && /* @__PURE__ */ jsxs("div", { className: "uix-stat__meta", children: [
|
|
11
|
-
trend != null && /* @__PURE__ */
|
|
11
|
+
trend != null && /* @__PURE__ */ jsxs("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`), children: [
|
|
12
|
+
/* @__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" }) }),
|
|
13
|
+
/* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: trend.direction === "up" ? "up" : "down" }),
|
|
14
|
+
trend.label
|
|
15
|
+
] }),
|
|
12
16
|
meta
|
|
13
17
|
] })
|
|
14
18
|
] });
|
|
@@ -49,6 +49,7 @@ interface LoadingStateProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
49
49
|
/** Number of skeleton rows to render. */
|
|
50
50
|
rows?: number;
|
|
51
51
|
density?: 'compact' | 'comfortable';
|
|
52
|
+
/** Announced loading text (default "Loading"). */
|
|
52
53
|
label?: string;
|
|
53
54
|
}
|
|
54
55
|
/** A stack of skeleton rows for list/section loading. `role="status"`. */
|
|
@@ -52,7 +52,13 @@ function Skeleton({ variant = "block", width, height, className, style, ...props
|
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
function LoadingState({ rows = 3, density = "comfortable", label, className, ...props }) {
|
|
55
|
-
return
|
|
55
|
+
return (
|
|
56
|
+
// no aria-busy: busy=true tells AT the region isn't ready and suppresses the announcement (UIX-A11Y-4)
|
|
57
|
+
/* @__PURE__ */ jsxs("div", { className: cx("uix-stack", density === "compact" && "uix-stack--compact", className), role: "status", ...props, children: [
|
|
58
|
+
/* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: label ?? "Loading" }),
|
|
59
|
+
Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx(Skeleton, { variant: "text", width: `${92 - i % 3 * 14}%` }, i))
|
|
60
|
+
] })
|
|
61
|
+
);
|
|
56
62
|
}
|
|
57
63
|
export {
|
|
58
64
|
EmptyState,
|
|
@@ -2,6 +2,11 @@ import * as react from 'react';
|
|
|
2
2
|
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, TdHTMLAttributes, TableHTMLAttributes, ThHTMLAttributes } from 'react';
|
|
3
3
|
|
|
4
4
|
interface TableWrapProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/**
|
|
6
|
+
* Polite live-region text for table state changes — "Sorted by …", "N results",
|
|
7
|
+
* "N selected". Pass `useTable().announcement` straight through (UIX-A11Y-2).
|
|
8
|
+
*/
|
|
9
|
+
announcement?: string;
|
|
5
10
|
children?: ReactNode;
|
|
6
11
|
}
|
|
7
12
|
declare const TableWrap: react.ForwardRefExoticComponent<TableWrapProps & react.RefAttributes<HTMLDivElement>>;
|
|
@@ -53,9 +58,11 @@ interface RowActionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
53
58
|
declare function RowAction({ children, className, type, ...props }: RowActionProps): react.JSX.Element;
|
|
54
59
|
interface ExpandToggleProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
55
60
|
expanded?: boolean;
|
|
61
|
+
/** id of the detail row this toggle controls → `aria-controls` (UIX-A11Y-2). */
|
|
62
|
+
controls?: string;
|
|
56
63
|
}
|
|
57
64
|
/** Chevron button that expands/collapses an inline detail row. */
|
|
58
|
-
declare function ExpandToggle({ expanded, className, type, ...props }: ExpandToggleProps): react.JSX.Element;
|
|
65
|
+
declare function ExpandToggle({ expanded, controls, className, type, ...props }: ExpandToggleProps): react.JSX.Element;
|
|
59
66
|
/** Emphasised primary cell text. */
|
|
60
67
|
declare function CellStrong({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
|
|
61
68
|
/** Secondary line under a primary cell value (muted, meta size). */
|
package/dist/components/Table.js
CHANGED
|
@@ -2,8 +2,11 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef } from "react";
|
|
3
3
|
import { cx } from "../cx.js";
|
|
4
4
|
import { highlightSegments } from "../table-engine.js";
|
|
5
|
-
const TableWrap = forwardRef(function TableWrap2({ children, className, ...props }, ref) {
|
|
6
|
-
return /* @__PURE__ */
|
|
5
|
+
const TableWrap = forwardRef(function TableWrap2({ announcement, children, className, ...props }, ref) {
|
|
6
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: cx("uix-table-wrap", className), ...props, children: [
|
|
7
|
+
announcement != null && /* @__PURE__ */ jsx("div", { role: "status", className: "uix-visually-hidden", children: announcement }),
|
|
8
|
+
children
|
|
9
|
+
] });
|
|
7
10
|
});
|
|
8
11
|
function Table({
|
|
9
12
|
density = "standard",
|
|
@@ -42,9 +45,9 @@ function Th({ sortable, sortDirection, sortOrder, onSort, className, children, o
|
|
|
42
45
|
"data-sort": sortable || void 0,
|
|
43
46
|
"data-sort-order": sortOrder != null && sortOrder > 0 ? sortOrder : void 0,
|
|
44
47
|
"aria-sort": sortDirection && sortDirection !== "none" ? sortDirection : void 0,
|
|
45
|
-
onClick: sortable
|
|
48
|
+
onClick: sortable && onSort ? void 0 : onClick,
|
|
46
49
|
...props,
|
|
47
|
-
children
|
|
50
|
+
children: sortable ? /* @__PURE__ */ jsx("button", { type: "button", className: "uix-th__sortbtn", onClick: onSort, children }) : children
|
|
48
51
|
}
|
|
49
52
|
);
|
|
50
53
|
}
|
|
@@ -56,7 +59,7 @@ function Tr({ selected, pinned, className, children, ...props }) {
|
|
|
56
59
|
"tr",
|
|
57
60
|
{
|
|
58
61
|
className,
|
|
59
|
-
"
|
|
62
|
+
"data-selected": selected || void 0,
|
|
60
63
|
"data-pinned": pinned || void 0,
|
|
61
64
|
...props,
|
|
62
65
|
children
|
|
@@ -79,13 +82,14 @@ function RowActions({ children, className, ...props }) {
|
|
|
79
82
|
function RowAction({ children, className, type = "button", ...props }) {
|
|
80
83
|
return /* @__PURE__ */ jsx("button", { type, className: cx("uix-rowact", className), ...props, children });
|
|
81
84
|
}
|
|
82
|
-
function ExpandToggle({ expanded, className, type = "button", ...props }) {
|
|
85
|
+
function ExpandToggle({ expanded, controls, className, type = "button", ...props }) {
|
|
83
86
|
return /* @__PURE__ */ jsx(
|
|
84
87
|
"button",
|
|
85
88
|
{
|
|
86
89
|
type,
|
|
87
90
|
className: cx("uix-table__expand", className),
|
|
88
91
|
"aria-expanded": expanded,
|
|
92
|
+
"aria-controls": controls,
|
|
89
93
|
"aria-label": expanded ? "Collapse row" : "Expand row",
|
|
90
94
|
...props,
|
|
91
95
|
children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M6 4l4 4-4 4" }) })
|