@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
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from "../cx.js";
|
|
3
|
-
function Progress({ value = 0, max = 100, indeterminate,
|
|
4
|
-
const
|
|
5
|
-
const pct = clamped / (max || 100) * 100;
|
|
3
|
+
function Progress({ value = 0, max = 100, indeterminate, className, ...props }) {
|
|
4
|
+
const pct = Math.max(0, Math.min(100, value / (max || 100) * 100));
|
|
6
5
|
return /* @__PURE__ */ jsx(
|
|
7
6
|
"div",
|
|
8
7
|
{
|
|
9
8
|
role: "progressbar",
|
|
10
9
|
"aria-valuemin": 0,
|
|
11
10
|
"aria-valuemax": max,
|
|
12
|
-
"aria-valuenow": indeterminate ? void 0 :
|
|
13
|
-
"aria-label": label,
|
|
11
|
+
"aria-valuenow": indeterminate ? void 0 : value,
|
|
14
12
|
className: cx("uix-progress", indeterminate && "uix-progress--indeterminate", className),
|
|
15
13
|
...props,
|
|
16
14
|
children: /* @__PURE__ */ jsx("div", { className: "uix-progress__bar", style: indeterminate ? void 0 : { width: `${pct}%` } })
|
|
@@ -8,9 +8,7 @@ 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;
|
|
13
11
|
}
|
|
14
|
-
declare function RadioGroup({ children, className
|
|
12
|
+
declare function RadioGroup({ children, className }: RadioGroupProps): react.JSX.Element;
|
|
15
13
|
|
|
16
14
|
export { Radio, RadioGroup, type RadioGroupProps, type RadioProps };
|
package/dist/components/Radio.js
CHANGED
|
@@ -9,12 +9,8 @@ const Radio = forwardRef(
|
|
|
9
9
|
] })
|
|
10
10
|
);
|
|
11
11
|
Radio.displayName = "Radio";
|
|
12
|
-
function RadioGroup({ children, className
|
|
13
|
-
|
|
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
|
-
] });
|
|
12
|
+
function RadioGroup({ children, className }) {
|
|
13
|
+
return /* @__PURE__ */ jsx("div", { className: cx("uix-radio-group", className), children });
|
|
18
14
|
}
|
|
19
15
|
export {
|
|
20
16
|
Radio,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import { createContext, useContext } from "react";
|
|
3
|
+
import { createContext, useContext, useMemo } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
const SegmentedCtx = createContext({});
|
|
6
6
|
function Segmented({ value, onChange, children, className, ...props }) {
|
|
7
|
-
|
|
7
|
+
const contextValue = useMemo(() => ({ value, onChange }), [value, onChange]);
|
|
8
|
+
return /* @__PURE__ */ jsx(SegmentedCtx.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { role: "group", className: cx("uix-segmented", className), ...props, children }) });
|
|
8
9
|
}
|
|
9
10
|
function SegmentedOption({
|
|
10
11
|
value,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
const ChevronIcon = () => /* @__PURE__ */ jsx("svg", { className: "uix-navgroup__chevron", 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" }) });
|
|
6
6
|
function Sidebar({ collapsed, onToggle, brand, toggleIcon, children, className, ...props }) {
|
|
@@ -55,14 +55,12 @@ function NavItem({ icon, badge, active, as: Tag = "a", children, className, ...p
|
|
|
55
55
|
}
|
|
56
56
|
function NavGroup({ icon, label, children, defaultExpanded = true }) {
|
|
57
57
|
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
58
|
-
const panelId = useId();
|
|
59
58
|
return /* @__PURE__ */ jsxs("div", { className: "uix-navgroup", children: [
|
|
60
59
|
/* @__PURE__ */ jsxs(
|
|
61
60
|
"button",
|
|
62
61
|
{
|
|
63
62
|
className: "uix-navitem uix-navgroup__trigger",
|
|
64
63
|
"aria-expanded": expanded,
|
|
65
|
-
"aria-controls": panelId,
|
|
66
64
|
onClick: () => setExpanded((v) => !v),
|
|
67
65
|
children: [
|
|
68
66
|
icon && /* @__PURE__ */ jsx("span", { className: "uix-navitem__icon", "aria-hidden": "true", children: icon }),
|
|
@@ -71,7 +69,7 @@ function NavGroup({ icon, label, children, defaultExpanded = true }) {
|
|
|
71
69
|
]
|
|
72
70
|
}
|
|
73
71
|
),
|
|
74
|
-
/* @__PURE__ */ jsx("div", { className: "uix-navgroup__panel",
|
|
72
|
+
/* @__PURE__ */ jsx("div", { className: "uix-navgroup__panel", children: /* @__PURE__ */ jsx("div", { children }) })
|
|
75
73
|
] });
|
|
76
74
|
}
|
|
77
75
|
function SubNavItem({ active, as: Tag = "a", children, className, ...props }) {
|
|
@@ -4,9 +4,7 @@ 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;
|
|
9
7
|
}
|
|
10
|
-
declare function Spinner({ size, accent,
|
|
8
|
+
declare function Spinner({ size, accent, className, ...props }: SpinnerProps): react.JSX.Element;
|
|
11
9
|
|
|
12
10
|
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,
|
|
3
|
+
function Spinner({ size = "md", accent, 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
|
+
"aria-label": "Loading",
|
|
10
|
+
...props
|
|
11
11
|
}
|
|
12
12
|
);
|
|
13
13
|
}
|
package/dist/components/Stat.js
CHANGED
|
@@ -8,11 +8,7 @@ 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__ */
|
|
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
|
-
] }),
|
|
11
|
+
trend != null && /* @__PURE__ */ jsx("span", { className: cx("uix-stat__trend", `uix-stat__trend--${trend.direction}`), children: trend.label }),
|
|
16
12
|
meta
|
|
17
13
|
] })
|
|
18
14
|
] });
|
|
@@ -31,10 +31,8 @@ declare function Skeleton({ variant, width, height, className, style, ...props }
|
|
|
31
31
|
interface LoadingStateProps extends HTMLAttributes<HTMLDivElement> {
|
|
32
32
|
/** Number of skeleton rows to render. */
|
|
33
33
|
rows?: number;
|
|
34
|
-
/** Announced loading text (default "Loading"). */
|
|
35
|
-
label?: string;
|
|
36
34
|
}
|
|
37
35
|
/** A stack of skeleton rows for list/section loading. `role="status"`. */
|
|
38
|
-
declare function LoadingState({ rows,
|
|
36
|
+
declare function LoadingState({ rows, className, ...props }: LoadingStateProps): react.JSX.Element;
|
|
39
37
|
|
|
40
38
|
export { EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, LoadingState, type LoadingStateProps, Skeleton, type SkeletonProps };
|
|
@@ -32,14 +32,8 @@ function Skeleton({ variant = "block", width, height, className, style, ...props
|
|
|
32
32
|
}
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
|
-
function LoadingState({ rows = 3,
|
|
36
|
-
return (
|
|
37
|
-
// no aria-busy: busy=true tells AT the region isn't ready and suppresses the announcement (UIX-A11Y-4)
|
|
38
|
-
/* @__PURE__ */ jsxs("div", { className: cx("uix-stack", className), role: "status", ...props, children: [
|
|
39
|
-
/* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: label ?? "Loading" }),
|
|
40
|
-
Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx(Skeleton, { variant: "text", width: `${92 - i % 3 * 14}%` }, i))
|
|
41
|
-
] })
|
|
42
|
-
);
|
|
35
|
+
function LoadingState({ rows = 3, className, ...props }) {
|
|
36
|
+
return /* @__PURE__ */ jsx("div", { className: cx("uix-stack", className), role: "status", "aria-busy": "true", ...props, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx(Skeleton, { variant: "text", width: `${92 - i % 3 * 14}%` }, i)) });
|
|
43
37
|
}
|
|
44
38
|
export {
|
|
45
39
|
EmptyState,
|
|
@@ -2,14 +2,9 @@ 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;
|
|
10
5
|
children?: ReactNode;
|
|
11
6
|
}
|
|
12
|
-
declare
|
|
7
|
+
declare const TableWrap: react.ForwardRefExoticComponent<TableWrapProps & react.RefAttributes<HTMLDivElement>>;
|
|
13
8
|
type TableDensity = 'compact' | 'standard' | 'comfortable';
|
|
14
9
|
type SortDirection = 'ascending' | 'descending' | 'none';
|
|
15
10
|
interface TableProps extends TableHTMLAttributes<HTMLTableElement> {
|
|
@@ -58,11 +53,9 @@ interface RowActionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
58
53
|
declare function RowAction({ children, className, type, ...props }: RowActionProps): react.JSX.Element;
|
|
59
54
|
interface ExpandToggleProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
60
55
|
expanded?: boolean;
|
|
61
|
-
/** id of the detail row this toggle controls → `aria-controls` (UIX-A11Y-2). */
|
|
62
|
-
controls?: string;
|
|
63
56
|
}
|
|
64
57
|
/** Chevron button that expands/collapses an inline detail row. */
|
|
65
|
-
declare function ExpandToggle({ expanded,
|
|
58
|
+
declare function ExpandToggle({ expanded, className, type, ...props }: ExpandToggleProps): react.JSX.Element;
|
|
66
59
|
/** Emphasised primary cell text. */
|
|
67
60
|
declare function CellStrong({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
|
|
68
61
|
/** Secondary line under a primary cell value (muted, meta size). */
|
package/dist/components/Table.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
2
3
|
import { cx } from "../cx.js";
|
|
3
4
|
import { highlightSegments } from "../table-engine.js";
|
|
4
|
-
|
|
5
|
-
return /* @__PURE__ */
|
|
6
|
-
|
|
7
|
-
children
|
|
8
|
-
] });
|
|
9
|
-
}
|
|
5
|
+
const TableWrap = forwardRef(function TableWrap2({ children, className, ...props }, ref) {
|
|
6
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cx("uix-table-wrap", className), ...props, children });
|
|
7
|
+
});
|
|
10
8
|
function Table({
|
|
11
9
|
density = "standard",
|
|
12
10
|
zebra = true,
|
|
@@ -44,9 +42,9 @@ function Th({ sortable, sortDirection, sortOrder, onSort, className, children, o
|
|
|
44
42
|
"data-sort": sortable || void 0,
|
|
45
43
|
"data-sort-order": sortOrder != null && sortOrder > 0 ? sortOrder : void 0,
|
|
46
44
|
"aria-sort": sortDirection && sortDirection !== "none" ? sortDirection : void 0,
|
|
47
|
-
onClick: sortable
|
|
45
|
+
onClick: sortable ? onSort ?? onClick : onClick,
|
|
48
46
|
...props,
|
|
49
|
-
children
|
|
47
|
+
children
|
|
50
48
|
}
|
|
51
49
|
);
|
|
52
50
|
}
|
|
@@ -58,7 +56,7 @@ function Tr({ selected, pinned, className, children, ...props }) {
|
|
|
58
56
|
"tr",
|
|
59
57
|
{
|
|
60
58
|
className,
|
|
61
|
-
"
|
|
59
|
+
"aria-selected": selected || void 0,
|
|
62
60
|
"data-pinned": pinned || void 0,
|
|
63
61
|
...props,
|
|
64
62
|
children
|
|
@@ -81,14 +79,13 @@ function RowActions({ children, className, ...props }) {
|
|
|
81
79
|
function RowAction({ children, className, type = "button", ...props }) {
|
|
82
80
|
return /* @__PURE__ */ jsx("button", { type, className: cx("uix-rowact", className), ...props, children });
|
|
83
81
|
}
|
|
84
|
-
function ExpandToggle({ expanded,
|
|
82
|
+
function ExpandToggle({ expanded, className, type = "button", ...props }) {
|
|
85
83
|
return /* @__PURE__ */ jsx(
|
|
86
84
|
"button",
|
|
87
85
|
{
|
|
88
86
|
type,
|
|
89
87
|
className: cx("uix-table__expand", className),
|
|
90
88
|
"aria-expanded": expanded,
|
|
91
|
-
"aria-controls": controls,
|
|
92
89
|
"aria-label": expanded ? "Collapse row" : "Expand row",
|
|
93
90
|
...props,
|
|
94
91
|
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" }) })
|
|
@@ -15,17 +15,5 @@ interface TabProps extends Omit<HTMLAttributes<HTMLButtonElement>, 'onChange'> {
|
|
|
15
15
|
disabled?: boolean;
|
|
16
16
|
}
|
|
17
17
|
declare function Tab({ value, children, disabled, className, onClick, ...props }: TabProps): react.JSX.Element;
|
|
18
|
-
interface TabPanelProps extends HTMLAttributes<HTMLDivElement> {
|
|
19
|
-
/** The owning `<Tab>`'s value — the panel renders only while that tab is selected. */
|
|
20
|
-
value: string;
|
|
21
|
-
children?: ReactNode;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* The tabpanel paired with a `<Tab>` by `value` (UIX-A11Y-2): labelled by its tab,
|
|
25
|
-
* `tabIndex 0` so Tab from the tablist lands in the content, rendered only while
|
|
26
|
-
* selected. Place it as a direct child of `<Tabs>` — it is hoisted out of the tablist —
|
|
27
|
-
* or anywhere the Tabs context reaches.
|
|
28
|
-
*/
|
|
29
|
-
declare function TabPanel({ value, children, ...props }: TabPanelProps): react.JSX.Element | null;
|
|
30
18
|
|
|
31
|
-
export { Tab,
|
|
19
|
+
export { Tab, type TabProps, Tabs, type TabsProps };
|
package/dist/components/Tabs.js
CHANGED
|
@@ -1,66 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx
|
|
3
|
-
import {
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useMemo } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
const TabsCtx = createContext({});
|
|
6
6
|
function Tabs({ variant = "line", value, onChange, children, className }) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const kids = Children.toArray(children);
|
|
10
|
-
const panels = kids.filter((k) => isValidElement(k) && k.type === TabPanel);
|
|
11
|
-
const tabs = kids.filter((k) => !(isValidElement(k) && k.type === TabPanel));
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
const list = listRef.current;
|
|
14
|
-
if (!list) return;
|
|
15
|
-
const all = Array.from(list.querySelectorAll('[role="tab"]'));
|
|
16
|
-
const enabled = all.filter((t) => !t.matches(":disabled"));
|
|
17
|
-
const active = enabled.find((t) => t.getAttribute("aria-selected") === "true") ?? enabled[0];
|
|
18
|
-
for (const t of all) t.tabIndex = t === active ? 0 : -1;
|
|
19
|
-
});
|
|
20
|
-
const onKeyDown = (e) => {
|
|
21
|
-
const items = Array.from(
|
|
22
|
-
listRef.current?.querySelectorAll('[role="tab"]:not(:disabled)') ?? []
|
|
23
|
-
);
|
|
24
|
-
const cur = e.target.closest('[role="tab"]');
|
|
25
|
-
const idx = cur ? items.indexOf(cur) : -1;
|
|
26
|
-
if (idx < 0 || items.length === 0) return;
|
|
27
|
-
let next;
|
|
28
|
-
switch (e.key) {
|
|
29
|
-
case "ArrowRight":
|
|
30
|
-
next = (idx + 1) % items.length;
|
|
31
|
-
break;
|
|
32
|
-
case "ArrowLeft":
|
|
33
|
-
next = (idx - 1 + items.length) % items.length;
|
|
34
|
-
break;
|
|
35
|
-
case "Home":
|
|
36
|
-
next = 0;
|
|
37
|
-
break;
|
|
38
|
-
case "End":
|
|
39
|
-
next = items.length - 1;
|
|
40
|
-
break;
|
|
41
|
-
default:
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
e.preventDefault();
|
|
45
|
-
const target = items[next];
|
|
46
|
-
if (target) {
|
|
47
|
-
target.focus();
|
|
48
|
-
target.click();
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
return /* @__PURE__ */ jsxs(TabsCtx.Provider, { value: { value, onChange, baseId }, children: [
|
|
52
|
-
/* @__PURE__ */ jsx(
|
|
53
|
-
"div",
|
|
54
|
-
{
|
|
55
|
-
ref: listRef,
|
|
56
|
-
role: "tablist",
|
|
57
|
-
className: cx("uix-tabs", `uix-tabs--${variant}`, className),
|
|
58
|
-
onKeyDown,
|
|
59
|
-
children: tabs
|
|
60
|
-
}
|
|
61
|
-
),
|
|
62
|
-
panels
|
|
63
|
-
] });
|
|
7
|
+
const contextValue = useMemo(() => ({ value, onChange }), [value, onChange]);
|
|
8
|
+
return /* @__PURE__ */ jsx(TabsCtx.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { role: "tablist", className: cx("uix-tabs", `uix-tabs--${variant}`, className), children }) });
|
|
64
9
|
}
|
|
65
10
|
function Tab({ value, children, disabled, className, onClick, ...props }) {
|
|
66
11
|
const ctx = useContext(TabsCtx);
|
|
@@ -69,11 +14,8 @@ function Tab({ value, children, disabled, className, onClick, ...props }) {
|
|
|
69
14
|
"button",
|
|
70
15
|
{
|
|
71
16
|
role: "tab",
|
|
72
|
-
id: ctx.baseId ? `${ctx.baseId}-tab-${value}` : void 0,
|
|
73
|
-
"aria-controls": ctx.baseId ? `${ctx.baseId}-panel-${value}` : void 0,
|
|
74
17
|
className: cx("uix-tab", className),
|
|
75
18
|
"aria-selected": selected,
|
|
76
|
-
tabIndex: selected ? 0 : -1,
|
|
77
19
|
disabled,
|
|
78
20
|
onClick: (e) => {
|
|
79
21
|
ctx.onChange?.(value);
|
|
@@ -84,23 +26,7 @@ function Tab({ value, children, disabled, className, onClick, ...props }) {
|
|
|
84
26
|
}
|
|
85
27
|
);
|
|
86
28
|
}
|
|
87
|
-
function TabPanel({ value, children, ...props }) {
|
|
88
|
-
const ctx = useContext(TabsCtx);
|
|
89
|
-
if (ctx.value !== value) return null;
|
|
90
|
-
return /* @__PURE__ */ jsx(
|
|
91
|
-
"div",
|
|
92
|
-
{
|
|
93
|
-
role: "tabpanel",
|
|
94
|
-
id: ctx.baseId ? `${ctx.baseId}-panel-${value}` : void 0,
|
|
95
|
-
"aria-labelledby": ctx.baseId ? `${ctx.baseId}-tab-${value}` : void 0,
|
|
96
|
-
tabIndex: 0,
|
|
97
|
-
...props,
|
|
98
|
-
children
|
|
99
|
-
}
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
29
|
export {
|
|
103
30
|
Tab,
|
|
104
|
-
TabPanel,
|
|
105
31
|
Tabs
|
|
106
32
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
-
interface TimelineProps extends HTMLAttributes<
|
|
4
|
+
interface TimelineProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
5
|
children?: ReactNode;
|
|
6
6
|
}
|
|
7
|
-
/** Activity timeline container over `.uix-timeline`.
|
|
7
|
+
/** Activity timeline container over `.uix-timeline`. */
|
|
8
8
|
declare function Timeline({ children, className, ...props }: TimelineProps): react.JSX.Element;
|
|
9
|
-
interface TimelineItemProps extends HTMLAttributes<
|
|
9
|
+
interface TimelineItemProps extends HTMLAttributes<HTMLDivElement> {
|
|
10
10
|
/**
|
|
11
11
|
* Custom rail node — an icon puck, an avatar, a tinted dot. Defaults to the
|
|
12
12
|
* accent `.uix-timeline__node` dot. Supply this to make a heterogeneous feed
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from "../cx.js";
|
|
3
3
|
function Timeline({ children, className, ...props }) {
|
|
4
|
-
return /* @__PURE__ */ jsx("
|
|
4
|
+
return /* @__PURE__ */ jsx("div", { className: cx("uix-timeline", className), ...props, children });
|
|
5
5
|
}
|
|
6
6
|
function TimelineItem({ node, meta, children, className, ...props }) {
|
|
7
|
-
return /* @__PURE__ */ jsxs("
|
|
8
|
-
/* @__PURE__ */ jsxs("div", { className: "uix-timeline__rail",
|
|
7
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("uix-timeline__item", className), ...props, children: [
|
|
8
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-timeline__rail", children: [
|
|
9
9
|
node ?? /* @__PURE__ */ jsx("span", { className: "uix-timeline__node" }),
|
|
10
10
|
/* @__PURE__ */ jsx("span", { className: "uix-timeline__line" })
|
|
11
11
|
] }),
|
package/dist/components/Toast.js
CHANGED
|
@@ -1,65 +1,28 @@
|
|
|
1
|
-
"use client";
|
|
2
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
4
2
|
import { cx } from "../cx.js";
|
|
5
|
-
const ToasterContext = createContext(null);
|
|
6
3
|
function Toast({ title, message, tone, icon, onClose, leaving, className, ...props }) {
|
|
7
4
|
const assertive = tone === "danger";
|
|
8
|
-
const toaster = useContext(ToasterContext);
|
|
9
|
-
const bodyRef = useRef(null);
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
if (assertive || !toaster) return;
|
|
12
|
-
const text = bodyRef.current?.textContent?.trim();
|
|
13
|
-
if (text) toaster.announce(text);
|
|
14
|
-
}, []);
|
|
15
|
-
const handleClose = (e) => {
|
|
16
|
-
const btn = e.currentTarget;
|
|
17
|
-
if (document.activeElement === btn) {
|
|
18
|
-
const toasterEl = btn.closest(".uix-toaster");
|
|
19
|
-
if (toasterEl) {
|
|
20
|
-
const closes = Array.from(toasterEl.querySelectorAll(".uix-toast__close"));
|
|
21
|
-
const i = closes.indexOf(btn);
|
|
22
|
-
(closes[i + 1] ?? closes[i - 1])?.focus();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
onClose?.();
|
|
26
|
-
};
|
|
27
|
-
const ownLiveRegion = assertive || !toaster;
|
|
28
5
|
return /* @__PURE__ */ jsxs(
|
|
29
6
|
"div",
|
|
30
7
|
{
|
|
31
8
|
className: cx("uix-toast", tone && `uix-toast--${tone}`, className),
|
|
32
9
|
"data-leaving": leaving || void 0,
|
|
33
|
-
role:
|
|
34
|
-
"aria-live":
|
|
10
|
+
role: assertive ? "alert" : "status",
|
|
11
|
+
"aria-live": assertive ? "assertive" : "polite",
|
|
35
12
|
...props,
|
|
36
13
|
children: [
|
|
37
14
|
icon && /* @__PURE__ */ jsx("div", { className: "uix-toast__icon", "aria-hidden": "true", children: icon }),
|
|
38
|
-
/* @__PURE__ */ jsxs("div", { className: "uix-toast__body",
|
|
15
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-toast__body", children: [
|
|
39
16
|
title && /* @__PURE__ */ jsx("div", { className: "uix-toast__title", children: title }),
|
|
40
17
|
message && /* @__PURE__ */ jsx("div", { className: "uix-toast__msg", children: message })
|
|
41
18
|
] }),
|
|
42
|
-
onClose && /* @__PURE__ */ jsx("button", { className: "uix-toast__close", onClick:
|
|
19
|
+
onClose && /* @__PURE__ */ jsx("button", { className: "uix-toast__close", onClick: onClose, "aria-label": "Dismiss", children: "\xD7" })
|
|
43
20
|
]
|
|
44
21
|
}
|
|
45
22
|
);
|
|
46
23
|
}
|
|
47
24
|
function Toaster({ children, className, ...props }) {
|
|
48
|
-
|
|
49
|
-
const clearTimer = useRef(null);
|
|
50
|
-
const announce = useCallback((text) => {
|
|
51
|
-
setAnnounced((cur) => cur ? `${cur} ${text}` : text);
|
|
52
|
-
if (clearTimer.current != null) clearTimeout(clearTimer.current);
|
|
53
|
-
clearTimer.current = window.setTimeout(() => setAnnounced(""), 3e3);
|
|
54
|
-
}, []);
|
|
55
|
-
useEffect(() => () => {
|
|
56
|
-
if (clearTimer.current != null) clearTimeout(clearTimer.current);
|
|
57
|
-
}, []);
|
|
58
|
-
const ctx = useMemo(() => ({ announce }), [announce]);
|
|
59
|
-
return /* @__PURE__ */ jsx(ToasterContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxs("div", { className: cx("uix-toaster", className), role: "region", "aria-label": "Notifications", ...props, children: [
|
|
60
|
-
/* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", role: "status", "aria-live": "polite", children: announced }),
|
|
61
|
-
children
|
|
62
|
-
] }) });
|
|
25
|
+
return /* @__PURE__ */ jsx("div", { className: cx("uix-toaster", className), ...props, children });
|
|
63
26
|
}
|
|
64
27
|
export {
|
|
65
28
|
Toast,
|
|
@@ -13,9 +13,7 @@ interface TooltipProps extends HTMLAttributes<HTMLSpanElement> {
|
|
|
13
13
|
* Tooltip whose bubble renders in the top layer via the native Popover API, so it
|
|
14
14
|
* escapes any `overflow: hidden/scroll` ancestor that would clip the old CSS-only
|
|
15
15
|
* `[data-uix-tip]` tooltip (UIX-FIX-02). Positioned by the shared overlay engine
|
|
16
|
-
* (flip/shift), shown on hover and keyboard focus, dismissed on blur or Escape
|
|
17
|
-
* (document-level, per WCAG 1.4.13), and hoverable: the bubble stays open while
|
|
18
|
-
* the pointer is over it (UIX-A11Y-1).
|
|
16
|
+
* (flip/shift), shown on hover and keyboard focus, dismissed on blur or Escape.
|
|
19
17
|
*/
|
|
20
18
|
declare function Tooltip({ label, placement, className, children, ...props }: TooltipProps): react.JSX.Element;
|
|
21
19
|
|
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
import { useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
6
6
|
function Tooltip({ label, placement = "top", className, children, ...props }) {
|
|
7
7
|
const triggerRef = useRef(null);
|
|
8
8
|
const bubbleRef = useRef(null);
|
|
9
|
-
const closeTimer = useRef(null);
|
|
10
9
|
const [open, setOpen] = useState(false);
|
|
11
10
|
const id = useId();
|
|
12
11
|
useAnchoredPosition(triggerRef, bubbleRef, { open, placement, offset: 6 });
|
|
13
|
-
const cancelClose = () => {
|
|
14
|
-
if (closeTimer.current != null) {
|
|
15
|
-
clearTimeout(closeTimer.current);
|
|
16
|
-
closeTimer.current = null;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
12
|
const show = () => {
|
|
20
|
-
cancelClose();
|
|
21
13
|
const b = bubbleRef.current;
|
|
22
14
|
if (b && !b.matches(":popover-open")) {
|
|
23
15
|
try {
|
|
@@ -28,7 +20,6 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
|
|
|
28
20
|
setOpen(true);
|
|
29
21
|
};
|
|
30
22
|
const hide = () => {
|
|
31
|
-
cancelClose();
|
|
32
23
|
const b = bubbleRef.current;
|
|
33
24
|
if (b && b.matches(":popover-open")) {
|
|
34
25
|
try {
|
|
@@ -38,20 +29,7 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
|
|
|
38
29
|
}
|
|
39
30
|
setOpen(false);
|
|
40
31
|
};
|
|
41
|
-
const scheduleHide = () => {
|
|
42
|
-
cancelClose();
|
|
43
|
-
closeTimer.current = window.setTimeout(hide, 100);
|
|
44
|
-
};
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
if (!open) return;
|
|
47
|
-
const onKey = (e) => {
|
|
48
|
-
if (e.key === "Escape") hide();
|
|
49
|
-
};
|
|
50
|
-
document.addEventListener("keydown", onKey);
|
|
51
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
52
|
-
}, [open]);
|
|
53
32
|
useEffect(() => () => {
|
|
54
|
-
if (closeTimer.current != null) clearTimeout(closeTimer.current);
|
|
55
33
|
const b = bubbleRef.current;
|
|
56
34
|
if (b && b.matches(":popover-open")) {
|
|
57
35
|
try {
|
|
@@ -61,19 +39,14 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
|
|
|
61
39
|
}
|
|
62
40
|
}, []);
|
|
63
41
|
const bubbleAttr = { popover: "manual" };
|
|
64
|
-
const single = isValidElement(children);
|
|
65
|
-
const child = single ? cloneElement(children, {
|
|
66
|
-
"aria-describedby": [children.props["aria-describedby"], id].filter(Boolean).join(" ")
|
|
67
|
-
}) : children;
|
|
68
42
|
return /* @__PURE__ */ jsxs(
|
|
69
43
|
"span",
|
|
70
44
|
{
|
|
71
45
|
ref: triggerRef,
|
|
72
46
|
className: cx("uix-tooltip", className),
|
|
73
|
-
"aria-describedby":
|
|
74
|
-
tabIndex: single ? void 0 : 0,
|
|
47
|
+
"aria-describedby": id,
|
|
75
48
|
onMouseEnter: show,
|
|
76
|
-
onMouseLeave:
|
|
49
|
+
onMouseLeave: hide,
|
|
77
50
|
onFocus: show,
|
|
78
51
|
onBlur: hide,
|
|
79
52
|
onKeyDown: (e) => {
|
|
@@ -81,20 +54,8 @@ function Tooltip({ label, placement = "top", className, children, ...props }) {
|
|
|
81
54
|
},
|
|
82
55
|
...props,
|
|
83
56
|
children: [
|
|
84
|
-
|
|
85
|
-
/* @__PURE__ */ jsx(
|
|
86
|
-
"span",
|
|
87
|
-
{
|
|
88
|
-
ref: bubbleRef,
|
|
89
|
-
id,
|
|
90
|
-
role: "tooltip",
|
|
91
|
-
className: "uix-tooltip__bubble",
|
|
92
|
-
onMouseEnter: cancelClose,
|
|
93
|
-
onMouseLeave: scheduleHide,
|
|
94
|
-
...bubbleAttr,
|
|
95
|
-
children: label
|
|
96
|
-
}
|
|
97
|
-
)
|
|
57
|
+
children,
|
|
58
|
+
/* @__PURE__ */ jsx("span", { ref: bubbleRef, id, role: "tooltip", className: "uix-tooltip__bubble", ...bubbleAttr, children: label })
|
|
98
59
|
]
|
|
99
60
|
}
|
|
100
61
|
);
|
|
@@ -4,8 +4,6 @@ import { HTMLAttributes, ReactNode } from 'react';
|
|
|
4
4
|
interface TreeNodeData {
|
|
5
5
|
id: string;
|
|
6
6
|
label: ReactNode;
|
|
7
|
-
/** Plain-text label for keyboard typeahead when `label` is not a string (UIX-A11Y-2). */
|
|
8
|
-
typeaheadLabel?: string;
|
|
9
7
|
icon?: ReactNode;
|
|
10
8
|
children?: TreeNodeData[];
|
|
11
9
|
}
|