@gouno/ui 0.3.2

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 (231) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/LICENSE +21 -0
  3. package/README.md +144 -0
  4. package/dist/base.css +239 -0
  5. package/dist/bootstrap.js +22 -0
  6. package/dist/components/primitives/alert-dialog.d.ts +18 -0
  7. package/dist/components/primitives/alert-dialog.js +43 -0
  8. package/dist/components/primitives/alert.d.ts +9 -0
  9. package/dist/components/primitives/alert.js +25 -0
  10. package/dist/components/primitives/avatar.d.ts +14 -0
  11. package/dist/components/primitives/avatar.js +42 -0
  12. package/dist/components/primitives/badge.d.ts +9 -0
  13. package/dist/components/primitives/badge.js +25 -0
  14. package/dist/components/primitives/button.d.ts +10 -0
  15. package/dist/components/primitives/button.js +36 -0
  16. package/dist/components/primitives/checkbox.d.ts +4 -0
  17. package/dist/components/primitives/checkbox.js +10 -0
  18. package/dist/components/primitives/dialog.d.ts +20 -0
  19. package/dist/components/primitives/dialog.js +37 -0
  20. package/dist/components/primitives/dropdown-menu.d.ts +25 -0
  21. package/dist/components/primitives/dropdown-menu.js +51 -0
  22. package/dist/components/primitives/empty.d.ts +11 -0
  23. package/dist/components/primitives/empty.js +33 -0
  24. package/dist/components/primitives/field.d.ts +24 -0
  25. package/dist/components/primitives/field.js +75 -0
  26. package/dist/components/primitives/input.d.ts +3 -0
  27. package/dist/components/primitives/input.js +7 -0
  28. package/dist/components/primitives/label.d.ts +4 -0
  29. package/dist/components/primitives/label.js +8 -0
  30. package/dist/components/primitives/popover.d.ts +16 -0
  31. package/dist/components/primitives/popover.js +31 -0
  32. package/dist/components/primitives/radio-group.d.ts +5 -0
  33. package/dist/components/primitives/radio-group.js +13 -0
  34. package/dist/components/primitives/select.d.ts +15 -0
  35. package/dist/components/primitives/select.js +38 -0
  36. package/dist/components/primitives/separator.d.ts +4 -0
  37. package/dist/components/primitives/separator.js +8 -0
  38. package/dist/components/primitives/sheet.d.ts +17 -0
  39. package/dist/components/primitives/sheet.js +41 -0
  40. package/dist/components/primitives/skeleton.d.ts +2 -0
  41. package/dist/components/primitives/skeleton.js +6 -0
  42. package/dist/components/primitives/switch.d.ts +6 -0
  43. package/dist/components/primitives/switch.js +8 -0
  44. package/dist/components/primitives/table.d.ts +28 -0
  45. package/dist/components/primitives/table.js +44 -0
  46. package/dist/components/primitives/tabs.d.ts +11 -0
  47. package/dist/components/primitives/tabs.js +30 -0
  48. package/dist/components/primitives/textarea.d.ts +3 -0
  49. package/dist/components/primitives/textarea.js +7 -0
  50. package/dist/components/primitives/tooltip.d.ts +13 -0
  51. package/dist/components/primitives/tooltip.js +24 -0
  52. package/dist/core/affix.d.ts +14 -0
  53. package/dist/core/affix.js +29 -0
  54. package/dist/core/alert.d.ts +54 -0
  55. package/dist/core/alert.js +56 -0
  56. package/dist/core/anchor.d.ts +16 -0
  57. package/dist/core/anchor.js +31 -0
  58. package/dist/core/app.d.ts +5 -0
  59. package/dist/core/app.js +5 -0
  60. package/dist/core/aspect-ratio.d.ts +6 -0
  61. package/dist/core/aspect-ratio.js +6 -0
  62. package/dist/core/autocomplete.d.ts +24 -0
  63. package/dist/core/autocomplete.js +139 -0
  64. package/dist/core/avatar.d.ts +26 -0
  65. package/dist/core/avatar.js +20 -0
  66. package/dist/core/badge.d.ts +16 -0
  67. package/dist/core/badge.js +22 -0
  68. package/dist/core/breadcrumb.d.ts +55 -0
  69. package/dist/core/breadcrumb.js +69 -0
  70. package/dist/core/button.d.ts +49 -0
  71. package/dist/core/button.js +66 -0
  72. package/dist/core/calendar.d.ts +48 -0
  73. package/dist/core/calendar.js +179 -0
  74. package/dist/core/card.d.ts +30 -0
  75. package/dist/core/card.js +12 -0
  76. package/dist/core/carousel.d.ts +49 -0
  77. package/dist/core/carousel.js +166 -0
  78. package/dist/core/cascader.d.ts +19 -0
  79. package/dist/core/cascader.js +45 -0
  80. package/dist/core/code-block.d.ts +16 -0
  81. package/dist/core/code-block.js +47 -0
  82. package/dist/core/collapse.d.ts +49 -0
  83. package/dist/core/collapse.js +96 -0
  84. package/dist/core/color-picker.d.ts +9 -0
  85. package/dist/core/color-picker.js +8 -0
  86. package/dist/core/config-provider.d.ts +10 -0
  87. package/dist/core/config-provider.js +14 -0
  88. package/dist/core/control-types.d.ts +2 -0
  89. package/dist/core/control-types.js +7 -0
  90. package/dist/core/date-picker.d.ts +13 -0
  91. package/dist/core/date-picker.js +14 -0
  92. package/dist/core/date-range-picker.d.ts +26 -0
  93. package/dist/core/date-range-picker.js +10 -0
  94. package/dist/core/descriptions.d.ts +41 -0
  95. package/dist/core/descriptions.js +133 -0
  96. package/dist/core/drawer.d.ts +9 -0
  97. package/dist/core/drawer.js +58 -0
  98. package/dist/core/empty.d.ts +8 -0
  99. package/dist/core/empty.js +5 -0
  100. package/dist/core/feedback.d.ts +5 -0
  101. package/dist/core/feedback.js +5 -0
  102. package/dist/core/field.d.ts +15 -0
  103. package/dist/core/field.js +19 -0
  104. package/dist/core/float-button.d.ts +13 -0
  105. package/dist/core/float-button.js +22 -0
  106. package/dist/core/form.d.ts +19 -0
  107. package/dist/core/form.js +56 -0
  108. package/dist/core/icon-button.d.ts +7 -0
  109. package/dist/core/icon-button.js +4 -0
  110. package/dist/core/icon.d.ts +17 -0
  111. package/dist/core/icon.js +35 -0
  112. package/dist/core/image.d.ts +76 -0
  113. package/dist/core/image.js +189 -0
  114. package/dist/core/index.d.ts +79 -0
  115. package/dist/core/index.js +77 -0
  116. package/dist/core/input-number.d.ts +24 -0
  117. package/dist/core/input-number.js +70 -0
  118. package/dist/core/input-otp.d.ts +14 -0
  119. package/dist/core/input-otp.js +76 -0
  120. package/dist/core/input.d.ts +14 -0
  121. package/dist/core/input.js +51 -0
  122. package/dist/core/kbd.d.ts +8 -0
  123. package/dist/core/kbd.js +11 -0
  124. package/dist/core/layout-primitives.d.ts +11 -0
  125. package/dist/core/layout-primitives.js +8 -0
  126. package/dist/core/layout.d.ts +71 -0
  127. package/dist/core/layout.js +119 -0
  128. package/dist/core/list.d.ts +37 -0
  129. package/dist/core/list.js +35 -0
  130. package/dist/core/locale.d.ts +48 -0
  131. package/dist/core/locale.js +32 -0
  132. package/dist/core/mentions.d.ts +10 -0
  133. package/dist/core/mentions.js +112 -0
  134. package/dist/core/menu.d.ts +79 -0
  135. package/dist/core/menu.js +265 -0
  136. package/dist/core/message.d.ts +16 -0
  137. package/dist/core/message.js +36 -0
  138. package/dist/core/modal.d.ts +40 -0
  139. package/dist/core/modal.js +67 -0
  140. package/dist/core/notification.d.ts +15 -0
  141. package/dist/core/notification.js +39 -0
  142. package/dist/core/page-layout.d.ts +6 -0
  143. package/dist/core/page-layout.js +7 -0
  144. package/dist/core/pagination.d.ts +28 -0
  145. package/dist/core/pagination.js +69 -0
  146. package/dist/core/popconfirm.d.ts +13 -0
  147. package/dist/core/popconfirm.js +42 -0
  148. package/dist/core/progress.d.ts +6 -0
  149. package/dist/core/progress.js +8 -0
  150. package/dist/core/public-props.d.ts +82 -0
  151. package/dist/core/public-props.js +1 -0
  152. package/dist/core/qrcode.d.ts +14 -0
  153. package/dist/core/qrcode.js +17 -0
  154. package/dist/core/rate.d.ts +11 -0
  155. package/dist/core/rate.js +48 -0
  156. package/dist/core/result.d.ts +12 -0
  157. package/dist/core/result.js +19 -0
  158. package/dist/core/segmented.d.ts +29 -0
  159. package/dist/core/segmented.js +38 -0
  160. package/dist/core/select.d.ts +27 -0
  161. package/dist/core/select.js +143 -0
  162. package/dist/core/selection-controls.d.ts +12 -0
  163. package/dist/core/selection-controls.js +23 -0
  164. package/dist/core/separator.d.ts +24 -0
  165. package/dist/core/separator.js +17 -0
  166. package/dist/core/slider.d.ts +2 -0
  167. package/dist/core/slider.js +6 -0
  168. package/dist/core/spin.d.ts +7 -0
  169. package/dist/core/spin.js +7 -0
  170. package/dist/core/spinner.d.ts +3 -0
  171. package/dist/core/spinner.js +6 -0
  172. package/dist/core/splitter.d.ts +44 -0
  173. package/dist/core/splitter.js +208 -0
  174. package/dist/core/statistic.d.ts +12 -0
  175. package/dist/core/statistic.js +6 -0
  176. package/dist/core/steps.d.ts +54 -0
  177. package/dist/core/steps.js +106 -0
  178. package/dist/core/tabs.d.ts +40 -0
  179. package/dist/core/tabs.js +80 -0
  180. package/dist/core/tag.d.ts +19 -0
  181. package/dist/core/tag.js +29 -0
  182. package/dist/core/textarea.d.ts +8 -0
  183. package/dist/core/textarea.js +14 -0
  184. package/dist/core/time-picker.d.ts +9 -0
  185. package/dist/core/time-picker.js +8 -0
  186. package/dist/core/timeline.d.ts +37 -0
  187. package/dist/core/timeline.js +48 -0
  188. package/dist/core/tour.d.ts +18 -0
  189. package/dist/core/tour.js +51 -0
  190. package/dist/core/transfer.d.ts +16 -0
  191. package/dist/core/transfer.js +46 -0
  192. package/dist/core/tree-select.d.ts +19 -0
  193. package/dist/core/tree-select.js +19 -0
  194. package/dist/core/tree.d.ts +89 -0
  195. package/dist/core/tree.js +386 -0
  196. package/dist/core/typography.d.ts +20 -0
  197. package/dist/core/typography.js +12 -0
  198. package/dist/core/upload.d.ts +20 -0
  199. package/dist/core/upload.js +72 -0
  200. package/dist/core/watermark.d.ts +10 -0
  201. package/dist/core/watermark.js +21 -0
  202. package/dist/fonts/inter-LICENSE +93 -0
  203. package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
  204. package/dist/fonts/jetbrains-mono-LICENSE +93 -0
  205. package/dist/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  206. package/dist/gouno/app-shell.d.ts +22 -0
  207. package/dist/gouno/app-shell.js +27 -0
  208. package/dist/gouno/index.d.ts +4 -0
  209. package/dist/gouno/index.js +4 -0
  210. package/dist/gouno/page-container.d.ts +4 -0
  211. package/dist/gouno/page-container.js +6 -0
  212. package/dist/gouno/page-header.d.ts +8 -0
  213. package/dist/gouno/page-header.js +6 -0
  214. package/dist/hooks/use-overlay-body.d.ts +6 -0
  215. package/dist/hooks/use-overlay-body.js +18 -0
  216. package/dist/index.d.ts +5 -0
  217. package/dist/index.js +5 -0
  218. package/dist/lib/utils.d.ts +2 -0
  219. package/dist/lib/utils.js +5 -0
  220. package/dist/patterns/bulk-action-bar.d.ts +8 -0
  221. package/dist/patterns/bulk-action-bar.js +7 -0
  222. package/dist/patterns/index.d.ts +5 -0
  223. package/dist/patterns/index.js +5 -0
  224. package/dist/theme/index.d.ts +2 -0
  225. package/dist/theme/index.js +2 -0
  226. package/dist/theme/provider.d.ts +22 -0
  227. package/dist/theme/provider.js +76 -0
  228. package/dist/theme/theme-toggle.d.ts +6 -0
  229. package/dist/theme/theme-toggle.js +10 -0
  230. package/dist/tokens.css +164 -0
  231. package/package.json +111 -0
