@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.
Files changed (335) hide show
  1. package/README.md +64 -0
  2. package/dist/Accordion.d.ts +3 -0
  3. package/dist/Accordion.d.ts.map +1 -0
  4. package/dist/Accordion.js +2 -0
  5. package/dist/Accordion.js.map +1 -0
  6. package/dist/Alert.d.ts +3 -0
  7. package/dist/Alert.d.ts.map +1 -0
  8. package/dist/Alert.js +2 -0
  9. package/dist/Alert.js.map +1 -0
  10. package/dist/AreaChart.d.ts +3 -0
  11. package/dist/AreaChart.d.ts.map +1 -0
  12. package/dist/AreaChart.js +2 -0
  13. package/dist/AreaChart.js.map +1 -0
  14. package/dist/AspectRatio.d.ts +3 -0
  15. package/dist/AspectRatio.d.ts.map +1 -0
  16. package/dist/AspectRatio.js +2 -0
  17. package/dist/AspectRatio.js.map +1 -0
  18. package/dist/Badge.d.ts +9 -0
  19. package/dist/Badge.d.ts.map +1 -0
  20. package/dist/Badge.js +6 -0
  21. package/dist/Badge.js.map +1 -0
  22. package/dist/BarChart.d.ts +3 -0
  23. package/dist/BarChart.d.ts.map +1 -0
  24. package/dist/BarChart.js +2 -0
  25. package/dist/BarChart.js.map +1 -0
  26. package/dist/Breadcrumb.d.ts +3 -0
  27. package/dist/Breadcrumb.d.ts.map +1 -0
  28. package/dist/Breadcrumb.js +2 -0
  29. package/dist/Breadcrumb.js.map +1 -0
  30. package/dist/Button.d.ts +14 -0
  31. package/dist/Button.d.ts.map +1 -0
  32. package/dist/Button.js +6 -0
  33. package/dist/Button.js.map +1 -0
  34. package/dist/Card.d.ts +8 -0
  35. package/dist/Card.d.ts.map +1 -0
  36. package/dist/Card.js +6 -0
  37. package/dist/Card.js.map +1 -0
  38. package/dist/ChatComposer.d.ts +3 -0
  39. package/dist/ChatComposer.d.ts.map +1 -0
  40. package/dist/ChatComposer.js +2 -0
  41. package/dist/ChatComposer.js.map +1 -0
  42. package/dist/ChatMessage.d.ts +3 -0
  43. package/dist/ChatMessage.d.ts.map +1 -0
  44. package/dist/ChatMessage.js +2 -0
  45. package/dist/ChatMessage.js.map +1 -0
  46. package/dist/ChatThread.d.ts +3 -0
  47. package/dist/ChatThread.d.ts.map +1 -0
  48. package/dist/ChatThread.js +2 -0
  49. package/dist/ChatThread.js.map +1 -0
  50. package/dist/Checkbox.d.ts +3 -0
  51. package/dist/Checkbox.d.ts.map +1 -0
  52. package/dist/Checkbox.js +2 -0
  53. package/dist/Checkbox.js.map +1 -0
  54. package/dist/CodeSnippet.d.ts +3 -0
  55. package/dist/CodeSnippet.d.ts.map +1 -0
  56. package/dist/CodeSnippet.js +2 -0
  57. package/dist/CodeSnippet.js.map +1 -0
  58. package/dist/Combobox.d.ts +3 -0
  59. package/dist/Combobox.d.ts.map +1 -0
  60. package/dist/Combobox.js +2 -0
  61. package/dist/Combobox.js.map +1 -0
  62. package/dist/ContentSwitcher.d.ts +3 -0
  63. package/dist/ContentSwitcher.d.ts.map +1 -0
  64. package/dist/ContentSwitcher.js +2 -0
  65. package/dist/ContentSwitcher.js.map +1 -0
  66. package/dist/CopyButton.d.ts +3 -0
  67. package/dist/CopyButton.d.ts.map +1 -0
  68. package/dist/CopyButton.js +2 -0
  69. package/dist/CopyButton.js.map +1 -0
  70. package/dist/DataTable.d.ts +3 -0
  71. package/dist/DataTable.d.ts.map +1 -0
  72. package/dist/DataTable.js +2 -0
  73. package/dist/DataTable.js.map +1 -0
  74. package/dist/DatePicker.d.ts +3 -0
  75. package/dist/DatePicker.d.ts.map +1 -0
  76. package/dist/DatePicker.js +2 -0
  77. package/dist/DatePicker.js.map +1 -0
  78. package/dist/DonutChart.d.ts +3 -0
  79. package/dist/DonutChart.d.ts.map +1 -0
  80. package/dist/DonutChart.js +2 -0
  81. package/dist/DonutChart.js.map +1 -0
  82. package/dist/Drawer.d.ts +3 -0
  83. package/dist/Drawer.d.ts.map +1 -0
  84. package/dist/Drawer.js +2 -0
  85. package/dist/Drawer.js.map +1 -0
  86. package/dist/Dropdown.d.ts +3 -0
  87. package/dist/Dropdown.d.ts.map +1 -0
  88. package/dist/Dropdown.js +2 -0
  89. package/dist/Dropdown.js.map +1 -0
  90. package/dist/EmptyState.d.ts +3 -0
  91. package/dist/EmptyState.d.ts.map +1 -0
  92. package/dist/EmptyState.js +2 -0
  93. package/dist/EmptyState.js.map +1 -0
  94. package/dist/FileUploader.d.ts +3 -0
  95. package/dist/FileUploader.d.ts.map +1 -0
  96. package/dist/FileUploader.js +2 -0
  97. package/dist/FileUploader.js.map +1 -0
  98. package/dist/Footer.d.ts +3 -0
  99. package/dist/Footer.d.ts.map +1 -0
  100. package/dist/Footer.js +2 -0
  101. package/dist/Footer.js.map +1 -0
  102. package/dist/ForceGraph.d.ts +3 -0
  103. package/dist/ForceGraph.d.ts.map +1 -0
  104. package/dist/ForceGraph.js +2 -0
  105. package/dist/ForceGraph.js.map +1 -0
  106. package/dist/Form.d.ts +3 -0
  107. package/dist/Form.d.ts.map +1 -0
  108. package/dist/Form.js +2 -0
  109. package/dist/Form.js.map +1 -0
  110. package/dist/FormGroup.d.ts +3 -0
  111. package/dist/FormGroup.d.ts.map +1 -0
  112. package/dist/FormGroup.js +2 -0
  113. package/dist/FormGroup.js.map +1 -0
  114. package/dist/Header.d.ts +3 -0
  115. package/dist/Header.d.ts.map +1 -0
  116. package/dist/Header.js +2 -0
  117. package/dist/Header.js.map +1 -0
  118. package/dist/Highlight.d.ts +3 -0
  119. package/dist/Highlight.d.ts.map +1 -0
  120. package/dist/Highlight.js +2 -0
  121. package/dist/Highlight.js.map +1 -0
  122. package/dist/IconButton.d.ts +3 -0
  123. package/dist/IconButton.d.ts.map +1 -0
  124. package/dist/IconButton.js +2 -0
  125. package/dist/IconButton.js.map +1 -0
  126. package/dist/InlineLoading.d.ts +3 -0
  127. package/dist/InlineLoading.d.ts.map +1 -0
  128. package/dist/InlineLoading.js +2 -0
  129. package/dist/InlineLoading.js.map +1 -0
  130. package/dist/Input.d.ts +17 -0
  131. package/dist/Input.d.ts.map +1 -0
  132. package/dist/Input.js +11 -0
  133. package/dist/Input.js.map +1 -0
  134. package/dist/LanguageSelector.d.ts +3 -0
  135. package/dist/LanguageSelector.d.ts.map +1 -0
  136. package/dist/LanguageSelector.js +2 -0
  137. package/dist/LanguageSelector.js.map +1 -0
  138. package/dist/LineChart.d.ts +3 -0
  139. package/dist/LineChart.d.ts.map +1 -0
  140. package/dist/LineChart.js +2 -0
  141. package/dist/LineChart.js.map +1 -0
  142. package/dist/Link.d.ts +3 -0
  143. package/dist/Link.d.ts.map +1 -0
  144. package/dist/Link.js +2 -0
  145. package/dist/Link.js.map +1 -0
  146. package/dist/LoadingState.d.ts +3 -0
  147. package/dist/LoadingState.d.ts.map +1 -0
  148. package/dist/LoadingState.js +2 -0
  149. package/dist/LoadingState.js.map +1 -0
  150. package/dist/Menu.d.ts +3 -0
  151. package/dist/Menu.d.ts.map +1 -0
  152. package/dist/Menu.js +2 -0
  153. package/dist/Menu.js.map +1 -0
  154. package/dist/MenuPopover.d.ts +3 -0
  155. package/dist/MenuPopover.d.ts.map +1 -0
  156. package/dist/MenuPopover.js +2 -0
  157. package/dist/MenuPopover.js.map +1 -0
  158. package/dist/MenuTriggerButton.d.ts +3 -0
  159. package/dist/MenuTriggerButton.d.ts.map +1 -0
  160. package/dist/MenuTriggerButton.js +2 -0
  161. package/dist/MenuTriggerButton.js.map +1 -0
  162. package/dist/MessageActions.d.ts +3 -0
  163. package/dist/MessageActions.d.ts.map +1 -0
  164. package/dist/MessageActions.js +2 -0
  165. package/dist/MessageActions.js.map +1 -0
  166. package/dist/MessageStatusBadge.d.ts +3 -0
  167. package/dist/MessageStatusBadge.d.ts.map +1 -0
  168. package/dist/MessageStatusBadge.js +2 -0
  169. package/dist/MessageStatusBadge.js.map +1 -0
  170. package/dist/Modal.d.ts +3 -0
  171. package/dist/Modal.d.ts.map +1 -0
  172. package/dist/Modal.js +2 -0
  173. package/dist/Modal.js.map +1 -0
  174. package/dist/MultiSelect.d.ts +3 -0
  175. package/dist/MultiSelect.d.ts.map +1 -0
  176. package/dist/MultiSelect.js +2 -0
  177. package/dist/MultiSelect.js.map +1 -0
  178. package/dist/NumberInput.d.ts +3 -0
  179. package/dist/NumberInput.d.ts.map +1 -0
  180. package/dist/NumberInput.js +2 -0
  181. package/dist/NumberInput.js.map +1 -0
  182. package/dist/OrderedList.d.ts +3 -0
  183. package/dist/OrderedList.d.ts.map +1 -0
  184. package/dist/OrderedList.js +2 -0
  185. package/dist/OrderedList.js.map +1 -0
  186. package/dist/OverflowMenu.d.ts +3 -0
  187. package/dist/OverflowMenu.d.ts.map +1 -0
  188. package/dist/OverflowMenu.js +2 -0
  189. package/dist/OverflowMenu.js.map +1 -0
  190. package/dist/Pagination.d.ts +3 -0
  191. package/dist/Pagination.d.ts.map +1 -0
  192. package/dist/Pagination.js +2 -0
  193. package/dist/Pagination.js.map +1 -0
  194. package/dist/PaginationNav.d.ts +3 -0
  195. package/dist/PaginationNav.d.ts.map +1 -0
  196. package/dist/PaginationNav.js +2 -0
  197. package/dist/PaginationNav.js.map +1 -0
  198. package/dist/PasswordInput.d.ts +3 -0
  199. package/dist/PasswordInput.d.ts.map +1 -0
  200. package/dist/PasswordInput.js +2 -0
  201. package/dist/PasswordInput.js.map +1 -0
  202. package/dist/Popover.d.ts +3 -0
  203. package/dist/Popover.d.ts.map +1 -0
  204. package/dist/Popover.js +2 -0
  205. package/dist/Popover.js.map +1 -0
  206. package/dist/ProgressBar.d.ts +3 -0
  207. package/dist/ProgressBar.d.ts.map +1 -0
  208. package/dist/ProgressBar.js +2 -0
  209. package/dist/ProgressBar.js.map +1 -0
  210. package/dist/ProgressIndicator.d.ts +3 -0
  211. package/dist/ProgressIndicator.d.ts.map +1 -0
  212. package/dist/ProgressIndicator.js +2 -0
  213. package/dist/ProgressIndicator.js.map +1 -0
  214. package/dist/Quote.d.ts +3 -0
  215. package/dist/Quote.d.ts.map +1 -0
  216. package/dist/Quote.js +2 -0
  217. package/dist/Quote.js.map +1 -0
  218. package/dist/Radio.d.ts +3 -0
  219. package/dist/Radio.d.ts.map +1 -0
  220. package/dist/Radio.js +2 -0
  221. package/dist/Radio.js.map +1 -0
  222. package/dist/ScatterPlot.d.ts +3 -0
  223. package/dist/ScatterPlot.d.ts.map +1 -0
  224. package/dist/ScatterPlot.js +2 -0
  225. package/dist/ScatterPlot.js.map +1 -0
  226. package/dist/Search.d.ts +3 -0
  227. package/dist/Search.d.ts.map +1 -0
  228. package/dist/Search.js +2 -0
  229. package/dist/Search.js.map +1 -0
  230. package/dist/Select.d.ts +3 -0
  231. package/dist/Select.d.ts.map +1 -0
  232. package/dist/Select.js +2 -0
  233. package/dist/Select.js.map +1 -0
  234. package/dist/SideNav.d.ts +3 -0
  235. package/dist/SideNav.d.ts.map +1 -0
  236. package/dist/SideNav.js +2 -0
  237. package/dist/SideNav.js.map +1 -0
  238. package/dist/SkeletonText.d.ts +3 -0
  239. package/dist/SkeletonText.d.ts.map +1 -0
  240. package/dist/SkeletonText.js +2 -0
  241. package/dist/SkeletonText.js.map +1 -0
  242. package/dist/SkipLink.d.ts +3 -0
  243. package/dist/SkipLink.d.ts.map +1 -0
  244. package/dist/SkipLink.js +2 -0
  245. package/dist/SkipLink.js.map +1 -0
  246. package/dist/Slider.d.ts +3 -0
  247. package/dist/Slider.d.ts.map +1 -0
  248. package/dist/Slider.js +2 -0
  249. package/dist/Slider.js.map +1 -0
  250. package/dist/Sparkline.d.ts +3 -0
  251. package/dist/Sparkline.d.ts.map +1 -0
  252. package/dist/Sparkline.js +2 -0
  253. package/dist/Sparkline.js.map +1 -0
  254. package/dist/StackedBarChart.d.ts +3 -0
  255. package/dist/StackedBarChart.d.ts.map +1 -0
  256. package/dist/StackedBarChart.js +2 -0
  257. package/dist/StackedBarChart.js.map +1 -0
  258. package/dist/StreamingMessage.d.ts +3 -0
  259. package/dist/StreamingMessage.d.ts.map +1 -0
  260. package/dist/StreamingMessage.js +2 -0
  261. package/dist/StreamingMessage.js.map +1 -0
  262. package/dist/StructuredList.d.ts +3 -0
  263. package/dist/StructuredList.d.ts.map +1 -0
  264. package/dist/StructuredList.js +2 -0
  265. package/dist/StructuredList.js.map +1 -0
  266. package/dist/Switch.d.ts +3 -0
  267. package/dist/Switch.d.ts.map +1 -0
  268. package/dist/Switch.js +2 -0
  269. package/dist/Switch.js.map +1 -0
  270. package/dist/Table.d.ts +3 -0
  271. package/dist/Table.d.ts.map +1 -0
  272. package/dist/Table.js +2 -0
  273. package/dist/Table.js.map +1 -0
  274. package/dist/Tabs.d.ts +3 -0
  275. package/dist/Tabs.d.ts.map +1 -0
  276. package/dist/Tabs.js +2 -0
  277. package/dist/Tabs.js.map +1 -0
  278. package/dist/Tag.d.ts +3 -0
  279. package/dist/Tag.d.ts.map +1 -0
  280. package/dist/Tag.js +2 -0
  281. package/dist/Tag.js.map +1 -0
  282. package/dist/Textarea.d.ts +3 -0
  283. package/dist/Textarea.d.ts.map +1 -0
  284. package/dist/Textarea.js +2 -0
  285. package/dist/Textarea.js.map +1 -0
  286. package/dist/ThemeProvider.d.ts +9 -0
  287. package/dist/ThemeProvider.d.ts.map +1 -0
  288. package/dist/ThemeProvider.js +23 -0
  289. package/dist/ThemeProvider.js.map +1 -0
  290. package/dist/Tile.d.ts +3 -0
  291. package/dist/Tile.d.ts.map +1 -0
  292. package/dist/Tile.js +2 -0
  293. package/dist/Tile.js.map +1 -0
  294. package/dist/TileGroup.d.ts +3 -0
  295. package/dist/TileGroup.d.ts.map +1 -0
  296. package/dist/TileGroup.js +2 -0
  297. package/dist/TileGroup.js.map +1 -0
  298. package/dist/Toast.d.ts +3 -0
  299. package/dist/Toast.d.ts.map +1 -0
  300. package/dist/Toast.js +2 -0
  301. package/dist/Toast.js.map +1 -0
  302. package/dist/Toggle.d.ts +3 -0
  303. package/dist/Toggle.d.ts.map +1 -0
  304. package/dist/Toggle.js +2 -0
  305. package/dist/Toggle.js.map +1 -0
  306. package/dist/Toggletip.d.ts +3 -0
  307. package/dist/Toggletip.d.ts.map +1 -0
  308. package/dist/Toggletip.js +2 -0
  309. package/dist/Toggletip.js.map +1 -0
  310. package/dist/Tooltip.d.ts +3 -0
  311. package/dist/Tooltip.d.ts.map +1 -0
  312. package/dist/Tooltip.js +2 -0
  313. package/dist/Tooltip.js.map +1 -0
  314. package/dist/TreeView.d.ts +3 -0
  315. package/dist/TreeView.d.ts.map +1 -0
  316. package/dist/TreeView.js +2 -0
  317. package/dist/TreeView.js.map +1 -0
  318. package/dist/UnorderedList.d.ts +3 -0
  319. package/dist/UnorderedList.d.ts.map +1 -0
  320. package/dist/UnorderedList.js +2 -0
  321. package/dist/UnorderedList.js.map +1 -0
  322. package/dist/catalog.d.ts +716 -0
  323. package/dist/catalog.d.ts.map +1 -0
  324. package/dist/catalog.js +732 -0
  325. package/dist/catalog.js.map +1 -0
  326. package/dist/classNames.d.ts +2 -0
  327. package/dist/classNames.d.ts.map +1 -0
  328. package/dist/classNames.js +4 -0
  329. package/dist/classNames.js.map +1 -0
  330. package/dist/index.d.ts +162 -0
  331. package/dist/index.d.ts.map +1 -0
  332. package/dist/index.js +82 -0
  333. package/dist/index.js.map +1 -0
  334. package/dist/styles.css +6366 -0
  335. package/package.json +51 -0
@@ -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