@sia.soul/sia-react-ui 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 (46) hide show
  1. package/README.md +37 -0
  2. package/THIRD_PARTY_NOTICES.md +12 -0
  3. package/dist/Select-CJJ5LQap.d.cts +44 -0
  4. package/dist/Select-CJJ5LQap.d.ts +44 -0
  5. package/dist/chart.cjs +7523 -0
  6. package/dist/chart.css +1036 -0
  7. package/dist/chart.d.cts +2061 -0
  8. package/dist/chart.d.ts +2061 -0
  9. package/dist/chart.js +120 -0
  10. package/dist/chunk-34TTF4Y7.js +812 -0
  11. package/dist/chunk-6VXOLMKZ.js +381 -0
  12. package/dist/chunk-DZ45HRVP.js +583 -0
  13. package/dist/chunk-I342FGQY.js +7344 -0
  14. package/dist/chunk-JKZGAZMB.js +318 -0
  15. package/dist/chunk-MBS2HXLZ.js +59 -0
  16. package/dist/chunk-NZAT2RUM.js +60 -0
  17. package/dist/chunk-OMA75YLM.js +298 -0
  18. package/dist/chunk-ULEGTKXR.js +2138 -0
  19. package/dist/chunk-YCVXUMGP.js +945 -0
  20. package/dist/core-BeiAQiDY.d.ts +1076 -0
  21. package/dist/core-DRICIs2n.d.cts +1076 -0
  22. package/dist/core.cjs +3353 -0
  23. package/dist/core.css +8734 -0
  24. package/dist/core.d.cts +3 -0
  25. package/dist/core.d.ts +3 -0
  26. package/dist/core.js +45 -0
  27. package/dist/index.cjs +19658 -0
  28. package/dist/index.css +9762 -0
  29. package/dist/index.d.cts +1222 -0
  30. package/dist/index.d.ts +1222 -0
  31. package/dist/index.js +6843 -0
  32. package/dist/markdown-editor.cjs +417 -0
  33. package/dist/markdown-editor.d.cts +28 -0
  34. package/dist/markdown-editor.d.ts +28 -0
  35. package/dist/markdown-editor.js +6 -0
  36. package/dist/rich-text-editor.cjs +1853 -0
  37. package/dist/rich-text-editor.d.cts +27 -0
  38. package/dist/rich-text-editor.d.ts +27 -0
  39. package/dist/rich-text-editor.js +11 -0
  40. package/dist/select-date-range-BDWdo7qt.d.ts +84 -0
  41. package/dist/select-date-range-DWik3ADr.d.cts +84 -0
  42. package/dist/select-date-range.cjs +2074 -0
  43. package/dist/select-date-range.d.cts +3 -0
  44. package/dist/select-date-range.d.ts +3 -0
  45. package/dist/select-date-range.js +8 -0
  46. package/package.json +129 -0
