@sentropic/design-system-react 0.1.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 +64 -0
- package/dist/Accordion.d.ts +3 -0
- package/dist/Accordion.d.ts.map +1 -0
- package/dist/Accordion.js +2 -0
- package/dist/Accordion.js.map +1 -0
- package/dist/Alert.d.ts +3 -0
- package/dist/Alert.d.ts.map +1 -0
- package/dist/Alert.js +2 -0
- package/dist/Alert.js.map +1 -0
- package/dist/AreaChart.d.ts +3 -0
- package/dist/AreaChart.d.ts.map +1 -0
- package/dist/AreaChart.js +2 -0
- package/dist/AreaChart.js.map +1 -0
- package/dist/AspectRatio.d.ts +3 -0
- package/dist/AspectRatio.d.ts.map +1 -0
- package/dist/AspectRatio.js +2 -0
- package/dist/AspectRatio.js.map +1 -0
- package/dist/Badge.d.ts +9 -0
- package/dist/Badge.d.ts.map +1 -0
- package/dist/Badge.js +6 -0
- package/dist/Badge.js.map +1 -0
- package/dist/BarChart.d.ts +3 -0
- package/dist/BarChart.d.ts.map +1 -0
- package/dist/BarChart.js +2 -0
- package/dist/BarChart.js.map +1 -0
- package/dist/Breadcrumb.d.ts +3 -0
- package/dist/Breadcrumb.d.ts.map +1 -0
- package/dist/Breadcrumb.js +2 -0
- package/dist/Breadcrumb.js.map +1 -0
- package/dist/Button.d.ts +14 -0
- package/dist/Button.d.ts.map +1 -0
- package/dist/Button.js +6 -0
- package/dist/Button.js.map +1 -0
- package/dist/Card.d.ts +8 -0
- package/dist/Card.d.ts.map +1 -0
- package/dist/Card.js +6 -0
- package/dist/Card.js.map +1 -0
- package/dist/ChatComposer.d.ts +3 -0
- package/dist/ChatComposer.d.ts.map +1 -0
- package/dist/ChatComposer.js +2 -0
- package/dist/ChatComposer.js.map +1 -0
- package/dist/ChatMessage.d.ts +3 -0
- package/dist/ChatMessage.d.ts.map +1 -0
- package/dist/ChatMessage.js +2 -0
- package/dist/ChatMessage.js.map +1 -0
- package/dist/ChatThread.d.ts +3 -0
- package/dist/ChatThread.d.ts.map +1 -0
- package/dist/ChatThread.js +2 -0
- package/dist/ChatThread.js.map +1 -0
- package/dist/Checkbox.d.ts +3 -0
- package/dist/Checkbox.d.ts.map +1 -0
- package/dist/Checkbox.js +2 -0
- package/dist/Checkbox.js.map +1 -0
- package/dist/CodeSnippet.d.ts +3 -0
- package/dist/CodeSnippet.d.ts.map +1 -0
- package/dist/CodeSnippet.js +2 -0
- package/dist/CodeSnippet.js.map +1 -0
- package/dist/Combobox.d.ts +3 -0
- package/dist/Combobox.d.ts.map +1 -0
- package/dist/Combobox.js +2 -0
- package/dist/Combobox.js.map +1 -0
- package/dist/ContentSwitcher.d.ts +3 -0
- package/dist/ContentSwitcher.d.ts.map +1 -0
- package/dist/ContentSwitcher.js +2 -0
- package/dist/ContentSwitcher.js.map +1 -0
- package/dist/CopyButton.d.ts +3 -0
- package/dist/CopyButton.d.ts.map +1 -0
- package/dist/CopyButton.js +2 -0
- package/dist/CopyButton.js.map +1 -0
- package/dist/DataTable.d.ts +3 -0
- package/dist/DataTable.d.ts.map +1 -0
- package/dist/DataTable.js +2 -0
- package/dist/DataTable.js.map +1 -0
- package/dist/DatePicker.d.ts +3 -0
- package/dist/DatePicker.d.ts.map +1 -0
- package/dist/DatePicker.js +2 -0
- package/dist/DatePicker.js.map +1 -0
- package/dist/DonutChart.d.ts +3 -0
- package/dist/DonutChart.d.ts.map +1 -0
- package/dist/DonutChart.js +2 -0
- package/dist/DonutChart.js.map +1 -0
- package/dist/Drawer.d.ts +3 -0
- package/dist/Drawer.d.ts.map +1 -0
- package/dist/Drawer.js +2 -0
- package/dist/Drawer.js.map +1 -0
- package/dist/Dropdown.d.ts +3 -0
- package/dist/Dropdown.d.ts.map +1 -0
- package/dist/Dropdown.js +2 -0
- package/dist/Dropdown.js.map +1 -0
- package/dist/EmptyState.d.ts +3 -0
- package/dist/EmptyState.d.ts.map +1 -0
- package/dist/EmptyState.js +2 -0
- package/dist/EmptyState.js.map +1 -0
- package/dist/FileUploader.d.ts +3 -0
- package/dist/FileUploader.d.ts.map +1 -0
- package/dist/FileUploader.js +2 -0
- package/dist/FileUploader.js.map +1 -0
- package/dist/Footer.d.ts +3 -0
- package/dist/Footer.d.ts.map +1 -0
- package/dist/Footer.js +2 -0
- package/dist/Footer.js.map +1 -0
- package/dist/ForceGraph.d.ts +3 -0
- package/dist/ForceGraph.d.ts.map +1 -0
- package/dist/ForceGraph.js +2 -0
- package/dist/ForceGraph.js.map +1 -0
- package/dist/Form.d.ts +3 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/Form.js +2 -0
- package/dist/Form.js.map +1 -0
- package/dist/FormGroup.d.ts +3 -0
- package/dist/FormGroup.d.ts.map +1 -0
- package/dist/FormGroup.js +2 -0
- package/dist/FormGroup.js.map +1 -0
- package/dist/Header.d.ts +3 -0
- package/dist/Header.d.ts.map +1 -0
- package/dist/Header.js +2 -0
- package/dist/Header.js.map +1 -0
- package/dist/Highlight.d.ts +3 -0
- package/dist/Highlight.d.ts.map +1 -0
- package/dist/Highlight.js +2 -0
- package/dist/Highlight.js.map +1 -0
- package/dist/IconButton.d.ts +3 -0
- package/dist/IconButton.d.ts.map +1 -0
- package/dist/IconButton.js +2 -0
- package/dist/IconButton.js.map +1 -0
- package/dist/InlineLoading.d.ts +3 -0
- package/dist/InlineLoading.d.ts.map +1 -0
- package/dist/InlineLoading.js +2 -0
- package/dist/InlineLoading.js.map +1 -0
- package/dist/Input.d.ts +17 -0
- package/dist/Input.d.ts.map +1 -0
- package/dist/Input.js +11 -0
- package/dist/Input.js.map +1 -0
- package/dist/LanguageSelector.d.ts +3 -0
- package/dist/LanguageSelector.d.ts.map +1 -0
- package/dist/LanguageSelector.js +2 -0
- package/dist/LanguageSelector.js.map +1 -0
- package/dist/LineChart.d.ts +3 -0
- package/dist/LineChart.d.ts.map +1 -0
- package/dist/LineChart.js +2 -0
- package/dist/LineChart.js.map +1 -0
- package/dist/Link.d.ts +3 -0
- package/dist/Link.d.ts.map +1 -0
- package/dist/Link.js +2 -0
- package/dist/Link.js.map +1 -0
- package/dist/LoadingState.d.ts +3 -0
- package/dist/LoadingState.d.ts.map +1 -0
- package/dist/LoadingState.js +2 -0
- package/dist/LoadingState.js.map +1 -0
- package/dist/Menu.d.ts +3 -0
- package/dist/Menu.d.ts.map +1 -0
- package/dist/Menu.js +2 -0
- package/dist/Menu.js.map +1 -0
- package/dist/MenuPopover.d.ts +3 -0
- package/dist/MenuPopover.d.ts.map +1 -0
- package/dist/MenuPopover.js +2 -0
- package/dist/MenuPopover.js.map +1 -0
- package/dist/MenuTriggerButton.d.ts +3 -0
- package/dist/MenuTriggerButton.d.ts.map +1 -0
- package/dist/MenuTriggerButton.js +2 -0
- package/dist/MenuTriggerButton.js.map +1 -0
- package/dist/MessageActions.d.ts +3 -0
- package/dist/MessageActions.d.ts.map +1 -0
- package/dist/MessageActions.js +2 -0
- package/dist/MessageActions.js.map +1 -0
- package/dist/MessageStatusBadge.d.ts +3 -0
- package/dist/MessageStatusBadge.d.ts.map +1 -0
- package/dist/MessageStatusBadge.js +2 -0
- package/dist/MessageStatusBadge.js.map +1 -0
- package/dist/Modal.d.ts +3 -0
- package/dist/Modal.d.ts.map +1 -0
- package/dist/Modal.js +2 -0
- package/dist/Modal.js.map +1 -0
- package/dist/MultiSelect.d.ts +3 -0
- package/dist/MultiSelect.d.ts.map +1 -0
- package/dist/MultiSelect.js +2 -0
- package/dist/MultiSelect.js.map +1 -0
- package/dist/NumberInput.d.ts +3 -0
- package/dist/NumberInput.d.ts.map +1 -0
- package/dist/NumberInput.js +2 -0
- package/dist/NumberInput.js.map +1 -0
- package/dist/OrderedList.d.ts +3 -0
- package/dist/OrderedList.d.ts.map +1 -0
- package/dist/OrderedList.js +2 -0
- package/dist/OrderedList.js.map +1 -0
- package/dist/OverflowMenu.d.ts +3 -0
- package/dist/OverflowMenu.d.ts.map +1 -0
- package/dist/OverflowMenu.js +2 -0
- package/dist/OverflowMenu.js.map +1 -0
- package/dist/Pagination.d.ts +3 -0
- package/dist/Pagination.d.ts.map +1 -0
- package/dist/Pagination.js +2 -0
- package/dist/Pagination.js.map +1 -0
- package/dist/PaginationNav.d.ts +3 -0
- package/dist/PaginationNav.d.ts.map +1 -0
- package/dist/PaginationNav.js +2 -0
- package/dist/PaginationNav.js.map +1 -0
- package/dist/PasswordInput.d.ts +3 -0
- package/dist/PasswordInput.d.ts.map +1 -0
- package/dist/PasswordInput.js +2 -0
- package/dist/PasswordInput.js.map +1 -0
- package/dist/Popover.d.ts +3 -0
- package/dist/Popover.d.ts.map +1 -0
- package/dist/Popover.js +2 -0
- package/dist/Popover.js.map +1 -0
- package/dist/ProgressBar.d.ts +3 -0
- package/dist/ProgressBar.d.ts.map +1 -0
- package/dist/ProgressBar.js +2 -0
- package/dist/ProgressBar.js.map +1 -0
- package/dist/ProgressIndicator.d.ts +3 -0
- package/dist/ProgressIndicator.d.ts.map +1 -0
- package/dist/ProgressIndicator.js +2 -0
- package/dist/ProgressIndicator.js.map +1 -0
- package/dist/Quote.d.ts +3 -0
- package/dist/Quote.d.ts.map +1 -0
- package/dist/Quote.js +2 -0
- package/dist/Quote.js.map +1 -0
- package/dist/Radio.d.ts +3 -0
- package/dist/Radio.d.ts.map +1 -0
- package/dist/Radio.js +2 -0
- package/dist/Radio.js.map +1 -0
- package/dist/ScatterPlot.d.ts +3 -0
- package/dist/ScatterPlot.d.ts.map +1 -0
- package/dist/ScatterPlot.js +2 -0
- package/dist/ScatterPlot.js.map +1 -0
- package/dist/Search.d.ts +3 -0
- package/dist/Search.d.ts.map +1 -0
- package/dist/Search.js +2 -0
- package/dist/Search.js.map +1 -0
- package/dist/Select.d.ts +3 -0
- package/dist/Select.d.ts.map +1 -0
- package/dist/Select.js +2 -0
- package/dist/Select.js.map +1 -0
- package/dist/SideNav.d.ts +3 -0
- package/dist/SideNav.d.ts.map +1 -0
- package/dist/SideNav.js +2 -0
- package/dist/SideNav.js.map +1 -0
- package/dist/SkeletonText.d.ts +3 -0
- package/dist/SkeletonText.d.ts.map +1 -0
- package/dist/SkeletonText.js +2 -0
- package/dist/SkeletonText.js.map +1 -0
- package/dist/SkipLink.d.ts +3 -0
- package/dist/SkipLink.d.ts.map +1 -0
- package/dist/SkipLink.js +2 -0
- package/dist/SkipLink.js.map +1 -0
- package/dist/Slider.d.ts +3 -0
- package/dist/Slider.d.ts.map +1 -0
- package/dist/Slider.js +2 -0
- package/dist/Slider.js.map +1 -0
- package/dist/Sparkline.d.ts +3 -0
- package/dist/Sparkline.d.ts.map +1 -0
- package/dist/Sparkline.js +2 -0
- package/dist/Sparkline.js.map +1 -0
- package/dist/StackedBarChart.d.ts +3 -0
- package/dist/StackedBarChart.d.ts.map +1 -0
- package/dist/StackedBarChart.js +2 -0
- package/dist/StackedBarChart.js.map +1 -0
- package/dist/StreamingMessage.d.ts +3 -0
- package/dist/StreamingMessage.d.ts.map +1 -0
- package/dist/StreamingMessage.js +2 -0
- package/dist/StreamingMessage.js.map +1 -0
- package/dist/StructuredList.d.ts +3 -0
- package/dist/StructuredList.d.ts.map +1 -0
- package/dist/StructuredList.js +2 -0
- package/dist/StructuredList.js.map +1 -0
- package/dist/Switch.d.ts +3 -0
- package/dist/Switch.d.ts.map +1 -0
- package/dist/Switch.js +2 -0
- package/dist/Switch.js.map +1 -0
- package/dist/Table.d.ts +3 -0
- package/dist/Table.d.ts.map +1 -0
- package/dist/Table.js +2 -0
- package/dist/Table.js.map +1 -0
- package/dist/Tabs.d.ts +3 -0
- package/dist/Tabs.d.ts.map +1 -0
- package/dist/Tabs.js +2 -0
- package/dist/Tabs.js.map +1 -0
- package/dist/Tag.d.ts +3 -0
- package/dist/Tag.d.ts.map +1 -0
- package/dist/Tag.js +2 -0
- package/dist/Tag.js.map +1 -0
- package/dist/Textarea.d.ts +3 -0
- package/dist/Textarea.d.ts.map +1 -0
- package/dist/Textarea.js +2 -0
- package/dist/Textarea.js.map +1 -0
- package/dist/ThemeProvider.d.ts +9 -0
- package/dist/ThemeProvider.d.ts.map +1 -0
- package/dist/ThemeProvider.js +23 -0
- package/dist/ThemeProvider.js.map +1 -0
- package/dist/Tile.d.ts +3 -0
- package/dist/Tile.d.ts.map +1 -0
- package/dist/Tile.js +2 -0
- package/dist/Tile.js.map +1 -0
- package/dist/TileGroup.d.ts +3 -0
- package/dist/TileGroup.d.ts.map +1 -0
- package/dist/TileGroup.js +2 -0
- package/dist/TileGroup.js.map +1 -0
- package/dist/Toast.d.ts +3 -0
- package/dist/Toast.d.ts.map +1 -0
- package/dist/Toast.js +2 -0
- package/dist/Toast.js.map +1 -0
- package/dist/Toggle.d.ts +3 -0
- package/dist/Toggle.d.ts.map +1 -0
- package/dist/Toggle.js +2 -0
- package/dist/Toggle.js.map +1 -0
- package/dist/Toggletip.d.ts +3 -0
- package/dist/Toggletip.d.ts.map +1 -0
- package/dist/Toggletip.js +2 -0
- package/dist/Toggletip.js.map +1 -0
- package/dist/Tooltip.d.ts +3 -0
- package/dist/Tooltip.d.ts.map +1 -0
- package/dist/Tooltip.js +2 -0
- package/dist/Tooltip.js.map +1 -0
- package/dist/TreeView.d.ts +3 -0
- package/dist/TreeView.d.ts.map +1 -0
- package/dist/TreeView.js +2 -0
- package/dist/TreeView.js.map +1 -0
- package/dist/UnorderedList.d.ts +3 -0
- package/dist/UnorderedList.d.ts.map +1 -0
- package/dist/UnorderedList.js +2 -0
- package/dist/UnorderedList.js.map +1 -0
- package/dist/catalog.d.ts +716 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +732 -0
- package/dist/catalog.js.map +1 -0
- package/dist/classNames.d.ts +2 -0
- package/dist/classNames.d.ts.map +1 -0
- package/dist/classNames.js +4 -0
- package/dist/classNames.js.map +1 -0
- package/dist/index.d.ts +162 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +6366 -0
- package/package.json +51 -0
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,732 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { classNames } from "./classNames.js";
|
|
4
|
+
const DATA_TONES = [
|
|
5
|
+
"category1",
|
|
6
|
+
"category2",
|
|
7
|
+
"category3",
|
|
8
|
+
"category4",
|
|
9
|
+
"category5",
|
|
10
|
+
"category6",
|
|
11
|
+
"category7",
|
|
12
|
+
"category8",
|
|
13
|
+
];
|
|
14
|
+
function node(value) {
|
|
15
|
+
return typeof value === "function" ? value() : value;
|
|
16
|
+
}
|
|
17
|
+
function text(value) {
|
|
18
|
+
if (value === null || value === undefined)
|
|
19
|
+
return "";
|
|
20
|
+
return String(value);
|
|
21
|
+
}
|
|
22
|
+
function idFrom(item, index, prefix) {
|
|
23
|
+
return item.id ?? item.value ?? `${prefix}-${index}`;
|
|
24
|
+
}
|
|
25
|
+
function optionFrom(item, index) {
|
|
26
|
+
const option = item;
|
|
27
|
+
return {
|
|
28
|
+
value: option.value ?? option.id ?? String(index),
|
|
29
|
+
label: option.label ?? option.value ?? option.id ?? String(index),
|
|
30
|
+
disabled: "disabled" in item ? Boolean(item.disabled) : false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function useControlled(value, defaultValue, onChange) {
|
|
34
|
+
const [local, setLocal] = React.useState(defaultValue);
|
|
35
|
+
return [
|
|
36
|
+
value ?? local,
|
|
37
|
+
(next) => {
|
|
38
|
+
if (value === undefined)
|
|
39
|
+
setLocal(next);
|
|
40
|
+
onChange?.(next);
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
const FOCUSABLE_SELECTOR = [
|
|
45
|
+
"a[href]",
|
|
46
|
+
"button:not([disabled])",
|
|
47
|
+
"input:not([disabled])",
|
|
48
|
+
"select:not([disabled])",
|
|
49
|
+
"textarea:not([disabled])",
|
|
50
|
+
"[tabindex]:not([tabindex='-1'])",
|
|
51
|
+
].join(",");
|
|
52
|
+
function focusableIn(root) {
|
|
53
|
+
if (!root)
|
|
54
|
+
return [];
|
|
55
|
+
return Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
56
|
+
}
|
|
57
|
+
function useBodyScrollLock(active) {
|
|
58
|
+
React.useEffect(() => {
|
|
59
|
+
if (!active)
|
|
60
|
+
return;
|
|
61
|
+
const previous = document.body.style.overflow;
|
|
62
|
+
document.body.style.overflow = "hidden";
|
|
63
|
+
return () => {
|
|
64
|
+
document.body.style.overflow = previous;
|
|
65
|
+
};
|
|
66
|
+
}, [active]);
|
|
67
|
+
}
|
|
68
|
+
function useOutsideMouseDown(active, ref, onOutside) {
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
if (!active)
|
|
71
|
+
return;
|
|
72
|
+
const onMouseDown = (event) => {
|
|
73
|
+
const target = event.target;
|
|
74
|
+
if (target && ref.current && !ref.current.contains(target))
|
|
75
|
+
onOutside();
|
|
76
|
+
};
|
|
77
|
+
document.addEventListener("mousedown", onMouseDown);
|
|
78
|
+
return () => document.removeEventListener("mousedown", onMouseDown);
|
|
79
|
+
}, [active, onOutside, ref]);
|
|
80
|
+
}
|
|
81
|
+
function useEscape(active, onClose) {
|
|
82
|
+
React.useEffect(() => {
|
|
83
|
+
if (!active || !onClose)
|
|
84
|
+
return;
|
|
85
|
+
const onKeyDown = (event) => {
|
|
86
|
+
if (event.key === "Escape") {
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
onClose();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
document.addEventListener("keydown", onKeyDown);
|
|
92
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
93
|
+
}, [active, onClose]);
|
|
94
|
+
}
|
|
95
|
+
function trapTabKey(event, root) {
|
|
96
|
+
if (event.key !== "Tab" || !root || !root.contains(document.activeElement))
|
|
97
|
+
return;
|
|
98
|
+
const focusable = focusableIn(root);
|
|
99
|
+
if (focusable.length === 0) {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
root.focus();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const first = focusable[0];
|
|
105
|
+
const last = focusable[focusable.length - 1];
|
|
106
|
+
if (event.shiftKey && document.activeElement === first) {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
last.focus();
|
|
109
|
+
}
|
|
110
|
+
else if (!event.shiftKey && document.activeElement === last) {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
first.focus();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function moveIndex(index, max, delta) {
|
|
116
|
+
if (max <= 0)
|
|
117
|
+
return -1;
|
|
118
|
+
return (index + delta + max) % max;
|
|
119
|
+
}
|
|
120
|
+
function Field({ label, helperText, errorText, invalid = false, className, children }) {
|
|
121
|
+
const reactId = React.useId();
|
|
122
|
+
const inputId = `st-field-${reactId}`;
|
|
123
|
+
const isInvalid = invalid || Boolean(errorText);
|
|
124
|
+
return (_jsxs("div", { className: classNames("st-field", className), children: [_jsxs("label", { className: "st-field__control", htmlFor: inputId, children: [label ? _jsx("span", { className: "st-field__label", children: label }) : null, children(inputId, isInvalid)] }), errorText ? (_jsx("span", { className: "st-field__error", children: errorText })) : helperText ? (_jsx("span", { className: "st-field__help", children: helperText })) : null] }));
|
|
125
|
+
}
|
|
126
|
+
function renderOptions(options) {
|
|
127
|
+
return options?.map((item, index) => {
|
|
128
|
+
const option = optionFrom(item, index);
|
|
129
|
+
return (_jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value));
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function clamp(value, min, max) {
|
|
133
|
+
return Math.min(max, Math.max(min, value));
|
|
134
|
+
}
|
|
135
|
+
function pct(value, min = 0, max = 100) {
|
|
136
|
+
if (max <= min)
|
|
137
|
+
return 0;
|
|
138
|
+
return clamp(((value - min) / (max - min)) * 100, 0, 100);
|
|
139
|
+
}
|
|
140
|
+
function pointsFrom(values, width, height) {
|
|
141
|
+
const ys = values.map((entry) => (typeof entry === "number" ? entry : entry.y ?? entry.value ?? 0));
|
|
142
|
+
const max = Math.max(...ys, 1);
|
|
143
|
+
return ys
|
|
144
|
+
.map((value, index) => {
|
|
145
|
+
const x = ys.length === 1 ? width / 2 : (index / (ys.length - 1)) * width;
|
|
146
|
+
const y = height - (value / max) * height;
|
|
147
|
+
return `${x},${y}`;
|
|
148
|
+
})
|
|
149
|
+
.join(" ");
|
|
150
|
+
}
|
|
151
|
+
export function Accordion({ items, openIds, defaultOpenIds = [], allowMultiple = true, onChange, className, ...rest }) {
|
|
152
|
+
const [open, setOpen] = useControlled(openIds, defaultOpenIds, onChange);
|
|
153
|
+
const toggle = (id) => {
|
|
154
|
+
const next = open.includes(id) ? open.filter((value) => value !== id) : allowMultiple ? [...open, id] : [id];
|
|
155
|
+
setOpen(next);
|
|
156
|
+
};
|
|
157
|
+
return (_jsx("div", { ...rest, className: classNames("st-accordion", className), children: items.map((item, index) => {
|
|
158
|
+
const itemId = idFrom(item, index, "accordion");
|
|
159
|
+
const isOpen = open.includes(itemId);
|
|
160
|
+
const triggerId = `st-accordion-trigger-${itemId}`;
|
|
161
|
+
const panelId = `st-accordion-panel-${itemId}`;
|
|
162
|
+
return (_jsxs("section", { className: classNames("st-accordion__item", isOpen && "st-accordion__item--open"), children: [_jsx("h3", { className: "st-accordion__heading", children: _jsxs("button", { id: triggerId, type: "button", className: "st-accordion__trigger", disabled: item.disabled, "aria-expanded": isOpen, "aria-controls": panelId, onClick: () => toggle(itemId), children: [_jsx("span", { className: "st-accordion__title", children: item.title }), _jsx("span", { className: "st-accordion__icon", "aria-hidden": "true", children: isOpen ? "-" : "+" })] }) }), isOpen ? (_jsx("div", { className: "st-accordion__panel", id: panelId, role: "region", "aria-labelledby": triggerId, children: node(item.content) })) : null] }, itemId));
|
|
163
|
+
}) }));
|
|
164
|
+
}
|
|
165
|
+
export function Alert({ tone = "info", title, message, actions, children, className, ...rest }) {
|
|
166
|
+
return (_jsxs("section", { ...rest, className: classNames("st-alert", `st-alert--${tone}`, className), role: tone === "warning" || tone === "error" ? "alert" : "status", children: [_jsxs("div", { className: "st-alert__content", children: [_jsx("h2", { className: "st-alert__title", children: title }), message ? _jsx("p", { className: "st-alert__message", children: message }) : null, children] }), actions ? _jsx("div", { className: "st-alert__actions", children: actions }) : null] }));
|
|
167
|
+
}
|
|
168
|
+
function LinearChart({ data, label, width = 320, height = 160, className, type }) {
|
|
169
|
+
const classBase = type === "areaChart" ? "st-areaChart" : "st-lineChart";
|
|
170
|
+
const points = pointsFrom(data, width, height);
|
|
171
|
+
const accessibleLabel = label ?? (type === "areaChart" ? "Area chart" : "Line chart");
|
|
172
|
+
return (_jsxs("figure", { className: classNames(classBase, className), "aria-label": accessibleLabel, children: [_jsx("span", { className: "st-visually-hidden", children: accessibleLabel }), _jsxs("svg", { viewBox: `0 0 `, "aria-hidden": "true", children: [_jsx("polyline", { className: `${classBase}__line`, points: points, fill: "none" }), type === "areaChart" ? _jsx("polygon", { className: "st-areaChart__area", points: `0,${height} ${points} ${width},${height}` }) : null, data.map((datum, index) => (_jsx("circle", { className: `${classBase}__dot`, cx: points.split(" ")[index]?.split(",")[0], cy: points.split(" ")[index]?.split(",")[1], r: "4" }, index)))] })] }));
|
|
173
|
+
}
|
|
174
|
+
export function AreaChart(props) {
|
|
175
|
+
return _jsx(LinearChart, { ...props, type: "areaChart" });
|
|
176
|
+
}
|
|
177
|
+
export function LineChart(props) {
|
|
178
|
+
return _jsx(LinearChart, { ...props, type: "lineChart" });
|
|
179
|
+
}
|
|
180
|
+
export function BarChart({ data, label = "Bar chart", width = 320, height = 160, className, ...rest }) {
|
|
181
|
+
const max = Math.max(...data.map((datum) => datum.value ?? datum.y ?? 0), 1);
|
|
182
|
+
return (_jsxs("figure", { ...rest, className: classNames("st-barChart", className), "aria-label": label, children: [_jsx("span", { className: "st-visually-hidden", children: label }), _jsx("svg", { viewBox: `0 0 `, "aria-hidden": "true", children: data.map((datum, index) => {
|
|
183
|
+
const value = datum.value ?? datum.y ?? 0;
|
|
184
|
+
const barWidth = width / Math.max(data.length, 1) - 8;
|
|
185
|
+
const barHeight = (value / max) * height;
|
|
186
|
+
return (_jsx("rect", { className: classNames("st-barChart__bar", `st-barChart__bar--${datum.tone ?? DATA_TONES[index % DATA_TONES.length]}`), x: index * (barWidth + 8) + 4, y: height - barHeight, width: barWidth, height: barHeight }, index));
|
|
187
|
+
}) })] }));
|
|
188
|
+
}
|
|
189
|
+
export function DonutChart({ data, label = "Donut chart", className, ...rest }) {
|
|
190
|
+
const total = data.reduce((sum, datum) => sum + (datum.value ?? datum.y ?? 0), 0);
|
|
191
|
+
return (_jsxs("figure", { ...rest, className: classNames("st-donutChart", className), "aria-label": label, children: [_jsx("span", { className: "st-visually-hidden", children: label }), _jsxs("svg", { viewBox: "0 0 120 120", "aria-hidden": "true", children: [data.map((datum, index) => (_jsx("circle", { className: classNames("st-donutChart__slice", `st-donutChart__slice--${datum.tone ?? DATA_TONES[index % DATA_TONES.length]}`), cx: "60", cy: "60", r: 36 - index * 3, fill: "none", strokeWidth: "8" }, index))), _jsx("text", { className: "st-donutChart__center", x: "60", y: "64", textAnchor: "middle", children: total })] })] }));
|
|
192
|
+
}
|
|
193
|
+
export function ScatterPlot({ data, label = "Scatter chart", className, ...rest }) {
|
|
194
|
+
return (_jsxs("figure", { ...rest, className: classNames("st-scatterPlot", className), "aria-label": label, children: [_jsx("span", { className: "st-visually-hidden", children: label }), _jsx("svg", { viewBox: "0 0 320 160", "aria-hidden": "true", children: data.map((datum, index) => (_jsx("circle", { className: classNames("st-scatterPlot__point", `st-scatterPlot__point--${datum.tone ?? DATA_TONES[index % DATA_TONES.length]}`), cx: clamp(datum.x * 24 + 24, 12, 308), cy: clamp(148 - datum.y * 24, 12, 148), r: "5", children: _jsx("title", { children: datum.label ?? `${datum.x}, ${datum.y}` }) }, index))) })] }));
|
|
195
|
+
}
|
|
196
|
+
export function StackedBarChart({ data, label = "Stacked bar chart", className, ...rest }) {
|
|
197
|
+
return (_jsxs("figure", { ...rest, className: classNames("st-stackedBar", className), "aria-label": label, children: [_jsx("span", { className: "st-visually-hidden", children: label }), _jsx("svg", { viewBox: "0 0 320 160", "aria-hidden": "true", children: data.map((bar, barIndex) => {
|
|
198
|
+
let x = 16;
|
|
199
|
+
const total = Math.max(bar.segments.reduce((sum, segment) => sum + segment.value, 0), 1);
|
|
200
|
+
return (_jsxs("g", { transform: `translate(0 ${barIndex * 32 + 16})`, children: [bar.segments.map((segment, index) => {
|
|
201
|
+
const width = (segment.value / total) * 220;
|
|
202
|
+
const rect = (_jsx("rect", { className: classNames("st-stackedBar__seg", `st-stackedBar__seg--${segment.tone ?? DATA_TONES[index % DATA_TONES.length]}`), x: x, y: "0", width: width, height: "20" }, segment.label));
|
|
203
|
+
x += width;
|
|
204
|
+
return rect;
|
|
205
|
+
}), _jsx("text", { className: "st-stackedBar__categoryLabel", x: "250", y: "15", children: bar.label })] }, bar.label));
|
|
206
|
+
}) })] }));
|
|
207
|
+
}
|
|
208
|
+
export function AspectRatio({ ratio = "16 / 9", className, style, children, ...rest }) {
|
|
209
|
+
const aspectRatio = typeof ratio === "number" ? String(ratio) : ratio;
|
|
210
|
+
return (_jsx("div", { ...rest, className: classNames("st-aspectRatio", className), style: { aspectRatio, ...style }, children: children }));
|
|
211
|
+
}
|
|
212
|
+
export function Breadcrumb({ items, label = "Breadcrumb", className, ...rest }) {
|
|
213
|
+
return (_jsx("nav", { ...rest, className: classNames("st-breadcrumb", className), "aria-label": label, children: _jsx("ol", { children: items.map((item, index) => (_jsxs("li", { children: [item.href && !item.current ? _jsx("a", { href: item.href, children: item.label }) : _jsx("span", { "aria-current": item.current ? "page" : undefined, children: item.label }), index < items.length - 1 ? _jsx("span", { className: "st-breadcrumb__separator", children: "/" }) : null] }, index))) }) }));
|
|
214
|
+
}
|
|
215
|
+
export function ChatMessage({ role = "assistant", status, content, timestamp, actions, children, className, ...rest }) {
|
|
216
|
+
const normalizedStatus = status === "streaming" ? "processing" : status === "error" ? "failed" : status;
|
|
217
|
+
return (_jsxs("article", { ...rest, className: classNames("st-chatMessage", `st-chatMessage--${role}`, normalizedStatus && `st-chatMessage--${normalizedStatus}`, className), children: [_jsx("div", { className: "st-chatMessage__avatar", "aria-hidden": "true", children: role[0]?.toUpperCase() }), _jsxs("div", { className: "st-chatMessage__body", children: [_jsx("div", { className: "st-chatMessage__bubble", children: _jsx("div", { className: "st-chatMessage__content", children: children ?? content }) }), timestamp || actions ? (_jsxs("footer", { className: "st-chatMessage__footer", children: [timestamp ? _jsx("span", { className: "st-chatMessage__timestamp", children: timestamp }) : null, actions ? _jsx("span", { className: "st-chatMessage__actions", children: actions }) : null] })) : null] })] }));
|
|
218
|
+
}
|
|
219
|
+
export function ChatThread({ messages, emptyLabel = "No messages", children, className, ...rest }) {
|
|
220
|
+
return (_jsx("section", { ...rest, className: classNames("st-chatThread", className), "aria-label": rest["aria-label"] ?? "Chat thread", children: _jsx("div", { className: "st-chatThread__list", children: messages?.length ? messages.map((message) => _jsx(ChatMessage, { role: message.role, status: message.status, content: message.content }, message.id)) : children ?? _jsx("p", { className: "st-chatThread__empty", children: emptyLabel }) }) }));
|
|
221
|
+
}
|
|
222
|
+
export function ChatComposer({ value = "", placeholder = "Message", submitLabel = "Send", onSubmit, className, children, ...rest }) {
|
|
223
|
+
const [draft, setDraft] = React.useState(value);
|
|
224
|
+
return (_jsxs("form", { ...rest, className: classNames("st-chatComposer", className), onSubmit: (event) => {
|
|
225
|
+
event.preventDefault();
|
|
226
|
+
onSubmit?.({ value: draft });
|
|
227
|
+
}, children: [_jsx("div", { className: "st-chatComposer__body", children: _jsx("div", { className: "st-chatComposer__inputShell", children: _jsx("textarea", { className: "st-chatComposer__textarea st-chatComposer__input", placeholder: placeholder, value: draft, onChange: (event) => setDraft(event.currentTarget.value) }) }) }), _jsxs("div", { className: "st-chatComposer__toolbar", children: [_jsx("div", { className: "st-chatComposer__actions st-chatComposer__actions--left", children: children }), _jsx("div", { className: "st-chatComposer__actions st-chatComposer__actions--right", children: _jsx("button", { type: "submit", className: "st-button st-button--primary st-button--sm", children: submitLabel }) })] })] }));
|
|
228
|
+
}
|
|
229
|
+
function Choice({ type, label, helperText, invalid = false, className, ...rest }) {
|
|
230
|
+
return (_jsxs("label", { className: classNames("st-choice", `st-choice--${type}`, className), children: [_jsx("input", { ...rest, className: "st-choice__input", type: type, "aria-invalid": invalid ? "true" : undefined }), _jsxs("span", { className: "st-choice__content", children: [_jsx("span", { className: "st-choice__label", children: label }), helperText ? _jsx("span", { className: "st-choice__help", children: helperText }) : null] })] }));
|
|
231
|
+
}
|
|
232
|
+
export function Checkbox(props) {
|
|
233
|
+
return _jsx(Choice, { ...props, type: "checkbox" });
|
|
234
|
+
}
|
|
235
|
+
export function Radio(props) {
|
|
236
|
+
return _jsx(Choice, { ...props, type: "radio" });
|
|
237
|
+
}
|
|
238
|
+
export function CodeSnippet({ code, inline = false, className, ...rest }) {
|
|
239
|
+
const Tag = inline ? "code" : "pre";
|
|
240
|
+
return (_jsx(Tag, { ...rest, className: classNames("st-codeSnippet", inline && "st-codeSnippet--inline", className), children: _jsx("code", { className: "st-codeSnippet__code", children: code }) }));
|
|
241
|
+
}
|
|
242
|
+
export function Combobox({ label, options, value, size = "md", placeholder = "Select or type", open: controlledOpen, allowCustomValue = true, noResultsLabel = "No results", onChange, onSelect, className, ...rest }) {
|
|
243
|
+
const reactId = React.useId();
|
|
244
|
+
const inputId = `st-combobox-input-${reactId}`;
|
|
245
|
+
const listId = `st-combobox-list-${reactId}`;
|
|
246
|
+
const initial = text(options.find((option) => option.value === value)?.label ?? value ?? "");
|
|
247
|
+
const [inputValue, setInputValue] = React.useState(initial);
|
|
248
|
+
const [open, setOpen] = useControlled(controlledOpen, false);
|
|
249
|
+
const [activeIndex, setActiveIndex] = React.useState(-1);
|
|
250
|
+
const filtered = options.filter((option) => {
|
|
251
|
+
const query = inputValue.trim().toLowerCase();
|
|
252
|
+
return !query || text(option.label).toLowerCase().includes(query);
|
|
253
|
+
});
|
|
254
|
+
const selected = options.find((option) => option.value === value);
|
|
255
|
+
const selectOption = (option) => {
|
|
256
|
+
if (option.disabled)
|
|
257
|
+
return;
|
|
258
|
+
setInputValue(text(option.label));
|
|
259
|
+
setOpen(false);
|
|
260
|
+
setActiveIndex(-1);
|
|
261
|
+
onSelect?.(option.value);
|
|
262
|
+
onChange?.(option.value);
|
|
263
|
+
};
|
|
264
|
+
return (_jsxs("div", { ...rest, className: classNames("st-combobox", `st-combobox--${size}`, className), children: [label ? _jsx("label", { className: "st-field__label", htmlFor: inputId, children: label }) : null, _jsx("input", { id: inputId, className: "st-combobox__control", role: "combobox", "aria-expanded": open, "aria-autocomplete": "list", "aria-controls": listId, "aria-activedescendant": activeIndex >= 0 && filtered[activeIndex] ? `${listId}-${filtered[activeIndex].value}` : undefined, placeholder: placeholder, value: selected?.label ? text(selected.label) : inputValue, onFocus: () => setOpen(true), onChange: (event) => {
|
|
265
|
+
setInputValue(event.currentTarget.value);
|
|
266
|
+
setOpen(true);
|
|
267
|
+
setActiveIndex(-1);
|
|
268
|
+
if (allowCustomValue)
|
|
269
|
+
onChange?.(event.currentTarget.value);
|
|
270
|
+
}, onKeyDown: (event) => {
|
|
271
|
+
if (event.key === "ArrowDown") {
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
setOpen(true);
|
|
274
|
+
setActiveIndex((index) => moveIndex(index, filtered.length, 1));
|
|
275
|
+
}
|
|
276
|
+
else if (event.key === "ArrowUp") {
|
|
277
|
+
event.preventDefault();
|
|
278
|
+
setOpen(true);
|
|
279
|
+
setActiveIndex((index) => moveIndex(index < 0 ? filtered.length : index, filtered.length, -1));
|
|
280
|
+
}
|
|
281
|
+
else if (event.key === "Enter" && open && activeIndex >= 0 && filtered[activeIndex]) {
|
|
282
|
+
event.preventDefault();
|
|
283
|
+
selectOption(filtered[activeIndex]);
|
|
284
|
+
}
|
|
285
|
+
else if (event.key === "Escape" && open) {
|
|
286
|
+
event.preventDefault();
|
|
287
|
+
setOpen(false);
|
|
288
|
+
setActiveIndex(-1);
|
|
289
|
+
}
|
|
290
|
+
} }), selected ? _jsx("span", { className: "st-combobox__value st-visually-hidden", children: selected.label }) : null, open ? (_jsx("ul", { id: listId, className: "st-combobox__list", role: "listbox", "aria-label": text(label) || "Options", children: filtered.length ? (filtered.map((option, index) => (_jsx("li", { id: `${listId}-${option.value}`, className: classNames("st-combobox__option", index === activeIndex && "st-combobox__option--active", option.value === value && "st-combobox__option--selected"), role: "option", "aria-selected": option.value === value, "aria-disabled": option.disabled ? "true" : undefined, onMouseDown: (event) => {
|
|
291
|
+
event.preventDefault();
|
|
292
|
+
selectOption(option);
|
|
293
|
+
}, children: option.label }, option.value)))) : (_jsx("li", { className: "st-combobox__empty", role: "option", "aria-disabled": "true", "aria-selected": "false", children: noResultsLabel })) })) : null] }));
|
|
294
|
+
}
|
|
295
|
+
export function ContentSwitcher({ items, value, activeId, onChange, size = "md", className, ...rest }) {
|
|
296
|
+
const current = value ?? activeId ?? idFrom(items[0] ?? {}, 0, "content");
|
|
297
|
+
return (_jsx("div", { ...rest, className: classNames("st-contentSwitcher", `st-contentSwitcher--${size}`, className), role: "group", children: items.map((item, index) => {
|
|
298
|
+
const itemId = idFrom(item, index, "content");
|
|
299
|
+
return (_jsx("button", { type: "button", className: classNames("st-contentSwitcher__option st-contentSwitcher__button", itemId === current && "st-contentSwitcher__option--selected"), disabled: item.disabled, "aria-pressed": itemId === current, onClick: () => onChange?.(itemId), children: item.label }, itemId));
|
|
300
|
+
}) }));
|
|
301
|
+
}
|
|
302
|
+
export function CopyButton({ text: copyText, value, label = "Copy", copiedLabel = "Copied", size = "md", className, onClick, ...rest }) {
|
|
303
|
+
const [copied, setCopied] = React.useState(false);
|
|
304
|
+
return (_jsx("button", { ...rest, type: "button", className: classNames("st-copyButton", `st-copyButton--${size}`, copied && "st-copyButton--copied", className), onClick: (event) => {
|
|
305
|
+
setCopied(true);
|
|
306
|
+
void navigator.clipboard?.writeText(value ?? copyText ?? "");
|
|
307
|
+
onClick?.(event);
|
|
308
|
+
}, children: _jsx("span", { className: "st-copyButton__label", children: copied ? copiedLabel : label }) }));
|
|
309
|
+
}
|
|
310
|
+
export function DataTable({ columns, rows, caption, size = "md", className, pageSize, page = 1, totalItems, ...rest }) {
|
|
311
|
+
const visibleRows = pageSize ? rows.slice((page - 1) * pageSize, page * pageSize) : rows;
|
|
312
|
+
const total = totalItems ?? rows.length;
|
|
313
|
+
return (_jsxs("div", { className: "st-dataTable-wrap", children: [_jsxs("table", { ...rest, className: classNames("st-dataTable", `st-dataTable--${size}`, className), children: [caption ? _jsx("caption", { children: caption }) : null, _jsx("thead", { children: _jsx("tr", { children: columns.map((column) => _jsx("th", { children: column.label }, column.key)) }) }), _jsx("tbody", { children: visibleRows.map((row) => (_jsx("tr", { children: columns.map((column) => (_jsx("td", { className: classNames(column.align === "center" && "st-dataTable__cell--center", column.align === "end" && "st-dataTable__cell--end"), children: column.render?.(row, column) ?? text(row[column.key]) }, column.key))) }, row.id))) })] }), pageSize ? _jsx("div", { className: "st-dataTable__pagerStatus", children: `${(page - 1) * pageSize + 1}-${Math.min(page * pageSize, total)} of ${total}` }) : null] }));
|
|
314
|
+
}
|
|
315
|
+
export function DatePicker({ label, value, size = "md", className, ...rest }) {
|
|
316
|
+
return (_jsx("div", { ...rest, className: classNames("st-datepicker", `st-datepicker--${size}`, className), children: _jsx(Field, { label: label, children: (inputId) => _jsx("input", { id: inputId, className: "st-control st-datepicker__control", type: "date", defaultValue: value }) }) }));
|
|
317
|
+
}
|
|
318
|
+
export function Drawer({ open = false, title, description, footer, placement = "right", onClose, children, className, ...rest }) {
|
|
319
|
+
const panelRef = React.useRef(null);
|
|
320
|
+
const closeRef = React.useRef(null);
|
|
321
|
+
useBodyScrollLock(open);
|
|
322
|
+
useEscape(open, onClose);
|
|
323
|
+
React.useEffect(() => {
|
|
324
|
+
if (open)
|
|
325
|
+
closeRef.current?.focus();
|
|
326
|
+
}, [open]);
|
|
327
|
+
React.useEffect(() => {
|
|
328
|
+
if (!open)
|
|
329
|
+
return;
|
|
330
|
+
const onKeyDown = (event) => trapTabKey(event, panelRef.current);
|
|
331
|
+
document.addEventListener("keydown", onKeyDown);
|
|
332
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
333
|
+
}, [open]);
|
|
334
|
+
if (!open)
|
|
335
|
+
return null;
|
|
336
|
+
return (_jsx("div", { className: "st-drawer__backdrop", "data-testid": "st-drawer-backdrop", role: "presentation", onClick: (event) => {
|
|
337
|
+
if (event.target === event.currentTarget)
|
|
338
|
+
onClose?.();
|
|
339
|
+
}, children: _jsxs("aside", { ...rest, ref: panelRef, className: classNames("st-drawer", `st-drawer--${placement}`, className), role: "dialog", "aria-modal": "true", "aria-label": text(title) || "Drawer", tabIndex: -1, onKeyDown: (event) => trapTabKey(event, panelRef.current), children: [_jsxs("div", { className: "st-drawer__header", children: [title ? _jsx("h2", { className: "st-drawer__title", children: title }) : null, _jsx("button", { ref: closeRef, type: "button", className: "st-drawer__close", onClick: onClose, "aria-label": "Close", children: "x" })] }), description ? _jsx("p", { className: "st-drawer__description", children: description }) : null, _jsx("div", { className: "st-drawer__body", children: children }), footer ? _jsx("div", { className: "st-drawer__footer", children: footer }) : null] }) }));
|
|
340
|
+
}
|
|
341
|
+
export function Dropdown({ label = "Select", options, value, open: controlledOpen, placeholder = "Select", onSelect, className, ...rest }) {
|
|
342
|
+
const hostRef = React.useRef(null);
|
|
343
|
+
const itemRefs = React.useRef([]);
|
|
344
|
+
const [open, setOpen] = useControlled(controlledOpen, false);
|
|
345
|
+
const [current, setCurrent] = useControlled(value, value ?? "");
|
|
346
|
+
const [activeIndex, setActiveIndex] = React.useState(-1);
|
|
347
|
+
const selected = options.find((option) => option.value === current);
|
|
348
|
+
const focusOption = (index) => {
|
|
349
|
+
setActiveIndex(index);
|
|
350
|
+
};
|
|
351
|
+
React.useEffect(() => {
|
|
352
|
+
if (open && activeIndex >= 0)
|
|
353
|
+
itemRefs.current[activeIndex]?.focus();
|
|
354
|
+
}, [activeIndex, open]);
|
|
355
|
+
const selectOption = (option) => {
|
|
356
|
+
if (option.disabled)
|
|
357
|
+
return;
|
|
358
|
+
setCurrent(option.value);
|
|
359
|
+
setOpen(false);
|
|
360
|
+
setActiveIndex(-1);
|
|
361
|
+
onSelect?.(option.value);
|
|
362
|
+
};
|
|
363
|
+
useOutsideMouseDown(open, hostRef, () => setOpen(false));
|
|
364
|
+
useEscape(open, () => setOpen(false));
|
|
365
|
+
return (_jsxs("div", { ...rest, ref: hostRef, className: classNames("st-dropdown", className), children: [_jsxs("button", { type: "button", className: "st-dropdown__button", "aria-haspopup": "listbox", "aria-expanded": open, onClick: () => setOpen(!open), onKeyDown: (event) => {
|
|
366
|
+
if (event.key === "ArrowDown") {
|
|
367
|
+
event.preventDefault();
|
|
368
|
+
setOpen(true);
|
|
369
|
+
focusOption(0);
|
|
370
|
+
}
|
|
371
|
+
}, children: [_jsx("span", { className: "st-dropdown__label", children: label }), ": ", _jsx("span", { className: "st-dropdown__value", children: selected?.label ?? placeholder })] }), open ? (_jsx("div", { className: "st-dropdown__list", role: "listbox", "aria-label": text(label) || "Options", children: options.map((option, index) => (_jsx("button", { ref: (node) => {
|
|
372
|
+
itemRefs.current[index] = node;
|
|
373
|
+
}, type: "button", role: "option", className: "st-dropdown__option", disabled: option.disabled, "aria-selected": option.value === current, onClick: () => selectOption(option), onKeyDown: (event) => {
|
|
374
|
+
if (event.key === "ArrowDown") {
|
|
375
|
+
event.preventDefault();
|
|
376
|
+
focusOption(moveIndex(index, options.length, 1));
|
|
377
|
+
}
|
|
378
|
+
else if (event.key === "ArrowUp") {
|
|
379
|
+
event.preventDefault();
|
|
380
|
+
focusOption(moveIndex(index, options.length, -1));
|
|
381
|
+
}
|
|
382
|
+
else if (event.key === "Enter" || event.key === " ") {
|
|
383
|
+
event.preventDefault();
|
|
384
|
+
selectOption(option);
|
|
385
|
+
}
|
|
386
|
+
else if (event.key === "Escape") {
|
|
387
|
+
event.preventDefault();
|
|
388
|
+
setOpen(false);
|
|
389
|
+
}
|
|
390
|
+
}, children: option.label }, option.value))) })) : null] }));
|
|
391
|
+
}
|
|
392
|
+
export function EmptyState({ title, message, action, children, className, ...rest }) {
|
|
393
|
+
return (_jsx("section", { ...rest, className: classNames("st-empty-state st-emptyState", className), children: _jsxs("div", { className: "st-empty-state__content", children: [_jsx("h2", { className: "st-empty-state__title st-emptyState__title", children: title }), message ? _jsx("p", { className: "st-empty-state__message st-emptyState__message", children: message }) : null, children, action ? _jsx("div", { className: "st-empty-state__action", children: action }) : null] }) }));
|
|
394
|
+
}
|
|
395
|
+
export function FileUploader({ label = "Upload", items = [], disabled = false, className, ...rest }) {
|
|
396
|
+
return (_jsxs("div", { ...rest, className: classNames("st-fileUploader-field", className), children: [_jsxs("div", { className: classNames("st-fileUploader__dropzone", disabled && "st-fileUploader__dropzone--disabled"), children: [_jsx("span", { className: "st-fileUploader__trigger", children: label }), _jsx("input", { className: "st-fileUploader__input", type: "file", disabled: disabled, "aria-label": text(label) })] }), _jsx("ul", { className: "st-fileUploader__list", children: items.map((item, index) => (_jsxs("li", { className: classNames("st-fileUploader__item", item.status && `st-fileUploader__item--${item.status}`), children: [_jsx("span", { className: "st-fileUploader__itemName st-fileUploader__name", children: item.name }), item.error ? _jsx("span", { className: "st-fileUploader__itemError", children: item.error }) : null] }, item.id ?? item.name ?? index))) })] }));
|
|
397
|
+
}
|
|
398
|
+
export function Footer({ brand, columns, links, copyright, className, ...rest }) {
|
|
399
|
+
const groups = columns ?? (links ? [{ links }] : []);
|
|
400
|
+
return (_jsxs("footer", { ...rest, className: classNames("st-footer", className), children: [_jsxs("div", { className: "st-footer__top", children: [brand ? _jsx("div", { className: "st-footer__brand", children: brand }) : null, _jsx("div", { className: "st-footer__columns", children: groups.map((group, index) => (_jsxs("nav", { children: [group.title ? _jsx("h2", { children: group.title }) : null, group.links.map((link) => (_jsx("a", { href: link.href, children: link.label }, link.href)))] }, index))) })] }), copyright ? _jsx("div", { className: "st-footer__copyright", children: copyright }) : null] }));
|
|
401
|
+
}
|
|
402
|
+
export function ForceGraph({ nodes, edges, label = "Force graph", selectedIds = [], focusId = null, onSelect, onOpenEntity, className, ...rest }) {
|
|
403
|
+
return (_jsxs("figure", { ...rest, className: classNames("st-forceGraph st-forceGraph--static", className), "aria-label": label, children: [_jsx("span", { className: "st-visually-hidden", children: label }), _jsxs("svg", { viewBox: "0 0 360 220", "aria-hidden": "true", children: [_jsx("g", { className: "st-forceGraph__edges", children: edges.map((edge, index) => (_jsx("line", { className: classNames("st-forceGraph__edge", edge.weak && "st-forceGraph__edge--weak"), x1: "40", y1: 40 + index * 20, x2: "260", y2: 80 + index * 20 }, `${edge.source}-${edge.target}-${index}`))) }), _jsx("g", { className: "st-forceGraph__nodes", children: nodes.map((graphNode, index) => {
|
|
404
|
+
const x = graphNode.fx ?? 48 + (index % 5) * 64;
|
|
405
|
+
const y = graphNode.fy ?? 56 + Math.floor(index / 5) * 56;
|
|
406
|
+
return (_jsxs("g", { className: classNames("st-forceGraph__node", `st-forceGraph__node--${graphNode.tone ?? DATA_TONES[index % DATA_TONES.length]}`, selectedIds.includes(graphNode.id) && "st-forceGraph__node--selected", focusId === graphNode.id && "st-forceGraph__node--focus"), tabIndex: 0, onClick: () => onSelect?.(graphNode.id), onDoubleClick: () => onOpenEntity?.(graphNode.id), children: [_jsx("circle", { className: "st-forceGraph__dot", cx: x, cy: y, r: 8 * (graphNode.weight ?? 1) }), _jsx("text", { className: "st-forceGraph__label", x: x + 12, y: y + 4, children: graphNode.label ?? graphNode.id })] }, graphNode.id));
|
|
407
|
+
}) })] })] }));
|
|
408
|
+
}
|
|
409
|
+
export function Form({ status = "idle", message, children, className, ...rest }) {
|
|
410
|
+
return (_jsxs("form", { ...rest, className: classNames("st-form", className), children: [_jsx("div", { className: "st-form__body", children: children }), message ? _jsx("p", { className: classNames("st-form__message", `st-form__message--${status === "submitted" ? "success" : status === "error" ? "error" : "help"}`), children: message }) : null] }));
|
|
411
|
+
}
|
|
412
|
+
export function FormGroup({ legend, helperText, children, className, ...rest }) {
|
|
413
|
+
return (_jsxs("fieldset", { ...rest, className: classNames("st-form-group st-formGroup", className), children: [_jsx("legend", { className: "st-form-group__legend st-formGroup__legend", children: legend }), helperText ? _jsx("p", { className: "st-form-group__help st-formGroup__help", children: helperText }) : null, _jsx("div", { className: "st-form-group__body st-formGroup__body", children: children })] }));
|
|
414
|
+
}
|
|
415
|
+
export function deriveInitials(name) {
|
|
416
|
+
return (name ?? "")
|
|
417
|
+
.trim()
|
|
418
|
+
.split(/\s+/)
|
|
419
|
+
.filter(Boolean)
|
|
420
|
+
.slice(0, 2)
|
|
421
|
+
.map((part) => part[0]?.toUpperCase())
|
|
422
|
+
.join("");
|
|
423
|
+
}
|
|
424
|
+
export function Header({ brand, title, navigation, navItems, account, sticky = false, className, ...rest }) {
|
|
425
|
+
const links = navigation ?? navItems ?? [];
|
|
426
|
+
return (_jsxs("header", { ...rest, className: classNames("st-header", sticky && "st-header--sticky", className), children: [_jsxs("div", { className: "st-header__leading", children: [brand ? _jsx("a", { className: "st-header__logo", href: "/", children: brand }) : null, title ? _jsx("span", { className: "st-header__title", children: title }) : null] }), _jsx("nav", { className: "st-header__navigation", children: links.map((link) => (_jsx("a", { href: link.href, children: link.label }, link.href))) }), account ? (_jsxs("div", { className: "st-header__account", children: [_jsx("span", { className: "st-header__avatar st-header__avatar--initials", children: deriveInitials(account.name) }), _jsx("span", { className: "st-header__account-name", children: account.name }), account.email ? _jsx("span", { className: "st-header__account-email", children: account.email }) : null] })) : null] }));
|
|
427
|
+
}
|
|
428
|
+
export function Highlight({ tone = "neutral", title, children, className, ...rest }) {
|
|
429
|
+
return (_jsxs("aside", { ...rest, className: classNames("st-highlight", `st-highlight--${tone}`, className), children: [title ? _jsx("h3", { className: "st-highlight__title", children: title }) : null, _jsx("div", { className: "st-highlight__body", children: children })] }));
|
|
430
|
+
}
|
|
431
|
+
export function IconButton({ size = "md", variant = "secondary", type = "button", className, children, ...rest }) {
|
|
432
|
+
return (_jsx("button", { ...rest, type: type, className: classNames("st-iconButton", `st-iconButton--${size}`, `st-iconButton--${variant}`, className), children: children }));
|
|
433
|
+
}
|
|
434
|
+
export function InlineLoading({ label = "Loading", status = "active", className, ...rest }) {
|
|
435
|
+
return (_jsxs("div", { ...rest, className: classNames("st-inlineLoading", `st-inlineLoading--${status}`, className), children: [_jsx("span", { className: "st-inlineLoading__spinner", "aria-hidden": "true" }), _jsx("span", { className: "st-inlineLoading__label", children: label })] }));
|
|
436
|
+
}
|
|
437
|
+
export function LanguageSelector({ options, value, onChange, open = false, className, ...rest }) {
|
|
438
|
+
const current = options.find((option) => option.value === value) ?? options[0];
|
|
439
|
+
return (_jsxs("div", { ...rest, className: classNames("st-languageSelector", className), children: [_jsx("button", { type: "button", className: "st-languageSelector__trigger", children: _jsx("span", { className: "st-languageSelector__current", children: current?.label }) }), open ? (_jsx("ul", { className: "st-languageSelector__menu", children: options.map((option) => (_jsx("li", { children: _jsx("button", { type: "button", className: classNames("st-languageSelector__option", option.value === value && "st-languageSelector__option--active"), onClick: () => onChange?.(option.value), children: option.label }) }, option.value))) })) : null] }));
|
|
440
|
+
}
|
|
441
|
+
export function Link({ muted = false, standalone = false, disabled = false, className, children, ...rest }) {
|
|
442
|
+
return (_jsx("a", { ...rest, className: classNames("st-link", muted && "st-link--muted", standalone && "st-link--standalone", disabled && "st-link--disabled", className), "aria-disabled": disabled || undefined, children: children }));
|
|
443
|
+
}
|
|
444
|
+
export function LoadingState({ label, title, variant = "spinner", className, ...rest }) {
|
|
445
|
+
return (_jsxs("section", { ...rest, className: classNames("st-loading", `st-loading--${variant}`, className), "aria-live": "polite", children: [_jsx("span", { className: "st-loading__spinner", "aria-hidden": "true" }), _jsx("span", { className: "st-loading__label", children: label ?? title ?? "Loading" })] }));
|
|
446
|
+
}
|
|
447
|
+
function isDivider(item) {
|
|
448
|
+
return "type" in item && item.type === "divider";
|
|
449
|
+
}
|
|
450
|
+
function isGroup(item) {
|
|
451
|
+
return "type" in item && item.type === "group";
|
|
452
|
+
}
|
|
453
|
+
export function Menu({ items, dense = false, onSelect, className, role, ...rest }) {
|
|
454
|
+
const rootRef = React.useRef(null);
|
|
455
|
+
const handleItemKeyDown = (event, item) => {
|
|
456
|
+
const focusable = Array.from(rootRef.current?.querySelectorAll('[role="menuitem"]:not(:disabled)') ?? []);
|
|
457
|
+
const currentIndex = focusable.indexOf(event.currentTarget);
|
|
458
|
+
const focusAt = (index) => focusable[index]?.focus();
|
|
459
|
+
if (event.key === "ArrowDown") {
|
|
460
|
+
event.preventDefault();
|
|
461
|
+
focusAt(moveIndex(currentIndex, focusable.length, 1));
|
|
462
|
+
}
|
|
463
|
+
else if (event.key === "ArrowUp") {
|
|
464
|
+
event.preventDefault();
|
|
465
|
+
focusAt(moveIndex(currentIndex < 0 ? focusable.length : currentIndex, focusable.length, -1));
|
|
466
|
+
}
|
|
467
|
+
else if (event.key === "Home") {
|
|
468
|
+
event.preventDefault();
|
|
469
|
+
focusAt(0);
|
|
470
|
+
}
|
|
471
|
+
else if (event.key === "End") {
|
|
472
|
+
event.preventDefault();
|
|
473
|
+
focusAt(focusable.length - 1);
|
|
474
|
+
}
|
|
475
|
+
else if (event.key === "Enter" || event.key === " ") {
|
|
476
|
+
event.preventDefault();
|
|
477
|
+
if (!item.disabled)
|
|
478
|
+
onSelect?.(item);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
return (_jsx("div", { ...rest, ref: rootRef, className: classNames("st-menu", dense && "st-menu--dense", className), role: role ?? "menu", children: items.map((item, index) => {
|
|
482
|
+
if (isDivider(item))
|
|
483
|
+
return _jsx("div", { className: "st-menu__divider", role: "separator" }, item.id ?? index);
|
|
484
|
+
if (isGroup(item)) {
|
|
485
|
+
return (_jsxs("section", { className: "st-menu__group", children: [_jsx("h3", { children: item.label }), item.items.map((child) => (_jsx("button", { type: "button", role: "menuitem", className: "st-menu__item", disabled: child.disabled, onClick: () => onSelect?.(child), onKeyDown: (event) => handleItemKeyDown(event, child), children: _jsx("span", { className: "st-menu__itemLabel", children: child.label }) }, child.id ?? text(child.label))))] }, item.id ?? index));
|
|
486
|
+
}
|
|
487
|
+
return (_jsx("button", { type: "button", role: "menuitem", disabled: item.disabled, className: classNames("st-menu__item", item.variant === "danger" && "st-menu__item--danger"), onClick: () => onSelect?.(item), onKeyDown: (event) => handleItemKeyDown(event, item), children: _jsx("span", { className: "st-menu__itemLabel", children: item.label }) }, item.id ?? text(item.label) ?? index));
|
|
488
|
+
}) }));
|
|
489
|
+
}
|
|
490
|
+
export function MenuPopover({ trigger, items = [], open = true, placement = "bottom-start", children, className, ...rest }) {
|
|
491
|
+
return (_jsxs("div", { ...rest, className: classNames("st-menuPopover", `st-menuPopover--${placement}`, className), children: [trigger, open ? _jsx("div", { className: "st-menuPopover__content", children: items.length ? _jsx(Menu, { items: items, role: "presentation" }) : children }) : null] }));
|
|
492
|
+
}
|
|
493
|
+
export function MenuTriggerButton({ open = false, type = "button", className, children, ...rest }) {
|
|
494
|
+
return (_jsx("button", { ...rest, type: type, className: classNames("st-menuTriggerButton st-button st-button--secondary st-button--sm", className), "aria-expanded": open, children: children }));
|
|
495
|
+
}
|
|
496
|
+
export function MessageActions({ actions, visibility = "always", className, ...rest }) {
|
|
497
|
+
return (_jsx("nav", { ...rest, className: classNames("st-messageActions", visibility === "hover" && "st-messageActions--hoverOnly", className), "aria-label": "Message actions", children: actions.map((action, index) => (_jsx("button", { type: "button", className: classNames("st-button st-button--ghost st-button--sm", action.variant === "danger" && "st-button--danger"), disabled: action.disabled, onClick: action.onClick, children: action.label }, action.id ?? index))) }));
|
|
498
|
+
}
|
|
499
|
+
export function MessageStatusBadge({ status, tone, labels, className, ...rest }) {
|
|
500
|
+
const normalized = status === "sent" ? "completed" : status === "streaming" ? "processing" : status === "error" ? "failed" : status;
|
|
501
|
+
const resolvedTone = tone ?? (normalized === "completed" ? "success" : normalized === "failed" ? "error" : normalized === "processing" ? "info" : "neutral");
|
|
502
|
+
const label = labels?.[status] ?? labels?.[normalized] ?? normalized.charAt(0).toUpperCase() + normalized.slice(1);
|
|
503
|
+
return (_jsxs("span", { ...rest, className: classNames("st-messageStatusBadge", `st-badge st-badge--${resolvedTone}`, className), children: [_jsx("span", { className: "st-messageStatusBadge__dot", "aria-hidden": "true" }), label] }));
|
|
504
|
+
}
|
|
505
|
+
export function Modal({ open = false, title, description, footer, onClose, children, className, ...rest }) {
|
|
506
|
+
const dialogRef = React.useRef(null);
|
|
507
|
+
const closeRef = React.useRef(null);
|
|
508
|
+
useBodyScrollLock(open);
|
|
509
|
+
useEscape(open, onClose);
|
|
510
|
+
React.useEffect(() => {
|
|
511
|
+
if (open)
|
|
512
|
+
closeRef.current?.focus();
|
|
513
|
+
}, [open]);
|
|
514
|
+
React.useEffect(() => {
|
|
515
|
+
if (!open)
|
|
516
|
+
return;
|
|
517
|
+
const onKeyDown = (event) => trapTabKey(event, dialogRef.current);
|
|
518
|
+
document.addEventListener("keydown", onKeyDown);
|
|
519
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
520
|
+
}, [open]);
|
|
521
|
+
if (!open)
|
|
522
|
+
return null;
|
|
523
|
+
return (_jsx("div", { className: "st-modal__backdrop", children: _jsxs("section", { ...rest, ref: dialogRef, className: classNames("st-modal", className), role: "dialog", "aria-modal": "true", "aria-label": text(title) || "Modal", tabIndex: -1, children: [_jsxs("div", { className: "st-modal__header", children: [title ? _jsx("h2", { className: "st-modal__title", children: title }) : null, _jsx("button", { ref: closeRef, type: "button", className: "st-modal__close", onClick: onClose, "aria-label": "Close", children: "x" })] }), description ? _jsx("p", { className: "st-modal__description", children: description }) : null, _jsx("div", { className: "st-modal__body", children: children }), footer ? _jsx("div", { className: "st-modal__footer", children: footer }) : null] }) }));
|
|
524
|
+
}
|
|
525
|
+
export function MultiSelect({ label, options, value, values, size = "md", open: controlledOpen, onChange, className, ...rest }) {
|
|
526
|
+
const reactId = React.useId();
|
|
527
|
+
const listId = `st-multiSelect-list-${reactId}`;
|
|
528
|
+
const [open, setOpen] = useControlled(controlledOpen, false);
|
|
529
|
+
const [selectedValues, setSelectedValues] = useControlled(value ?? values, value ?? values ?? [], onChange);
|
|
530
|
+
const selected = new Set(selectedValues);
|
|
531
|
+
const selectedOptions = options.filter((option) => selected.has(option.value));
|
|
532
|
+
const toggleOption = (option) => {
|
|
533
|
+
if (option.disabled)
|
|
534
|
+
return;
|
|
535
|
+
const next = selected.has(option.value)
|
|
536
|
+
? selectedValues.filter((entry) => entry !== option.value)
|
|
537
|
+
: [...selectedValues, option.value];
|
|
538
|
+
setSelectedValues(next);
|
|
539
|
+
setOpen(false);
|
|
540
|
+
};
|
|
541
|
+
return (_jsxs("div", { ...rest, className: classNames("st-multiSelect", `st-multiSelect--${size}`, className), children: [label ? _jsx("span", { className: "st-field__label", children: label }) : null, _jsxs("button", { type: "button", className: "st-multiSelect__trigger", "aria-label": text(label) || "Select options", "aria-haspopup": "listbox", "aria-expanded": open, "aria-controls": listId, onClick: () => setOpen(!open), children: [label ? _jsx("span", { className: "st-multiSelect__triggerLabel", children: label }) : null, _jsx("span", { className: "st-multiSelect__tags", children: selectedOptions.length ? selectedOptions.map((option) => (_jsx("span", { className: "st-multiSelect__tag", children: _jsx("span", { className: "st-multiSelect__tagLabel", children: option.label }) }, option.value))) : _jsx("span", { className: "st-multiSelect__placeholder", children: "Select" }) })] }), open ? (_jsx("ul", { id: listId, className: "st-multiSelect__list", role: "listbox", "aria-label": text(label) || "Options", "aria-multiselectable": "true", children: options.map((option) => (_jsx("li", { className: classNames("st-multiSelect__option", selected.has(option.value) && "st-multiSelect__option--selected"), role: "option", "aria-selected": selected.has(option.value), "aria-disabled": option.disabled ? "true" : undefined, tabIndex: option.disabled ? undefined : 0, onClick: () => toggleOption(option), onKeyDown: (event) => {
|
|
542
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
543
|
+
event.preventDefault();
|
|
544
|
+
toggleOption(option);
|
|
545
|
+
}
|
|
546
|
+
}, children: option.label }, option.value))) })) : null] }));
|
|
547
|
+
}
|
|
548
|
+
export function NumberInput({ label, helperText, errorText, size = "md", className, ...rest }) {
|
|
549
|
+
return (_jsx(Field, { label: label, helperText: helperText, errorText: errorText, className: classNames("st-numberInput", `st-numberInput--${size}`, className), children: (inputId, isInvalid) => _jsx("input", { ...rest, id: inputId, className: "st-control st-numberInput__control", type: "number", "aria-invalid": isInvalid ? "true" : undefined }) }));
|
|
550
|
+
}
|
|
551
|
+
function renderListItem(item, index, ordered) {
|
|
552
|
+
if (typeof item === "object" && item !== null && "label" in item) {
|
|
553
|
+
const cast = item;
|
|
554
|
+
return (_jsxs("li", { className: ordered ? "st-orderedList__item" : "st-unorderedList__item", children: [cast.label, cast.children ? (ordered ? _jsx(OrderedList, { items: cast.children }) : _jsx(UnorderedList, { items: cast.children })) : null] }, index));
|
|
555
|
+
}
|
|
556
|
+
return (_jsx("li", { className: ordered ? "st-orderedList__item" : "st-unorderedList__item", children: item }, index));
|
|
557
|
+
}
|
|
558
|
+
export function OrderedList({ items, className, ...rest }) {
|
|
559
|
+
return (_jsx("ol", { ...rest, className: classNames("st-orderedList st-ol", className), children: items.map((item, index) => renderListItem(item, index, true)) }));
|
|
560
|
+
}
|
|
561
|
+
export function OverflowMenu({ items, label = "More", open: controlledOpen, dense = false, placement = "bottom-start", className, ...rest }) {
|
|
562
|
+
const [open, setOpen] = useControlled(controlledOpen, false);
|
|
563
|
+
return (_jsxs("div", { ...rest, className: classNames("st-overflowMenu", dense && "st-overflowMenu--dense", className), children: [_jsx("button", { type: "button", className: "st-overflowMenu__trigger", "aria-expanded": open, onClick: () => setOpen(!open), children: label }), open ? _jsx("div", { className: classNames("st-overflowMenu__list", `st-overflowMenu__list--${placement}`), children: _jsx(Menu, { items: items }) }) : null] }));
|
|
564
|
+
}
|
|
565
|
+
export function Pagination({ page, pageSize = 10, totalItems, totalPages, pageCount, onPageChange, className, ...rest }) {
|
|
566
|
+
const pages = pageCount ?? totalPages ?? (totalItems ? Math.max(1, Math.ceil(totalItems / pageSize)) : page);
|
|
567
|
+
const start = totalItems ? (page - 1) * pageSize + 1 : page;
|
|
568
|
+
const end = totalItems ? Math.min(page * pageSize, totalItems) : page;
|
|
569
|
+
const visiblePages = Array.from({ length: pages }, (_, index) => index + 1);
|
|
570
|
+
return (_jsxs("nav", { ...rest, className: classNames("st-pagination", className), "aria-label": "Pagination", children: [_jsx("button", { type: "button", disabled: page <= 1, onClick: () => onPageChange?.(page - 1), children: "Previous" }), _jsx("span", { className: "st-pagination__page--active", children: totalItems ? `${start}-${end} of ${totalItems}` : `Page ${page} of ${pages}` }), _jsx("span", { className: "st-pagination__pages", children: visiblePages.map((pageNumber) => (_jsx("button", { type: "button", className: classNames("st-pagination__page", pageNumber === page && "st-pagination__page--active"), "aria-label": `Page ${pageNumber}`, "aria-current": pageNumber === page ? "page" : undefined, onClick: () => onPageChange?.(pageNumber), children: pageNumber }, pageNumber))) }), _jsx("button", { type: "button", disabled: page >= pages, onClick: () => onPageChange?.(page + 1), children: "Next" })] }));
|
|
571
|
+
}
|
|
572
|
+
export function PaginationNav({ page = 1, totalPages = 1, previousHref, nextHref, className, ...rest }) {
|
|
573
|
+
return (_jsxs("nav", { ...rest, className: classNames("st-paginationNav", className), "aria-label": "Pagination navigation", children: [previousHref ? _jsx("a", { href: previousHref, children: "Previous" }) : _jsx("button", { type: "button", disabled: page <= 1, children: "Previous" }), _jsx("ol", { className: "st-paginationNav__list", children: Array.from({ length: totalPages }, (_, index) => index + 1).map((item) => (_jsx("li", { children: _jsxs("button", { type: "button", className: classNames("st-paginationNav__page", item === page && "st-paginationNav__page--active"), children: ["Page ", item] }) }, item))) }), nextHref ? _jsx("a", { href: nextHref, children: "Next" }) : _jsx("button", { type: "button", disabled: page >= totalPages, children: "Next" })] }));
|
|
574
|
+
}
|
|
575
|
+
export function PasswordInput({ label, helperText, errorText, size = "md", className, ...rest }) {
|
|
576
|
+
const [shown, setShown] = React.useState(false);
|
|
577
|
+
return (_jsx(Field, { label: label, helperText: helperText, errorText: errorText, className: classNames("st-passwordInput", `st-passwordInput--${size}`, className), children: (inputId, isInvalid) => (_jsxs("span", { className: "st-passwordInput__control", children: [_jsx("input", { ...rest, id: inputId, className: "st-control", type: shown ? "text" : "password", "aria-invalid": isInvalid ? "true" : undefined }), _jsx("button", { type: "button", className: "st-passwordInput__toggle", onClick: () => setShown((next) => !next), children: shown ? "Hide" : "Show" })] })) }));
|
|
578
|
+
}
|
|
579
|
+
export function Popover({ trigger, content, open: controlledOpen, placement = "bottom", children, className, ...rest }) {
|
|
580
|
+
const hostRef = React.useRef(null);
|
|
581
|
+
const [open, setOpen] = useControlled(controlledOpen, false);
|
|
582
|
+
const triggerNode = trigger ?? children;
|
|
583
|
+
const contentNode = content ?? (trigger ? children : null);
|
|
584
|
+
const label = text(React.isValidElement(triggerNode) ? triggerNode.props.children : triggerNode) || "Popover";
|
|
585
|
+
useOutsideMouseDown(open, hostRef, () => setOpen(false));
|
|
586
|
+
useEscape(open, () => setOpen(false));
|
|
587
|
+
return (_jsxs("span", { ...rest, ref: hostRef, className: classNames("st-popover-host", className), onClick: () => setOpen(true), children: [triggerNode, open ? (_jsx("span", { className: classNames("st-popover", `st-popover--${placement}`), role: "dialog", "aria-label": label, children: contentNode })) : null] }));
|
|
588
|
+
}
|
|
589
|
+
export function ProgressBar({ label, value = 0, max = 100, tone = "neutral", size = "md", indeterminate = false, className, ...rest }) {
|
|
590
|
+
const percent = pct(value, 0, max);
|
|
591
|
+
return (_jsxs("div", { ...rest, className: classNames("st-progressBar", className), children: [label ? _jsx("div", { className: "st-progressBar__label", children: label }) : null, _jsx("div", { className: classNames("st-progressBar__track", `st-progressBar__track--${tone}`, `st-progressBar__track--${size}`, indeterminate && "st-progressBar__track--indeterminate"), role: "progressbar", "aria-valuenow": indeterminate ? undefined : value, "aria-valuemin": 0, "aria-valuemax": max, children: _jsx("div", { className: "st-progressBar__fill", style: { width: indeterminate ? undefined : `${percent}%` } }) }), _jsxs("span", { className: "st-progressBar__value", children: [Math.round(percent), "%"] })] }));
|
|
592
|
+
}
|
|
593
|
+
export function ProgressIndicator({ items, orientation = "horizontal", className, ...rest }) {
|
|
594
|
+
return (_jsx("ol", { ...rest, className: classNames("st-progressIndicator", `st-progressIndicator--${orientation}`, className), children: items.map((item, index) => (_jsxs("li", { className: classNames("st-progressIndicator__step", `st-progressIndicator__step--${item.status ?? "incomplete"}`), children: [_jsx("span", { className: "st-progressIndicator__indicator", children: item.status === "complete" ? "✓" : index + 1 }), _jsxs("span", { className: "st-progressIndicator__text", children: [_jsx("span", { className: "st-progressIndicator__label", children: item.label }), item.description ? _jsx("span", { className: "st-progressIndicator__description", children: item.description }) : null] })] }, item.id ?? index))) }));
|
|
595
|
+
}
|
|
596
|
+
export function Quote({ author, source, children, className, ...rest }) {
|
|
597
|
+
return (_jsxs("blockquote", { ...rest, className: classNames("st-quote", className), children: [_jsx("p", { className: "st-quote__text", children: children }), author || source ? (_jsxs("footer", { className: "st-quote__attribution", children: [author ? _jsx("span", { className: "st-quote__author", children: author }) : null, source ? _jsx("span", { className: "st-quote__source", children: source }) : null] })) : null] }));
|
|
598
|
+
}
|
|
599
|
+
export function Search({ label, size = "md", onClear, className, ...rest }) {
|
|
600
|
+
const reactId = React.useId();
|
|
601
|
+
const inputId = rest.id ?? `st-search-${reactId}`;
|
|
602
|
+
return (_jsxs("div", { className: classNames("st-search", `st-search--${size}`, className), children: [label ? _jsx("label", { className: "st-field__label", htmlFor: inputId, children: label }) : null, _jsx("span", { className: "st-search__icon", "aria-hidden": "true", children: "\u2315" }), _jsx("input", { ...rest, id: inputId, className: "st-search__control st-search__input", type: "search" }), onClear ? _jsx("button", { type: "button", className: "st-search__clear", onClick: onClear, children: "Clear" }) : null] }));
|
|
603
|
+
}
|
|
604
|
+
export function Select({ label, helperText, errorText, invalid, size = "md", options, className, children, ...rest }) {
|
|
605
|
+
return (_jsx(Field, { label: label, helperText: helperText, errorText: errorText, invalid: invalid, className: className, children: (inputId, isInvalid) => (_jsx("select", { ...rest, id: inputId, className: classNames("st-select", `st-select--${size}`), "aria-invalid": isInvalid ? "true" : undefined, children: children ?? renderOptions(options) })) }));
|
|
606
|
+
}
|
|
607
|
+
export function SideNav({ items, label = "Navigation", className, ...rest }) {
|
|
608
|
+
return (_jsx("nav", { ...rest, className: classNames("st-sidenav st-sideNav", className), "aria-label": label, children: items.map((item) => (_jsx("a", { href: item.href, className: classNames("st-sidenav__link st-sideNav__link", item.active && "st-sidenav__link--active st-sideNav__link--active"), children: item.label }, item.href))) }));
|
|
609
|
+
}
|
|
610
|
+
export function SkeletonText({ lines = 3, label = "Loading", className, ...rest }) {
|
|
611
|
+
return (_jsxs("div", { ...rest, className: classNames("st-skeleton", className), "aria-label": label, children: [_jsx("span", { className: "st-visually-hidden", children: label }), Array.from({ length: lines }, (_, index) => _jsx("span", { className: classNames("st-skeleton__line", index === 0 && "st-skeleton__line--heading") }, index))] }));
|
|
612
|
+
}
|
|
613
|
+
export function SkipLink({ href = "#main", className, children = "Skip to content", ...rest }) {
|
|
614
|
+
return (_jsx("a", { ...rest, href: href, className: classNames("st-skipLink", className), children: children }));
|
|
615
|
+
}
|
|
616
|
+
export function Slider({ label, size = "md", value, defaultValue, min = 0, max = 100, className, ...rest }) {
|
|
617
|
+
const numeric = Number(value ?? defaultValue ?? 0);
|
|
618
|
+
return (_jsxs("div", { className: classNames("st-slider", `st-slider--${size}`, className), children: [_jsxs("div", { className: "st-slider__header", children: [label ? _jsx("label", { className: "st-field__label", children: label }) : null, _jsx("span", { className: "st-slider__value", children: numeric })] }), _jsx("input", { ...rest, className: "st-slider__input", type: "range", min: min, max: max, defaultValue: defaultValue, value: value })] }));
|
|
619
|
+
}
|
|
620
|
+
export function Sparkline({ data, label = "Sparkline", tone = "neutral", className, ...rest }) {
|
|
621
|
+
return (_jsxs("figure", { ...rest, className: classNames("st-sparkline", `st-sparkline--${tone}`, className), "aria-label": label, children: [_jsx("span", { className: "st-visually-hidden", children: label }), _jsx("svg", { viewBox: "0 0 120 40", "aria-hidden": "true", children: _jsx("polyline", { className: "st-sparkline__line", points: pointsFrom(data, 120, 40), fill: "none" }) })] }));
|
|
622
|
+
}
|
|
623
|
+
export function StreamingMessage({ text: messageText, events = [], mode = "live", className, ...rest }) {
|
|
624
|
+
return (_jsxs("section", { ...rest, className: classNames("st-streamingMessage", `st-streamingMessage--${mode}`, className), children: [_jsx("div", { className: "st-streamingMessage__text", children: messageText }), _jsx("ul", { className: "st-streamingMessage__trailList", children: events.map((event) => _jsx("li", { children: event.label }, event.id)) })] }));
|
|
625
|
+
}
|
|
626
|
+
export function StructuredList({ items, bordered = false, className, ...rest }) {
|
|
627
|
+
return (_jsx("dl", { ...rest, className: classNames("st-structuredList", bordered && "st-structuredList--bordered", className), children: items.map((item, index) => (_jsxs("div", { className: "st-structuredList__row", children: [_jsx("dt", { className: "st-structuredList__term", children: item.term ?? item.label }), _jsx("dd", { className: "st-structuredList__definition", children: item.description ?? item.value })] }, index))) }));
|
|
628
|
+
}
|
|
629
|
+
export function Switch({ label, helperText, className, ...rest }) {
|
|
630
|
+
return (_jsxs("label", { className: classNames("st-switch", className), children: [_jsx("input", { ...rest, className: "st-switch__input", type: "checkbox", role: "switch", "aria-checked": rest.checked ?? rest.defaultChecked ?? undefined }), _jsx("span", { className: "st-switch__track", children: _jsx("span", { className: "st-switch__thumb" }) }), _jsxs("span", { className: "st-switch__content", children: [_jsx("span", { className: "st-switch__label", children: label }), helperText ? _jsx("span", { className: "st-switch__help", children: helperText }) : null] })] }));
|
|
631
|
+
}
|
|
632
|
+
export function Table({ columns, rows, caption = "Table", className, ...rest }) {
|
|
633
|
+
return (_jsx("div", { className: "st-table-wrap", children: _jsxs("table", { ...rest, className: classNames("st-table", className), children: [_jsx("caption", { children: caption }), _jsx("thead", { children: _jsx("tr", { children: columns.map((column) => _jsx("th", { children: column.label }, column.key)) }) }), _jsx("tbody", { children: rows.map((row, index) => (_jsx("tr", { children: columns.map((column) => _jsx("td", { className: classNames(column.align === "center" && "st-table__cell--center", (column.align === "right" || column.align === "end") && "st-table__cell--right"), children: text(row[column.key]) }, column.key)) }, text(row.id) || index))) })] }) }));
|
|
634
|
+
}
|
|
635
|
+
export function Tabs({ items, activeValue, activeId, label = "Tabs", onChange, className, ...rest }) {
|
|
636
|
+
const reactId = React.useId();
|
|
637
|
+
const tabRefs = React.useRef([]);
|
|
638
|
+
const first = items.find((item) => !item.disabled) ?? items[0];
|
|
639
|
+
const [current, setCurrent] = useControlled(activeValue ?? activeId, idFrom(first ?? {}, 0, "tab"), onChange);
|
|
640
|
+
const itemIds = items.map((item, index) => idFrom(item, index, "tab"));
|
|
641
|
+
const activeIndex = Math.max(0, itemIds.indexOf(current));
|
|
642
|
+
const active = items[activeIndex] ?? first;
|
|
643
|
+
const activateIndex = (index) => {
|
|
644
|
+
const item = items[index];
|
|
645
|
+
if (!item || item.disabled)
|
|
646
|
+
return;
|
|
647
|
+
setCurrent(itemIds[index]);
|
|
648
|
+
tabRefs.current[index]?.focus();
|
|
649
|
+
};
|
|
650
|
+
const moveTab = (index, delta) => {
|
|
651
|
+
const enabled = items.map((item, itemIndex) => ({ item, itemIndex })).filter(({ item }) => !item.disabled);
|
|
652
|
+
const enabledIndex = enabled.findIndex(({ itemIndex }) => itemIndex === index);
|
|
653
|
+
const next = enabled[moveIndex(enabledIndex, enabled.length, delta)];
|
|
654
|
+
if (next)
|
|
655
|
+
activateIndex(next.itemIndex);
|
|
656
|
+
};
|
|
657
|
+
return (_jsxs("section", { ...rest, className: classNames("st-tabs", className), children: [_jsx("div", { className: "st-tabs__list", role: "tablist", "aria-label": label, children: items.map((item, index) => {
|
|
658
|
+
const itemId = idFrom(item, index, "tab");
|
|
659
|
+
const tabId = `st-tabs-${reactId}-tab-${itemId}`;
|
|
660
|
+
const panelId = `st-tabs-${reactId}-panel-${itemId}`;
|
|
661
|
+
return (_jsx("button", { ref: (node) => {
|
|
662
|
+
tabRefs.current[index] = node;
|
|
663
|
+
}, id: tabId, type: "button", role: "tab", className: classNames("st-tabs__tab", itemId === current && "st-tabs__tab--active"), "aria-selected": itemId === current, "aria-controls": panelId, tabIndex: itemId === current ? 0 : -1, disabled: item.disabled, onClick: () => activateIndex(index), onKeyDown: (event) => {
|
|
664
|
+
if (event.key === "ArrowRight") {
|
|
665
|
+
event.preventDefault();
|
|
666
|
+
moveTab(index, 1);
|
|
667
|
+
}
|
|
668
|
+
else if (event.key === "ArrowLeft") {
|
|
669
|
+
event.preventDefault();
|
|
670
|
+
moveTab(index, -1);
|
|
671
|
+
}
|
|
672
|
+
else if (event.key === "Home") {
|
|
673
|
+
event.preventDefault();
|
|
674
|
+
const firstEnabled = items.findIndex((candidate) => !candidate.disabled);
|
|
675
|
+
activateIndex(firstEnabled >= 0 ? firstEnabled : 0);
|
|
676
|
+
}
|
|
677
|
+
else if (event.key === "End") {
|
|
678
|
+
event.preventDefault();
|
|
679
|
+
const lastEnabled = items.map((candidate, candidateIndex) => ({ candidate, candidateIndex })).filter(({ candidate }) => !candidate.disabled).at(-1)?.candidateIndex ?? items.length - 1;
|
|
680
|
+
activateIndex(lastEnabled);
|
|
681
|
+
}
|
|
682
|
+
}, children: item.label }, itemId));
|
|
683
|
+
}) }), _jsx("div", { id: `st-tabs-${reactId}-panel-${itemIds[activeIndex]}`, className: "st-tabs__panel", role: "tabpanel", "aria-labelledby": `st-tabs-${reactId}-tab-${itemIds[activeIndex]}`, children: active?.content })] }));
|
|
684
|
+
}
|
|
685
|
+
export function Tag({ tone = "neutral", size = "md", disabled = false, onDismiss, className, children, ...rest }) {
|
|
686
|
+
return (_jsxs("span", { ...rest, className: classNames("st-tag", `st-tag--${tone}`, `st-tag--${size}`, disabled && "st-tag--disabled", className), children: [_jsx("span", { className: "st-tag__label", children: children }), onDismiss ? _jsx("button", { type: "button", className: "st-tag__dismiss", onClick: onDismiss, children: "x" }) : null] }));
|
|
687
|
+
}
|
|
688
|
+
export function Textarea({ label, helperText, errorText, invalid, className, ...rest }) {
|
|
689
|
+
return (_jsx(Field, { label: label, helperText: helperText, errorText: errorText, invalid: invalid, className: className, children: (inputId, isInvalid) => _jsx("textarea", { ...rest, id: inputId, className: "st-textarea st-control", "aria-invalid": isInvalid ? "true" : undefined }) }));
|
|
690
|
+
}
|
|
691
|
+
export function Tile({ title, description, variant = "static", selected = false, disabled = false, children, className, ...rest }) {
|
|
692
|
+
return (_jsx("section", { ...rest, className: classNames("st-tile", `st-tile--${variant}`, selected && "st-tile--selected", disabled && "st-tile--disabled", className), children: _jsxs("div", { className: "st-tile__content", children: [title ? _jsx("h3", { className: "st-tile__title", children: title }) : null, description ? _jsx("p", { className: "st-tile__description", children: description }) : null, children] }) }));
|
|
693
|
+
}
|
|
694
|
+
export function TileGroup({ legend, items, value, disabled = false, className, ...rest }) {
|
|
695
|
+
return (_jsxs("fieldset", { ...rest, className: classNames("st-tileGroup", disabled && "st-tileGroup--disabled", className), children: [legend ? _jsx("legend", { className: "st-tileGroup__legend", children: legend }) : null, _jsx("div", { className: "st-tileGroup__items", children: items.map((item) => (_jsxs("label", { className: classNames("st-tileGroup__tile", item.value === value && "st-tileGroup__tile--checked", item.disabled && "st-tileGroup__tile--disabled"), children: [_jsx("input", { className: "st-tileGroup__input", type: "radio", value: item.value, checked: item.value === value, disabled: disabled || item.disabled, readOnly: true }), _jsxs("span", { className: "st-tileGroup__content", children: [_jsx("span", { className: "st-tileGroup__label", children: item.title }), item.description ? _jsx("span", { className: "st-tileGroup__description", children: item.description }) : null] })] }, item.value))) })] }));
|
|
696
|
+
}
|
|
697
|
+
export function Toast({ tone = "info", title, message, actions, onClose, items, autoDismiss = false, duration = 5000, onDismiss, children, className, ...rest }) {
|
|
698
|
+
React.useEffect(() => {
|
|
699
|
+
if (!autoDismiss || !items?.length || !onDismiss)
|
|
700
|
+
return;
|
|
701
|
+
const timeout = window.setTimeout(() => onDismiss(items[0].id), duration);
|
|
702
|
+
return () => window.clearTimeout(timeout);
|
|
703
|
+
}, [autoDismiss, duration, items, onDismiss]);
|
|
704
|
+
if (items?.length) {
|
|
705
|
+
return (_jsx("div", { ...rest, className: classNames("st-toastQueue", className), children: items.map((item) => (_jsxs("aside", { className: classNames("st-toast", `st-toast--${item.tone ?? "info"}`), role: "status", children: [_jsxs("div", { className: "st-toast__content", children: [_jsx("h2", { className: "st-toast__title", children: item.title }), item.message ? _jsx("p", { className: "st-toast__message", children: item.message }) : null] }), item.actions ? _jsx("div", { className: "st-toast__actions", children: item.actions }) : null, onDismiss ? (_jsx("button", { type: "button", onClick: () => onDismiss(item.id), "aria-label": `Dismiss ${text(item.title)}`, children: "Close" })) : null] }, item.id))) }));
|
|
706
|
+
}
|
|
707
|
+
return (_jsxs("aside", { ...rest, className: classNames("st-toast", `st-toast--${tone}`, className), role: "status", children: [_jsxs("div", { className: "st-toast__content", children: [_jsx("h2", { className: "st-toast__title", children: title }), message ? _jsx("p", { className: "st-toast__message", children: message }) : children] }), actions ? _jsx("div", { className: "st-toast__actions", children: actions }) : null, onClose ? _jsx("button", { type: "button", onClick: onClose, children: "Close" }) : null] }));
|
|
708
|
+
}
|
|
709
|
+
export function Toggle({ label, helperText, size = "md", className, ...rest }) {
|
|
710
|
+
return (_jsxs("label", { className: classNames("st-toggle", `st-toggle--${size}`, className), children: [_jsxs("span", { className: "st-toggle__row", children: [_jsx("span", { className: "st-toggle__label", children: label }), _jsx("input", { ...rest, className: "st-toggle__input", type: "checkbox", role: "switch", "aria-checked": rest.checked ?? rest.defaultChecked ?? undefined }), _jsx("span", { className: "st-toggle__track", children: _jsx("span", { className: "st-toggle__thumb" }) })] }), helperText ? _jsx("span", { className: "st-toggle__help", children: helperText }) : null] }));
|
|
711
|
+
}
|
|
712
|
+
export function Toggletip({ label, content, open: controlledOpen, placement = "top", children, className, ...rest }) {
|
|
713
|
+
const [open, setOpen] = useControlled(controlledOpen, false);
|
|
714
|
+
useEscape(open, () => setOpen(false));
|
|
715
|
+
return (_jsxs("span", { ...rest, className: classNames("st-toggletip", `st-toggletip--${placement}`, className), children: [_jsx("button", { type: "button", className: "st-toggletip__trigger", "aria-expanded": open, onClick: () => setOpen(!open), children: label }), open ? _jsx("span", { className: "st-toggletip__bubble", role: "status", children: _jsx("span", { className: "st-toggletip__content", children: content ?? children }) }) : null] }));
|
|
716
|
+
}
|
|
717
|
+
export function Tooltip({ content, placement = "top", children, className, ...rest }) {
|
|
718
|
+
const [open, setOpen] = React.useState(false);
|
|
719
|
+
const tooltipId = React.useId();
|
|
720
|
+
return (_jsxs("span", { ...rest, className: classNames("st-tooltip", `st-tooltip--${placement}`, className), onFocus: () => setOpen(true), onBlur: () => setOpen(false), onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false), children: [_jsx("span", { className: "st-tooltip__trigger", children: children }), _jsx("span", { id: tooltipId, className: "st-tooltip__content", role: "tooltip", "aria-hidden": open ? "false" : "true", children: content })] }));
|
|
721
|
+
}
|
|
722
|
+
function TreeRows({ nodes, expanded, selectedId }) {
|
|
723
|
+
return (_jsx(_Fragment, { children: nodes.map((treeNode) => (_jsxs("div", { children: [_jsxs("div", { className: classNames("st-treeView__row", treeNode.id === selectedId && "st-treeView__row--selected", treeNode.disabled && "st-treeView__row--disabled"), children: [_jsx("span", { className: classNames("st-treeView__caret", !treeNode.children?.length && "st-treeView__caret--leaf", expanded.has(treeNode.id) && "st-treeView__caret--open"), children: "\u203A" }), _jsx("span", { className: "st-treeView__label", children: treeNode.label })] }), treeNode.children?.length && expanded.has(treeNode.id) ? _jsx(TreeRows, { nodes: treeNode.children, expanded: expanded, selectedId: selectedId }) : null] }, treeNode.id))) }));
|
|
724
|
+
}
|
|
725
|
+
export function TreeView({ nodes, selectedId, expandedIds, defaultExpandedIds = [], className, ...rest }) {
|
|
726
|
+
const expanded = new Set(expandedIds ?? defaultExpandedIds);
|
|
727
|
+
return (_jsx("div", { ...rest, className: classNames("st-treeView", className), role: "tree", children: _jsx(TreeRows, { nodes: nodes, expanded: expanded, selectedId: selectedId }) }));
|
|
728
|
+
}
|
|
729
|
+
export function UnorderedList({ items, className, ...rest }) {
|
|
730
|
+
return (_jsx("ul", { ...rest, className: classNames("st-unorderedList", className), children: items.map((item, index) => renderListItem(item, index, false)) }));
|
|
731
|
+
}
|
|
732
|
+
//# sourceMappingURL=catalog.js.map
|