@tensor_1/react 2.14.2 → 2.16.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 +41 -9
- 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 +41 -9
- package/dist/chart.d.cts +2 -2
- package/dist/chart.d.ts +1 -1
- package/dist/chart.js +4 -1
- package/dist/combobox-model.d.ts +9 -0
- package/dist/combobox-model.js +10 -0
- package/dist/components/AsyncOperationStatus.d.ts +16 -0
- package/dist/components/AsyncOperationStatus.js +24 -0
- package/dist/components/Breadcrumbs.d.ts +18 -0
- package/dist/components/Breadcrumbs.js +14 -0
- package/dist/components/Card.d.ts +11 -2
- package/dist/components/Card.js +16 -1
- 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 +38 -9
- package/dist/components/CollapsibleSection.d.ts +11 -0
- package/dist/components/CollapsibleSection.js +17 -0
- package/dist/components/Combobox.d.ts +19 -0
- package/dist/components/Combobox.js +120 -0
- package/dist/components/DetailPage.d.ts +33 -0
- package/dist/components/DetailPage.js +19 -0
- package/dist/components/Dialogs.d.ts +35 -0
- package/dist/components/Dialogs.js +55 -0
- package/dist/components/Flow.d.ts +26 -0
- package/dist/components/Flow.js +48 -0
- package/dist/components/Modal.d.ts +3 -1
- package/dist/components/Modal.js +6 -4
- package/dist/components/Pipeline.d.ts +25 -0
- package/dist/components/Pipeline.js +65 -0
- package/dist/components/RelatedLinks.d.ts +16 -0
- package/dist/components/RelatedLinks.js +14 -0
- package/dist/components/RelativeTime.d.ts +23 -0
- package/dist/components/RelativeTime.js +40 -0
- package/dist/components/Sidebar.d.ts +7 -2
- package/dist/components/Sidebar.js +27 -9
- package/dist/components/States.d.ts +23 -4
- package/dist/components/States.js +28 -6
- package/dist/components/TableControls.d.ts +77 -0
- package/dist/components/TableControls.js +61 -0
- package/dist/components/ToggleRow.d.ts +14 -0
- package/dist/components/ToggleRow.js +16 -0
- package/dist/index.cjs +1392 -786
- package/dist/index.d.cts +323 -8
- package/dist/index.d.ts +16 -2
- package/dist/index.js +40 -2
- package/dist/relative-time-clock.d.ts +4 -0
- package/dist/relative-time-clock.js +33 -0
- package/dist/relative-time-model.d.ts +9 -0
- package/dist/relative-time-model.js +16 -0
- package/package.json +1 -1
- package/dist/ChartCore-Bt1C84ty.d.cts +0 -22
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "../cx.js";
|
|
3
|
+
function CollapsibleSection({ title, summary, children, className, ...props }) {
|
|
4
|
+
return /* @__PURE__ */ jsxs("details", { className: cx("uix-collapsible", className), ...props, children: [
|
|
5
|
+
/* @__PURE__ */ jsxs("summary", { className: "uix-collapsible__summary", children: [
|
|
6
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
7
|
+
/* @__PURE__ */ jsx("span", { className: "uix-collapsible__title", children: title }),
|
|
8
|
+
summary != null && /* @__PURE__ */ jsx("span", { className: "uix-collapsible__meta", children: summary })
|
|
9
|
+
] }),
|
|
10
|
+
/* @__PURE__ */ jsx("span", { className: "uix-collapsible__chevron", "aria-hidden": "true", children: "\u2304" })
|
|
11
|
+
] }),
|
|
12
|
+
/* @__PURE__ */ jsx("div", { className: "uix-collapsible__body", children })
|
|
13
|
+
] });
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
CollapsibleSection
|
|
17
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes } from 'react';
|
|
3
|
+
import { ComboboxOption } from '../combobox-model.js';
|
|
4
|
+
|
|
5
|
+
interface ComboboxProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
6
|
+
options: readonly ComboboxOption[];
|
|
7
|
+
value?: string;
|
|
8
|
+
defaultValue?: string;
|
|
9
|
+
onValueChange?: (value: string, option: ComboboxOption) => void;
|
|
10
|
+
label: string;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
emptyLabel: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Searchable single-select combobox with keyboard navigation and no framework dependencies. */
|
|
17
|
+
declare function Combobox({ options, value, defaultValue, onValueChange, label, placeholder, emptyLabel, name, disabled, className, ...props }: ComboboxProps): react.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { Combobox, ComboboxOption, type ComboboxProps };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { cx } from "../cx.js";
|
|
5
|
+
import { filterComboboxOptions } from "../combobox-model.js";
|
|
6
|
+
function Combobox({
|
|
7
|
+
options,
|
|
8
|
+
value,
|
|
9
|
+
defaultValue,
|
|
10
|
+
onValueChange,
|
|
11
|
+
label,
|
|
12
|
+
placeholder,
|
|
13
|
+
emptyLabel,
|
|
14
|
+
name,
|
|
15
|
+
disabled,
|
|
16
|
+
className,
|
|
17
|
+
...props
|
|
18
|
+
}) {
|
|
19
|
+
const generatedId = useId();
|
|
20
|
+
const listboxId = `${generatedId}-listbox`;
|
|
21
|
+
const rootRef = useRef(null);
|
|
22
|
+
const [internalValue, setInternalValue] = useState(defaultValue ?? "");
|
|
23
|
+
const selectedValue = value ?? internalValue;
|
|
24
|
+
const selected = options.find((option) => option.value === selectedValue);
|
|
25
|
+
const [query, setQuery] = useState(selected?.label ?? "");
|
|
26
|
+
const [open, setOpen] = useState(false);
|
|
27
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
28
|
+
const filtered = useMemo(() => filterComboboxOptions(options, open ? query : ""), [open, options, query]);
|
|
29
|
+
const activeOption = filtered[activeIndex];
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!open) setQuery(options.find((option) => option.value === selectedValue)?.label ?? "");
|
|
32
|
+
}, [open, options, selectedValue]);
|
|
33
|
+
const select = (option) => {
|
|
34
|
+
if (option.disabled) return;
|
|
35
|
+
if (value == null) setInternalValue(option.value);
|
|
36
|
+
setQuery(option.label);
|
|
37
|
+
setOpen(false);
|
|
38
|
+
onValueChange?.(option.value, option);
|
|
39
|
+
};
|
|
40
|
+
const move = (step) => {
|
|
41
|
+
if (!filtered.length) return;
|
|
42
|
+
let next = activeIndex;
|
|
43
|
+
for (let attempts = 0; attempts < filtered.length; attempts += 1) {
|
|
44
|
+
next = (next + step + filtered.length) % filtered.length;
|
|
45
|
+
if (!filtered[next]?.disabled) break;
|
|
46
|
+
}
|
|
47
|
+
setActiveIndex(next);
|
|
48
|
+
};
|
|
49
|
+
const handleKeyDown = (event) => {
|
|
50
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
if (!open) setOpen(true);
|
|
53
|
+
else move(event.key === "ArrowDown" ? 1 : -1);
|
|
54
|
+
} else if (event.key === "Enter" && open && activeOption) {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
select(activeOption);
|
|
57
|
+
} else if (event.key === "Escape") {
|
|
58
|
+
setOpen(false);
|
|
59
|
+
setQuery(selected?.label ?? "");
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const handleBlur = (event) => {
|
|
63
|
+
if (!rootRef.current?.contains(event.relatedTarget)) {
|
|
64
|
+
setOpen(false);
|
|
65
|
+
setQuery(options.find((option) => option.value === selectedValue)?.label ?? "");
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const handleChange = (event) => {
|
|
69
|
+
setQuery(event.target.value);
|
|
70
|
+
setActiveIndex(0);
|
|
71
|
+
setOpen(true);
|
|
72
|
+
};
|
|
73
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cx("uix-combobox", className), onBlur: handleBlur, ...props, children: [
|
|
74
|
+
name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: selectedValue }),
|
|
75
|
+
/* @__PURE__ */ jsx(
|
|
76
|
+
"input",
|
|
77
|
+
{
|
|
78
|
+
className: "uix-input",
|
|
79
|
+
role: "combobox",
|
|
80
|
+
"aria-label": label,
|
|
81
|
+
"aria-autocomplete": "list",
|
|
82
|
+
"aria-expanded": open,
|
|
83
|
+
"aria-controls": listboxId,
|
|
84
|
+
"aria-activedescendant": open && activeOption ? `${listboxId}-${activeIndex}` : void 0,
|
|
85
|
+
value: query,
|
|
86
|
+
placeholder,
|
|
87
|
+
disabled,
|
|
88
|
+
onChange: handleChange,
|
|
89
|
+
onFocus: () => {
|
|
90
|
+
setQuery("");
|
|
91
|
+
setOpen(true);
|
|
92
|
+
setActiveIndex(Math.max(0, options.findIndex((option) => option.value === selectedValue)));
|
|
93
|
+
},
|
|
94
|
+
onKeyDown: handleKeyDown
|
|
95
|
+
}
|
|
96
|
+
),
|
|
97
|
+
open && /* @__PURE__ */ jsxs("ul", { id: listboxId, className: "uix-listbox uix-combobox__listbox", role: "listbox", children: [
|
|
98
|
+
filtered.length === 0 && /* @__PURE__ */ jsx("li", { className: "uix-listbox__empty", children: emptyLabel }),
|
|
99
|
+
filtered.map((option, index) => /* @__PURE__ */ jsx(
|
|
100
|
+
"li",
|
|
101
|
+
{
|
|
102
|
+
id: `${listboxId}-${index}`,
|
|
103
|
+
className: "uix-listbox__option",
|
|
104
|
+
role: "option",
|
|
105
|
+
"aria-selected": option.value === selectedValue,
|
|
106
|
+
"aria-disabled": option.disabled || void 0,
|
|
107
|
+
"data-active": index === activeIndex || void 0,
|
|
108
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
109
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
110
|
+
onClick: () => select(option),
|
|
111
|
+
children: option.label
|
|
112
|
+
},
|
|
113
|
+
option.value
|
|
114
|
+
))
|
|
115
|
+
] })
|
|
116
|
+
] });
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
Combobox
|
|
120
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface DetailPageTab {
|
|
5
|
+
id: string;
|
|
6
|
+
label: ReactNode;
|
|
7
|
+
href: string;
|
|
8
|
+
active?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface DetailPageMetric {
|
|
11
|
+
id: string;
|
|
12
|
+
label: ReactNode;
|
|
13
|
+
value: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
interface DetailPageProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
|
|
16
|
+
back?: {
|
|
17
|
+
href: string;
|
|
18
|
+
label: ReactNode;
|
|
19
|
+
};
|
|
20
|
+
eyebrow?: ReactNode;
|
|
21
|
+
title: ReactNode;
|
|
22
|
+
subtitle?: ReactNode;
|
|
23
|
+
actions?: ReactNode;
|
|
24
|
+
tabs?: readonly DetailPageTab[];
|
|
25
|
+
metrics?: readonly DetailPageMetric[];
|
|
26
|
+
side?: ReactNode;
|
|
27
|
+
children?: ReactNode;
|
|
28
|
+
tabsLabel?: string;
|
|
29
|
+
}
|
|
30
|
+
/** Framework-neutral record-detail scaffold; routing and data policy stay with the application. */
|
|
31
|
+
declare function DetailPage({ back, eyebrow, title, subtitle, actions, tabs, metrics, side, children, tabsLabel, className, ...props }: DetailPageProps): react.JSX.Element;
|
|
32
|
+
|
|
33
|
+
export { DetailPage, type DetailPageMetric, type DetailPageProps, type DetailPageTab };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "../cx.js";
|
|
3
|
+
import { DetailLayout } from "./DetailLayout.js";
|
|
4
|
+
import { PageHeader } from "./PageHeader.js";
|
|
5
|
+
function DetailPage({ back, eyebrow, title, subtitle, actions, tabs, metrics, side, children, tabsLabel, className, ...props }) {
|
|
6
|
+
return /* @__PURE__ */ jsxs("section", { className: cx("uix-detail-page", className), ...props, children: [
|
|
7
|
+
back && /* @__PURE__ */ jsx("a", { className: "uix-link uix-link--quiet uix-detail-page__back", href: back.href, children: back.label }),
|
|
8
|
+
/* @__PURE__ */ jsx(PageHeader, { eyebrow, title, subtitle, actions }),
|
|
9
|
+
metrics && metrics.length > 0 && /* @__PURE__ */ jsx("dl", { className: "uix-detail-page__metrics", children: metrics.map((metric) => /* @__PURE__ */ jsxs("div", { children: [
|
|
10
|
+
/* @__PURE__ */ jsx("dt", { children: metric.label }),
|
|
11
|
+
/* @__PURE__ */ jsx("dd", { children: metric.value })
|
|
12
|
+
] }, metric.id)) }),
|
|
13
|
+
tabs && tabs.length > 0 && /* @__PURE__ */ jsx("nav", { className: "uix-tabs", "aria-label": tabsLabel, children: tabs.map((tab) => /* @__PURE__ */ jsx("a", { className: "uix-tab", "aria-current": tab.active ? "page" : void 0, href: tab.href, children: tab.label }, tab.id)) }),
|
|
14
|
+
/* @__PURE__ */ jsx(DetailLayout, { side, children })
|
|
15
|
+
] });
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
DetailPage
|
|
19
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ConfirmDialogProps {
|
|
5
|
+
open: boolean;
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
confirmLabel: ReactNode;
|
|
9
|
+
cancelLabel: ReactNode;
|
|
10
|
+
closeLabel: string;
|
|
11
|
+
onConfirm: () => void | Promise<void>;
|
|
12
|
+
onCancel: () => void;
|
|
13
|
+
pending?: boolean;
|
|
14
|
+
destructive?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Generic confirmation shell. Audit, authorization and compensation policy remain application-owned. */
|
|
17
|
+
declare function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, closeLabel, onConfirm, onCancel, pending, destructive }: ConfirmDialogProps): react.JSX.Element;
|
|
18
|
+
interface PromptDialogProps {
|
|
19
|
+
open: boolean;
|
|
20
|
+
title: ReactNode;
|
|
21
|
+
description?: ReactNode;
|
|
22
|
+
inputLabel: string;
|
|
23
|
+
defaultValue?: string;
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
submitLabel: ReactNode;
|
|
26
|
+
cancelLabel: ReactNode;
|
|
27
|
+
closeLabel: string;
|
|
28
|
+
onSubmit: (value: string) => void | Promise<void>;
|
|
29
|
+
onCancel: () => void;
|
|
30
|
+
validate?: (value: string) => ReactNode | undefined;
|
|
31
|
+
pending?: boolean;
|
|
32
|
+
}
|
|
33
|
+
declare function PromptDialog({ open, title, description, inputLabel, defaultValue, placeholder, submitLabel, cancelLabel, closeLabel, onSubmit, onCancel, validate, pending }: PromptDialogProps): react.JSX.Element;
|
|
34
|
+
|
|
35
|
+
export { ConfirmDialog, type ConfirmDialogProps, PromptDialog, type PromptDialogProps };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useState } from "react";
|
|
4
|
+
import { Button } from "./Button.js";
|
|
5
|
+
import { Input } from "./Input.js";
|
|
6
|
+
import { Modal } from "./Modal.js";
|
|
7
|
+
function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, closeLabel, onConfirm, onCancel, pending, destructive }) {
|
|
8
|
+
return /* @__PURE__ */ jsx(
|
|
9
|
+
Modal,
|
|
10
|
+
{
|
|
11
|
+
open,
|
|
12
|
+
onClose: onCancel,
|
|
13
|
+
title,
|
|
14
|
+
closeLabel,
|
|
15
|
+
role: "alertdialog",
|
|
16
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17
|
+
/* @__PURE__ */ jsx(Button, { type: "button", onClick: onCancel, disabled: pending, children: cancelLabel }),
|
|
18
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: destructive ? "danger" : "primary", onClick: () => void onConfirm(), loading: pending, children: confirmLabel })
|
|
19
|
+
] }),
|
|
20
|
+
children: description
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
function PromptDialog({ open, title, description, inputLabel, defaultValue = "", placeholder, submitLabel, cancelLabel, closeLabel, onSubmit, onCancel, validate, pending }) {
|
|
25
|
+
const inputId = useId();
|
|
26
|
+
const errorId = `${inputId}-error`;
|
|
27
|
+
const [value, setValue] = useState(defaultValue);
|
|
28
|
+
const [error, setError] = useState();
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (open) {
|
|
31
|
+
setValue(defaultValue);
|
|
32
|
+
setError(void 0);
|
|
33
|
+
}
|
|
34
|
+
}, [defaultValue, open]);
|
|
35
|
+
const handleSubmit = (event) => {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
const issue = validate?.(value);
|
|
38
|
+
setError(issue);
|
|
39
|
+
if (issue == null) void onSubmit(value);
|
|
40
|
+
};
|
|
41
|
+
return /* @__PURE__ */ jsx(Modal, { open, onClose: onCancel, title, closeLabel, children: /* @__PURE__ */ jsxs("form", { className: "uix-prompt", onSubmit: handleSubmit, children: [
|
|
42
|
+
description != null && /* @__PURE__ */ jsx("div", { children: description }),
|
|
43
|
+
/* @__PURE__ */ jsx("label", { className: "uix-label", htmlFor: inputId, children: inputLabel }),
|
|
44
|
+
/* @__PURE__ */ jsx(Input, { id: inputId, value, placeholder, "aria-describedby": error ? errorId : void 0, invalid: error != null, onChange: (event) => setValue(event.currentTarget.value), autoFocus: true }),
|
|
45
|
+
error != null && /* @__PURE__ */ jsx("div", { id: errorId, className: "uix-field__error", role: "alert", children: error }),
|
|
46
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-dialog__footer uix-prompt__actions", children: [
|
|
47
|
+
/* @__PURE__ */ jsx(Button, { type: "button", onClick: onCancel, disabled: pending, children: cancelLabel }),
|
|
48
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", variant: "primary", loading: pending, children: submitLabel })
|
|
49
|
+
] })
|
|
50
|
+
] }) });
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
ConfirmDialog,
|
|
54
|
+
PromptDialog
|
|
55
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type FlowVariant = 'linear' | 'branch' | 'loop' | 'mindmap' | 'canvas';
|
|
5
|
+
type FlowNodeState = 'pending' | 'active' | 'running' | 'done' | 'error';
|
|
6
|
+
interface FlowProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
variant?: FlowVariant;
|
|
8
|
+
panel?: boolean;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/** Presentational workflow surface. Consumers provide graph geometry and connectors. */
|
|
12
|
+
declare function Flow({ variant, panel, children, className, role, ...props }: FlowProps): react.JSX.Element;
|
|
13
|
+
interface FlowNodeProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
14
|
+
title: ReactNode;
|
|
15
|
+
state?: FlowNodeState;
|
|
16
|
+
stateLabel?: ReactNode;
|
|
17
|
+
eyebrow?: ReactNode;
|
|
18
|
+
meta?: ReactNode;
|
|
19
|
+
icon?: ReactNode;
|
|
20
|
+
footer?: ReactNode;
|
|
21
|
+
wide?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Workflow node with explicit text state and optional operational metadata. */
|
|
24
|
+
declare function FlowNode({ title, state, stateLabel, eyebrow, meta, icon, footer, wide, className, ...props }: FlowNodeProps): react.JSX.Element;
|
|
25
|
+
|
|
26
|
+
export { Flow, FlowNode, type FlowNodeProps, type FlowNodeState, type FlowProps, type FlowVariant };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "../cx.js";
|
|
3
|
+
function Flow({ variant = "linear", panel = false, children, className, role = "group", ...props }) {
|
|
4
|
+
return /* @__PURE__ */ jsx(
|
|
5
|
+
"div",
|
|
6
|
+
{
|
|
7
|
+
className: cx("uix-flow", `uix-flow--${variant}`, panel && "uix-flow--panel", className),
|
|
8
|
+
role,
|
|
9
|
+
...props,
|
|
10
|
+
children
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
const FLOW_STATE_LABELS = {
|
|
15
|
+
pending: "Pending",
|
|
16
|
+
active: "Active",
|
|
17
|
+
running: "Running",
|
|
18
|
+
done: "Done",
|
|
19
|
+
error: "Error"
|
|
20
|
+
};
|
|
21
|
+
function FlowNode({
|
|
22
|
+
title,
|
|
23
|
+
state = "pending",
|
|
24
|
+
stateLabel,
|
|
25
|
+
eyebrow,
|
|
26
|
+
meta,
|
|
27
|
+
icon,
|
|
28
|
+
footer,
|
|
29
|
+
wide = false,
|
|
30
|
+
className,
|
|
31
|
+
...props
|
|
32
|
+
}) {
|
|
33
|
+
const resolvedStateLabel = stateLabel ?? FLOW_STATE_LABELS[state];
|
|
34
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("uix-node", `uix-node--${state}`, icon == null && "uix-node--no-icon", wide && "uix-node--wide", className), ...props, children: [
|
|
35
|
+
icon != null && /* @__PURE__ */ jsx("span", { className: "uix-node__icon", "aria-hidden": "true", children: icon }),
|
|
36
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-node__body", children: [
|
|
37
|
+
eyebrow != null && /* @__PURE__ */ jsx("div", { className: "uix-node__eyebrow", children: eyebrow }),
|
|
38
|
+
/* @__PURE__ */ jsx("div", { className: "uix-node__title", children: title }),
|
|
39
|
+
meta != null && /* @__PURE__ */ jsx("div", { className: "uix-node__meta", children: meta }),
|
|
40
|
+
/* @__PURE__ */ jsx("div", { className: "uix-node__status", children: resolvedStateLabel })
|
|
41
|
+
] }),
|
|
42
|
+
footer != null && /* @__PURE__ */ jsx("div", { className: "uix-node__footer", children: footer })
|
|
43
|
+
] });
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
Flow,
|
|
47
|
+
FlowNode
|
|
48
|
+
};
|
|
@@ -9,7 +9,9 @@ interface ModalProps {
|
|
|
9
9
|
footer?: ReactNode;
|
|
10
10
|
className?: string;
|
|
11
11
|
style?: CSSProperties;
|
|
12
|
+
closeLabel?: string;
|
|
13
|
+
role?: 'dialog' | 'alertdialog';
|
|
12
14
|
}
|
|
13
|
-
declare function Modal({ open, onClose, title, children, footer, className, style }: ModalProps): react.JSX.Element;
|
|
15
|
+
declare function Modal({ open, onClose, title, children, footer, className, style, closeLabel, role }: ModalProps): react.JSX.Element;
|
|
14
16
|
|
|
15
17
|
export { Modal, type ModalProps };
|
package/dist/components/Modal.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
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
|
-
function Modal({ open, onClose, title, children, footer, className, style }) {
|
|
7
|
+
function Modal({ open, onClose, title, children, footer, className, style, closeLabel = "Close dialog", role = "dialog" }) {
|
|
7
8
|
const ref = useDialog(open);
|
|
8
|
-
|
|
9
|
+
const titleId = useId();
|
|
10
|
+
return /* @__PURE__ */ jsxs("dialog", { ref, className: cx("uix-dialog", className), style, onClose, role, "aria-labelledby": title != null ? titleId : void 0, children: [
|
|
9
11
|
(title != null || onClose) && /* @__PURE__ */ jsxs("div", { className: "uix-dialog__header", children: [
|
|
10
|
-
title && /* @__PURE__ */ jsx("div", { className: "uix-dialog__title", children: title }),
|
|
11
|
-
onClose && /* @__PURE__ */ jsx("button", { className: "uix-dialog__close", onClick: onClose, "aria-label":
|
|
12
|
+
title && /* @__PURE__ */ jsx("div", { id: titleId, className: "uix-dialog__title", children: title }),
|
|
13
|
+
onClose && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-dialog__close", onClick: onClose, "aria-label": closeLabel, children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
12
14
|
] }),
|
|
13
15
|
children != null && /* @__PURE__ */ jsx("div", { className: "uix-dialog__body", children }),
|
|
14
16
|
footer != null && /* @__PURE__ */ jsx("div", { className: "uix-dialog__footer", children: footer })
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, HTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
interface RelatedLinkItem {
|
|
5
|
+
id: string;
|
|
6
|
+
label: ReactNode;
|
|
7
|
+
href: string;
|
|
8
|
+
meta?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
interface RelatedLinksProps extends Omit<HTMLAttributes<HTMLElement>, 'title' | 'children'> {
|
|
11
|
+
title?: ReactNode;
|
|
12
|
+
items: readonly RelatedLinkItem[];
|
|
13
|
+
}
|
|
14
|
+
declare function RelatedLinks({ title, items, className, ...props }: RelatedLinksProps): react.JSX.Element;
|
|
15
|
+
|
|
16
|
+
export { type RelatedLinkItem, RelatedLinks, type RelatedLinksProps };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "../cx.js";
|
|
3
|
+
function RelatedLinks({ title, items, className, ...props }) {
|
|
4
|
+
return /* @__PURE__ */ jsxs("section", { className: cx("uix-related-links", className), ...props, children: [
|
|
5
|
+
title != null && /* @__PURE__ */ jsx("h2", { className: "uix-related-links__title", children: title }),
|
|
6
|
+
/* @__PURE__ */ jsx("ul", { className: "uix-related-links__list", children: items.map((item) => /* @__PURE__ */ jsxs("li", { children: [
|
|
7
|
+
/* @__PURE__ */ jsx("a", { className: "uix-link uix-link--quiet", href: item.href, children: item.label }),
|
|
8
|
+
item.meta != null && /* @__PURE__ */ jsx("span", { children: item.meta })
|
|
9
|
+
] }, item.id)) })
|
|
10
|
+
] });
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
RelatedLinks
|
|
14
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface RelativeTimeFormatContext {
|
|
5
|
+
date: Date;
|
|
6
|
+
now: Date;
|
|
7
|
+
locale?: string | readonly string[];
|
|
8
|
+
timeZone?: string;
|
|
9
|
+
}
|
|
10
|
+
interface RelativeTimeProps extends Omit<HTMLAttributes<HTMLTimeElement>, 'children' | 'dateTime'> {
|
|
11
|
+
value: Date | number | string;
|
|
12
|
+
now?: Date | number;
|
|
13
|
+
locale?: string | readonly string[];
|
|
14
|
+
timeZone?: string;
|
|
15
|
+
numeric?: Intl.RelativeTimeFormatNumeric;
|
|
16
|
+
invalidLabel?: ReactNode;
|
|
17
|
+
refreshInterval?: number | false;
|
|
18
|
+
formatter?: (context: RelativeTimeFormatContext) => ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/** Locale-aware relative time with deterministic `now` support for SSR and tests. */
|
|
21
|
+
declare function RelativeTime({ value, now, locale, timeZone, numeric, invalidLabel, refreshInterval, formatter, title, ...props }: RelativeTimeProps): react.JSX.Element;
|
|
22
|
+
|
|
23
|
+
export { RelativeTime, type RelativeTimeFormatContext, type RelativeTimeProps };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
|
4
|
+
import { parseDateValue, relativeTimeValue } from "../relative-time-model.js";
|
|
5
|
+
import { readRelativeClock, subscribeRelativeClock } from "../relative-time-clock.js";
|
|
6
|
+
function RelativeTime({
|
|
7
|
+
value,
|
|
8
|
+
now,
|
|
9
|
+
locale,
|
|
10
|
+
timeZone,
|
|
11
|
+
numeric = "auto",
|
|
12
|
+
invalidLabel = "\u2014",
|
|
13
|
+
refreshInterval = 3e4,
|
|
14
|
+
formatter,
|
|
15
|
+
title,
|
|
16
|
+
...props
|
|
17
|
+
}) {
|
|
18
|
+
const interval = refreshInterval === false ? 0 : Math.max(0, refreshInterval);
|
|
19
|
+
const fixedNow = now == null ? void 0 : new Date(now).getTime();
|
|
20
|
+
const subscribe = useCallback((listener) => fixedNow == null ? subscribeRelativeClock(interval, listener) : () => {
|
|
21
|
+
}, [fixedNow, interval]);
|
|
22
|
+
const getSnapshot = useCallback(() => fixedNow ?? readRelativeClock(interval), [fixedNow, interval]);
|
|
23
|
+
const getServerSnapshot = useCallback(() => fixedNow ?? Date.now(), [fixedNow]);
|
|
24
|
+
const clock = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
25
|
+
const date = useMemo(() => parseDateValue(value), [value]);
|
|
26
|
+
if (!date) return /* @__PURE__ */ jsx("time", { "data-invalid": "true", suppressHydrationWarning: true, ...props, children: invalidLabel });
|
|
27
|
+
const current = new Date(clock);
|
|
28
|
+
const content = formatter ? formatter({ date, now: current, locale, timeZone }) : (() => {
|
|
29
|
+
const relative = relativeTimeValue(date, current);
|
|
30
|
+
if (relative.unit === "day" && Math.abs(relative.value) >= 7) {
|
|
31
|
+
return new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeZone }).format(date);
|
|
32
|
+
}
|
|
33
|
+
return new Intl.RelativeTimeFormat(locale, { numeric }).format(relative.value, relative.unit);
|
|
34
|
+
})();
|
|
35
|
+
const absolute = new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short", timeZone }).format(date);
|
|
36
|
+
return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), title: title ?? absolute, suppressHydrationWarning: true, ...props, children: content });
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
RelativeTime
|
|
40
|
+
};
|
|
@@ -3,12 +3,15 @@ import { ReactNode, AnchorHTMLAttributes, HTMLAttributes } from 'react';
|
|
|
3
3
|
|
|
4
4
|
interface SidebarProps extends HTMLAttributes<HTMLElement> {
|
|
5
5
|
collapsed?: boolean;
|
|
6
|
+
nav?: 'full' | 'rail';
|
|
6
7
|
onToggle?: () => void;
|
|
7
8
|
brand?: ReactNode;
|
|
8
9
|
toggleIcon?: ReactNode;
|
|
9
10
|
children?: ReactNode;
|
|
11
|
+
expandLabel?: string;
|
|
12
|
+
collapseLabel?: string;
|
|
10
13
|
}
|
|
11
|
-
declare function Sidebar({ collapsed, onToggle, brand, toggleIcon, children, className, ...props }: SidebarProps): react.JSX.Element;
|
|
14
|
+
declare function Sidebar({ collapsed, nav, onToggle, brand, toggleIcon, children, expandLabel, collapseLabel, className, ...props }: SidebarProps): react.JSX.Element;
|
|
12
15
|
interface SidebarSectionProps {
|
|
13
16
|
label?: string;
|
|
14
17
|
children?: ReactNode;
|
|
@@ -27,8 +30,10 @@ interface NavGroupProps {
|
|
|
27
30
|
label: ReactNode;
|
|
28
31
|
children?: ReactNode;
|
|
29
32
|
defaultExpanded?: boolean;
|
|
33
|
+
expanded?: boolean;
|
|
34
|
+
onExpandedChange?: (expanded: boolean) => void;
|
|
30
35
|
}
|
|
31
|
-
declare function NavGroup({ icon, label, children, defaultExpanded }: NavGroupProps): react.JSX.Element;
|
|
36
|
+
declare function NavGroup({ icon, label, children, defaultExpanded, expanded: controlledExpanded, onExpandedChange }: NavGroupProps): react.JSX.Element;
|
|
32
37
|
interface SubNavItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
33
38
|
active?: boolean;
|
|
34
39
|
as?: 'a' | 'button';
|