@@ -0,0 +1,143 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useComponentLocale } from "./config-provider.js";
3
+ import * as React from "react";
4
+ import { Check, ChevronDown, X } from "lucide-react";
5
+ import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../components/primitives/popover.js";
6
+ import { cn } from "../lib/utils.js";
7
+ import { controlSizeClass } from "./control-types.js";
8
+ function readOptions(children) {
9
+ const options = [];
10
+ React.Children.forEach(children, (child) => {
11
+ if (!React.isValidElement(child))
12
+ return;
13
+ const childProps = child.props;
14
+ if (child.type === React.Fragment) {
15
+ options.push(...readOptions(childProps.children));
16
+ return;
17
+ }
18
+ if (typeof child.type === "string" && child.type === "option") {
19
+ options.push({ value: String(childProps.value ?? childProps.children ?? ""), label: childProps.children, disabled: childProps.disabled });
20
+ return;
21
+ }
22
+ if (typeof child.type === "string" && child.type === "optgroup")
23
+ options.push(...readOptions(childProps.children));
24
+ });
25
+ return options;
26
+ }
27
+ export const Select = React.forwardRef(function Select({ locale, size = "middle", status, loading = false, placeholder, allowClear = false, onClear, mode = "single", showSearch = false, optionFilterProp = "label", maxTagCount, value, defaultValue, onChange, onSearch, name, id, required, disabled, children, className, ...props }, ref) {
28
+ const text = useComponentLocale("select", locale);
29
+ const generatedId = React.useId();
30
+ const baseId = id ?? `select-${generatedId}`;
31
+ const listboxId = `${baseId}-listbox`;
32
+ const searchRef = React.useRef(null);
33
+ const searchable = showSearch || mode === "tags";
34
+ const options = React.useMemo(() => readOptions(children), [children]);
35
+ const selectRef = React.useRef(null);
36
+ const triggerRef = React.useRef(null);
37
+ const initial = defaultValue === undefined ? (mode === "single" ? "" : []) : defaultValue;
38
+ const [innerValue, setInnerValue] = React.useState(initial);
39
+ const [open, setOpen] = React.useState(false);
40
+ const [search, setSearch] = React.useState("");
41
+ const [activeIndex, setActiveIndex] = React.useState(0);
42
+ React.useImperativeHandle(ref, () => selectRef.current);
43
+ const selected = value === undefined ? innerValue : value;
44
+ const selectedValues = Array.isArray(selected) ? [...selected] : selected ? [selected] : [];
45
+ const selectedOptions = selectedValues.map((item) => options.find((option) => option.value === item) ?? { value: item, label: item });
46
+ const filteredOptions = options.filter((option) => {
47
+ if (!search)
48
+ return true;
49
+ const target = optionFilterProp === "value" ? option.value : String(option.label ?? "");
50
+ return target.toLowerCase().includes(search.toLowerCase());
51
+ });
52
+ React.useEffect(() => {
53
+ setActiveIndex((current) => Math.min(current, Math.max(0, filteredOptions.length - 1)));
54
+ }, [search, filteredOptions.length]);
55
+ const moveActive = (direction) => {
56
+ if (!filteredOptions.length)
57
+ return;
58
+ setActiveIndex((current) => {
59
+ for (let offset = 1; offset <= filteredOptions.length; offset += 1) {
60
+ const next = (current + direction * offset + filteredOptions.length) % filteredOptions.length;
61
+ if (!filteredOptions[next].disabled)
62
+ return next;
63
+ }
64
+ return current;
65
+ });
66
+ };
67
+ const multi = mode !== "single";
68
+ const commit = (next, option) => { if (value === undefined)
69
+ setInnerValue(next); onChange?.(next, option); };
70
+ const choose = (option) => {
71
+ if (option.disabled || loading || disabled)
72
+ return;
73
+ if (multi) {
74
+ const next = selectedValues.includes(option.value) ? selectedValues.filter((item) => item !== option.value) : [...selectedValues, option.value];
75
+ commit(next, next.map((item) => options.find((entry) => entry.value === item) ?? { value: item, label: item }));
76
+ if (mode === "multiple")
77
+ setSearch("");
78
+ return;
79
+ }
80
+ commit(option.value, option);
81
+ setOpen(false);
82
+ setSearch("");
83
+ };
84
+ const clear = () => { if (disabled || loading)
85
+ return; commit(multi ? [] : "", []); onClear?.(); setSearch(""); setOpen(false); triggerRef.current?.focus(); };
86
+ const addTag = () => { const trimmed = search.trim(); if (!trimmed || selectedValues.includes(trimmed))
87
+ return; const option = { value: trimmed, label: trimmed }; commit([...selectedValues, trimmed], [...selectedOptions, option]); setSearch(""); };
88
+ const hasValue = selectedValues.length > 0;
89
+ const canClear = allowClear && hasValue && !disabled && !loading;
90
+ const display = multi ? null : selectedOptions[0]?.label;
91
+ const hiddenValue = multi ? selectedValues : selectedValues[0] ?? "";
92
+ const activeOptionId = open && filteredOptions[activeIndex] ? `${baseId}-option-${activeIndex}` : undefined;
93
+ const remove = (option) => {
94
+ if (disabled || loading || option.disabled)
95
+ return;
96
+ commit(selectedValues.filter((item) => item !== option.value), selectedOptions.filter((item) => item.value !== option.value));
97
+ triggerRef.current?.focus();
98
+ };
99
+ const selectActive = () => { const option = filteredOptions[activeIndex]; if (option)
100
+ choose(option); };
101
+ const resolvedPlaceholder = placeholder ?? text.placeholder;
102
+ return _jsxs("div", { className: "relative min-w-0", "data-slot": "select", children: [_jsxs("select", { ...props, id: id, name: name, required: required, disabled: disabled || loading, multiple: multi, value: hiddenValue, onChange: () => undefined, ref: selectRef, "aria-hidden": "true", tabIndex: -1, className: "pointer-events-none absolute inset-0 h-full w-full opacity-0", children: [children, selectedValues.filter((item) => !options.some((option) => option.value === item)).map((item) => _jsx("option", { value: item, children: item }, item))] }), _jsxs(Popover, { open: open, onOpenChange: (next) => { if (!disabled && !loading)
103
+ setOpen(next); }, children: [_jsx(PopoverAnchor, { asChild: true, children: _jsxs("div", { "data-slot": "select-control", className: cn("flex w-full min-w-0 items-center gap-2 rounded-md border border-border bg-input px-3 text-foreground focus-within:ring-2 focus-within:ring-ring", controlSizeClass(size), multi && "h-auto min-h-9 py-1", status === "error" && "border-destructive focus-within:ring-destructive", status === "warning" && "border-warning focus-within:ring-warning", (disabled || loading) && "cursor-not-allowed opacity-50", className), children: [multi && hasValue ? _jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap gap-1", "data-slot": "select-tags", children: [selectedOptions.slice(0, maxTagCount).map((option) => _jsxs("span", { className: "inline-flex max-w-full items-center gap-1 rounded bg-secondary px-1.5 py-0.5 text-xs", children: [_jsx("span", { className: "truncate", children: option.label }), _jsx("button", { type: "button", disabled: disabled || loading || option.disabled, "aria-label": text.removeLabel(typeof option.label === "string" || typeof option.label === "number" ? String(option.label) : option.value), className: "shrink-0 rounded outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none", onClick: () => remove(option), children: _jsx(X, { "aria-hidden": "true", className: "size-3" }) })] }, option.value)), maxTagCount !== undefined && selectedOptions.length > maxTagCount ? _jsxs("span", { className: "text-xs text-muted-foreground", children: ["+", selectedOptions.length - maxTagCount] }) : null] }) : null, _jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { ref: triggerRef, type: "button", id: `${baseId}-trigger`, role: "combobox", "aria-haspopup": "listbox", "aria-label": props["aria-label"], "aria-labelledby": props["aria-labelledby"], "aria-describedby": props["aria-describedby"], "aria-expanded": open, "aria-controls": listboxId, "aria-activedescendant": !searchable ? activeOptionId : undefined, "aria-invalid": status === "error" || props["aria-invalid"] || undefined, "aria-busy": loading || undefined, disabled: disabled || loading, onKeyDown: (event) => {
104
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
105
+ event.preventDefault();
106
+ if (!open)
107
+ setOpen(true);
108
+ else
109
+ moveActive(event.key === "ArrowDown" ? 1 : -1);
110
+ }
111
+ else if (event.key === "Enter" || event.key === " ") {
112
+ event.preventDefault();
113
+ if (open)
114
+ selectActive();
115
+ else
116
+ setOpen(true);
117
+ }
118
+ else if (event.key === "Escape" && open) {
119
+ event.preventDefault();
120
+ setOpen(false);
121
+ }
122
+ }, className: cn("flex min-w-0 items-center gap-2 self-stretch text-left outline-none disabled:cursor-not-allowed", multi && hasValue ? "shrink-0" : "flex-1"), children: [_jsx("span", { className: cn("min-w-0 flex-1 truncate", !hasValue && "text-muted-foreground", multi && hasValue && "sr-only"), children: multi && hasValue ? selectedOptions.map((option) => typeof option.label === "string" ? option.label : option.value).join(", ") : display ?? resolvedPlaceholder }), _jsx(ChevronDown, { "aria-hidden": "true", className: "size-4 shrink-0 text-muted-foreground" })] }) }), canClear ? _jsx("button", { type: "button", "aria-label": text.clearLabel, className: "flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring", onClick: clear, children: _jsx(X, { "aria-hidden": "true", className: "size-3.5" }) }) : null] }) }), _jsxs(PopoverContent, { role: "presentation", placement: "bottom-start", className: "w-[var(--radix-popover-trigger-width)] min-w-48 p-1", onOpenAutoFocus: (event) => { event.preventDefault(); if (searchable)
123
+ searchRef.current?.focus();
124
+ else
125
+ triggerRef.current?.focus(); }, onCloseAutoFocus: (event) => { event.preventDefault(); triggerRef.current?.focus(); }, children: [searchable ? _jsx("div", { className: "p-1", children: _jsx("input", { ref: searchRef, role: "combobox", "aria-autocomplete": "list", "aria-expanded": open, "aria-controls": listboxId, "aria-activedescendant": activeOptionId, value: search, onChange: (event) => { setSearch(event.target.value); setActiveIndex(0); onSearch?.(event.target.value); }, onKeyDown: (event) => {
126
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
127
+ event.preventDefault();
128
+ moveActive(event.key === "ArrowDown" ? 1 : -1);
129
+ }
130
+ else if (event.key === "Enter") {
131
+ event.preventDefault();
132
+ if (mode === "tags" && search.trim() && !filteredOptions.length)
133
+ addTag();
134
+ else
135
+ selectActive();
136
+ }
137
+ else if (event.key === "Escape") {
138
+ event.preventDefault();
139
+ setOpen(false);
140
+ }
141
+ }, placeholder: text.searchPlaceholder, "aria-label": text.searchLabel, className: "h-8 w-full rounded border border-border bg-input px-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring" }) }) : null, _jsx("div", { id: listboxId, role: "listbox", "aria-label": props["aria-label"] ?? text.searchLabel, "aria-labelledby": props["aria-labelledby"], "aria-multiselectable": multi || undefined, className: "max-h-60 overflow-y-auto", "data-slot": "select-list", children: filteredOptions.map((option, optionIndex) => { const checked = selectedValues.includes(option.value); const active = optionIndex === activeIndex; return _jsxs("div", { id: `${baseId}-option-${optionIndex}`, role: "option", "aria-selected": checked, "aria-disabled": option.disabled || undefined, onMouseDown: (event) => event.preventDefault(), onMouseEnter: () => { if (!option.disabled)
142
+ setActiveIndex(optionIndex); }, onClick: () => choose(option), className: cn("flex w-full cursor-default items-center gap-2 rounded px-2 py-1.5 text-left text-sm", !option.disabled && "hover:bg-accent", option.disabled && "opacity-50", active && "bg-accent", checked && "bg-accent/60"), children: [multi ? _jsx("span", { className: cn("flex size-4 items-center justify-center rounded border", checked && "border-primary bg-primary text-primary-foreground"), children: checked ? _jsx(Check, { "aria-hidden": "true", className: "size-3" }) : null }) : null, _jsx("span", { className: "min-w-0 flex-1 truncate", children: option.label })] }, option.value); }) }), filteredOptions.length === 0 ? _jsx("div", { role: "status", className: "px-2 py-3 text-center text-sm text-muted-foreground", children: text.emptyText }) : null] })] })] });
143
+ });
@@ -0,0 +1,12 @@
1
+ import { type InputHTMLAttributes, type LabelHTMLAttributes, type ReactNode } from "react";
2
+ export type CheckProps = Omit<InputHTMLAttributes<HTMLInputElement>, "type"> & {
3
+ label?: ReactNode;
4
+ };
5
+ export declare const Checkbox: (props: CheckProps) => import("react").JSX.Element;
6
+ export declare const Radio: (props: CheckProps) => import("react").JSX.Element;
7
+ export declare function Switch({ label, id, className, ...props }: CheckProps): import("react").JSX.Element;
8
+ export declare const CheckboxField: import("react").ForwardRefExoticComponent<LabelHTMLAttributes<HTMLLabelElement> & import("react").RefAttributes<HTMLLabelElement>>;
9
+ export declare function CheckboxGroup({ label, children }: {
10
+ label: string;
11
+ children: ReactNode;
12
+ }): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useId, } from "react";
3
+ import { FieldGroup, FieldLegend, FieldSet } from "../components/primitives/field.js";
4
+ import { cn } from "../lib/utils.js";
5
+ function CheckControl({ label, id, kind, className, ...props }) {
6
+ const generated = useId();
7
+ const controlId = id || generated;
8
+ const control = _jsx("input", { ...props, id: controlId, type: kind, className: cn("size-4 shrink-0 accent-primary disabled:opacity-50", className) });
9
+ return label ? _jsxs("label", { htmlFor: controlId, className: "flex items-center gap-2 text-sm", children: [control, _jsx("span", { children: label })] }) : control;
10
+ }
11
+ export const Checkbox = (props) => _jsx(CheckControl, { ...props, kind: "checkbox" });
12
+ export const Radio = (props) => _jsx(CheckControl, { ...props, kind: "radio" });
13
+ export function Switch({ label, id, className, ...props }) {
14
+ const generated = useId();
15
+ const controlId = id || generated;
16
+ return _jsxs("label", { className: cn("flex items-center gap-3", className), htmlFor: controlId, children: [_jsx("input", { ...props, id: controlId, type: "checkbox", role: "switch", className: "peer sr-only" }), _jsx("span", { className: "flex h-6 w-10 shrink-0 items-center rounded-full border border-border bg-secondary p-0.5 peer-checked:justify-end peer-checked:bg-primary peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-ring peer-disabled:opacity-50", children: _jsx("span", { className: "size-4 rounded-full bg-background" }) }), label ? _jsx("span", { children: label }) : null] });
17
+ }
18
+ export const CheckboxField = forwardRef(function CheckboxField({ children, className, ...props }, ref) {
19
+ return (_jsx("label", { ...props, ref: ref, "data-slot": "checkbox-field", className: cn("flex items-center gap-2", className), children: children }));
20
+ });
21
+ export function CheckboxGroup({ label, children }) {
22
+ return _jsxs(FieldSet, { children: [_jsx(FieldLegend, { children: label }), _jsx(FieldGroup, { className: "flex-row flex-wrap gap-4", children: children })] });
23
+ }
@@ -0,0 +1,24 @@
1
+ import { type CSSProperties, type HTMLAttributes, type ReactNode } from "react";
2
+ export type SeparatorOrientation = "horizontal" | "vertical";
3
+ export type SeparatorVariant = "solid" | "dashed" | "dotted";
4
+ export type SeparatorTitlePlacement = "start" | "center" | "end";
5
+ export type SeparatorSemantic = "root" | "line" | "content";
6
+ export type SeparatorClassNames = Partial<Record<SeparatorSemantic, string>>;
7
+ export type SeparatorStyles = Partial<Record<SeparatorSemantic, CSSProperties>>;
8
+ export interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {
9
+ /** Separator axis. */
10
+ orientation?: SeparatorOrientation;
11
+ /** Remove separator semantics when the line is purely visual. */
12
+ decorative?: boolean;
13
+ /** Line style. */
14
+ variant?: SeparatorVariant;
15
+ /** Optional horizontal title/content. Vertical separators remain line-only. */
16
+ children?: ReactNode;
17
+ /** Horizontal title placement when children are present. */
18
+ titlePlacement?: SeparatorTitlePlacement;
19
+ /** Semantic slot class overrides. */
20
+ classNames?: SeparatorClassNames;
21
+ /** Semantic slot style overrides. */
22
+ styles?: SeparatorStyles;
23
+ }
24
+ export declare const Separator: import("react").ForwardRefExoticComponent<SeparatorProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ function lineClass(orientation, variant) {
5
+ if (orientation === "vertical") {
6
+ return cn("h-full min-h-4 w-0 shrink-0", variant === "solid" && "border-l border-solid border-border", variant === "dashed" && "border-l border-dashed border-border", variant === "dotted" && "border-l border-dotted border-border");
7
+ }
8
+ return cn("h-0 min-w-0 border-t border-border", variant === "solid" && "border-solid", variant === "dashed" && "border-dashed", variant === "dotted" && "border-dotted");
9
+ }
10
+ export const Separator = forwardRef(function Separator({ orientation = "horizontal", decorative = true, variant = "solid", children, titlePlacement = "center", className, classNames, style, styles, role, ...props }, ref) {
11
+ const hasContent = orientation === "horizontal" && children !== undefined && children !== null;
12
+ const semanticRole = role ?? (decorative ? "presentation" : "separator");
13
+ if (!hasContent) {
14
+ return (_jsx("div", { ...props, ref: ref, role: semanticRole, "aria-orientation": !decorative ? orientation : undefined, "data-slot": "separator", "data-orientation": orientation, "data-variant": variant, className: cn(orientation === "vertical" ? "inline-flex self-stretch" : "flex w-full items-center", classNames?.root, className), style: { ...styles?.root, ...style }, children: _jsx("span", { "aria-hidden": "true", "data-slot": "separator-line", className: cn(lineClass(orientation, variant), orientation === "horizontal" ? "w-full" : undefined, classNames?.line), style: styles?.line }) }));
15
+ }
16
+ return (_jsxs("div", { ...props, ref: ref, role: semanticRole, "aria-orientation": !decorative ? "horizontal" : undefined, "data-slot": "separator", "data-orientation": "horizontal", "data-variant": variant, "data-title-placement": titlePlacement, className: cn("flex w-full items-center gap-3", classNames?.root, className), style: { ...styles?.root, ...style }, children: [_jsx("span", { "aria-hidden": "true", "data-slot": "separator-line", className: cn(lineClass("horizontal", variant), titlePlacement === "center" && "flex-1", titlePlacement === "start" && "basis-[5%]", titlePlacement === "end" && "flex-1", classNames?.line), style: styles?.line }), _jsx("span", { "data-slot": "separator-content", className: cn("shrink-0 text-sm text-muted-foreground", classNames?.content), style: styles?.content, children: children }), _jsx("span", { "aria-hidden": "true", "data-slot": "separator-line", className: cn(lineClass("horizontal", variant), titlePlacement === "center" && "flex-1", titlePlacement === "start" && "flex-1", titlePlacement === "end" && "basis-[5%]", classNames?.line), style: styles?.line })] }));
17
+ });
@@ -0,0 +1,2 @@
1
+ import { type InputHTMLAttributes } from "react";
2
+ export declare const Slider: import("react").ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "type"> & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ export const Slider = forwardRef(function Slider({ className, value, defaultValue, min = 0, max = 100, step = 1, ...props }, ref) {
5
+ return (_jsx("input", { ...props, ref: ref, "data-slot": "slider", type: "range", value: value, defaultValue: defaultValue, min: min, max: max, step: step, className: cn("h-2 w-full cursor-pointer accent-primary outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", className) }));
6
+ });
@@ -0,0 +1,7 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ export interface SpinProps extends Omit<HTMLAttributes<HTMLDivElement>, "aria-busy" | "children"> {
3
+ spinning?: boolean;
4
+ tip?: ReactNode;
5
+ children?: ReactNode;
6
+ }
7
+ export declare const Spin: import("react").ForwardRefExoticComponent<SpinProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ import { Spinner } from "./spinner.js";
5
+ export const Spin = forwardRef(function Spin({ spinning = true, tip, children, className, ...props }, ref) {
6
+ return (_jsxs("div", { ...props, ref: ref, "data-slot": "spin", "aria-busy": spinning || undefined, className: cn("relative", className), children: [children, spinning ? (_jsxs("div", { "data-slot": "spin-overlay", className: "absolute inset-0 flex flex-col items-center justify-center gap-2 bg-background/70", children: [_jsx(Spinner, { className: "size-5 text-primary" }), tip ? (_jsx("span", { "data-slot": "spin-tip", className: "text-sm text-muted-foreground", children: tip })) : null] })) : null] }));
7
+ });
@@ -0,0 +1,3 @@
1
+ import { type HTMLAttributes } from "react";
2
+ export type SpinnerProps = HTMLAttributes<HTMLSpanElement>;
3
+ export declare const Spinner: import("react").ForwardRefExoticComponent<SpinnerProps & import("react").RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef, } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ export const Spinner = forwardRef(function Spinner({ className, "aria-hidden": ariaHidden = true, ...props }, ref) {
5
+ return (_jsx("span", { ...props, ref: ref, "aria-hidden": ariaHidden, "data-slot": "spinner", className: cn("inline-block size-4 animate-spin rounded-full border-2 border-current border-r-transparent", className) }));
6
+ });
@@ -0,0 +1,44 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ export type SplitterOrientation = "horizontal" | "vertical";
3
+ export interface SplitterPanelProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
4
+ children?: ReactNode;
5
+ /** Initial panel share in percent when Splitter.defaultSizes is not provided. */
6
+ defaultSize?: number;
7
+ /** Minimum panel share in percent while resizing. */
8
+ min?: number;
9
+ /** Maximum panel share in percent while resizing. */
10
+ max?: number;
11
+ /** Disables both adjacent resize handles when false. */
12
+ resizable?: boolean;
13
+ }
14
+ export declare const SplitterPanel: import("react").ForwardRefExoticComponent<SplitterPanelProps & import("react").RefAttributes<HTMLDivElement>>;
15
+ export interface SplitterProps extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "onResize"> {
16
+ /** Canonical compound content. Direct children should be SplitterPanel. */
17
+ children?: ReactNode;
18
+ orientation?: SplitterOrientation;
19
+ /** Controlled panel shares. Values are normalized to a 100 percent total. */
20
+ sizes?: readonly number[];
21
+ /** Uncontrolled initial panel shares. Values are normalized to a 100 percent total. */
22
+ defaultSizes?: readonly number[];
23
+ /** Canonical full-size-vector change callback. */
24
+ onSizesChange?: (sizes: readonly number[]) => void;
25
+ onResizeStart?: (sizes: readonly number[]) => void;
26
+ onResizeEnd?: (sizes: readonly number[]) => void;
27
+ /** Keyboard resize increment in percentage points. Shift multiplies it by five. */
28
+ step?: number;
29
+ /** @deprecated Prefer SplitterPanel children. */
30
+ first?: ReactNode;
31
+ /** @deprecated Prefer SplitterPanel children. */
32
+ second?: ReactNode;
33
+ /** @deprecated Prefer defaultSizes or SplitterPanel.defaultSize. */
34
+ defaultSize?: number;
35
+ /** @deprecated Prefer SplitterPanel.min. Applies to the legacy first panel. */
36
+ min?: number;
37
+ /** @deprecated Prefer SplitterPanel.max. Applies to the legacy first panel. */
38
+ max?: number;
39
+ /** @deprecated Use onSizesChange. Retained with the original first-panel number contract. */
40
+ onResize?: (size: number) => void;
41
+ }
42
+ export declare const Splitter: import("react").ForwardRefExoticComponent<SplitterProps & import("react").RefAttributes<HTMLDivElement>> & {
43
+ Panel: import("react").ForwardRefExoticComponent<SplitterPanelProps & import("react").RefAttributes<HTMLDivElement>>;
44
+ };
@@ -0,0 +1,208 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Children, Fragment, cloneElement, forwardRef, isValidElement, useRef, useState, } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ export const SplitterPanel = forwardRef(function SplitterPanel({ defaultSize: _defaultSize, min: _min, max: _max, resizable = true, className, ...props }, ref) {
5
+ return (_jsx("div", { ...props, ref: ref, "data-slot": "splitter-panel", "data-resizable": resizable || undefined, className: cn("min-h-0 min-w-0 overflow-auto", className) }));
6
+ });
7
+ function clamp(value, min, max) {
8
+ return Math.min(max, Math.max(min, value));
9
+ }
10
+ function finitePercent(value, fallback) {
11
+ return value !== undefined && Number.isFinite(value)
12
+ ? clamp(value, 0, 100)
13
+ : fallback;
14
+ }
15
+ function equalSizes(count) {
16
+ if (count <= 0)
17
+ return [];
18
+ return Array.from({ length: count }, () => 100 / count);
19
+ }
20
+ function normalizeSizes(values, count) {
21
+ if (!values || values.length !== count)
22
+ return equalSizes(count);
23
+ const sanitized = values.map((value) => Number.isFinite(value) ? Math.max(0, value) : 0);
24
+ const total = sanitized.reduce((sum, value) => sum + value, 0);
25
+ if (total <= 0)
26
+ return equalSizes(count);
27
+ return sanitized.map((value) => (value / total) * 100);
28
+ }
29
+ function initialPanelSizes(panels, defaultSizes, legacyDefaultSize) {
30
+ if (defaultSizes)
31
+ return normalizeSizes(defaultSizes, panels.length);
32
+ if (legacyDefaultSize !== undefined && panels.length === 2) {
33
+ const first = finitePercent(legacyDefaultSize, 50);
34
+ return normalizeSizes([first, 100 - first], 2);
35
+ }
36
+ const declared = panels.map((panel) => panel.props.defaultSize);
37
+ if (!declared.some((value) => value !== undefined))
38
+ return equalSizes(panels.length);
39
+ const specifiedTotal = declared.reduce((sum, value) => sum + (value === undefined ? 0 : finitePercent(value, 0)), 0);
40
+ const unspecifiedCount = declared.filter((value) => value === undefined).length;
41
+ const remaining = Math.max(0, 100 - specifiedTotal);
42
+ const fallback = unspecifiedCount > 0 ? remaining / unspecifiedCount : 0;
43
+ return normalizeSizes(declared.map((value) => value === undefined ? fallback : finitePercent(value, 0)), panels.length);
44
+ }
45
+ function panelConfig(panel) {
46
+ const min = finitePercent(panel.props.min, 0);
47
+ const max = Math.max(min, finitePercent(panel.props.max, 100));
48
+ return {
49
+ min,
50
+ max,
51
+ resizable: panel.props.resizable !== false,
52
+ defaultSize: panel.props.defaultSize,
53
+ };
54
+ }
55
+ function assignRef(ref, value) {
56
+ if (typeof ref === "function")
57
+ ref(value);
58
+ else if (ref)
59
+ ref.current = value;
60
+ }
61
+ const SplitterRoot = forwardRef(function Splitter({ children, orientation = "horizontal", sizes, defaultSizes, onSizesChange, onResizeStart, onResizeEnd, step = 1, first, second, defaultSize, min, max, onResize, className, ...props }, forwardedRef) {
62
+ const childPanels = Children.toArray(children).filter((child) => isValidElement(child) && child.type === SplitterPanel);
63
+ const legacyMode = childPanels.length === 0 && (first !== undefined || second !== undefined);
64
+ const panels = legacyMode
65
+ ? [
66
+ _jsx(SplitterPanel, { min: min, max: max, children: first }, "legacy-first"),
67
+ _jsx(SplitterPanel, { children: second }, "legacy-second"),
68
+ ]
69
+ : childPanels;
70
+ const initial = initialPanelSizes(panels, defaultSizes, defaultSize);
71
+ const [internalSizes, setInternalSizes] = useState(initial);
72
+ const resolvedSizes = sizes
73
+ ? normalizeSizes(sizes, panels.length)
74
+ : internalSizes.length === panels.length
75
+ ? internalSizes
76
+ : initial;
77
+ const panelConfigs = panels.map(panelConfig);
78
+ const rootRef = useRef(null);
79
+ const currentSizesRef = useRef(resolvedSizes);
80
+ const proposedSizesRef = useRef(resolvedSizes);
81
+ const dragRef = useRef(null);
82
+ currentSizesRef.current = resolvedSizes;
83
+ if (!dragRef.current)
84
+ proposedSizesRef.current = resolvedSizes;
85
+ const vertical = orientation === "vertical";
86
+ const keyboardStep = Number.isFinite(step) ? Math.max(0.1, step) : 1;
87
+ const pairBounds = (index, source = currentSizesRef.current) => {
88
+ const pairTotal = source[index] + source[index + 1];
89
+ const left = panelConfigs[index];
90
+ const right = panelConfigs[index + 1];
91
+ return {
92
+ pairTotal,
93
+ minLeft: Math.max(left.min, pairTotal - right.max),
94
+ maxLeft: Math.min(left.max, pairTotal - right.min),
95
+ };
96
+ };
97
+ const commitResize = (index, requestedLeft, source) => {
98
+ const { pairTotal, minLeft, maxLeft } = pairBounds(index, source);
99
+ const nextLeft = clamp(requestedLeft, minLeft, maxLeft);
100
+ const next = [...source];
101
+ next[index] = nextLeft;
102
+ next[index + 1] = pairTotal - nextLeft;
103
+ proposedSizesRef.current = next;
104
+ if (!sizes) {
105
+ currentSizesRef.current = next;
106
+ setInternalSizes(next);
107
+ }
108
+ onSizesChange?.(next);
109
+ if (legacyMode)
110
+ onResize?.(next[0] ?? 0);
111
+ return next;
112
+ };
113
+ const canResize = (index) => panelConfigs[index]?.resizable !== false &&
114
+ panelConfigs[index + 1]?.resizable !== false;
115
+ const handlePointerDown = (index, event) => {
116
+ if (!canResize(index) || !rootRef.current)
117
+ return;
118
+ const startSizes = [...currentSizesRef.current];
119
+ dragRef.current = {
120
+ index,
121
+ startCoordinate: vertical ? event.clientY : event.clientX,
122
+ startSizes,
123
+ };
124
+ proposedSizesRef.current = startSizes;
125
+ if (typeof event.currentTarget.setPointerCapture === "function") {
126
+ event.currentTarget.setPointerCapture(event.pointerId);
127
+ }
128
+ onResizeStart?.(startSizes);
129
+ };
130
+ const handlePointerMove = (index, event) => {
131
+ const drag = dragRef.current;
132
+ const root = rootRef.current;
133
+ if (!drag || drag.index !== index || !root)
134
+ return;
135
+ const rect = root.getBoundingClientRect();
136
+ const axisLength = vertical ? rect.height : rect.width;
137
+ if (axisLength <= 0)
138
+ return;
139
+ const coordinate = vertical ? event.clientY : event.clientX;
140
+ const delta = ((coordinate - drag.startCoordinate) / axisLength) * 100;
141
+ commitResize(index, drag.startSizes[index] + delta, drag.startSizes);
142
+ };
143
+ const finishPointerResize = (index, event) => {
144
+ const drag = dragRef.current;
145
+ if (!drag || drag.index !== index)
146
+ return;
147
+ if (typeof event.currentTarget.hasPointerCapture === "function" &&
148
+ event.currentTarget.hasPointerCapture(event.pointerId) &&
149
+ typeof event.currentTarget.releasePointerCapture === "function") {
150
+ event.currentTarget.releasePointerCapture(event.pointerId);
151
+ }
152
+ dragRef.current = null;
153
+ onResizeEnd?.([...proposedSizesRef.current]);
154
+ };
155
+ const handleKeyDown = (index, event) => {
156
+ if (!canResize(index))
157
+ return;
158
+ const direction = vertical
159
+ ? event.key === "ArrowDown"
160
+ ? 1
161
+ : event.key === "ArrowUp"
162
+ ? -1
163
+ : 0
164
+ : event.key === "ArrowRight"
165
+ ? 1
166
+ : event.key === "ArrowLeft"
167
+ ? -1
168
+ : 0;
169
+ const isBoundaryKey = event.key === "Home" || event.key === "End";
170
+ if (direction === 0 && !isBoundaryKey)
171
+ return;
172
+ event.preventDefault();
173
+ const startSizes = [...currentSizesRef.current];
174
+ const { minLeft, maxLeft } = pairBounds(index, startSizes);
175
+ const requested = event.key === "Home"
176
+ ? minLeft
177
+ : event.key === "End"
178
+ ? maxLeft
179
+ : startSizes[index] +
180
+ direction * keyboardStep * (event.shiftKey ? 5 : 1);
181
+ onResizeStart?.(startSizes);
182
+ const next = commitResize(index, requested, startSizes);
183
+ onResizeEnd?.(next);
184
+ };
185
+ return (_jsx("div", { ...props, ref: (node) => {
186
+ rootRef.current = node;
187
+ assignRef(forwardedRef, node);
188
+ }, "data-slot": "splitter", "data-orientation": orientation, className: cn("flex min-h-32 min-w-0 overflow-hidden rounded-md border", vertical ? "flex-col" : "flex-row", className), children: panels.map((panel, index) => {
189
+ const size = resolvedSizes[index] ?? 0;
190
+ const nextPanel = panels[index + 1];
191
+ const disabled = nextPanel ? !canResize(index) : false;
192
+ const bounds = nextPanel ? pairBounds(index) : null;
193
+ const panelStyle = {
194
+ ...panel.props.style,
195
+ flexBasis: 0,
196
+ flexGrow: size,
197
+ flexShrink: 1,
198
+ };
199
+ return (_jsxs(Fragment, { children: [cloneElement(panel, { style: panelStyle }), nextPanel ? (_jsx("div", { role: "separator", "aria-orientation": vertical ? "horizontal" : "vertical", "aria-disabled": disabled || undefined, "aria-valuemin": bounds?.minLeft, "aria-valuemax": bounds?.maxLeft, "aria-valuenow": size, "aria-valuetext": `${Math.round(size * 10) / 10}%`, tabIndex: disabled ? -1 : 0, "data-slot": "splitter-handle", "data-disabled": disabled || undefined, onPointerDown: (event) => handlePointerDown(index, event), onPointerMove: (event) => handlePointerMove(index, event), onPointerUp: (event) => finishPointerResize(index, event), onPointerCancel: (event) => finishPointerResize(index, event), onKeyDown: (event) => handleKeyDown(index, event), className: cn("relative shrink-0 bg-border outline-none transition-colors", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", disabled
200
+ ? "cursor-not-allowed opacity-50"
201
+ : "hover:bg-primary/60", vertical
202
+ ? "h-1 w-full cursor-row-resize"
203
+ : "h-full w-1 cursor-col-resize") })) : null] }, panel.key ?? `splitter-panel-${index}`));
204
+ }) }));
205
+ });
206
+ export const Splitter = Object.assign(SplitterRoot, {
207
+ Panel: SplitterPanel,
208
+ });
@@ -0,0 +1,12 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ export interface StatisticProps extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "prefix" | "title"> {
3
+ /** Human-readable label for the metric. */
4
+ title: ReactNode;
5
+ /** Caller-owned displayed metric value. */
6
+ value: ReactNode;
7
+ /** Optional content rendered before the value. */
8
+ prefix?: ReactNode;
9
+ /** Optional content rendered after the value. */
10
+ suffix?: ReactNode;
11
+ }
12
+ export declare const Statistic: import("react").ForwardRefExoticComponent<StatisticProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ export const Statistic = forwardRef(function Statistic({ title, value, prefix, suffix, className, ...props }, ref) {
5
+ return (_jsxs("div", { ...props, ref: ref, "data-slot": "statistic", className: cn("space-y-1", className), children: [_jsx("div", { "data-slot": "statistic-title", className: "text-sm text-muted-foreground", children: title }), _jsxs("div", { "data-slot": "statistic-value", className: "text-2xl font-semibold", children: [prefix, value, suffix] })] }));
6
+ });
@@ -0,0 +1,54 @@
1
+ import { type CSSProperties, type HTMLAttributes, type Key, type ReactNode, type Ref } from "react";
2
+ export type StepsStatus = "wait" | "process" | "finish" | "error";
3
+ export type StepsOrientation = "horizontal" | "vertical";
4
+ export type StepsTitlePlacement = "horizontal" | "vertical";
5
+ export type StepsType = "default" | "dot" | "inline" | "navigation" | "panel";
6
+ export type StepsVariant = "filled" | "outlined";
7
+ export type StepsSize = "small" | "middle";
8
+ export interface StepItem {
9
+ key: Key;
10
+ title: ReactNode;
11
+ content?: ReactNode;
12
+ subTitle?: ReactNode;
13
+ icon?: ReactNode;
14
+ status?: StepsStatus;
15
+ disabled?: boolean;
16
+ }
17
+ export interface StepsIconRenderInfo {
18
+ index: number;
19
+ active: boolean;
20
+ status: StepsStatus;
21
+ item: StepItem;
22
+ }
23
+ export type StepsSemantic = "root" | "item" | "marker" | "connector" | "title" | "subTitle" | "content" | "progress";
24
+ export interface StepsSemanticInfo {
25
+ props: Readonly<{
26
+ orientation: StepsOrientation;
27
+ titlePlacement: StepsTitlePlacement;
28
+ type: StepsType;
29
+ variant: StepsVariant;
30
+ size: StepsSize;
31
+ }>;
32
+ }
33
+ export type StepsClassNames = Partial<Record<StepsSemantic, string>> | ((info: StepsSemanticInfo) => Partial<Record<StepsSemantic, string>>);
34
+ export type StepsStyles = Partial<Record<StepsSemantic, CSSProperties>> | ((info: StepsSemanticInfo) => Partial<Record<StepsSemantic, CSSProperties>>);
35
+ export interface StepsProps extends Omit<HTMLAttributes<HTMLOListElement>, "children" | "onChange"> {
36
+ items: readonly StepItem[];
37
+ current?: number;
38
+ initial?: number;
39
+ orientation?: StepsOrientation;
40
+ titlePlacement?: StepsTitlePlacement;
41
+ type?: StepsType;
42
+ variant?: StepsVariant;
43
+ size?: StepsSize;
44
+ status?: StepsStatus;
45
+ percent?: number;
46
+ maxCount?: number;
47
+ responsive?: boolean;
48
+ iconRender?: (origin: ReactNode, info: StepsIconRenderInfo) => ReactNode;
49
+ onChange?: (current: number) => void;
50
+ classNames?: StepsClassNames;
51
+ styles?: StepsStyles;
52
+ ref?: Ref<HTMLOListElement>;
53
+ }
54
+ export declare function Steps({ items, current, initial, orientation, titlePlacement, type, variant, size, status, percent, maxCount, responsive, iconRender, onChange, classNames, styles, className, style, ref, ...props }: StepsProps): import("react").JSX.Element;