@@ -0,0 +1,2138 @@
1
+ import {
2
+ TextArea
3
+ } from "./chunk-NZAT2RUM.js";
4
+ import {
5
+ Dropdown
6
+ } from "./chunk-DZ45HRVP.js";
7
+ import {
8
+ Button
9
+ } from "./chunk-MBS2HXLZ.js";
10
+ import {
11
+ Icon,
12
+ useControllableState
13
+ } from "./chunk-YCVXUMGP.js";
14
+
15
+ // src/components/Card.tsx
16
+ import { useState } from "react";
17
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
18
+ function Card({
19
+ title,
20
+ description,
21
+ extra,
22
+ accent,
23
+ accentColor,
24
+ collapsible = false,
25
+ collapsed,
26
+ defaultCollapsed = false,
27
+ onCollapsedChange,
28
+ bodyHeight,
29
+ bodyClassName = "",
30
+ bodyStyle,
31
+ className = "",
32
+ style,
33
+ children,
34
+ ...props
35
+ }) {
36
+ const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed);
37
+ const isCollapsed = collapsed ?? internalCollapsed;
38
+ const hasHeader = title || extra || collapsible;
39
+ const mergedStyle = accentColor ? { "--sia-card-accent": accentColor, ...style } : style;
40
+ const mergedBodyStyle = bodyHeight === void 0 ? { ...bodyStyle } : { height: bodyHeight, overflowY: "auto", ...bodyStyle };
41
+ function toggleCollapsed() {
42
+ const nextCollapsed = !isCollapsed;
43
+ if (collapsed === void 0) setInternalCollapsed(nextCollapsed);
44
+ onCollapsedChange?.(nextCollapsed);
45
+ }
46
+ const heading = /* @__PURE__ */ jsxs("span", { className: "sia-card__heading", children: [
47
+ accent || accentColor ? /* @__PURE__ */ jsx("span", { className: `sia-card__accent${accent ? ` sia-card__accent--${accent}` : ""}`, "aria-hidden": "true" }) : null,
48
+ title ? /* @__PURE__ */ jsx("h3", { className: "sia-card__title", children: title }) : null
49
+ ] });
50
+ return /* @__PURE__ */ jsxs("section", { className: `sia-card${isCollapsed ? " sia-card--collapsed" : ""} ${className}`.trim(), style: mergedStyle, ...props, children: [
51
+ hasHeader ? /* @__PURE__ */ jsxs("header", { className: "sia-card__header", children: [
52
+ collapsible ? /* @__PURE__ */ jsxs("button", { type: "button", className: "sia-card__collapse-trigger", "aria-expanded": !isCollapsed, onClick: toggleCollapsed, children: [
53
+ heading,
54
+ /* @__PURE__ */ jsx(Icon, { name: isCollapsed ? "chevron-down" : "chevron-up", size: 16 })
55
+ ] }) : heading,
56
+ extra ? /* @__PURE__ */ jsx("div", { className: "sia-card__extra", children: extra }) : null
57
+ ] }) : null,
58
+ !isCollapsed ? /* @__PURE__ */ jsxs(Fragment, { children: [
59
+ description ? /* @__PURE__ */ jsx("p", { className: "sia-card__description", children: description }) : null,
60
+ /* @__PURE__ */ jsx("div", { className: `sia-card__body ${bodyClassName}`.trim(), style: mergedBodyStyle, children })
61
+ ] }) : null
62
+ ] });
63
+ }
64
+
65
+ // src/components/Tag.tsx
66
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
67
+ function Tag({
68
+ status = "default",
69
+ compact = false,
70
+ variant = "soft",
71
+ icon,
72
+ closable = false,
73
+ disabled = false,
74
+ onClose,
75
+ className = "",
76
+ children,
77
+ ...props
78
+ }) {
79
+ return /* @__PURE__ */ jsxs2(
80
+ "span",
81
+ {
82
+ className: `sia-tag sia-tag--${status} sia-tag--${variant}${compact ? " sia-tag--compact" : ""}${disabled ? " sia-tag--disabled" : ""} ${className}`.trim(),
83
+ "aria-disabled": disabled || void 0,
84
+ ...props,
85
+ children: [
86
+ icon ? /* @__PURE__ */ jsx2("span", { className: "sia-tag__icon", children: icon }) : null,
87
+ /* @__PURE__ */ jsx2("span", { children }),
88
+ closable ? /* @__PURE__ */ jsx2(
89
+ "button",
90
+ {
91
+ type: "button",
92
+ className: "sia-tag__close",
93
+ "aria-label": "\u79FB\u9664\u6807\u7B7E",
94
+ disabled,
95
+ onClick: (event) => {
96
+ event.stopPropagation();
97
+ onClose?.(event);
98
+ },
99
+ children: /* @__PURE__ */ jsx2(Icon, { name: "close", size: 12 })
100
+ }
101
+ ) : null
102
+ ]
103
+ }
104
+ );
105
+ }
106
+
107
+ // src/components/Tabs.tsx
108
+ import { useId, useMemo, useState as useState2 } from "react";
109
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
110
+ function Tabs({
111
+ items,
112
+ activeKey,
113
+ defaultActiveKey,
114
+ onChange,
115
+ type = "line",
116
+ size = "medium",
117
+ tabPosition,
118
+ orientation = "horizontal",
119
+ centered = false,
120
+ tabBarTitle,
121
+ tabBarExtraContent,
122
+ destroyInactiveTabPane = true,
123
+ closable = false,
124
+ onEdit,
125
+ tabContextMenu,
126
+ onTabContextMenuClick,
127
+ className = "",
128
+ ...props
129
+ }) {
130
+ const firstEnabledKey = items.find((item) => !item.disabled)?.key ?? "";
131
+ const [internalActiveKey, setInternalActiveKey] = useState2(defaultActiveKey ?? firstEnabledKey);
132
+ const currentKey = activeKey ?? internalActiveKey;
133
+ const selectedKey = items.some((item) => item.key === currentKey && !item.disabled) ? currentKey : firstEnabledKey;
134
+ const baseId = useId().replace(/:/g, "");
135
+ const enabledItems = useMemo(() => items.filter((item) => !item.disabled), [items]);
136
+ const resolvedPosition = tabPosition ?? (orientation === "vertical" ? "left" : "top");
137
+ const resolvedOrientation = resolvedPosition === "left" || resolvedPosition === "right" ? "vertical" : "horizontal";
138
+ function selectTab(key) {
139
+ if (key === selectedKey) return;
140
+ if (activeKey === void 0) setInternalActiveKey(key);
141
+ onChange?.(key);
142
+ }
143
+ function focusAndSelect(key) {
144
+ selectTab(key);
145
+ document.getElementById(`${baseId}-tab-${key}`)?.focus();
146
+ }
147
+ function handleKeyDown(event, key) {
148
+ const previousKey = resolvedOrientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
149
+ const nextKey = resolvedOrientation === "horizontal" ? "ArrowRight" : "ArrowDown";
150
+ if (![previousKey, nextKey, "Home", "End"].includes(event.key) || enabledItems.length === 0) return;
151
+ event.preventDefault();
152
+ const currentIndex = Math.max(0, enabledItems.findIndex((item) => item.key === key));
153
+ if (event.key === "Home") return focusAndSelect(enabledItems[0].key);
154
+ if (event.key === "End") return focusAndSelect(enabledItems[enabledItems.length - 1].key);
155
+ const offset = event.key === nextKey ? 1 : -1;
156
+ const nextIndex = (currentIndex + offset + enabledItems.length) % enabledItems.length;
157
+ focusAndSelect(enabledItems[nextIndex].key);
158
+ }
159
+ const hasPanels = items.some((item) => item.children !== void 0);
160
+ return /* @__PURE__ */ jsxs3(
161
+ "div",
162
+ {
163
+ className: `sia-tabs sia-tabs--${type} sia-tabs--${size} sia-tabs--${resolvedOrientation} sia-tabs--${resolvedPosition}${centered ? " sia-tabs--centered" : ""} ${className}`.trim(),
164
+ ...props,
165
+ children: [
166
+ /* @__PURE__ */ jsxs3("div", { className: "sia-tabs__header", children: [
167
+ tabBarTitle ? /* @__PURE__ */ jsxs3("div", { className: "sia-tabs__title", children: [
168
+ tabBarTitle,
169
+ type === "tech-line" ? /* @__PURE__ */ jsx3("svg", { className: "sia-tabs__title-connector", viewBox: "0 0 32 40", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("path", { d: "M0 39 H5 Q8 39 10 35 L28 3 Q29 1 32 1", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }) }) : null
170
+ ] }) : null,
171
+ /* @__PURE__ */ jsx3("div", { className: "sia-tabs__list", role: "tablist", "aria-orientation": resolvedOrientation, children: items.map((item) => {
172
+ const selected = item.key === selectedKey;
173
+ const canClose = item.closable ?? closable;
174
+ const tabNode = /* @__PURE__ */ jsxs3("span", { className: `sia-tabs__tab-wrap${canClose ? " is-closable" : ""}`, children: [
175
+ /* @__PURE__ */ jsxs3(
176
+ "button",
177
+ {
178
+ id: `${baseId}-tab-${item.key}`,
179
+ type: "button",
180
+ className: "sia-tabs__tab",
181
+ role: "tab",
182
+ "aria-selected": selected,
183
+ "aria-controls": hasPanels ? `${baseId}-panel-${item.key}` : void 0,
184
+ tabIndex: selected ? 0 : -1,
185
+ disabled: item.disabled,
186
+ onClick: () => selectTab(item.key),
187
+ onKeyDown: (event) => handleKeyDown(event, item.key),
188
+ children: [
189
+ type === "tech-line" ? /* @__PURE__ */ jsxs3("svg", { className: "sia-tabs__tab-shape", viewBox: "0 0 100 34", preserveAspectRatio: "none", "aria-hidden": "true", children: [
190
+ /* @__PURE__ */ jsx3("defs", { children: /* @__PURE__ */ jsxs3("linearGradient", { id: `${baseId}-tab-fill-${item.key}`, x1: "0", y1: "0", x2: "1", y2: "0", children: [
191
+ /* @__PURE__ */ jsx3("stop", { offset: "0", stopColor: "var(--sia-tabs-line-fill-edge, var(--sia-tabs-line-fill))" }),
192
+ /* @__PURE__ */ jsx3("stop", { offset: ".53", stopColor: "var(--sia-tabs-line-fill-center, var(--sia-tabs-line-fill))" }),
193
+ /* @__PURE__ */ jsx3("stop", { offset: "1", stopColor: "var(--sia-tabs-line-fill-edge, var(--sia-tabs-line-fill))" })
194
+ ] }) }),
195
+ /* @__PURE__ */ jsx3(
196
+ "path",
197
+ {
198
+ d: "M19 1 H96 Q99 1 97.5 4 L83.5 30 Q82 33 79 33 H4 Q1 33 2.5 30 L16.5 4 Q18 1 19 1 Z",
199
+ fill: `url(#${baseId}-tab-fill-${item.key})`,
200
+ stroke: "currentColor",
201
+ strokeWidth: "1.5",
202
+ vectorEffect: "non-scaling-stroke"
203
+ }
204
+ )
205
+ ] }) : null,
206
+ item.icon ? /* @__PURE__ */ jsx3("span", { className: "sia-tabs__icon", children: item.icon }) : null,
207
+ /* @__PURE__ */ jsx3("span", { children: item.label })
208
+ ]
209
+ }
210
+ ),
211
+ canClose ? /* @__PURE__ */ jsx3(
212
+ "button",
213
+ {
214
+ type: "button",
215
+ className: "sia-tabs__close",
216
+ "aria-label": `\u5173\u95ED${typeof item.label === "string" ? item.label : "\u6807\u7B7E\u9875"}`,
217
+ disabled: item.disabled,
218
+ onClick: () => onEdit?.(item.key, "remove"),
219
+ children: /* @__PURE__ */ jsx3(Icon, { name: "close", size: 12 })
220
+ }
221
+ ) : null
222
+ ] }, item.key);
223
+ const contextMenuItems = typeof tabContextMenu === "function" ? tabContextMenu(item) : tabContextMenu;
224
+ if (!contextMenuItems?.length) return tabNode;
225
+ return /* @__PURE__ */ jsx3(
226
+ Dropdown,
227
+ {
228
+ className: "sia-tabs__tab-context-trigger",
229
+ popupClassName: "sia-tabs__tab-context-menu",
230
+ trigger: ["contextMenu"],
231
+ tabIndex: -1,
232
+ menu: {
233
+ items: contextMenuItems,
234
+ selectable: false,
235
+ onClick: (info) => onTabContextMenuClick?.({ ...info, tabKey: item.key, tab: item })
236
+ },
237
+ children: tabNode
238
+ },
239
+ item.key
240
+ );
241
+ }) }),
242
+ tabBarExtraContent ? /* @__PURE__ */ jsx3("div", { className: "sia-tabs__extra", children: tabBarExtraContent }) : null
243
+ ] }),
244
+ hasPanels ? /* @__PURE__ */ jsx3("div", { className: "sia-tabs__panels", children: items.map((item) => {
245
+ const selected = item.key === selectedKey;
246
+ if (destroyInactiveTabPane && !selected) return null;
247
+ return /* @__PURE__ */ jsx3(
248
+ "div",
249
+ {
250
+ id: `${baseId}-panel-${item.key}`,
251
+ className: "sia-tabs__panel",
252
+ role: "tabpanel",
253
+ "aria-labelledby": `${baseId}-tab-${item.key}`,
254
+ hidden: !selected,
255
+ tabIndex: 0,
256
+ children: item.children
257
+ },
258
+ item.key
259
+ );
260
+ }) }) : null
261
+ ]
262
+ }
263
+ );
264
+ }
265
+
266
+ // src/components/Checkbox.tsx
267
+ import { createContext, forwardRef, useContext, useEffect, useId as useId2, useMemo as useMemo2, useRef } from "react";
268
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
269
+ var CheckboxGroupContext = createContext(null);
270
+ var CheckboxRoot = forwardRef(function Checkbox({ value, indeterminate = false, children, disabled, checked, defaultChecked, className = "", onChange, ...props }, forwardedRef) {
271
+ const group = useContext(CheckboxGroupContext);
272
+ const localRef = useRef(null);
273
+ const fallbackId = useId2();
274
+ const grouped = group !== null && value !== void 0;
275
+ const currentChecked = grouped ? group.values.includes(value) : checked;
276
+ useEffect(() => {
277
+ if (localRef.current) localRef.current.indeterminate = indeterminate;
278
+ }, [indeterminate]);
279
+ function setRef(node) {
280
+ localRef.current = node;
281
+ if (typeof forwardedRef === "function") forwardedRef(node);
282
+ else if (forwardedRef) forwardedRef.current = node;
283
+ }
284
+ return /* @__PURE__ */ jsxs4("label", { className: `sia-checkbox${disabled || group?.disabled ? " is-disabled" : ""} ${className}`.trim(), children: [
285
+ /* @__PURE__ */ jsx4(
286
+ "input",
287
+ {
288
+ ...props,
289
+ ref: setRef,
290
+ id: props.id ?? fallbackId,
291
+ className: "sia-checkbox__input",
292
+ type: "checkbox",
293
+ name: group?.name ?? props.name,
294
+ disabled: disabled || group?.disabled,
295
+ checked: currentChecked,
296
+ defaultChecked: grouped ? void 0 : defaultChecked,
297
+ "aria-checked": indeterminate ? "mixed" : currentChecked,
298
+ onChange: (event) => {
299
+ if (grouped) group.toggle(value, event.currentTarget.checked);
300
+ onChange?.(event.currentTarget.checked, event);
301
+ }
302
+ }
303
+ ),
304
+ /* @__PURE__ */ jsx4("span", { className: "sia-checkbox__control", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("span", {}) }),
305
+ children !== void 0 ? /* @__PURE__ */ jsx4("span", { className: "sia-checkbox__label", children }) : null
306
+ ] });
307
+ });
308
+ function CheckboxGroup({
309
+ value,
310
+ defaultValue = [],
311
+ options,
312
+ disabled,
313
+ name,
314
+ className = "",
315
+ children,
316
+ onChange
317
+ }) {
318
+ const [values, setValues] = useControllableState({ value, defaultValue, onChange });
319
+ const context = useMemo2(() => ({
320
+ values,
321
+ disabled,
322
+ name,
323
+ toggle(optionValue, checked) {
324
+ const next = checked ? values.includes(optionValue) ? values : [...values, optionValue] : values.filter((item) => item !== optionValue);
325
+ setValues(next);
326
+ }
327
+ }), [disabled, name, setValues, values]);
328
+ return /* @__PURE__ */ jsx4(CheckboxGroupContext.Provider, { value: context, children: /* @__PURE__ */ jsxs4("div", { className: `sia-checkbox-group ${className}`.trim(), role: "group", children: [
329
+ options?.map((option) => {
330
+ const normalized = typeof option === "object" ? option : { label: String(option), value: option };
331
+ return /* @__PURE__ */ jsx4(CheckboxRoot, { value: normalized.value, disabled: normalized.disabled, children: normalized.label }, normalized.value);
332
+ }),
333
+ children
334
+ ] }) });
335
+ }
336
+ var Checkbox2 = Object.assign(CheckboxRoot, { Group: CheckboxGroup });
337
+
338
+ // src/components/FloatingDisplay.tsx
339
+ import { cloneElement, useEffect as useEffect2, useId as useId3, useLayoutEffect, useMemo as useMemo3, useRef as useRef2, useState as useState3 } from "react";
340
+ import { createPortal } from "react-dom";
341
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
342
+ var FLOATING_GAP = 9;
343
+ var FLOATING_VIEWPORT_PADDING = 8;
344
+ var FLOATING_ARROW_EDGE_OFFSET = 16;
345
+ var activeTooltipClose;
346
+ function clampFloating(value, min, max) {
347
+ return Math.min(Math.max(value, min), Math.max(min, max));
348
+ }
349
+ function resolveFloatingPosition(trigger, overlay, placement) {
350
+ const viewportWidth = document.documentElement.clientWidth;
351
+ const viewportHeight = document.documentElement.clientHeight;
352
+ let resolvedPlacement = placement;
353
+ if (placement.startsWith("top") && trigger.top - overlay.height - FLOATING_GAP < FLOATING_VIEWPORT_PADDING && trigger.bottom + overlay.height + FLOATING_GAP <= viewportHeight - FLOATING_VIEWPORT_PADDING) {
354
+ resolvedPlacement = placement.replace("top", "bottom");
355
+ } else if (placement.startsWith("bottom") && trigger.bottom + overlay.height + FLOATING_GAP > viewportHeight - FLOATING_VIEWPORT_PADDING && trigger.top - overlay.height - FLOATING_GAP >= FLOATING_VIEWPORT_PADDING) {
356
+ resolvedPlacement = placement.replace("bottom", "top");
357
+ } else if (placement === "left" && trigger.left - overlay.width - FLOATING_GAP < FLOATING_VIEWPORT_PADDING && trigger.right + overlay.width + FLOATING_GAP <= viewportWidth - FLOATING_VIEWPORT_PADDING) {
358
+ resolvedPlacement = "right";
359
+ } else if (placement === "right" && trigger.right + overlay.width + FLOATING_GAP > viewportWidth - FLOATING_VIEWPORT_PADDING && trigger.left - overlay.width - FLOATING_GAP >= FLOATING_VIEWPORT_PADDING) {
360
+ resolvedPlacement = "left";
361
+ }
362
+ let top = trigger.top;
363
+ let left = trigger.left;
364
+ if (resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom")) {
365
+ top = resolvedPlacement.startsWith("top") ? trigger.top - overlay.height - FLOATING_GAP : trigger.bottom + FLOATING_GAP;
366
+ left = resolvedPlacement.endsWith("-start") ? trigger.left : resolvedPlacement.endsWith("-end") ? trigger.right - overlay.width : trigger.left + (trigger.width - overlay.width) / 2;
367
+ } else {
368
+ top = trigger.top + (trigger.height - overlay.height) / 2;
369
+ left = resolvedPlacement === "left" ? trigger.left - overlay.width - FLOATING_GAP : trigger.right + FLOATING_GAP;
370
+ }
371
+ top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
372
+ left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
373
+ const result = { top, left, placement: resolvedPlacement };
374
+ if (resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom")) {
375
+ result.arrowX = resolvedPlacement.endsWith("-start") ? clampFloating(FLOATING_ARROW_EDGE_OFFSET, 8, overlay.width - 16) : resolvedPlacement.endsWith("-end") ? clampFloating(overlay.width - FLOATING_ARROW_EDGE_OFFSET - 8, 8, overlay.width - 16) : clampFloating(trigger.left + trigger.width / 2 - left - 4, 8, overlay.width - 16);
376
+ } else {
377
+ result.arrowY = clampFloating(trigger.top + trigger.height / 2 - top - 4, 8, overlay.height - 16);
378
+ }
379
+ return result;
380
+ }
381
+ function Floating({
382
+ children,
383
+ content,
384
+ placement = "top",
385
+ trigger = "hover",
386
+ open,
387
+ defaultOpen = false,
388
+ mouseEnterDelay = 0.1,
389
+ mouseLeaveDelay = 0.1,
390
+ arrow = true,
391
+ color,
392
+ className = "",
393
+ overlayClassName = "",
394
+ role = "tooltip",
395
+ onOpenChange
396
+ }) {
397
+ const rootRef = useRef2(null);
398
+ const overlayRef = useRef2(null);
399
+ const enterTimer = useRef2();
400
+ const leaveTimer = useRef2();
401
+ const contentId = useId3();
402
+ const triggers = Array.isArray(trigger) ? trigger : [trigger];
403
+ const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
404
+ const [position, setPosition] = useState3();
405
+ const setVisibleRef = useRef2(setVisible);
406
+ setVisibleRef.current = setVisible;
407
+ const closeSelfRef = useRef2();
408
+ if (!closeSelfRef.current) closeSelfRef.current = () => setVisibleRef.current(false);
409
+ const exclusiveTooltip = role === "tooltip" && triggers.includes("hover");
410
+ function openNow() {
411
+ if (exclusiveTooltip && activeTooltipClose !== closeSelfRef.current) {
412
+ activeTooltipClose?.();
413
+ activeTooltipClose = closeSelfRef.current;
414
+ }
415
+ setVisible(true);
416
+ }
417
+ function closeNow() {
418
+ if (activeTooltipClose === closeSelfRef.current) activeTooltipClose = void 0;
419
+ setVisible(false);
420
+ }
421
+ function clearTimers() {
422
+ window.clearTimeout(enterTimer.current);
423
+ window.clearTimeout(leaveTimer.current);
424
+ }
425
+ function show(delay = 0) {
426
+ clearTimers();
427
+ if (delay <= 0) openNow();
428
+ else enterTimer.current = window.setTimeout(openNow, delay * 1e3);
429
+ }
430
+ function hide(delay = 0) {
431
+ clearTimers();
432
+ if (delay <= 0) closeNow();
433
+ else leaveTimer.current = window.setTimeout(closeNow, delay * 1e3);
434
+ }
435
+ useEffect2(() => {
436
+ if (!visible || !triggers.includes("click")) return;
437
+ const close = (event) => {
438
+ const target = event.target;
439
+ if (!rootRef.current?.contains(target) && !overlayRef.current?.contains(target)) closeNow();
440
+ };
441
+ document.addEventListener("pointerdown", close);
442
+ return () => document.removeEventListener("pointerdown", close);
443
+ }, [triggers.join("|"), visible]);
444
+ useLayoutEffect(() => {
445
+ if (!visible) {
446
+ setPosition(void 0);
447
+ return;
448
+ }
449
+ const update = () => {
450
+ if (!rootRef.current || !overlayRef.current) return;
451
+ setPosition(resolveFloatingPosition(rootRef.current.getBoundingClientRect(), overlayRef.current.getBoundingClientRect(), placement));
452
+ };
453
+ update();
454
+ window.addEventListener("resize", update);
455
+ window.addEventListener("scroll", update, true);
456
+ const observer = new ResizeObserver(update);
457
+ if (rootRef.current) observer.observe(rootRef.current);
458
+ if (overlayRef.current) observer.observe(overlayRef.current);
459
+ return () => {
460
+ window.removeEventListener("resize", update);
461
+ window.removeEventListener("scroll", update, true);
462
+ observer.disconnect();
463
+ };
464
+ }, [children, content, placement, visible]);
465
+ useEffect2(() => () => {
466
+ clearTimers();
467
+ if (activeTooltipClose === closeSelfRef.current) activeTooltipClose = void 0;
468
+ }, []);
469
+ const child = cloneElement(children, {
470
+ ...triggers.includes("hover") ? { onMouseEnter: (event) => {
471
+ children.props.onMouseEnter?.(event);
472
+ show(mouseEnterDelay);
473
+ }, onMouseLeave: (event) => {
474
+ children.props.onMouseLeave?.(event);
475
+ hide(mouseLeaveDelay);
476
+ } } : {},
477
+ ...triggers.includes("focus") ? { onFocus: (event) => {
478
+ children.props.onFocus?.(event);
479
+ show();
480
+ }, onBlur: (event) => {
481
+ children.props.onBlur?.(event);
482
+ hide();
483
+ } } : {},
484
+ ...triggers.includes("click") ? { onClick: (event) => {
485
+ children.props.onClick?.(event);
486
+ if (visible) closeNow();
487
+ else openNow();
488
+ } } : {},
489
+ "aria-describedby": visible ? contentId : void 0
490
+ });
491
+ const overlay = visible && content !== null && content !== void 0 && typeof document !== "undefined" ? createPortal(
492
+ /* @__PURE__ */ jsxs5(
493
+ "span",
494
+ {
495
+ ref: overlayRef,
496
+ id: contentId,
497
+ role,
498
+ "data-custom-color": color ? "" : void 0,
499
+ className: `sia-floating__overlay sia-floating__overlay--${position?.placement ?? placement} ${overlayClassName}`.trim(),
500
+ style: {
501
+ "--sia-floating-color": color,
502
+ "--sia-floating-arrow-x": position?.arrowX == null ? void 0 : `${position.arrowX}px`,
503
+ "--sia-floating-arrow-y": position?.arrowY == null ? void 0 : `${position.arrowY}px`,
504
+ top: position?.top ?? 0,
505
+ left: position?.left ?? 0,
506
+ visibility: position ? "visible" : "hidden"
507
+ },
508
+ onMouseEnter: triggers.includes("hover") ? () => show() : void 0,
509
+ onMouseLeave: triggers.includes("hover") ? () => hide(mouseLeaveDelay) : void 0,
510
+ children: [
511
+ content,
512
+ arrow ? /* @__PURE__ */ jsx5("span", { className: "sia-floating__arrow" }) : null
513
+ ]
514
+ }
515
+ ),
516
+ document.body
517
+ ) : null;
518
+ return /* @__PURE__ */ jsxs5(Fragment2, { children: [
519
+ /* @__PURE__ */ jsx5("span", { ref: rootRef, className: `sia-floating ${className}`.trim(), children: child }),
520
+ overlay
521
+ ] });
522
+ }
523
+ function Tooltip(props) {
524
+ return /* @__PURE__ */ jsx5(Floating, { ...props, content: props.title });
525
+ }
526
+ function Popover({ title, content, trigger = "click", overlayClassName = "", ...props }) {
527
+ return /* @__PURE__ */ jsx5(Floating, { ...props, trigger, role: "dialog", overlayClassName: `sia-popover ${overlayClassName}`.trim(), content: /* @__PURE__ */ jsxs5(Fragment2, { children: [
528
+ title ? /* @__PURE__ */ jsx5("strong", { className: "sia-popover__title", children: title }) : null,
529
+ /* @__PURE__ */ jsx5("span", { className: "sia-popover__content", children: content })
530
+ ] }) });
531
+ }
532
+ function Timeline({ items = [], mode = "left", pending = false, pendingDot, reverse = false, className = "", ...props }) {
533
+ const values = [...items, ...pending ? [{ children: pending === true ? "\u52A0\u8F7D\u4E2D..." : pending, dot: pendingDot ?? /* @__PURE__ */ jsx5(Icon, { name: "loader", className: "sia-spin-icon" }) }] : []];
534
+ if (reverse) values.reverse();
535
+ return /* @__PURE__ */ jsx5("ul", { className: `sia-timeline sia-timeline--${mode} ${className}`.trim(), ...props, children: values.map((item, index) => {
536
+ const position = item.position ?? (mode === "alternate" ? index % 2 ? "right" : "left" : mode);
537
+ return /* @__PURE__ */ jsxs5("li", { className: `sia-timeline__item sia-timeline__item--${position}`, children: [
538
+ item.label ? /* @__PURE__ */ jsx5("span", { className: "sia-timeline__label", children: item.label }) : null,
539
+ /* @__PURE__ */ jsx5("span", { className: "sia-timeline__rail", children: /* @__PURE__ */ jsx5("span", { className: "sia-timeline__dot", style: { color: item.color && !["blue", "red", "green", "gray"].includes(item.color) ? item.color : void 0 }, "data-color": item.color ?? "blue", children: item.dot }) }),
540
+ /* @__PURE__ */ jsx5("span", { className: "sia-timeline__content", children: item.children })
541
+ ] }, index);
542
+ }) });
543
+ }
544
+ function collectKeys(nodes, branchOnly = false, result = []) {
545
+ nodes.forEach((node) => {
546
+ if (!branchOnly || node.children?.length) result.push(node.key);
547
+ if (node.children) collectKeys(node.children, branchOnly, result);
548
+ });
549
+ return result;
550
+ }
551
+ function descendants(node) {
552
+ return node.children ? collectKeys(node.children) : [];
553
+ }
554
+ function Tree({
555
+ treeData,
556
+ selectedKeys,
557
+ defaultSelectedKeys = [],
558
+ expandedKeys,
559
+ defaultExpandedKeys = [],
560
+ defaultExpandAll = false,
561
+ checkedKeys,
562
+ defaultCheckedKeys = [],
563
+ loadingKeys = [],
564
+ checkable = false,
565
+ checkStrictly = false,
566
+ multiple = false,
567
+ selectable = true,
568
+ showLine = false,
569
+ showIcon = false,
570
+ blockNode = false,
571
+ indentSize = 20,
572
+ switcherWidth = 24,
573
+ stickyAncestors = false,
574
+ stickyRowHeight = 34,
575
+ draggable = false,
576
+ loadData,
577
+ onSelect,
578
+ onCheck,
579
+ onExpand,
580
+ onDrop,
581
+ className = "",
582
+ ...props
583
+ }) {
584
+ const [selected, setSelected] = useControllableState({ value: selectedKeys, defaultValue: defaultSelectedKeys });
585
+ const [expanded, setExpanded] = useControllableState({ value: expandedKeys, defaultValue: defaultExpandAll ? collectKeys(treeData, true) : defaultExpandedKeys });
586
+ const [checked, setChecked] = useControllableState({ value: checkedKeys, defaultValue: defaultCheckedKeys });
587
+ const [loading, setLoading] = useState3(/* @__PURE__ */ new Set());
588
+ const controlledLoading = useMemo3(() => new Set(loadingKeys), [loadingKeys]);
589
+ const selectedKeySet = useMemo3(() => new Set(selected), [selected]);
590
+ const selectedAncestorKeys = useMemo3(() => {
591
+ const ancestors = /* @__PURE__ */ new Set();
592
+ const visit = (nodes, parentKeys) => {
593
+ nodes.forEach((node) => {
594
+ if (selectedKeySet.has(node.key)) parentKeys.forEach((key) => ancestors.add(key));
595
+ if (node.children?.length) visit(node.children, [...parentKeys, node.key]);
596
+ });
597
+ };
598
+ visit(treeData, []);
599
+ return ancestors;
600
+ }, [selectedKeySet, treeData]);
601
+ const dragNodeRef = useRef2();
602
+ const pointerDragRef = useRef2();
603
+ const suppressClickRef = useRef2(false);
604
+ const [dragOver, setDragOver] = useState3();
605
+ const normalizedSwitcherWidth = Math.max(0, switcherWidth);
606
+ async function toggleExpand(node) {
607
+ const nextExpanded = !expanded.includes(node.key);
608
+ if (nextExpanded && node.loaded !== true && !node.children?.length && node.isLeaf === false && loadData) {
609
+ setLoading((keys) => new Set(keys).add(node.key));
610
+ try {
611
+ await loadData(node);
612
+ } finally {
613
+ setLoading((keys) => {
614
+ const next2 = new Set(keys);
615
+ next2.delete(node.key);
616
+ return next2;
617
+ });
618
+ }
619
+ }
620
+ const next = nextExpanded ? [...expanded, node.key] : expanded.filter((key) => key !== node.key);
621
+ setExpanded(next);
622
+ onExpand?.([...next], { expanded: nextExpanded, node });
623
+ }
624
+ function check(node) {
625
+ const nodeChecked = checked.includes(node.key);
626
+ const affected = checkStrictly ? [node.key] : [node.key, ...descendants(node)];
627
+ const next = nodeChecked ? checked.filter((key) => !affected.includes(key)) : [.../* @__PURE__ */ new Set([...checked, ...affected])];
628
+ setChecked(next);
629
+ onCheck?.([...next], { checked: !nodeChecked, node });
630
+ }
631
+ function select(node, event) {
632
+ if (!selectable || node.selectable === false || node.disabled) return;
633
+ const exists = selected.includes(node.key);
634
+ const next = multiple ? exists ? selected.filter((key) => key !== node.key) : [...selected, node.key] : exists ? [] : [node.key];
635
+ setSelected(next);
636
+ onSelect?.([...next], { selected: !exists, node, nativeEvent: event });
637
+ }
638
+ function selectForContextMenu(node, event) {
639
+ if (!selectable || node.selectable === false || node.disabled || selected.includes(node.key)) return;
640
+ const next = [node.key];
641
+ setSelected(next);
642
+ onSelect?.(next, { selected: true, node, nativeEvent: event });
643
+ }
644
+ function findNode(key, nodes = treeData) {
645
+ for (const node of nodes) {
646
+ if (String(node.key) === key) return node;
647
+ const child = node.children?.length ? findNode(key, node.children) : void 0;
648
+ if (child) return child;
649
+ }
650
+ return void 0;
651
+ }
652
+ function getPointerDropTarget(clientX, clientY, dragNode) {
653
+ const targetElement = document.elementFromPoint(clientX, clientY)?.closest("[data-sia-tree-drop-key]");
654
+ if (!targetElement) return void 0;
655
+ const targetNode = targetElement?.dataset.siaTreeDropKey ? findNode(targetElement.dataset.siaTreeDropKey) : void 0;
656
+ if (!targetNode || targetNode.key === dragNode.key || targetNode.disabled || targetNode.droppable === false) return void 0;
657
+ const bounds = targetElement.getBoundingClientRect();
658
+ const relativeY = bounds.height > 0 ? (clientY - bounds.top) / bounds.height : 0.5;
659
+ const dropPosition = relativeY < 0.25 ? "before" : relativeY > 0.75 ? "after" : "inside";
660
+ return { node: targetNode, dropPosition };
661
+ }
662
+ function beginPointerDrag(node, event) {
663
+ if (event.button !== 0) return;
664
+ pointerDragRef.current = {
665
+ node,
666
+ pointerId: event.pointerId,
667
+ startX: event.clientX,
668
+ startY: event.clientY,
669
+ active: false
670
+ };
671
+ event.currentTarget.setPointerCapture(event.pointerId);
672
+ }
673
+ function movePointerDrag(event) {
674
+ const pointerDrag = pointerDragRef.current;
675
+ if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
676
+ if (!pointerDrag.active && Math.hypot(event.clientX - pointerDrag.startX, event.clientY - pointerDrag.startY) < 5) return;
677
+ pointerDrag.active = true;
678
+ dragNodeRef.current = pointerDrag.node;
679
+ event.preventDefault();
680
+ const target = getPointerDropTarget(event.clientX, event.clientY, pointerDrag.node);
681
+ setDragOver(target ? { key: target.node.key, position: target.dropPosition } : void 0);
682
+ }
683
+ function finishPointerDrag(event) {
684
+ const pointerDrag = pointerDragRef.current;
685
+ if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
686
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
687
+ if (pointerDrag.active) {
688
+ event.preventDefault();
689
+ suppressClickRef.current = true;
690
+ const target = getPointerDropTarget(event.clientX, event.clientY, pointerDrag.node);
691
+ if (target) onDrop?.({ dragNode: pointerDrag.node, node: target.node, dropPosition: target.dropPosition });
692
+ window.setTimeout(() => {
693
+ suppressClickRef.current = false;
694
+ }, 0);
695
+ }
696
+ pointerDragRef.current = void 0;
697
+ dragNodeRef.current = void 0;
698
+ setDragOver(void 0);
699
+ }
700
+ function cancelPointerDrag(event) {
701
+ const pointerDrag = pointerDragRef.current;
702
+ if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
703
+ pointerDragRef.current = void 0;
704
+ dragNodeRef.current = void 0;
705
+ setDragOver(void 0);
706
+ }
707
+ function render(nodes, depth = 0) {
708
+ return nodes.map((node) => {
709
+ const open = expanded.includes(node.key);
710
+ const isSelected = selected.includes(node.key);
711
+ const isSelectedAncestor = selectedAncestorKeys.has(node.key);
712
+ const isChecked = checked.includes(node.key);
713
+ const hasChildren = Boolean(node.children?.length || node.isLeaf === false);
714
+ const nodeLoading = loading.has(node.key) || controlledLoading.has(node.key);
715
+ const sticky = stickyAncestors && hasChildren && open;
716
+ const canDrag = draggable && node.draggable !== false && !node.disabled;
717
+ const { className: rowClassName = "", style: rowStyle, onClick: onRowClick, ...rowProps } = node.rowProps ?? {};
718
+ const unloaded = hasChildren && node.loaded === false;
719
+ const dropPosition = dragOver?.key === node.key ? dragOver.position : void 0;
720
+ return /* @__PURE__ */ jsxs5("div", { className: `sia-tree__node${isSelected ? " is-selected" : ""}${isSelectedAncestor ? " is-selected-ancestor" : ""}${dropPosition ? ` is-drag-over-${dropPosition}` : ""}${node.disabled ? " is-disabled" : ""}${unloaded ? " is-unloaded" : ""}`, role: "treeitem", "aria-expanded": hasChildren ? open : void 0, "aria-selected": isSelected, children: [
721
+ /* @__PURE__ */ jsx5(
722
+ "div",
723
+ {
724
+ ...rowProps,
725
+ className: `sia-tree__row${blockNode ? " sia-tree__row--block" : ""}${sticky ? " sia-tree__row--sticky" : ""} ${rowClassName}`.trim(),
726
+ style: {
727
+ ...rowStyle,
728
+ paddingInlineStart: depth * Math.max(0, indentSize),
729
+ top: sticky ? depth * Math.max(1, stickyRowHeight) : rowStyle?.top,
730
+ zIndex: sticky ? Math.max(1, 100 - depth) : rowStyle?.zIndex
731
+ },
732
+ "aria-busy": nodeLoading || void 0,
733
+ "data-sia-tree-drop-key": String(node.key),
734
+ "data-sia-tree-draggable": canDrag || void 0,
735
+ onClick: (event) => {
736
+ onRowClick?.(event);
737
+ if (event.defaultPrevented || suppressClickRef.current || node.disabled) return;
738
+ select(node, event);
739
+ if (hasChildren) void toggleExpand(node);
740
+ },
741
+ children: (() => {
742
+ const content = /* @__PURE__ */ jsxs5("span", { className: "sia-tree__context-content", children: [
743
+ hasChildren ? /* @__PURE__ */ jsx5("button", { type: "button", className: "sia-tree__switcher", style: { width: normalizedSwitcherWidth, flexBasis: normalizedSwitcherWidth }, disabled: node.disabled, onClick: (event) => {
744
+ event.stopPropagation();
745
+ void toggleExpand(node);
746
+ }, children: nodeLoading ? /* @__PURE__ */ jsx5(Icon, { name: "loader", className: "sia-spin-icon", size: 13 }) : /* @__PURE__ */ jsx5(Icon, { name: open ? "chevron-down" : "chevron-right", size: 13 }) }) : /* @__PURE__ */ jsx5("span", { className: "sia-tree__switcher", style: { width: normalizedSwitcherWidth, flexBasis: normalizedSwitcherWidth }, "aria-hidden": "true" }),
747
+ checkable || node.checkable ? /* @__PURE__ */ jsx5("span", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx5(Checkbox2, { checked: isChecked, disabled: node.disabled || node.disableCheckbox, onChange: () => check(node) }) }) : null,
748
+ node.prefix ? /* @__PURE__ */ jsx5("span", { className: "sia-tree__prefix", onClick: (event) => event.stopPropagation(), children: node.prefix }) : null,
749
+ showIcon ? /* @__PURE__ */ jsx5("span", { className: "sia-tree__icon", children: node.icon ?? /* @__PURE__ */ jsx5(Icon, { name: hasChildren ? "folder" : "file", size: 15 }) }) : null,
750
+ /* @__PURE__ */ jsx5(
751
+ "button",
752
+ {
753
+ type: "button",
754
+ className: "sia-tree__title",
755
+ disabled: node.disabled,
756
+ onPointerDown: canDrag ? (event) => beginPointerDrag(node, event) : void 0,
757
+ onPointerMove: canDrag ? movePointerDrag : void 0,
758
+ onPointerUp: canDrag ? finishPointerDrag : void 0,
759
+ onPointerCancel: canDrag ? cancelPointerDrag : void 0,
760
+ children: node.title
761
+ }
762
+ ),
763
+ nodeLoading ? /* @__PURE__ */ jsx5("span", { className: "sia-tree__loading-text", role: "status", children: node.loadingText ?? "\u6B63\u5728\u52A0\u8F7D\u2026" }) : null,
764
+ node.extra ? /* @__PURE__ */ jsx5("span", { className: "sia-tree__extra", onClick: (event) => event.stopPropagation(), children: node.extra }) : null
765
+ ] });
766
+ return node.contextMenu ? /* @__PURE__ */ jsx5(
767
+ Dropdown,
768
+ {
769
+ className: "sia-tree__context-trigger",
770
+ popupClassName: node.contextMenuPopupClassName,
771
+ trigger: ["contextMenu"],
772
+ menu: node.contextMenu,
773
+ onContextMenu: (event) => selectForContextMenu(node, event),
774
+ children: content
775
+ }
776
+ ) : content;
777
+ })()
778
+ }
779
+ ),
780
+ open && node.children?.length ? /* @__PURE__ */ jsx5("div", { className: "sia-tree__children", role: "group", children: render(node.children, depth + 1) }) : null
781
+ ] }, node.key);
782
+ });
783
+ }
784
+ return /* @__PURE__ */ jsx5("div", { className: `sia-tree${showLine ? " sia-tree--line" : ""}${stickyAncestors ? " sia-tree--sticky-ancestors" : ""} ${className}`.trim(), role: "tree", "aria-multiselectable": multiple || void 0, ...props, children: render(treeData) });
785
+ }
786
+
787
+ // src/components/Feedback.tsx
788
+ import { useEffect as useEffect3, useMemo as useMemo4, useState as useState4 } from "react";
789
+ import { createPortal as createPortal2 } from "react-dom";
790
+ import { createRoot } from "react-dom/client";
791
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
792
+ function Popconfirm({
793
+ children,
794
+ title,
795
+ description,
796
+ okText = "\u786E\u5B9A",
797
+ cancelText = "\u53D6\u6D88",
798
+ okButtonProps,
799
+ cancelButtonProps,
800
+ placement = "top",
801
+ trigger = "click",
802
+ open,
803
+ defaultOpen = false,
804
+ disabled = false,
805
+ showCancel = true,
806
+ icon = /* @__PURE__ */ jsx6(Icon, { name: "question", variant: "filled" }),
807
+ onConfirm,
808
+ onCancel,
809
+ onOpenChange
810
+ }) {
811
+ const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
812
+ const [loading, setLoading] = useState4(false);
813
+ const content = /* @__PURE__ */ jsxs6("div", { className: "sia-popconfirm", children: [
814
+ /* @__PURE__ */ jsxs6("div", { className: "sia-popconfirm__message", children: [
815
+ /* @__PURE__ */ jsx6("span", { children: icon }),
816
+ /* @__PURE__ */ jsxs6("div", { children: [
817
+ /* @__PURE__ */ jsx6("strong", { children: title }),
818
+ description ? /* @__PURE__ */ jsx6("p", { children: description }) : null
819
+ ] })
820
+ ] }),
821
+ /* @__PURE__ */ jsxs6("div", { className: "sia-popconfirm__actions", children: [
822
+ showCancel ? /* @__PURE__ */ jsx6(Button, { size: "small", ...cancelButtonProps, onClick: (event) => {
823
+ cancelButtonProps?.onClick?.(event);
824
+ onCancel?.(event);
825
+ setVisible(false);
826
+ }, children: cancelText }) : null,
827
+ /* @__PURE__ */ jsx6(Button, { size: "small", variant: "primary", ...okButtonProps, loading: loading || okButtonProps?.loading, onClick: async (event) => {
828
+ okButtonProps?.onClick?.(event);
829
+ const result = onConfirm?.(event);
830
+ if (result instanceof Promise) {
831
+ setLoading(true);
832
+ try {
833
+ if (await result !== false) setVisible(false);
834
+ } finally {
835
+ setLoading(false);
836
+ }
837
+ } else if (result !== false) setVisible(false);
838
+ }, children: okText })
839
+ ] })
840
+ ] });
841
+ return /* @__PURE__ */ jsx6(Popover, { content, placement, trigger: disabled ? [] : trigger, open: visible, onOpenChange: setVisible, children });
842
+ }
843
+ function Progress({
844
+ percent = 0,
845
+ type = "line",
846
+ status,
847
+ showInfo = true,
848
+ format,
849
+ strokeColor,
850
+ trailColor,
851
+ strokeWidth = 8,
852
+ width = 120,
853
+ steps,
854
+ success,
855
+ size = "default",
856
+ className = "",
857
+ style,
858
+ ...props
859
+ }) {
860
+ const safe = Math.max(0, Math.min(100, percent));
861
+ const resolved = status ?? (safe >= 100 ? "success" : "normal");
862
+ const color = typeof strokeColor === "string" ? strokeColor : void 0;
863
+ const background = typeof strokeColor === "object" ? `linear-gradient(90deg, ${strokeColor.from}, ${strokeColor.to})` : color;
864
+ const label = format?.(safe, success?.percent) ?? (resolved === "exception" ? /* @__PURE__ */ jsx6(Icon, { name: "close" }) : resolved === "success" ? /* @__PURE__ */ jsx6(Icon, { name: "check" }) : `${safe}%`);
865
+ if (type !== "line") {
866
+ const radius = 46;
867
+ const circumference = 2 * Math.PI * radius;
868
+ const dash = circumference * (safe / 100);
869
+ return /* @__PURE__ */ jsxs6("div", { className: `sia-progress sia-progress--${type} sia-progress--${resolved} ${className}`.trim(), style: { width, height: width, ...style }, ...props, children: [
870
+ /* @__PURE__ */ jsxs6("svg", { viewBox: "0 0 100 100", role: "progressbar", "aria-valuenow": safe, children: [
871
+ /* @__PURE__ */ jsx6("circle", { className: "sia-progress__trail", cx: "50", cy: "50", r: radius, style: { stroke: trailColor } }),
872
+ /* @__PURE__ */ jsx6("circle", { className: "sia-progress__circle", cx: "50", cy: "50", r: radius, style: { stroke: color, strokeDasharray: type === "dashboard" ? `${circumference * 0.75} ${circumference * 0.25}` : circumference, strokeDashoffset: (type === "dashboard" ? circumference * 0.75 : circumference) - dash * (type === "dashboard" ? 0.75 : 1), strokeWidth } })
873
+ ] }),
874
+ showInfo ? /* @__PURE__ */ jsx6("span", { className: "sia-progress__text", children: label }) : null
875
+ ] });
876
+ }
877
+ const height = Array.isArray(size) ? size[1] : typeof size === "number" ? size : size === "small" ? 6 : strokeWidth;
878
+ return /* @__PURE__ */ jsxs6("div", { className: `sia-progress sia-progress--line sia-progress--${resolved} ${className}`.trim(), style, ...props, children: [
879
+ /* @__PURE__ */ jsx6("div", { className: "sia-progress__outer", style: { height, backgroundColor: trailColor }, children: steps ? /* @__PURE__ */ jsx6("div", { className: "sia-progress__steps", children: Array.from({ length: steps }, (_, index) => /* @__PURE__ */ jsx6("span", { className: index < Math.round(steps * safe / 100) ? "is-active" : "", style: { background: index < Math.round(steps * safe / 100) ? background : trailColor } }, index)) }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
880
+ /* @__PURE__ */ jsx6("span", { className: "sia-progress__bar", style: { width: `${safe}%`, background } }),
881
+ success?.percent ? /* @__PURE__ */ jsx6("span", { className: "sia-progress__success", style: { width: `${success.percent}%`, background: success.strokeColor } }) : null
882
+ ] }) }),
883
+ showInfo ? /* @__PURE__ */ jsx6("span", { className: "sia-progress__info", children: label }) : null
884
+ ] });
885
+ }
886
+ function Spin({ spinning = true, size = "default", tip, indicator, delay = 0, fullscreen = false, className = "", children, ...props }) {
887
+ const [visible, setVisible] = useState4(delay === 0 && spinning);
888
+ useEffect3(() => {
889
+ if (!spinning) {
890
+ setVisible(false);
891
+ return;
892
+ }
893
+ const timer = window.setTimeout(() => setVisible(true), delay);
894
+ return () => window.clearTimeout(timer);
895
+ }, [delay, spinning]);
896
+ const spinner = visible ? /* @__PURE__ */ jsxs6("div", { className: `sia-spin sia-spin--${size}`, role: "status", "aria-live": "polite", children: [
897
+ indicator ?? /* @__PURE__ */ jsxs6("span", { className: "sia-spin__indicator", children: [
898
+ /* @__PURE__ */ jsx6("i", {}),
899
+ /* @__PURE__ */ jsx6("i", {}),
900
+ /* @__PURE__ */ jsx6("i", {}),
901
+ /* @__PURE__ */ jsx6("i", {})
902
+ ] }),
903
+ tip ? /* @__PURE__ */ jsx6("span", { className: "sia-spin__tip", children: tip }) : null
904
+ ] }) : null;
905
+ if (fullscreen) return visible && typeof document !== "undefined" ? createPortal2(/* @__PURE__ */ jsx6("div", { className: "sia-spin-fullscreen", children: spinner }), document.body) : null;
906
+ if (!children) return /* @__PURE__ */ jsx6("div", { className: `sia-spin-wrap ${className}`.trim(), ...props, children: spinner });
907
+ return /* @__PURE__ */ jsxs6("div", { className: `sia-spin-container${visible ? " is-spinning" : ""} ${className}`.trim(), ...props, children: [
908
+ children,
909
+ visible ? /* @__PURE__ */ jsx6("div", { className: "sia-spin-mask", children: spinner }) : null
910
+ ] });
911
+ }
912
+ function escapeXml(value) {
913
+ return value.replace(/[&<>"']/g, (char) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&apos;" })[char]);
914
+ }
915
+ function Watermark({ content = "Sia Web UI", image, width = 120, height = 64, rotate = -22, zIndex = 9, gap = [100, 100], offset = [0, 0], font, className = "", children, ...props }) {
916
+ const background = useMemo4(() => {
917
+ const tileWidth = width + gap[0], tileHeight = height + gap[1];
918
+ const lines = Array.isArray(content) ? content : [content];
919
+ const family = font?.fontFamily ?? "sans-serif", size = font?.fontSize ?? 16, weight = font?.fontWeight ?? 400, color = font?.color ?? "rgba(0,0,0,.15)";
920
+ const body = image ? `<image href="${escapeXml(image)}" x="0" y="0" width="${width}" height="${height}"/>` : lines.map((line, index) => `<text x="${width / 2}" y="${height / 2 + (index - (lines.length - 1) / 2) * (size + 5)}" text-anchor="middle" dominant-baseline="middle" fill="${color}" font-size="${size}" font-weight="${weight}" font-family="${family}">${escapeXml(line)}</text>`).join("");
921
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${tileWidth}" height="${tileHeight}"><g transform="translate(${offset[0]} ${offset[1]}) rotate(${rotate} ${width / 2} ${height / 2})">${body}</g></svg>`;
922
+ return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
923
+ }, [content, font?.color, font?.fontFamily, font?.fontSize, font?.fontWeight, gap[0], gap[1], height, image, offset[0], offset[1], rotate, width]);
924
+ return /* @__PURE__ */ jsxs6("div", { className: `sia-watermark ${className}`.trim(), ...props, children: [
925
+ children,
926
+ /* @__PURE__ */ jsx6("div", { className: "sia-watermark__layer", "aria-hidden": "true", style: { zIndex, backgroundImage: background } })
927
+ ] });
928
+ }
929
+ var notificationListeners = /* @__PURE__ */ new Set();
930
+ var notificationEntries = [];
931
+ var notificationSeed = 0;
932
+ var notificationHost = null;
933
+ var notificationTimers = /* @__PURE__ */ new Map();
934
+ function emitNotifications() {
935
+ notificationListeners.forEach((listener) => listener([...notificationEntries]));
936
+ }
937
+ function closeNotification(key) {
938
+ const entry = notificationEntries.find((item) => item.key === key);
939
+ notificationEntries = notificationEntries.filter((item) => item.key !== key);
940
+ window.clearTimeout(notificationTimers.get(key));
941
+ notificationTimers.delete(key);
942
+ emitNotifications();
943
+ entry?.onClose?.();
944
+ }
945
+ function NotificationHost() {
946
+ const [entries, setEntries] = useState4(notificationEntries);
947
+ useEffect3(() => {
948
+ notificationListeners.add(setEntries);
949
+ return () => {
950
+ notificationListeners.delete(setEntries);
951
+ };
952
+ }, []);
953
+ const placements = ["topLeft", "topRight", "bottomLeft", "bottomRight"];
954
+ return /* @__PURE__ */ jsx6(Fragment3, { children: placements.map((placement) => /* @__PURE__ */ jsx6("div", { className: `sia-notification sia-notification--${placement}`, children: entries.filter((item) => (item.placement ?? "topRight") === placement).map((item) => /* @__PURE__ */ jsxs6("div", { className: `sia-notification__notice sia-notification__notice--${item.type ?? "info"}`, role: item.role ?? "alert", onClick: item.onClick, children: [
955
+ /* @__PURE__ */ jsx6("span", { className: "sia-notification__icon", children: item.icon ?? /* @__PURE__ */ jsx6(Icon, { name: item.type === "success" ? "circle-check" : item.type === "warning" ? "warning" : item.type === "error" ? "circle-close" : "info", variant: "filled" }) }),
956
+ /* @__PURE__ */ jsxs6("div", { children: [
957
+ /* @__PURE__ */ jsx6("strong", { children: item.message }),
958
+ item.description ? /* @__PURE__ */ jsx6("p", { children: item.description }) : null,
959
+ item.btn
960
+ ] }),
961
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "\u5173\u95ED\u901A\u77E5", onClick: (event) => {
962
+ event.stopPropagation();
963
+ closeNotification(item.key);
964
+ }, children: item.closeIcon ?? /* @__PURE__ */ jsx6(Icon, { name: "close", size: 14 }) })
965
+ ] }, item.key)) }, placement)) });
966
+ }
967
+ function ensureNotificationHost() {
968
+ if (typeof document === "undefined" || notificationHost) return;
969
+ notificationHost = document.createElement("div");
970
+ notificationHost.dataset.siaNotificationHost = "";
971
+ document.body.appendChild(notificationHost);
972
+ createRoot(notificationHost).render(/* @__PURE__ */ jsx6(NotificationHost, {}));
973
+ }
974
+ function openNotification(config) {
975
+ if (typeof window === "undefined" || typeof document === "undefined") return { key: config.key ?? "ssr", close: () => void 0 };
976
+ ensureNotificationHost();
977
+ const key = config.key ?? `sia-notification-${++notificationSeed}`;
978
+ const entry = { ...config, key };
979
+ const exists = notificationEntries.some((item) => item.key === key);
980
+ notificationEntries = exists ? notificationEntries.map((item) => item.key === key ? entry : item) : [...notificationEntries, entry];
981
+ emitNotifications();
982
+ window.clearTimeout(notificationTimers.get(key));
983
+ if ((config.duration ?? 4.5) > 0) notificationTimers.set(key, window.setTimeout(() => closeNotification(key), (config.duration ?? 4.5) * 1e3));
984
+ return { key, close: () => closeNotification(key) };
985
+ }
986
+ var notification = {
987
+ open: openNotification,
988
+ info: (config) => openNotification({ ...config, type: "info" }),
989
+ success: (config) => openNotification({ ...config, type: "success" }),
990
+ warning: (config) => openNotification({ ...config, type: "warning" }),
991
+ error: (config) => openNotification({ ...config, type: "error" }),
992
+ destroy: (key) => {
993
+ if (key !== void 0) closeNotification(key);
994
+ else {
995
+ [...notificationEntries].forEach((item) => closeNotification(item.key));
996
+ }
997
+ }
998
+ };
999
+ function Tour({ open = false, steps, current, defaultCurrent = 0, mask = true, closable = true, disabledInteraction = false, onChange, onClose, onFinish }) {
1000
+ const [index, setIndex] = useControllableState({ value: current, defaultValue: defaultCurrent, onChange });
1001
+ const [, force] = useState4(0);
1002
+ useEffect3(() => {
1003
+ if (!open) return;
1004
+ const update = () => force((value) => value + 1);
1005
+ window.addEventListener("resize", update);
1006
+ window.addEventListener("scroll", update, true);
1007
+ return () => {
1008
+ window.removeEventListener("resize", update);
1009
+ window.removeEventListener("scroll", update, true);
1010
+ };
1011
+ }, [open]);
1012
+ if (!open || !steps[index] || typeof document === "undefined") return null;
1013
+ const step = steps[index];
1014
+ const target = typeof step.target === "function" ? step.target() : step.target;
1015
+ const rect = target?.getBoundingClientRect();
1016
+ const placement = step.placement ?? (rect ? "bottom" : "center");
1017
+ const panelStyle = placement === "center" || !rect ? { top: "50%", left: "50%", transform: "translate(-50%, -50%)" } : placement.startsWith("bottom") ? { top: rect.bottom + 14, left: rect.left + rect.width / 2, transform: "translateX(-50%)" } : placement.startsWith("top") ? { top: rect.top - 14, left: rect.left + rect.width / 2, transform: "translate(-50%, -100%)" } : placement === "left" ? { top: rect.top + rect.height / 2, left: rect.left - 14, transform: "translate(-100%, -50%)" } : { top: rect.top + rect.height / 2, left: rect.right + 14, transform: "translateY(-50%)" };
1018
+ return createPortal2(/* @__PURE__ */ jsxs6("div", { className: "sia-tour", role: "dialog", "aria-modal": "true", children: [
1019
+ mask && !rect ? /* @__PURE__ */ jsx6("div", { className: "sia-tour__mask" }) : null,
1020
+ rect ? /* @__PURE__ */ jsx6("div", { className: "sia-tour__target", style: { top: rect.top - 5, left: rect.left - 5, width: rect.width + 10, height: rect.height + 10, pointerEvents: disabledInteraction ? "auto" : "none", boxShadow: mask ? "0 0 0 5px var(--sia-color-surface), 0 0 0 9999px rgb(0 0 0 / 46%)" : "0 0 0 5px var(--sia-color-surface)" } }) : null,
1021
+ /* @__PURE__ */ jsxs6("div", { className: "sia-tour__panel", style: panelStyle, children: [
1022
+ closable ? /* @__PURE__ */ jsx6("button", { className: "sia-tour__close", "aria-label": "\u5173\u95ED\u5F15\u5BFC", onClick: () => onClose?.(index), children: /* @__PURE__ */ jsx6(Icon, { name: "close", size: 14 }) }) : null,
1023
+ step.cover,
1024
+ /* @__PURE__ */ jsx6("strong", { children: step.title }),
1025
+ step.description ? /* @__PURE__ */ jsx6("div", { className: "sia-tour__description", children: step.description }) : null,
1026
+ /* @__PURE__ */ jsxs6("footer", { children: [
1027
+ /* @__PURE__ */ jsxs6("span", { children: [
1028
+ index + 1,
1029
+ " / ",
1030
+ steps.length
1031
+ ] }),
1032
+ /* @__PURE__ */ jsxs6("div", { children: [
1033
+ index > 0 ? /* @__PURE__ */ jsx6(Button, { size: "small", ...step.prevButtonProps, onClick: () => setIndex(index - 1), children: step.prevButtonProps?.children ?? "\u4E0A\u4E00\u6B65" }) : null,
1034
+ /* @__PURE__ */ jsx6(Button, { size: "small", variant: "primary", ...step.nextButtonProps, onClick: () => {
1035
+ if (index >= steps.length - 1) onFinish?.();
1036
+ else setIndex(index + 1);
1037
+ }, children: step.nextButtonProps?.children ?? (index >= steps.length - 1 ? "\u5B8C\u6210" : "\u4E0B\u4E00\u6B65") })
1038
+ ] })
1039
+ ] })
1040
+ ] })
1041
+ ] }), document.body);
1042
+ }
1043
+
1044
+ // src/components/DataDisplay.tsx
1045
+ import { Children, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef5, useState as useState5 } from "react";
1046
+ import { createPortal as createPortal4 } from "react-dom";
1047
+
1048
+ // src/components/Overlay.tsx
1049
+ import { useEffect as useEffect4, useRef as useRef4 } from "react";
1050
+ import { createPortal as createPortal3 } from "react-dom";
1051
+ var bodyLockCount = 0;
1052
+ var previousBodyOverflow = "";
1053
+ var overlayStack = [];
1054
+ function lockBodyScroll() {
1055
+ if (bodyLockCount === 0) {
1056
+ previousBodyOverflow = document.body.style.overflow;
1057
+ document.body.style.overflow = "hidden";
1058
+ }
1059
+ bodyLockCount += 1;
1060
+ return () => {
1061
+ bodyLockCount = Math.max(0, bodyLockCount - 1);
1062
+ if (bodyLockCount === 0) document.body.style.overflow = previousBodyOverflow;
1063
+ };
1064
+ }
1065
+ function focusableElements(container) {
1066
+ return [...container.querySelectorAll(
1067
+ 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
1068
+ )].filter((element) => !element.hidden && element.getAttribute("aria-hidden") !== "true");
1069
+ }
1070
+ function useOverlayLifecycle(open, panelRef, onRequestClose, keyboard = true) {
1071
+ const overlayIdRef = useRef4(/* @__PURE__ */ Symbol("sia-overlay"));
1072
+ const closeRef = useRef4(onRequestClose);
1073
+ closeRef.current = onRequestClose;
1074
+ useEffect4(() => {
1075
+ if (!open || typeof document === "undefined") return void 0;
1076
+ const overlayId = overlayIdRef.current;
1077
+ const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1078
+ overlayStack.push(overlayId);
1079
+ const unlockBody = lockBodyScroll();
1080
+ const focusTimer = window.setTimeout(() => {
1081
+ const panel = panelRef.current;
1082
+ if (!panel) return;
1083
+ const [firstFocusable] = focusableElements(panel);
1084
+ (firstFocusable ?? panel).focus({ preventScroll: true });
1085
+ }, 0);
1086
+ function handleKeyDown(event) {
1087
+ if (overlayStack.at(-1) !== overlayId) return;
1088
+ if (event.key === "Escape" && keyboard) {
1089
+ event.preventDefault();
1090
+ closeRef.current();
1091
+ return;
1092
+ }
1093
+ if (event.key !== "Tab" || !panelRef.current) return;
1094
+ const focusable = focusableElements(panelRef.current);
1095
+ if (focusable.length === 0) {
1096
+ event.preventDefault();
1097
+ panelRef.current.focus();
1098
+ return;
1099
+ }
1100
+ const first = focusable[0];
1101
+ const last = focusable.at(-1);
1102
+ if (event.shiftKey && document.activeElement === first) {
1103
+ event.preventDefault();
1104
+ last.focus();
1105
+ } else if (!event.shiftKey && document.activeElement === last) {
1106
+ event.preventDefault();
1107
+ first.focus();
1108
+ }
1109
+ }
1110
+ document.addEventListener("keydown", handleKeyDown);
1111
+ return () => {
1112
+ window.clearTimeout(focusTimer);
1113
+ document.removeEventListener("keydown", handleKeyDown);
1114
+ const index = overlayStack.lastIndexOf(overlayId);
1115
+ if (index >= 0) overlayStack.splice(index, 1);
1116
+ unlockBody();
1117
+ previouslyFocused?.focus({ preventScroll: true });
1118
+ };
1119
+ }, [keyboard, open, panelRef]);
1120
+ }
1121
+ function OverlayPortal({ children, container }) {
1122
+ if (typeof document === "undefined") return null;
1123
+ const target = typeof container === "function" ? container() : container ?? document.body;
1124
+ return createPortal3(children, target);
1125
+ }
1126
+
1127
+ // src/components/DataDisplay.tsx
1128
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1129
+ function Rate({ value, defaultValue = 0, count = 5, allowHalf = false, allowClear = true, disabled = false, character, tooltips, onChange, onHoverChange, className = "", ...props }) {
1130
+ const [current, setCurrent] = useControllableState({ value, defaultValue, onChange });
1131
+ const [hover, setHover] = useState5(0);
1132
+ const shown = hover || current;
1133
+ function choose(next) {
1134
+ setCurrent(allowClear && next === current ? 0 : next);
1135
+ }
1136
+ return /* @__PURE__ */ jsx7("div", { className: `sia-rate${disabled ? " is-disabled" : ""} ${className}`.trim(), role: "radiogroup", "aria-label": "\u8BC4\u5206", onMouseLeave: () => {
1137
+ setHover(0);
1138
+ onHoverChange?.(0);
1139
+ }, ...props, children: Array.from({ length: count }, (_, index) => {
1140
+ const whole = index + 1;
1141
+ const fill = Math.max(0, Math.min(1, shown - index));
1142
+ const content = typeof character === "function" ? character(index) : character ?? /* @__PURE__ */ jsx7(Icon, { name: "star", variant: "filled" });
1143
+ return /* @__PURE__ */ jsx7("span", { className: "sia-rate__item", title: tooltips?.[index], children: /* @__PURE__ */ jsxs7("button", { type: "button", disabled, role: "radio", "aria-checked": current === whole, "aria-label": `${whole} \u661F`, onMouseMove: (event) => {
1144
+ const rect = event.currentTarget.getBoundingClientRect();
1145
+ const next = allowHalf && event.clientX - rect.left < rect.width / 2 ? whole - 0.5 : whole;
1146
+ setHover(next);
1147
+ onHoverChange?.(next);
1148
+ }, onClick: (event) => {
1149
+ const rect = event.currentTarget.getBoundingClientRect();
1150
+ choose(allowHalf && event.clientX - rect.left < rect.width / 2 ? whole - 0.5 : whole);
1151
+ }, onKeyDown: (event) => {
1152
+ if (event.key === "ArrowRight" || event.key === "ArrowUp") {
1153
+ event.preventDefault();
1154
+ setCurrent(Math.min(count, current + (allowHalf ? 0.5 : 1)));
1155
+ }
1156
+ if (event.key === "ArrowLeft" || event.key === "ArrowDown") {
1157
+ event.preventDefault();
1158
+ setCurrent(Math.max(0, current - (allowHalf ? 0.5 : 1)));
1159
+ }
1160
+ }, children: [
1161
+ /* @__PURE__ */ jsx7("span", { className: "sia-rate__base", children: content }),
1162
+ /* @__PURE__ */ jsx7("span", { className: "sia-rate__fill", style: { width: `${fill * 100}%` }, children: content })
1163
+ ] }) }, whole);
1164
+ }) });
1165
+ }
1166
+ function BadgeRibbon({ text, color, placement = "end", className = "", children, ...props }) {
1167
+ return /* @__PURE__ */ jsxs7("div", { className: `sia-ribbon-wrap ${className}`.trim(), ...props, children: [
1168
+ children,
1169
+ /* @__PURE__ */ jsx7("span", { className: `sia-ribbon sia-ribbon--${placement}`, style: { backgroundColor: color }, children: text })
1170
+ ] });
1171
+ }
1172
+ function Badge({ count, showZero = false, overflowCount = 99, dot = false, status, text, color, offset = [0, 0], size = "default", className = "", children, style, ...props }) {
1173
+ const numeric = typeof count === "number";
1174
+ const hidden = !dot && !status && (count === void 0 || count === null || count === 0 && !showZero);
1175
+ const display = numeric && count > overflowCount ? `${overflowCount}+` : count;
1176
+ const badge = !hidden ? /* @__PURE__ */ jsx7("sup", { className: `sia-badge__count${dot || status ? " sia-badge__dot" : ""}${status ? ` sia-badge__dot--${status}` : ""} sia-badge__count--${size}`, style: { backgroundColor: color, transform: `translate(calc(50% + ${offset[0]}px), calc(-50% + ${offset[1]}px))` }, children: dot || status ? null : display }) : null;
1177
+ if (status && !children) return /* @__PURE__ */ jsxs7("span", { className: `sia-badge sia-badge--status ${className}`.trim(), style, ...props, children: [
1178
+ badge,
1179
+ text ? /* @__PURE__ */ jsx7("span", { className: "sia-badge__text", children: text }) : null
1180
+ ] });
1181
+ return /* @__PURE__ */ jsxs7("span", { className: `sia-badge ${className}`.trim(), style, ...props, children: [
1182
+ children,
1183
+ badge,
1184
+ text && !status ? /* @__PURE__ */ jsx7("span", { className: "sia-badge__text", children: text }) : null
1185
+ ] });
1186
+ }
1187
+ Badge.Ribbon = BadgeRibbon;
1188
+ function pad(value) {
1189
+ return String(value).padStart(2, "0");
1190
+ }
1191
+ function formatDate(date) {
1192
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
1193
+ }
1194
+ function parseDate(value) {
1195
+ const date = value ? /* @__PURE__ */ new Date(`${value}T00:00:00`) : /* @__PURE__ */ new Date();
1196
+ return Number.isNaN(date.getTime()) ? /* @__PURE__ */ new Date() : date;
1197
+ }
1198
+ var WEEK = ["\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u65E5"];
1199
+ var MONTHS = ["\u4E00\u6708", "\u4E8C\u6708", "\u4E09\u6708", "\u56DB\u6708", "\u4E94\u6708", "\u516D\u6708", "\u4E03\u6708", "\u516B\u6708", "\u4E5D\u6708", "\u5341\u6708", "\u5341\u4E00\u6708", "\u5341\u4E8C\u6708"];
1200
+ function Calendar({ value, defaultValue, mode = "month", fullscreen = true, validRange, disabledDate, dateCellRender, fullCellRender, headerRender, onChange, onSelect, onPanelChange, className = "", ...props }) {
1201
+ const [selected, setSelected] = useControllableState({ value, defaultValue: defaultValue ?? formatDate(/* @__PURE__ */ new Date()), onChange });
1202
+ const [panelMode, setPanelMode] = useState5(mode);
1203
+ const [panel, setPanel] = useState5(() => {
1204
+ const date = parseDate(value ?? defaultValue);
1205
+ return new Date(date.getFullYear(), date.getMonth(), 1);
1206
+ });
1207
+ useEffect5(() => {
1208
+ if (value) {
1209
+ const date = parseDate(value);
1210
+ setPanel(new Date(date.getFullYear(), date.getMonth(), 1));
1211
+ }
1212
+ }, [value]);
1213
+ const grid = useMemo5(() => {
1214
+ const first = new Date(panel.getFullYear(), panel.getMonth(), 1);
1215
+ const mondayIndex = (first.getDay() + 6) % 7;
1216
+ return Array.from({ length: 42 }, (_, index) => new Date(panel.getFullYear(), panel.getMonth(), index - mondayIndex + 1));
1217
+ }, [panel]);
1218
+ function setPanelValue(next) {
1219
+ setPanel(next);
1220
+ onPanelChange?.(formatDate(next), panelMode);
1221
+ }
1222
+ function setMode(next) {
1223
+ setPanelMode(next);
1224
+ onPanelChange?.(formatDate(panel), next);
1225
+ }
1226
+ const headerConfig = { value: formatDate(panel), mode: panelMode, onChange: (next) => setPanelValue(parseDate(next)), onTypeChange: setMode };
1227
+ return /* @__PURE__ */ jsxs7("div", { className: `sia-calendar${fullscreen ? " sia-calendar--fullscreen" : " sia-calendar--mini"} ${className}`.trim(), ...props, children: [
1228
+ /* @__PURE__ */ jsx7("div", { className: "sia-calendar__header", children: headerRender ? headerRender(headerConfig) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
1229
+ /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "\u4E0A\u4E00\u9875", onClick: () => setPanelValue(new Date(panel.getFullYear() - (panelMode === "year" ? 1 : 0), panel.getMonth() - (panelMode === "month" ? 1 : 0), 1)), children: /* @__PURE__ */ jsx7(Icon, { name: "chevron-left" }) }),
1230
+ /* @__PURE__ */ jsxs7("strong", { children: [
1231
+ panel.getFullYear(),
1232
+ " \u5E74",
1233
+ panelMode === "month" ? ` ${panel.getMonth() + 1} \u6708` : ""
1234
+ ] }),
1235
+ /* @__PURE__ */ jsxs7("div", { className: "sia-calendar__modes", children: [
1236
+ /* @__PURE__ */ jsx7("button", { className: panelMode === "month" ? "is-active" : "", onClick: () => setMode("month"), children: "\u6708" }),
1237
+ /* @__PURE__ */ jsx7("button", { className: panelMode === "year" ? "is-active" : "", onClick: () => setMode("year"), children: "\u5E74" })
1238
+ ] }),
1239
+ /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "\u4E0B\u4E00\u9875", onClick: () => setPanelValue(new Date(panel.getFullYear() + (panelMode === "year" ? 1 : 0), panel.getMonth() + (panelMode === "month" ? 1 : 0), 1)), children: /* @__PURE__ */ jsx7(Icon, { name: "chevron-right" }) })
1240
+ ] }) }),
1241
+ panelMode === "year" ? /* @__PURE__ */ jsx7("div", { className: "sia-calendar__months", children: MONTHS.map((month, index) => /* @__PURE__ */ jsx7("button", { className: panel.getMonth() === index ? "is-selected" : "", onClick: () => {
1242
+ setPanelValue(new Date(panel.getFullYear(), index, 1));
1243
+ setMode("month");
1244
+ }, children: month }, month)) }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
1245
+ /* @__PURE__ */ jsx7("div", { className: "sia-calendar__week", children: WEEK.map((day) => /* @__PURE__ */ jsx7("span", { children: day }, day)) }),
1246
+ /* @__PURE__ */ jsx7("div", { className: "sia-calendar__grid", children: grid.map((date) => {
1247
+ const key = formatDate(date);
1248
+ const outside = date.getMonth() !== panel.getMonth();
1249
+ const disabled = Boolean(disabledDate?.(key) || validRange && (key < validRange[0] || key > validRange[1]));
1250
+ const origin = /* @__PURE__ */ jsxs7(Fragment4, { children: [
1251
+ /* @__PURE__ */ jsx7("span", { children: date.getDate() }),
1252
+ dateCellRender?.(key)
1253
+ ] });
1254
+ return /* @__PURE__ */ jsx7("button", { disabled, className: `${outside ? "is-outside" : ""}${selected === key ? " is-selected" : ""}${formatDate(/* @__PURE__ */ new Date()) === key ? " is-today" : ""}`, onClick: () => {
1255
+ setSelected(key);
1256
+ onSelect?.(key);
1257
+ if (outside) setPanelValue(new Date(date.getFullYear(), date.getMonth(), 1));
1258
+ }, children: fullCellRender?.(key, { originNode: origin, type: "date" }) ?? origin }, key);
1259
+ }) })
1260
+ ] })
1261
+ ] });
1262
+ }
1263
+ function Carousel({ autoplay = false, autoplaySpeed = 3e3, arrows = false, dots = true, effect = "scroll", infinite = true, initialSlide = 0, pauseOnHover = true, beforeChange, afterChange, className = "", children, ...props }) {
1264
+ const slides = Children.toArray(children);
1265
+ const [current, setCurrent] = useState5(Math.min(initialSlide, Math.max(0, slides.length - 1)));
1266
+ const [paused, setPaused] = useState5(false);
1267
+ function go(next) {
1268
+ if (!slides.length) return;
1269
+ const resolved = infinite ? (next + slides.length) % slides.length : Math.max(0, Math.min(slides.length - 1, next));
1270
+ if (resolved === current) return;
1271
+ beforeChange?.(current, resolved);
1272
+ setCurrent(resolved);
1273
+ afterChange?.(resolved);
1274
+ }
1275
+ useEffect5(() => {
1276
+ if (!autoplay || paused || slides.length < 2) return;
1277
+ const timer = window.setInterval(() => go(current + 1), autoplaySpeed);
1278
+ return () => window.clearInterval(timer);
1279
+ }, [autoplay, autoplaySpeed, current, paused, slides.length]);
1280
+ return /* @__PURE__ */ jsxs7("div", { className: `sia-carousel sia-carousel--${effect} ${className}`.trim(), onMouseEnter: pauseOnHover ? () => setPaused(true) : void 0, onMouseLeave: pauseOnHover ? () => setPaused(false) : void 0, ...props, children: [
1281
+ /* @__PURE__ */ jsx7("div", { className: "sia-carousel__viewport", children: /* @__PURE__ */ jsx7("div", { className: "sia-carousel__track", style: effect === "scroll" ? { transform: `translateX(-${current * 100}%)` } : void 0, children: slides.map((slide, index) => /* @__PURE__ */ jsx7("div", { className: `sia-carousel__slide${index === current ? " is-active" : ""}`, "aria-hidden": index !== current, children: slide }, index)) }) }),
1282
+ arrows ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
1283
+ /* @__PURE__ */ jsx7("button", { className: "sia-carousel__arrow sia-carousel__arrow--prev", disabled: !infinite && current === 0, "aria-label": "\u4E0A\u4E00\u5F20", onClick: () => go(current - 1), children: /* @__PURE__ */ jsx7(Icon, { name: "chevron-left" }) }),
1284
+ /* @__PURE__ */ jsx7("button", { className: "sia-carousel__arrow sia-carousel__arrow--next", disabled: !infinite && current === slides.length - 1, "aria-label": "\u4E0B\u4E00\u5F20", onClick: () => go(current + 1), children: /* @__PURE__ */ jsx7(Icon, { name: "chevron-right" }) })
1285
+ ] }) : null,
1286
+ dots ? /* @__PURE__ */ jsx7("div", { className: `sia-carousel__dots${typeof dots === "object" && dots.className ? ` ${dots.className}` : ""}`, children: slides.map((_, index) => /* @__PURE__ */ jsx7("button", { "aria-label": `\u5207\u6362\u5230\u7B2C ${index + 1} \u5F20`, "aria-current": index === current, onClick: () => go(index), children: /* @__PURE__ */ jsx7("span", {}) }, index)) }) : null
1287
+ ] });
1288
+ }
1289
+ function CollapsePanel({
1290
+ open,
1291
+ forceRender = false,
1292
+ destroyInactivePanel = false,
1293
+ children
1294
+ }) {
1295
+ const [keepChildren, setKeepChildren] = useState5(open || forceRender || !destroyInactivePanel);
1296
+ useEffect5(() => {
1297
+ if (open || forceRender || !destroyInactivePanel) {
1298
+ setKeepChildren(true);
1299
+ return void 0;
1300
+ }
1301
+ const timer = window.setTimeout(() => setKeepChildren(false), 240);
1302
+ return () => window.clearTimeout(timer);
1303
+ }, [destroyInactivePanel, forceRender, open]);
1304
+ const renderChildren = open || forceRender || !destroyInactivePanel || keepChildren;
1305
+ return /* @__PURE__ */ jsx7("div", { className: "sia-collapse__panel", "aria-hidden": !open, children: /* @__PURE__ */ jsx7("div", { className: "sia-collapse__panel-motion", children: /* @__PURE__ */ jsx7("div", { className: "sia-collapse__panel-body", children: renderChildren ? children : null }) }) });
1306
+ }
1307
+ function Collapse({ items, activeKey, defaultActiveKey = [], accordion = false, bordered = true, ghost = false, destroyInactivePanel = false, expandIconPosition = "start", onChange, className = "", ...props }) {
1308
+ const normalize = (key) => Array.isArray(key) ? [...key] : key === void 0 ? [] : [key];
1309
+ const controlled = activeKey !== void 0;
1310
+ const [internal, setInternal] = useState5(normalize(defaultActiveKey));
1311
+ const openKeys = controlled ? normalize(activeKey) : internal;
1312
+ function toggle(item) {
1313
+ if (item.disabled || item.collapsible === "disabled") return;
1314
+ const open = openKeys.includes(item.key);
1315
+ const next = accordion ? open ? [] : [item.key] : open ? openKeys.filter((key) => key !== item.key) : [...openKeys, item.key];
1316
+ if (!controlled) setInternal(next);
1317
+ onChange?.(accordion ? next[0] ?? "" : next);
1318
+ }
1319
+ const borderClassName = !bordered || ghost ? "sia-collapse--borderless" : "sia-collapse--bordered";
1320
+ return /* @__PURE__ */ jsx7("div", { className: `sia-collapse ${borderClassName}${ghost ? " sia-collapse--ghost" : ""} sia-collapse--icon-${expandIconPosition} ${className}`.trim(), ...props, children: items.map((item) => {
1321
+ const open = openKeys.includes(item.key);
1322
+ const arrow = item.showArrow === false ? null : /* @__PURE__ */ jsx7("button", { type: "button", className: "sia-collapse__arrow", "aria-label": open ? "\u6536\u8D77" : "\u5C55\u5F00", onClick: item.collapsible === "icon" ? () => toggle(item) : void 0, children: /* @__PURE__ */ jsx7(Icon, { name: "chevron-right", size: 14 }) });
1323
+ return /* @__PURE__ */ jsxs7("section", { className: `sia-collapse__item${open ? " is-open" : ""}${item.disabled ? " is-disabled" : ""} ${item.className ?? ""}`.trim(), children: [
1324
+ /* @__PURE__ */ jsxs7("header", { className: "sia-collapse__header", role: "button", tabIndex: item.disabled ? -1 : 0, "aria-expanded": open, onClick: item.collapsible === "icon" ? void 0 : () => toggle(item), onKeyDown: (event) => {
1325
+ if (event.key === "Enter" || event.key === " ") {
1326
+ event.preventDefault();
1327
+ toggle(item);
1328
+ }
1329
+ }, children: [
1330
+ expandIconPosition === "start" ? arrow : null,
1331
+ /* @__PURE__ */ jsx7("span", { className: "sia-collapse__label", children: item.label }),
1332
+ item.extra ? /* @__PURE__ */ jsx7("span", { className: "sia-collapse__extra", onClick: (event) => event.stopPropagation(), children: item.extra }) : null,
1333
+ expandIconPosition === "end" ? arrow : null
1334
+ ] }),
1335
+ /* @__PURE__ */ jsx7(CollapsePanel, { open, forceRender: item.forceRender, destroyInactivePanel, children: item.children })
1336
+ ] }, item.key);
1337
+ }) });
1338
+ }
1339
+ function ImagePreview({ open, src, alt = "", onOpenChange }) {
1340
+ const previewRef = useRef5(null);
1341
+ useOverlayLifecycle(open, previewRef, () => onOpenChange(false));
1342
+ if (!open || !src || typeof document === "undefined") return null;
1343
+ return createPortal4(/* @__PURE__ */ jsxs7("div", { ref: previewRef, className: "sia-image-preview", role: "dialog", "aria-modal": "true", "aria-label": "\u56FE\u7247\u9884\u89C8", tabIndex: -1, onClick: () => onOpenChange(false), children: [
1344
+ /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "\u5173\u95ED\u9884\u89C8", onClick: () => onOpenChange(false), children: /* @__PURE__ */ jsx7(Icon, { name: "close" }) }),
1345
+ /* @__PURE__ */ jsx7("img", { src, alt, onClick: (event) => event.stopPropagation() })
1346
+ ] }), document.body);
1347
+ }
1348
+ function Image({ fallback, placeholder, preview = true, rootClassName = "", className = "", src, alt = "", onError, style, ...props }) {
1349
+ const config = typeof preview === "object" ? preview : {};
1350
+ const controlled = typeof preview === "object" && preview.open !== void 0;
1351
+ const [internalOpen, setInternalOpen] = useState5(false);
1352
+ const open = controlled ? config.open : internalOpen;
1353
+ const [loaded, setLoaded] = useState5(false);
1354
+ const [failed, setFailed] = useState5(false);
1355
+ const displaySrc = failed && fallback ? fallback : src;
1356
+ const radius = typeof style?.borderRadius === "number" ? `${style.borderRadius}px` : style?.borderRadius;
1357
+ const rootStyle = {
1358
+ ...style,
1359
+ "--sia-image-radius": radius ?? "var(--sia-radius)"
1360
+ };
1361
+ function setOpen(next) {
1362
+ if (!controlled) setInternalOpen(next);
1363
+ config.onOpenChange?.(next);
1364
+ }
1365
+ return /* @__PURE__ */ jsxs7("span", { className: `sia-image ${rootClassName}`.trim(), style: rootStyle, children: [
1366
+ !loaded && placeholder ? /* @__PURE__ */ jsx7("span", { className: "sia-image__placeholder", children: placeholder }) : null,
1367
+ /* @__PURE__ */ jsx7("img", { ...props, src: displaySrc, alt, className, onLoad: () => setLoaded(true), onError: (event) => {
1368
+ if (!failed && fallback) setFailed(true);
1369
+ onError?.(event);
1370
+ } }),
1371
+ preview ? /* @__PURE__ */ jsx7("button", { type: "button", className: "sia-image__mask", "aria-label": "\u9884\u89C8\u56FE\u7247", onClick: () => setOpen(true), children: config.mask ?? /* @__PURE__ */ jsxs7(Fragment4, { children: [
1372
+ /* @__PURE__ */ jsx7(Icon, { name: "eye" }),
1373
+ "\u9884\u89C8"
1374
+ ] }) }) : null,
1375
+ /* @__PURE__ */ jsx7(ImagePreview, { open, src: config.src ?? displaySrc, alt, onOpenChange: setOpen })
1376
+ ] });
1377
+ }
1378
+
1379
+ // src/components/Upload.tsx
1380
+ import { useId as useId4, useRef as useRef6 } from "react";
1381
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1382
+ var LIST_IGNORE = /* @__PURE__ */ Symbol("SIA_UPLOAD_LIST_IGNORE");
1383
+ function UploadRoot({
1384
+ accept,
1385
+ multiple = false,
1386
+ directory = false,
1387
+ disabled = false,
1388
+ maxCount: maxCount2,
1389
+ fileList,
1390
+ defaultFileList = [],
1391
+ listType = "text",
1392
+ showUploadList = true,
1393
+ beforeUpload,
1394
+ customRequest,
1395
+ onChange,
1396
+ onRemove,
1397
+ children,
1398
+ className = "",
1399
+ onDragOver,
1400
+ onDrop,
1401
+ ...props
1402
+ }) {
1403
+ const inputRef = useRef6(null);
1404
+ const filesRef = useRef6(fileList ?? defaultFileList);
1405
+ const id = useId4();
1406
+ const [files, setFiles] = useControllableState({ value: fileList, defaultValue: defaultFileList });
1407
+ filesRef.current = files;
1408
+ function emit(file, nextList) {
1409
+ filesRef.current = nextList;
1410
+ setFiles(nextList);
1411
+ onChange?.({ file, fileList: nextList });
1412
+ }
1413
+ async function processFile(file, allFiles) {
1414
+ const beforeResult = await beforeUpload?.(file, allFiles);
1415
+ if (beforeResult === LIST_IGNORE) return;
1416
+ if (beforeResult === false) {
1417
+ const pending = { uid: `${Date.now()}-${file.name}`, name: file.name, size: file.size, type: file.type, status: "ready", originFileObj: file };
1418
+ emit(pending, maxCount2 === 1 ? [pending] : [...filesRef.current, pending].slice(-(maxCount2 ?? Number.POSITIVE_INFINITY)));
1419
+ return;
1420
+ }
1421
+ const uploadFile = beforeResult instanceof File ? beforeResult : file;
1422
+ const item = { uid: `${Date.now()}-${Math.random().toString(36).slice(2)}`, name: uploadFile.name, size: uploadFile.size, type: uploadFile.type, status: "uploading", percent: 0, originFileObj: uploadFile };
1423
+ const nextList = maxCount2 === 1 ? [item] : [...filesRef.current, item].slice(-(maxCount2 ?? Number.POSITIVE_INFINITY));
1424
+ emit(item, nextList);
1425
+ const request = {
1426
+ file: uploadFile,
1427
+ filename: uploadFile.name,
1428
+ onProgress: (percent) => {
1429
+ const progressing = { ...item, status: "uploading", percent };
1430
+ const progressList = filesRef.current.map((entry) => entry.uid === item.uid ? progressing : entry);
1431
+ emit(progressing, progressList);
1432
+ },
1433
+ onSuccess: (response) => {
1434
+ const done = { ...item, status: "done", percent: 100, response };
1435
+ const completed = filesRef.current.map((entry) => entry.uid === item.uid ? done : entry);
1436
+ emit(done, completed);
1437
+ },
1438
+ onError: (error) => {
1439
+ const failed = { ...item, status: "error", error };
1440
+ const completed = filesRef.current.map((entry) => entry.uid === item.uid ? failed : entry);
1441
+ emit(failed, completed);
1442
+ }
1443
+ };
1444
+ if (customRequest) customRequest(request);
1445
+ else window.setTimeout(() => request.onSuccess({ local: true }), 180);
1446
+ }
1447
+ function handleFiles(event) {
1448
+ const selected = [...event.currentTarget.files ?? []];
1449
+ selected.forEach((file) => void processFile(file, selected));
1450
+ event.currentTarget.value = "";
1451
+ }
1452
+ function handleDrop(event) {
1453
+ onDrop?.(event);
1454
+ if (event.defaultPrevented || disabled) return;
1455
+ event.preventDefault();
1456
+ const selected = [...event.dataTransfer.files];
1457
+ selected.forEach((file) => void processFile(file, selected));
1458
+ }
1459
+ async function remove(file) {
1460
+ if (await onRemove?.(file) === false) return;
1461
+ const next = files.filter((item) => item.uid !== file.uid);
1462
+ emit({ ...file, status: "ready" }, next);
1463
+ }
1464
+ return /* @__PURE__ */ jsxs8(
1465
+ "div",
1466
+ {
1467
+ className: `sia-upload sia-upload--${listType} ${className}`.trim(),
1468
+ onDragOver: (event) => {
1469
+ onDragOver?.(event);
1470
+ if (!event.defaultPrevented && !disabled) event.preventDefault();
1471
+ },
1472
+ onDrop: handleDrop,
1473
+ ...props,
1474
+ children: [
1475
+ /* @__PURE__ */ jsx8(
1476
+ "input",
1477
+ {
1478
+ ref: inputRef,
1479
+ id,
1480
+ className: "sia-upload__input",
1481
+ type: "file",
1482
+ accept,
1483
+ multiple,
1484
+ disabled,
1485
+ ...directory ? { webkitdirectory: "", directory: "" } : {},
1486
+ onChange: handleFiles
1487
+ }
1488
+ ),
1489
+ /* @__PURE__ */ jsx8("div", { className: "sia-upload__trigger", onClick: () => !disabled && inputRef.current?.click(), children: children ?? /* @__PURE__ */ jsx8(Button, { icon: /* @__PURE__ */ jsx8(Icon, { name: "upload", size: 16 }), disabled, children: "\u9009\u62E9\u6587\u4EF6" }) }),
1490
+ showUploadList && files.length ? /* @__PURE__ */ jsx8("div", { className: "sia-upload__list", children: files.map((file) => /* @__PURE__ */ jsxs8("div", { className: `sia-upload__item sia-upload__item--${file.status ?? "ready"}`, children: [
1491
+ /* @__PURE__ */ jsx8(Icon, { name: file.status === "done" ? "circle-check" : "file", size: 16 }),
1492
+ /* @__PURE__ */ jsx8("span", { className: "sia-upload__name", title: file.name, children: file.name }),
1493
+ file.status === "uploading" ? /* @__PURE__ */ jsx8("span", { className: "sia-upload__progress", children: /* @__PURE__ */ jsx8("span", { style: { width: `${file.percent ?? 0}%` } }) }) : null,
1494
+ /* @__PURE__ */ jsx8("button", { type: "button", "aria-label": `\u79FB\u9664 ${file.name}`, onClick: () => void remove(file), children: /* @__PURE__ */ jsx8(Icon, { name: "close", size: 14 }) })
1495
+ ] }, file.uid)) }) : null
1496
+ ]
1497
+ }
1498
+ );
1499
+ }
1500
+ function UploadDragger({ hint = "\u652F\u6301\u5355\u4E2A\u6216\u6279\u91CF\u4E0A\u4F20", children, className = "", ...props }) {
1501
+ return /* @__PURE__ */ jsx8(UploadRoot, { ...props, className: `sia-upload-dragger ${className}`.trim(), children: children ?? /* @__PURE__ */ jsxs8("div", { className: "sia-upload-dragger__content", children: [
1502
+ /* @__PURE__ */ jsx8(Icon, { name: "upload", size: 28 }),
1503
+ /* @__PURE__ */ jsx8("strong", { children: "\u70B9\u51FB\u6216\u62D6\u62FD\u6587\u4EF6\u5230\u6B64\u533A\u57DF\u4E0A\u4F20" }),
1504
+ /* @__PURE__ */ jsx8("span", { children: hint })
1505
+ ] }) });
1506
+ }
1507
+ var Upload = Object.assign(UploadRoot, { Dragger: UploadDragger, LIST_IGNORE });
1508
+
1509
+ // src/components/Modal.tsx
1510
+ import { forwardRef as forwardRef2, useEffect as useEffect6, useId as useId5, useRef as useRef7, useState as useState6 } from "react";
1511
+ import { createRoot as createRoot2 } from "react-dom/client";
1512
+ import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1513
+ var modalHandles = /* @__PURE__ */ new Set();
1514
+ var MODAL_MOTION_DURATION = 220;
1515
+ var typeIcons = {
1516
+ info: /* @__PURE__ */ jsx9(Icon, { name: "info", size: 23 }),
1517
+ success: /* @__PURE__ */ jsx9(Icon, { name: "circle-check", size: 23 }),
1518
+ warning: /* @__PURE__ */ jsx9(Icon, { name: "warning", size: 23 }),
1519
+ error: /* @__PURE__ */ jsx9(Icon, { name: "circle-close", size: 23 }),
1520
+ confirm: /* @__PURE__ */ jsx9(Icon, { name: "question", size: 23 })
1521
+ };
1522
+ var ModalRoot = forwardRef2(function Modal({
1523
+ open,
1524
+ title,
1525
+ children,
1526
+ footer,
1527
+ type = "default",
1528
+ okText = "\u786E\u5B9A",
1529
+ cancelText = "\u53D6\u6D88",
1530
+ showCancel = type === "default" || type === "confirm",
1531
+ confirmLoading = false,
1532
+ okButtonProps,
1533
+ cancelButtonProps,
1534
+ closable = true,
1535
+ maskClosable = true,
1536
+ keyboard = true,
1537
+ centered = false,
1538
+ width = 520,
1539
+ zIndex = 1e3,
1540
+ getContainer,
1541
+ onOk,
1542
+ onCancel,
1543
+ onOpenChange,
1544
+ className = "",
1545
+ style,
1546
+ ...props
1547
+ }, forwardedRef) {
1548
+ const localRef = useRef7(null);
1549
+ const titleId = useId5();
1550
+ const [submitting, setSubmitting] = useState6(false);
1551
+ const [rendered, setRendered] = useState6(open);
1552
+ const [closing, setClosing] = useState6(false);
1553
+ useEffect6(() => {
1554
+ if (open) {
1555
+ setRendered(true);
1556
+ setClosing(false);
1557
+ return void 0;
1558
+ }
1559
+ if (!rendered) return void 0;
1560
+ setClosing(true);
1561
+ const timer = window.setTimeout(() => {
1562
+ setRendered(false);
1563
+ setClosing(false);
1564
+ }, MODAL_MOTION_DURATION);
1565
+ return () => window.clearTimeout(timer);
1566
+ }, [open, rendered]);
1567
+ function setRef(node) {
1568
+ localRef.current = node;
1569
+ if (typeof forwardedRef === "function") forwardedRef(node);
1570
+ else if (forwardedRef) forwardedRef.current = node;
1571
+ }
1572
+ function requestClose() {
1573
+ if (submitting || confirmLoading) return;
1574
+ onCancel?.();
1575
+ onOpenChange?.(false);
1576
+ }
1577
+ async function handleOk() {
1578
+ if (!onOk) {
1579
+ onOpenChange?.(false);
1580
+ return;
1581
+ }
1582
+ try {
1583
+ const result = onOk();
1584
+ if (result instanceof Promise) {
1585
+ setSubmitting(true);
1586
+ const resolved = await result;
1587
+ if (resolved !== false) onOpenChange?.(false);
1588
+ } else if (result !== false) {
1589
+ onOpenChange?.(false);
1590
+ }
1591
+ } catch {
1592
+ return;
1593
+ } finally {
1594
+ setSubmitting(false);
1595
+ }
1596
+ }
1597
+ useOverlayLifecycle(rendered, localRef, requestClose, keyboard);
1598
+ if (!rendered) return null;
1599
+ const mergedStyle = {
1600
+ ...style,
1601
+ "--sia-modal-width": typeof width === "number" ? `${width}px` : width
1602
+ };
1603
+ const loading = submitting || confirmLoading;
1604
+ const defaultFooter = /* @__PURE__ */ jsxs9(Fragment5, { children: [
1605
+ showCancel ? /* @__PURE__ */ jsx9(Button, { ...cancelButtonProps, onClick: requestClose, disabled: loading || cancelButtonProps?.disabled, children: cancelText }) : null,
1606
+ /* @__PURE__ */ jsx9(Button, { variant: "primary", ...okButtonProps, onClick: handleOk, loading, children: okText })
1607
+ ] });
1608
+ return /* @__PURE__ */ jsx9(OverlayPortal, { container: getContainer, children: /* @__PURE__ */ jsx9(
1609
+ "div",
1610
+ {
1611
+ className: `sia-modal-root${centered ? " sia-modal-root--centered" : ""}`,
1612
+ "data-state": closing ? "closing" : "open",
1613
+ style: { zIndex },
1614
+ onMouseDown: (event) => {
1615
+ if (event.target === event.currentTarget && maskClosable) requestClose();
1616
+ },
1617
+ children: /* @__PURE__ */ jsxs9(
1618
+ "div",
1619
+ {
1620
+ ref: setRef,
1621
+ className: `sia-modal sia-modal--${type} ${className}`.trim(),
1622
+ style: mergedStyle,
1623
+ role: "dialog",
1624
+ "aria-modal": "true",
1625
+ "aria-labelledby": title ? titleId : void 0,
1626
+ tabIndex: -1,
1627
+ ...props,
1628
+ children: [
1629
+ /* @__PURE__ */ jsxs9("div", { className: "sia-modal__header", children: [
1630
+ /* @__PURE__ */ jsxs9("div", { className: "sia-modal__heading", children: [
1631
+ typeIcons[type] ? /* @__PURE__ */ jsx9("span", { className: "sia-modal__type-icon", "aria-hidden": "true", children: typeIcons[type] }) : null,
1632
+ title ? /* @__PURE__ */ jsx9("strong", { id: titleId, children: title }) : null
1633
+ ] }),
1634
+ closable ? /* @__PURE__ */ jsx9("button", { type: "button", className: "sia-modal__close", "aria-label": "\u5173\u95ED\u5BF9\u8BDD\u6846", onClick: requestClose, children: /* @__PURE__ */ jsx9(Icon, { name: "close", size: 17 }) }) : null
1635
+ ] }),
1636
+ children !== void 0 ? /* @__PURE__ */ jsx9("div", { className: "sia-modal__body", children }) : null,
1637
+ footer !== null ? /* @__PURE__ */ jsx9("div", { className: "sia-modal__footer", children: footer ?? defaultFooter }) : null
1638
+ ]
1639
+ }
1640
+ )
1641
+ }
1642
+ ) });
1643
+ });
1644
+ function openModal(config) {
1645
+ if (typeof document === "undefined") return { destroy() {
1646
+ }, update() {
1647
+ } };
1648
+ const container = document.createElement("div");
1649
+ container.className = "sia-modal-api-host";
1650
+ document.body.appendChild(container);
1651
+ const root = createRoot2(container);
1652
+ let currentConfig = config;
1653
+ let currentOpen = true;
1654
+ let destroyed = false;
1655
+ let cleanupTimer;
1656
+ function cleanup() {
1657
+ if (destroyed) return;
1658
+ destroyed = true;
1659
+ if (cleanupTimer !== void 0) window.clearTimeout(cleanupTimer);
1660
+ root.unmount();
1661
+ container.remove();
1662
+ modalHandles.delete(handle);
1663
+ }
1664
+ function closeWithMotion() {
1665
+ if (destroyed || !currentOpen) return;
1666
+ currentOpen = false;
1667
+ render();
1668
+ cleanupTimer = window.setTimeout(cleanup, MODAL_MOTION_DURATION);
1669
+ }
1670
+ function render() {
1671
+ root.render(/* @__PURE__ */ jsx9(ModalRoot, { ...currentConfig, open: currentOpen, onOpenChange: (nextOpen) => {
1672
+ currentConfig.onOpenChange?.(nextOpen);
1673
+ if (!nextOpen) closeWithMotion();
1674
+ } }));
1675
+ }
1676
+ const handle = {
1677
+ destroy: closeWithMotion,
1678
+ update(next) {
1679
+ if (destroyed) return;
1680
+ currentConfig = { ...currentConfig, ...next };
1681
+ render();
1682
+ }
1683
+ };
1684
+ modalHandles.add(handle);
1685
+ render();
1686
+ return handle;
1687
+ }
1688
+ function preset(type, defaults = {}) {
1689
+ return (config) => openModal({
1690
+ okText: type === "confirm" ? "\u786E\u5B9A" : "\u77E5\u9053\u4E86",
1691
+ showCancel: type === "confirm",
1692
+ closable: type !== "confirm",
1693
+ maskClosable: type !== "confirm",
1694
+ ...defaults,
1695
+ ...config,
1696
+ type
1697
+ });
1698
+ }
1699
+ var Modal2 = Object.assign(ModalRoot, {
1700
+ open: openModal,
1701
+ info: preset("info", { title: "\u63D0\u793A" }),
1702
+ success: preset("success", { title: "\u64CD\u4F5C\u6210\u529F" }),
1703
+ warning: preset("warning", { title: "\u8BF7\u6CE8\u610F" }),
1704
+ error: preset("error", { title: "\u64CD\u4F5C\u5931\u8D25" }),
1705
+ confirm: preset("confirm", { title: "\u786E\u8BA4\u64CD\u4F5C" }),
1706
+ destroyAll() {
1707
+ [...modalHandles].forEach((handle) => handle.destroy());
1708
+ }
1709
+ });
1710
+
1711
+ // src/components/Message.tsx
1712
+ import { createRoot as createRoot3 } from "react-dom/client";
1713
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1714
+ var messageSeed = 0;
1715
+ var messageRoot = null;
1716
+ var messageContainer = null;
1717
+ var messageItems = [];
1718
+ var defaultDuration = 3;
1719
+ var maxCount = 5;
1720
+ var messageTimers = /* @__PURE__ */ new Map();
1721
+ var messageIcons = {
1722
+ info: /* @__PURE__ */ jsx10(Icon, { name: "info", size: 18 }),
1723
+ success: /* @__PURE__ */ jsx10(Icon, { name: "circle-check", size: 18 }),
1724
+ warning: /* @__PURE__ */ jsx10(Icon, { name: "warning", size: 18 }),
1725
+ error: /* @__PURE__ */ jsx10(Icon, { name: "circle-close", size: 18 }),
1726
+ loading: /* @__PURE__ */ jsx10(Icon, { name: "loader", size: 18, spin: true })
1727
+ };
1728
+ function ensureMessageRoot() {
1729
+ if (typeof document === "undefined") return false;
1730
+ if (!messageContainer) {
1731
+ messageContainer = document.createElement("div");
1732
+ messageContainer.className = "sia-message-root";
1733
+ document.body.appendChild(messageContainer);
1734
+ messageRoot = createRoot3(messageContainer);
1735
+ }
1736
+ return true;
1737
+ }
1738
+ function renderMessages() {
1739
+ if (!ensureMessageRoot()) return;
1740
+ messageRoot.render(/* @__PURE__ */ jsx10("div", { className: "sia-message-list", "aria-live": "polite", children: messageItems.map((item) => /* @__PURE__ */ jsxs10("div", { className: `sia-message sia-message--${item.type}`, role: item.type === "loading" ? "status" : "alert", children: [
1741
+ /* @__PURE__ */ jsx10("span", { className: "sia-message__icon", "aria-hidden": "true", children: messageIcons[item.type] }),
1742
+ /* @__PURE__ */ jsx10("span", { className: "sia-message__content", children: item.content }),
1743
+ item.closable ? /* @__PURE__ */ jsx10("button", { type: "button", className: "sia-message__close", "aria-label": "\u5173\u95ED\u63D0\u793A", onClick: () => closeMessage(item.key), children: /* @__PURE__ */ jsx10(Icon, { name: "close", size: 14 }) }) : null
1744
+ ] }, item.key)) }));
1745
+ }
1746
+ function closeMessage(key) {
1747
+ const item = messageItems.find((candidate) => candidate.key === key);
1748
+ const timer = messageTimers.get(key);
1749
+ if (timer !== void 0) window.clearTimeout(timer);
1750
+ messageTimers.delete(key);
1751
+ messageItems = messageItems.filter((candidate) => candidate.key !== key);
1752
+ item?.onClose?.();
1753
+ renderMessages();
1754
+ }
1755
+ function scheduleMessage(item) {
1756
+ const existingTimer = messageTimers.get(item.key);
1757
+ if (existingTimer !== void 0) window.clearTimeout(existingTimer);
1758
+ const duration = item.duration ?? (item.type === "loading" ? 0 : defaultDuration);
1759
+ if (duration > 0) {
1760
+ messageTimers.set(item.key, window.setTimeout(() => closeMessage(item.key), duration * 1e3));
1761
+ }
1762
+ }
1763
+ function openMessage(input) {
1764
+ const config = typeof input === "object" && input !== null && "content" in input ? input : { content: input };
1765
+ const key = config.key ?? `sia-message-${++messageSeed}`;
1766
+ const item = { ...config, key, type: config.type ?? "info" };
1767
+ const existingIndex = messageItems.findIndex((candidate) => candidate.key === key);
1768
+ if (existingIndex >= 0) messageItems = messageItems.map((candidate, index) => index === existingIndex ? item : candidate);
1769
+ else messageItems = [...messageItems, item];
1770
+ while (messageItems.length > maxCount) closeMessage(messageItems[0].key);
1771
+ renderMessages();
1772
+ scheduleMessage(item);
1773
+ return {
1774
+ close: () => closeMessage(key),
1775
+ update(next) {
1776
+ const current = messageItems.find((candidate) => candidate.key === key);
1777
+ if (!current) return;
1778
+ const updated = { ...current, ...next, key, type: next.type ?? current.type };
1779
+ messageItems = messageItems.map((candidate) => candidate.key === key ? updated : candidate);
1780
+ renderMessages();
1781
+ scheduleMessage(updated);
1782
+ }
1783
+ };
1784
+ }
1785
+ function shortcut(type) {
1786
+ return (content, duration) => openMessage({ content, duration, type });
1787
+ }
1788
+ var message = {
1789
+ open: openMessage,
1790
+ info: shortcut("info"),
1791
+ success: shortcut("success"),
1792
+ warning: shortcut("warning"),
1793
+ error: shortcut("error"),
1794
+ loading: shortcut("loading"),
1795
+ destroy(key) {
1796
+ if (key !== void 0) {
1797
+ closeMessage(key);
1798
+ return;
1799
+ }
1800
+ [...messageItems].forEach((item) => closeMessage(item.key));
1801
+ },
1802
+ config(config) {
1803
+ if (config.duration !== void 0) defaultDuration = config.duration;
1804
+ if (config.maxCount !== void 0) maxCount = Math.max(1, config.maxCount);
1805
+ }
1806
+ };
1807
+
1808
+ // src/components/Breadcrumb.tsx
1809
+ import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1810
+ function Breadcrumb({ items, separator = "/", itemRender, className = "", ...props }) {
1811
+ return /* @__PURE__ */ jsx11("nav", { "aria-label": "\u9762\u5305\u5C51\u5BFC\u822A", ...props, className: `sia-breadcrumb ${className}`.trim(), children: /* @__PURE__ */ jsx11("ol", { className: "sia-breadcrumb__list", children: items.map((item, index) => {
1812
+ const current = index === items.length - 1;
1813
+ const content = /* @__PURE__ */ jsxs11(Fragment6, { children: [
1814
+ item.icon ? /* @__PURE__ */ jsx11("span", { className: "sia-breadcrumb__icon", "aria-hidden": "true", children: item.icon }) : null,
1815
+ /* @__PURE__ */ jsx11("span", { className: "sia-breadcrumb__title", children: item.title })
1816
+ ] });
1817
+ const custom = itemRender?.(item, index, items);
1818
+ const label = item.disabled ? /* @__PURE__ */ jsx11("span", { className: "sia-breadcrumb__label", "aria-disabled": "true", children: content }) : custom !== void 0 ? /* @__PURE__ */ jsx11("span", { className: "sia-breadcrumb__label", children: custom }) : item.href ? /* @__PURE__ */ jsx11("a", { className: "sia-breadcrumb__label", href: item.href, target: item.target, rel: item.target === "_blank" ? "noopener noreferrer" : void 0, onClick: item.onClick, children: content }) : item.onClick ? /* @__PURE__ */ jsx11(Button, { className: "sia-breadcrumb__label", variant: "text", onClick: item.onClick, children: content }) : /* @__PURE__ */ jsx11("span", { className: "sia-breadcrumb__label", children: content });
1819
+ return /* @__PURE__ */ jsxs11("li", { className: `sia-breadcrumb__item${current ? " is-current" : ""}${item.disabled ? " is-disabled" : ""}`, children: [
1820
+ /* @__PURE__ */ jsxs11("span", { className: "sia-breadcrumb__entry", "aria-current": current ? "page" : void 0, children: [
1821
+ label,
1822
+ item.menu?.items.length ? /* @__PURE__ */ jsx11(Dropdown, { menu: item.menu, trigger: ["click"], disabled: item.disabled, children: /* @__PURE__ */ jsx11(Button, { className: "sia-breadcrumb__menu-trigger", variant: "text", size: "small", disabled: item.disabled, "aria-label": `\u5C55\u5F00${typeof item.title === "string" ? item.title : "\u5C42\u7EA7"}\u83DC\u5355`, icon: /* @__PURE__ */ jsx11(Icon, { name: "chevron-down", size: 12 }) }) }) : null
1823
+ ] }),
1824
+ !current ? /* @__PURE__ */ jsx11("span", { className: "sia-breadcrumb__separator", "aria-hidden": "true", children: item.separator === void 0 ? separator : item.separator }) : null
1825
+ ] }, item.key ?? index);
1826
+ }) }) });
1827
+ }
1828
+
1829
+ // src/components/Typography.tsx
1830
+ import { useEffect as useEffect7, useLayoutEffect as useLayoutEffect2, useRef as useRef8, useState as useState7 } from "react";
1831
+ import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1832
+ function TypographyContent({
1833
+ as: Tag2 = "span",
1834
+ type,
1835
+ disabled,
1836
+ strong,
1837
+ italic,
1838
+ underline,
1839
+ delete: deleted,
1840
+ mark,
1841
+ code,
1842
+ keyboard,
1843
+ copyable,
1844
+ editable,
1845
+ ellipsis,
1846
+ children,
1847
+ className = "",
1848
+ ...props
1849
+ }) {
1850
+ const contentRef = useRef8(null);
1851
+ const editRef = useRef8(null);
1852
+ const timer = useRef8();
1853
+ const [localText, setLocalText] = useState7();
1854
+ const [draft, setDraft] = useState7("");
1855
+ const [editing, setEditing] = useState7(false);
1856
+ const [copied, setCopied] = useState7(false);
1857
+ const [copyError, setCopyError] = useState7(false);
1858
+ const [expanded, setExpanded] = useState7(false);
1859
+ const [overflow, setOverflow] = useState7(false);
1860
+ const editConfig = typeof editable === "object" ? editable : void 0;
1861
+ const content = editConfig?.text ?? localText ?? children;
1862
+ const requestedRows = typeof ellipsis === "object" ? ellipsis.rows ?? 1 : 1;
1863
+ const rows = Number.isFinite(requestedRows) ? Math.max(1, Math.floor(requestedRows)) : 1;
1864
+ const expandable = typeof ellipsis === "object" && ellipsis.expandable;
1865
+ useEffect7(() => {
1866
+ setLocalText(void 0);
1867
+ }, [children]);
1868
+ useEffect7(() => () => clearTimeout(timer.current), []);
1869
+ useLayoutEffect2(() => {
1870
+ const element = contentRef.current;
1871
+ if (!element || !ellipsis || editing || expanded) return;
1872
+ const measure = () => setOverflow(element.scrollHeight > element.clientHeight + 1 || element.scrollWidth > element.clientWidth + 1);
1873
+ measure();
1874
+ const observer = new ResizeObserver(measure);
1875
+ observer.observe(element);
1876
+ return () => observer.disconnect();
1877
+ }, [content, ellipsis, rows, editing, expanded]);
1878
+ async function copy() {
1879
+ try {
1880
+ const text = typeof copyable === "object" ? copyable.text ?? contentRef.current?.textContent ?? "" : contentRef.current?.textContent ?? "";
1881
+ await navigator.clipboard.writeText(text);
1882
+ setCopied(true);
1883
+ setCopyError(false);
1884
+ clearTimeout(timer.current);
1885
+ timer.current = setTimeout(() => setCopied(false), 2e3);
1886
+ if (typeof copyable === "object") copyable.onCopy?.();
1887
+ } catch {
1888
+ setCopyError(true);
1889
+ }
1890
+ }
1891
+ function finish(save) {
1892
+ if (save) {
1893
+ setLocalText(draft);
1894
+ editConfig?.onChange?.(draft);
1895
+ }
1896
+ setEditing(false);
1897
+ requestAnimationFrame(() => editRef.current?.focus());
1898
+ }
1899
+ let formatted = content;
1900
+ if (strong) formatted = /* @__PURE__ */ jsx12("strong", { children: formatted });
1901
+ if (italic) formatted = /* @__PURE__ */ jsx12("em", { children: formatted });
1902
+ if (underline) formatted = /* @__PURE__ */ jsx12("u", { children: formatted });
1903
+ if (deleted) formatted = /* @__PURE__ */ jsx12("del", { children: formatted });
1904
+ if (mark) formatted = /* @__PURE__ */ jsx12("mark", { children: formatted });
1905
+ if (code) formatted = /* @__PURE__ */ jsx12("code", { children: formatted });
1906
+ if (keyboard) formatted = /* @__PURE__ */ jsx12("kbd", { children: formatted });
1907
+ return /* @__PURE__ */ jsx12(Tag2, { ...props, "aria-disabled": disabled || void 0, className: `sia-typography sia-typography--${Tag2}${type ? ` sia-typography--${type}` : ""}${disabled ? " is-disabled" : ""} ${className}`.trim(), children: editing ? /* @__PURE__ */ jsxs12("span", { className: "sia-typography__editor", children: [
1908
+ /* @__PURE__ */ jsx12(
1909
+ TextArea,
1910
+ {
1911
+ autoFocus: true,
1912
+ "aria-label": "\u7F16\u8F91\u6587\u672C",
1913
+ value: draft,
1914
+ maxLength: editConfig?.maxLength,
1915
+ rows: 3,
1916
+ onChange: (event) => setDraft(event.target.value),
1917
+ onKeyDown: (event) => {
1918
+ if (event.nativeEvent.isComposing) return;
1919
+ if (event.key === "Escape") {
1920
+ event.preventDefault();
1921
+ finish(false);
1922
+ }
1923
+ if (event.key === "Enter" && !event.shiftKey) {
1924
+ event.preventDefault();
1925
+ finish(true);
1926
+ }
1927
+ }
1928
+ }
1929
+ ),
1930
+ /* @__PURE__ */ jsxs12("span", { className: "sia-typography__edit-actions", children: [
1931
+ /* @__PURE__ */ jsx12(Button, { size: "small", onClick: () => finish(false), children: "\u53D6\u6D88" }),
1932
+ /* @__PURE__ */ jsx12(Button, { size: "small", variant: "primary", onClick: () => finish(true), children: "\u4FDD\u5B58" })
1933
+ ] })
1934
+ ] }) : /* @__PURE__ */ jsxs12(Fragment7, { children: [
1935
+ /* @__PURE__ */ jsx12("span", { ref: contentRef, className: ellipsis && !expanded ? "sia-typography__ellipsis" : void 0, style: ellipsis && !expanded ? { "--sia-typography-rows": rows } : void 0, children: formatted }),
1936
+ expandable && (overflow || expanded) ? /* @__PURE__ */ jsx12(Button, { variant: "link", size: "small", className: "sia-typography__action", "aria-expanded": expanded, disabled, onClick: () => setExpanded(!expanded), children: expanded ? "\u6536\u8D77" : "\u5C55\u5F00" }) : null,
1937
+ editable ? /* @__PURE__ */ jsx12(Button, { ref: editRef, variant: "text", size: "small", className: "sia-typography__action", "aria-label": "\u7F16\u8F91\u6587\u672C", title: "\u7F16\u8F91", disabled, icon: /* @__PURE__ */ jsx12(Icon, { name: "edit", size: 14 }), onClick: () => {
1938
+ setDraft(contentRef.current?.textContent ?? "");
1939
+ setEditing(true);
1940
+ } }) : null,
1941
+ copyable ? /* @__PURE__ */ jsx12(Button, { variant: "text", size: "small", className: "sia-typography__action", "aria-label": copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u6587\u672C", title: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236", disabled, icon: /* @__PURE__ */ jsx12(Icon, { name: copied ? "check" : "copy", size: 14 }), onClick: () => void copy() }) : null,
1942
+ copyError ? /* @__PURE__ */ jsx12("span", { role: "status", className: "sia-typography--danger", children: "\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u6587\u672C\u590D\u5236\u3002" }) : null
1943
+ ] }) });
1944
+ }
1945
+ function Title({ level = 1, ...props }) {
1946
+ return /* @__PURE__ */ jsx12(TypographyContent, { ...props, as: `h${level}` });
1947
+ }
1948
+ function Text(props) {
1949
+ return /* @__PURE__ */ jsx12(TypographyContent, { ...props });
1950
+ }
1951
+ function Paragraph(props) {
1952
+ return /* @__PURE__ */ jsx12(TypographyContent, { ...props, as: "p" });
1953
+ }
1954
+ function Link({ disabled, className = "", onClick, href, target, rel, ...props }) {
1955
+ return /* @__PURE__ */ jsx12(
1956
+ "a",
1957
+ {
1958
+ ...props,
1959
+ href: disabled ? void 0 : href,
1960
+ target,
1961
+ rel: rel ?? (target === "_blank" ? "noopener noreferrer" : void 0),
1962
+ "aria-disabled": disabled || void 0,
1963
+ tabIndex: disabled ? -1 : props.tabIndex,
1964
+ className: `sia-typography sia-typography--link${disabled ? " is-disabled" : ""} ${className}`.trim(),
1965
+ onClick: (event) => {
1966
+ if (disabled) event.preventDefault();
1967
+ else onClick?.(event);
1968
+ }
1969
+ }
1970
+ );
1971
+ }
1972
+ function TypographyRoot({ className = "", ...props }) {
1973
+ return /* @__PURE__ */ jsx12("div", { ...props, className: `sia-typography ${className}`.trim() });
1974
+ }
1975
+ var Typography = Object.assign(TypographyRoot, { Title, Text, Paragraph, Link });
1976
+
1977
+ // src/components/FloatButton.tsx
1978
+ import { createContext as createContext2, forwardRef as forwardRef3, useContext as useContext2, useEffect as useEffect8, useId as useId6, useRef as useRef9, useState as useState8 } from "react";
1979
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1980
+ var GroupShape = createContext2(void 0);
1981
+ var FloatButtonRoot = forwardRef3(function FloatButton({
1982
+ icon,
1983
+ description,
1984
+ tooltip,
1985
+ type = "default",
1986
+ shape = "circle",
1987
+ badge,
1988
+ htmlType = "button",
1989
+ className = "",
1990
+ style,
1991
+ children,
1992
+ ...props
1993
+ }, ref) {
1994
+ const groupShape = useContext2(GroupShape);
1995
+ const label = props["aria-label"] ?? (typeof tooltip === "string" ? tooltip : typeof description === "string" ? description : "\u60AC\u6D6E\u64CD\u4F5C");
1996
+ const button = /* @__PURE__ */ jsx13(
1997
+ "button",
1998
+ {
1999
+ ...props,
2000
+ ref,
2001
+ type: htmlType,
2002
+ "aria-label": label,
2003
+ className: `sia-float-button sia-float-button--${groupShape ?? shape} sia-float-button--${type} ${className}`.trim(),
2004
+ children: /* @__PURE__ */ jsx13(Badge, { ...badge, className: "sia-float-button__badge", children: /* @__PURE__ */ jsxs13("span", { className: "sia-float-button__body", children: [
2005
+ icon !== null ? /* @__PURE__ */ jsx13("span", { className: "sia-float-button__icon", children: icon ?? /* @__PURE__ */ jsx13(Icon, { name: "question", size: 20 }) }) : null,
2006
+ description != null || children != null ? /* @__PURE__ */ jsx13("span", { className: "sia-float-button__description", children: description ?? children }) : null
2007
+ ] }) })
2008
+ }
2009
+ );
2010
+ return /* @__PURE__ */ jsx13("span", { className: "sia-float-button-root", style, children: tooltip ? /* @__PURE__ */ jsx13(Tooltip, { title: tooltip, placement: "left", children: button }) : button });
2011
+ });
2012
+ function FloatButtonGroup({
2013
+ shape = "circle",
2014
+ type = "default",
2015
+ icon,
2016
+ closeIcon,
2017
+ tooltip,
2018
+ trigger,
2019
+ placement = "top",
2020
+ open,
2021
+ defaultOpen = false,
2022
+ onOpenChange,
2023
+ children,
2024
+ className = "",
2025
+ onMouseEnter,
2026
+ onMouseLeave,
2027
+ onKeyDown,
2028
+ onBlur,
2029
+ ...props
2030
+ }) {
2031
+ const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
2032
+ const rootRef = useRef9(null);
2033
+ const triggerRef = useRef9(null);
2034
+ const id = useId6();
2035
+ useEffect8(() => {
2036
+ if (!trigger || !visible) return;
2037
+ const close = (event) => {
2038
+ if (!rootRef.current?.contains(event.target)) setVisible(false);
2039
+ };
2040
+ document.addEventListener("pointerdown", close);
2041
+ return () => document.removeEventListener("pointerdown", close);
2042
+ }, [trigger, visible, setVisible]);
2043
+ return /* @__PURE__ */ jsx13(GroupShape.Provider, { value: shape, children: /* @__PURE__ */ jsxs13(
2044
+ "div",
2045
+ {
2046
+ ...props,
2047
+ ref: rootRef,
2048
+ role: "group",
2049
+ className: `sia-float-button-group sia-float-button-group--${shape} sia-float-button-group--${placement}${trigger ? " sia-float-button-group--menu" : ""} ${className}`.trim(),
2050
+ onMouseEnter: (event) => {
2051
+ onMouseEnter?.(event);
2052
+ if (trigger === "hover") setVisible(true);
2053
+ },
2054
+ onMouseLeave: (event) => {
2055
+ onMouseLeave?.(event);
2056
+ if (trigger === "hover" && !event.currentTarget.contains(document.activeElement)) setVisible(false);
2057
+ },
2058
+ onBlur: (event) => {
2059
+ onBlur?.(event);
2060
+ if (trigger === "hover" && !event.currentTarget.contains(event.relatedTarget) && !event.currentTarget.matches(":hover")) setVisible(false);
2061
+ },
2062
+ onKeyDown: (event) => {
2063
+ onKeyDown?.(event);
2064
+ if (!event.defaultPrevented && trigger && event.key === "Escape") {
2065
+ setVisible(false);
2066
+ triggerRef.current?.focus();
2067
+ }
2068
+ },
2069
+ children: [
2070
+ !trigger || visible ? /* @__PURE__ */ jsx13("div", { id, className: "sia-float-button-group__list", children }) : null,
2071
+ trigger ? /* @__PURE__ */ jsx13(
2072
+ FloatButtonRoot,
2073
+ {
2074
+ ref: triggerRef,
2075
+ type,
2076
+ icon: visible ? closeIcon ?? /* @__PURE__ */ jsx13(Icon, { name: "close", size: 20 }) : icon ?? /* @__PURE__ */ jsx13(Icon, { name: "plus", size: 20 }),
2077
+ tooltip,
2078
+ "aria-label": visible ? "\u6536\u8D77\u60AC\u6D6E\u83DC\u5355" : "\u5C55\u5F00\u60AC\u6D6E\u83DC\u5355",
2079
+ "aria-expanded": visible,
2080
+ "aria-controls": visible ? id : void 0,
2081
+ onClick: () => setVisible(!visible)
2082
+ }
2083
+ ) : null
2084
+ ]
2085
+ }
2086
+ ) });
2087
+ }
2088
+ function FloatButtonBackTop({ target, visibilityHeight = 400, behavior = "smooth", onClick, icon, tooltip = "\u8FD4\u56DE\u9876\u90E8", ...props }) {
2089
+ const [visible, setVisible] = useState8(false);
2090
+ useEffect8(() => {
2091
+ const element = target ? target() : window;
2092
+ if (!element) return;
2093
+ const update = () => setVisible((element === window ? window.scrollY : element.scrollTop) >= visibilityHeight);
2094
+ update();
2095
+ element.addEventListener("scroll", update, { passive: true });
2096
+ return () => element.removeEventListener("scroll", update);
2097
+ }, [target, visibilityHeight]);
2098
+ if (!visible) return null;
2099
+ return /* @__PURE__ */ jsx13(FloatButtonRoot, { ...props, tooltip, icon: icon ?? /* @__PURE__ */ jsx13(Icon, { name: "arrow-up", size: 20 }), onClick: (event) => {
2100
+ onClick?.(event);
2101
+ if (event.defaultPrevented) return;
2102
+ const element = target ? target() : window;
2103
+ element?.scrollTo({ top: 0, behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : behavior });
2104
+ } });
2105
+ }
2106
+ var FloatButton2 = Object.assign(FloatButtonRoot, { Group: FloatButtonGroup, BackTop: FloatButtonBackTop });
2107
+
2108
+ export {
2109
+ Card,
2110
+ Tag,
2111
+ Tabs,
2112
+ Checkbox2 as Checkbox,
2113
+ Tooltip,
2114
+ Popover,
2115
+ Timeline,
2116
+ Tree,
2117
+ Popconfirm,
2118
+ Progress,
2119
+ Spin,
2120
+ Watermark,
2121
+ notification,
2122
+ Tour,
2123
+ useOverlayLifecycle,
2124
+ OverlayPortal,
2125
+ Rate,
2126
+ Badge,
2127
+ Calendar,
2128
+ Carousel,
2129
+ Collapse,
2130
+ ImagePreview,
2131
+ Image,
2132
+ Upload,
2133
+ Modal2 as Modal,
2134
+ message,
2135
+ Breadcrumb,
2136
+ Typography,
2137
+ FloatButton2 as FloatButton
2138
+ };