@sia.soul/sia-react-ui 0.1.5 → 0.1.7

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.
@@ -0,0 +1,1331 @@
1
+ import {
2
+ TextArea
3
+ } from "./chunk-WHARTF2I.js";
4
+ import {
5
+ Popover,
6
+ Tooltip,
7
+ useOverlayLifecycle
8
+ } from "./chunk-SMNSQDXN.js";
9
+ import {
10
+ Dropdown,
11
+ Icon
12
+ } from "./chunk-JJVD2ITI.js";
13
+ import {
14
+ Button
15
+ } from "./chunk-MBS2HXLZ.js";
16
+ import {
17
+ useControllableState
18
+ } from "./chunk-EJDPRAU2.js";
19
+
20
+ // src/components/Card.tsx
21
+ import { useState } from "react";
22
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
23
+ function Card({
24
+ title,
25
+ description,
26
+ extra,
27
+ accent,
28
+ accentColor,
29
+ collapsible = false,
30
+ collapsed,
31
+ defaultCollapsed = false,
32
+ onCollapsedChange,
33
+ bodyHeight,
34
+ bodyClassName = "",
35
+ bodyStyle,
36
+ className = "",
37
+ style,
38
+ children,
39
+ ...props
40
+ }) {
41
+ const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed);
42
+ const isCollapsed = collapsed ?? internalCollapsed;
43
+ const hasHeader = title || extra || collapsible;
44
+ const mergedStyle = accentColor ? { "--sia-card-accent": accentColor, ...style } : style;
45
+ const mergedBodyStyle = bodyHeight === void 0 ? { ...bodyStyle } : { height: bodyHeight, overflowY: "auto", ...bodyStyle };
46
+ function toggleCollapsed() {
47
+ const nextCollapsed = !isCollapsed;
48
+ if (collapsed === void 0) setInternalCollapsed(nextCollapsed);
49
+ onCollapsedChange?.(nextCollapsed);
50
+ }
51
+ const heading = /* @__PURE__ */ jsxs("span", { className: "sia-card__heading", children: [
52
+ accent || accentColor ? /* @__PURE__ */ jsx("span", { className: `sia-card__accent${accent ? ` sia-card__accent--${accent}` : ""}`, "aria-hidden": "true" }) : null,
53
+ title ? /* @__PURE__ */ jsx("h3", { className: "sia-card__title", children: title }) : null
54
+ ] });
55
+ return /* @__PURE__ */ jsxs("section", { className: `sia-card${isCollapsed ? " sia-card--collapsed" : ""} ${className}`.trim(), style: mergedStyle, ...props, children: [
56
+ hasHeader ? /* @__PURE__ */ jsxs("header", { className: "sia-card__header", children: [
57
+ collapsible ? /* @__PURE__ */ jsxs("button", { type: "button", className: "sia-card__collapse-trigger", "aria-expanded": !isCollapsed, onClick: toggleCollapsed, children: [
58
+ heading,
59
+ /* @__PURE__ */ jsx(Icon, { name: isCollapsed ? "chevron-down" : "chevron-up", size: 16 })
60
+ ] }) : heading,
61
+ extra ? /* @__PURE__ */ jsx("div", { className: "sia-card__extra", children: extra }) : null
62
+ ] }) : null,
63
+ !isCollapsed ? /* @__PURE__ */ jsxs(Fragment, { children: [
64
+ description ? /* @__PURE__ */ jsx("p", { className: "sia-card__description", children: description }) : null,
65
+ /* @__PURE__ */ jsx("div", { className: `sia-card__body ${bodyClassName}`.trim(), style: mergedBodyStyle, children })
66
+ ] }) : null
67
+ ] });
68
+ }
69
+
70
+ // src/components/Tag.tsx
71
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
72
+ function Tag({
73
+ status = "default",
74
+ compact = false,
75
+ variant = "soft",
76
+ icon,
77
+ closable = false,
78
+ disabled = false,
79
+ onClose,
80
+ className = "",
81
+ children,
82
+ ...props
83
+ }) {
84
+ return /* @__PURE__ */ jsxs2(
85
+ "span",
86
+ {
87
+ className: `sia-tag sia-tag--${status} sia-tag--${variant}${compact ? " sia-tag--compact" : ""}${disabled ? " sia-tag--disabled" : ""} ${className}`.trim(),
88
+ "aria-disabled": disabled || void 0,
89
+ ...props,
90
+ children: [
91
+ icon ? /* @__PURE__ */ jsx2("span", { className: "sia-tag__icon", children: icon }) : null,
92
+ /* @__PURE__ */ jsx2("span", { children }),
93
+ closable ? /* @__PURE__ */ jsx2(
94
+ "button",
95
+ {
96
+ type: "button",
97
+ className: "sia-tag__close",
98
+ "aria-label": "\u79FB\u9664\u6807\u7B7E",
99
+ disabled,
100
+ onClick: (event) => {
101
+ event.stopPropagation();
102
+ onClose?.(event);
103
+ },
104
+ children: /* @__PURE__ */ jsx2(Icon, { name: "close", size: 12 })
105
+ }
106
+ ) : null
107
+ ]
108
+ }
109
+ );
110
+ }
111
+
112
+ // src/components/Tabs.tsx
113
+ import { useId, useMemo, useState as useState2 } from "react";
114
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
115
+ function Tabs({
116
+ items,
117
+ activeKey,
118
+ defaultActiveKey,
119
+ onChange,
120
+ type = "line",
121
+ size = "medium",
122
+ tabPosition,
123
+ orientation = "horizontal",
124
+ centered = false,
125
+ tabBarTitle,
126
+ tabBarExtraContent,
127
+ destroyInactiveTabPane = true,
128
+ closable = false,
129
+ onEdit,
130
+ tabContextMenu,
131
+ onTabContextMenuClick,
132
+ className = "",
133
+ ...props
134
+ }) {
135
+ const firstEnabledKey = items.find((item) => !item.disabled)?.key ?? "";
136
+ const [internalActiveKey, setInternalActiveKey] = useState2(defaultActiveKey ?? firstEnabledKey);
137
+ const currentKey = activeKey ?? internalActiveKey;
138
+ const selectedKey = items.some((item) => item.key === currentKey && !item.disabled) ? currentKey : firstEnabledKey;
139
+ const baseId = useId().replace(/:/g, "");
140
+ const enabledItems = useMemo(() => items.filter((item) => !item.disabled), [items]);
141
+ const resolvedPosition = tabPosition ?? (orientation === "vertical" ? "left" : "top");
142
+ const resolvedOrientation = resolvedPosition === "left" || resolvedPosition === "right" ? "vertical" : "horizontal";
143
+ function selectTab(key) {
144
+ if (key === selectedKey) return;
145
+ if (activeKey === void 0) setInternalActiveKey(key);
146
+ onChange?.(key);
147
+ }
148
+ function focusAndSelect(key) {
149
+ selectTab(key);
150
+ document.getElementById(`${baseId}-tab-${key}`)?.focus();
151
+ }
152
+ function handleKeyDown(event, key) {
153
+ const previousKey = resolvedOrientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
154
+ const nextKey = resolvedOrientation === "horizontal" ? "ArrowRight" : "ArrowDown";
155
+ if (![previousKey, nextKey, "Home", "End"].includes(event.key) || enabledItems.length === 0) return;
156
+ event.preventDefault();
157
+ const currentIndex = Math.max(0, enabledItems.findIndex((item) => item.key === key));
158
+ if (event.key === "Home") return focusAndSelect(enabledItems[0].key);
159
+ if (event.key === "End") return focusAndSelect(enabledItems[enabledItems.length - 1].key);
160
+ const offset = event.key === nextKey ? 1 : -1;
161
+ const nextIndex = (currentIndex + offset + enabledItems.length) % enabledItems.length;
162
+ focusAndSelect(enabledItems[nextIndex].key);
163
+ }
164
+ const hasPanels = items.some((item) => item.children !== void 0);
165
+ return /* @__PURE__ */ jsxs3(
166
+ "div",
167
+ {
168
+ className: `sia-tabs sia-tabs--${type} sia-tabs--${size} sia-tabs--${resolvedOrientation} sia-tabs--${resolvedPosition}${centered ? " sia-tabs--centered" : ""} ${className}`.trim(),
169
+ ...props,
170
+ children: [
171
+ /* @__PURE__ */ jsxs3("div", { className: "sia-tabs__header", children: [
172
+ tabBarTitle ? /* @__PURE__ */ jsxs3("div", { className: "sia-tabs__title", children: [
173
+ tabBarTitle,
174
+ 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
175
+ ] }) : null,
176
+ /* @__PURE__ */ jsx3("div", { className: "sia-tabs__list", role: "tablist", "aria-orientation": resolvedOrientation, children: items.map((item) => {
177
+ const selected = item.key === selectedKey;
178
+ const canClose = item.closable ?? closable;
179
+ const tabNode = /* @__PURE__ */ jsxs3("span", { className: `sia-tabs__tab-wrap${canClose ? " is-closable" : ""}`, children: [
180
+ /* @__PURE__ */ jsxs3(
181
+ "button",
182
+ {
183
+ id: `${baseId}-tab-${item.key}`,
184
+ type: "button",
185
+ className: "sia-tabs__tab",
186
+ role: "tab",
187
+ "aria-selected": selected,
188
+ "aria-controls": hasPanels ? `${baseId}-panel-${item.key}` : void 0,
189
+ tabIndex: selected ? 0 : -1,
190
+ disabled: item.disabled,
191
+ onClick: () => selectTab(item.key),
192
+ onKeyDown: (event) => handleKeyDown(event, item.key),
193
+ children: [
194
+ type === "tech-line" ? /* @__PURE__ */ jsxs3("svg", { className: "sia-tabs__tab-shape", viewBox: "0 0 100 34", preserveAspectRatio: "none", "aria-hidden": "true", children: [
195
+ /* @__PURE__ */ jsx3("defs", { children: /* @__PURE__ */ jsxs3("linearGradient", { id: `${baseId}-tab-fill-${item.key}`, x1: "0", y1: "0", x2: "1", y2: "0", children: [
196
+ /* @__PURE__ */ jsx3("stop", { offset: "0", stopColor: "var(--sia-tabs-line-fill-edge, var(--sia-tabs-line-fill))" }),
197
+ /* @__PURE__ */ jsx3("stop", { offset: ".53", stopColor: "var(--sia-tabs-line-fill-center, var(--sia-tabs-line-fill))" }),
198
+ /* @__PURE__ */ jsx3("stop", { offset: "1", stopColor: "var(--sia-tabs-line-fill-edge, var(--sia-tabs-line-fill))" })
199
+ ] }) }),
200
+ /* @__PURE__ */ jsx3(
201
+ "path",
202
+ {
203
+ 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",
204
+ fill: `url(#${baseId}-tab-fill-${item.key})`,
205
+ stroke: "currentColor",
206
+ strokeWidth: "1.5",
207
+ vectorEffect: "non-scaling-stroke"
208
+ }
209
+ )
210
+ ] }) : null,
211
+ item.icon ? /* @__PURE__ */ jsx3("span", { className: "sia-tabs__icon", children: item.icon }) : null,
212
+ /* @__PURE__ */ jsx3("span", { children: item.label })
213
+ ]
214
+ }
215
+ ),
216
+ canClose ? /* @__PURE__ */ jsx3(
217
+ "button",
218
+ {
219
+ type: "button",
220
+ className: "sia-tabs__close",
221
+ "aria-label": `\u5173\u95ED${typeof item.label === "string" ? item.label : "\u6807\u7B7E\u9875"}`,
222
+ disabled: item.disabled,
223
+ onClick: () => onEdit?.(item.key, "remove"),
224
+ children: /* @__PURE__ */ jsx3(Icon, { name: "close", size: 12 })
225
+ }
226
+ ) : null
227
+ ] }, item.key);
228
+ const contextMenuItems = typeof tabContextMenu === "function" ? tabContextMenu(item) : tabContextMenu;
229
+ if (!contextMenuItems?.length) return tabNode;
230
+ return /* @__PURE__ */ jsx3(
231
+ Dropdown,
232
+ {
233
+ className: "sia-tabs__tab-context-trigger",
234
+ popupClassName: "sia-tabs__tab-context-menu",
235
+ trigger: ["contextMenu"],
236
+ tabIndex: -1,
237
+ menu: {
238
+ items: contextMenuItems,
239
+ selectable: false,
240
+ onClick: (info) => onTabContextMenuClick?.({ ...info, tabKey: item.key, tab: item })
241
+ },
242
+ children: tabNode
243
+ },
244
+ item.key
245
+ );
246
+ }) }),
247
+ tabBarExtraContent ? /* @__PURE__ */ jsx3("div", { className: "sia-tabs__extra", children: tabBarExtraContent }) : null
248
+ ] }),
249
+ hasPanels ? /* @__PURE__ */ jsx3("div", { className: "sia-tabs__panels", children: items.map((item) => {
250
+ const selected = item.key === selectedKey;
251
+ if (destroyInactiveTabPane && !selected) return null;
252
+ return /* @__PURE__ */ jsx3(
253
+ "div",
254
+ {
255
+ id: `${baseId}-panel-${item.key}`,
256
+ className: "sia-tabs__panel",
257
+ role: "tabpanel",
258
+ "aria-labelledby": `${baseId}-tab-${item.key}`,
259
+ hidden: !selected,
260
+ tabIndex: 0,
261
+ children: item.children
262
+ },
263
+ item.key
264
+ );
265
+ }) }) : null
266
+ ]
267
+ }
268
+ );
269
+ }
270
+
271
+ // src/components/Feedback.tsx
272
+ import { useEffect, useMemo as useMemo2, useState as useState3 } from "react";
273
+ import { createPortal } from "react-dom";
274
+ import { createRoot } from "react-dom/client";
275
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
276
+ function Popconfirm({
277
+ children,
278
+ title,
279
+ description,
280
+ okText = "\u786E\u5B9A",
281
+ cancelText = "\u53D6\u6D88",
282
+ okButtonProps,
283
+ cancelButtonProps,
284
+ placement = "top",
285
+ trigger = "click",
286
+ open,
287
+ defaultOpen = false,
288
+ disabled = false,
289
+ showCancel = true,
290
+ icon = /* @__PURE__ */ jsx4(Icon, { name: "question", variant: "filled" }),
291
+ onConfirm,
292
+ onCancel,
293
+ onOpenChange
294
+ }) {
295
+ const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
296
+ const [loading, setLoading] = useState3(false);
297
+ const content = /* @__PURE__ */ jsxs4("div", { className: "sia-popconfirm", children: [
298
+ /* @__PURE__ */ jsxs4("div", { className: "sia-popconfirm__message", children: [
299
+ /* @__PURE__ */ jsx4("span", { children: icon }),
300
+ /* @__PURE__ */ jsxs4("div", { children: [
301
+ /* @__PURE__ */ jsx4("strong", { children: title }),
302
+ description ? /* @__PURE__ */ jsx4("p", { children: description }) : null
303
+ ] })
304
+ ] }),
305
+ /* @__PURE__ */ jsxs4("div", { className: "sia-popconfirm__actions", children: [
306
+ showCancel ? /* @__PURE__ */ jsx4(Button, { size: "small", ...cancelButtonProps, onClick: (event) => {
307
+ cancelButtonProps?.onClick?.(event);
308
+ onCancel?.(event);
309
+ setVisible(false);
310
+ }, children: cancelText }) : null,
311
+ /* @__PURE__ */ jsx4(Button, { size: "small", variant: "primary", ...okButtonProps, loading: loading || okButtonProps?.loading, onClick: async (event) => {
312
+ okButtonProps?.onClick?.(event);
313
+ const result = onConfirm?.(event);
314
+ if (result instanceof Promise) {
315
+ setLoading(true);
316
+ try {
317
+ if (await result !== false) setVisible(false);
318
+ } finally {
319
+ setLoading(false);
320
+ }
321
+ } else if (result !== false) setVisible(false);
322
+ }, children: okText })
323
+ ] })
324
+ ] });
325
+ return /* @__PURE__ */ jsx4(Popover, { content, placement, trigger: disabled ? [] : trigger, open: visible, onOpenChange: setVisible, children });
326
+ }
327
+ function Progress({
328
+ percent = 0,
329
+ type = "line",
330
+ status,
331
+ showInfo = true,
332
+ format,
333
+ strokeColor,
334
+ trailColor,
335
+ strokeWidth = 8,
336
+ width = 120,
337
+ steps,
338
+ success,
339
+ size = "default",
340
+ className = "",
341
+ style,
342
+ ...props
343
+ }) {
344
+ const safe = Math.max(0, Math.min(100, percent));
345
+ const resolved = status ?? (safe >= 100 ? "success" : "normal");
346
+ const color = typeof strokeColor === "string" ? strokeColor : void 0;
347
+ const background = typeof strokeColor === "object" ? `linear-gradient(90deg, ${strokeColor.from}, ${strokeColor.to})` : color;
348
+ const label = format?.(safe, success?.percent) ?? (resolved === "exception" ? /* @__PURE__ */ jsx4(Icon, { name: "close" }) : resolved === "success" ? /* @__PURE__ */ jsx4(Icon, { name: "check" }) : `${safe}%`);
349
+ if (type !== "line") {
350
+ const radius = 46;
351
+ const circumference = 2 * Math.PI * radius;
352
+ const dash = circumference * (safe / 100);
353
+ return /* @__PURE__ */ jsxs4("div", { className: `sia-progress sia-progress--${type} sia-progress--${resolved} ${className}`.trim(), style: { width, height: width, ...style }, ...props, children: [
354
+ /* @__PURE__ */ jsxs4("svg", { viewBox: "0 0 100 100", role: "progressbar", "aria-valuenow": safe, children: [
355
+ /* @__PURE__ */ jsx4("circle", { className: "sia-progress__trail", cx: "50", cy: "50", r: radius, style: { stroke: trailColor } }),
356
+ /* @__PURE__ */ jsx4("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 } })
357
+ ] }),
358
+ showInfo ? /* @__PURE__ */ jsx4("span", { className: "sia-progress__text", children: label }) : null
359
+ ] });
360
+ }
361
+ const height = Array.isArray(size) ? size[1] : typeof size === "number" ? size : size === "small" ? 6 : strokeWidth;
362
+ return /* @__PURE__ */ jsxs4("div", { className: `sia-progress sia-progress--line sia-progress--${resolved} ${className}`.trim(), style, ...props, children: [
363
+ /* @__PURE__ */ jsx4("div", { className: "sia-progress__outer", style: { height, backgroundColor: trailColor }, children: steps ? /* @__PURE__ */ jsx4("div", { className: "sia-progress__steps", children: Array.from({ length: steps }, (_, index) => /* @__PURE__ */ jsx4("span", { className: index < Math.round(steps * safe / 100) ? "is-active" : "", style: { background: index < Math.round(steps * safe / 100) ? background : trailColor } }, index)) }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
364
+ /* @__PURE__ */ jsx4("span", { className: "sia-progress__bar", style: { width: `${safe}%`, background } }),
365
+ success?.percent ? /* @__PURE__ */ jsx4("span", { className: "sia-progress__success", style: { width: `${success.percent}%`, background: success.strokeColor } }) : null
366
+ ] }) }),
367
+ showInfo ? /* @__PURE__ */ jsx4("span", { className: "sia-progress__info", children: label }) : null
368
+ ] });
369
+ }
370
+ function Spin({ spinning = true, size = "default", tip, indicator, delay = 0, fullscreen = false, className = "", children, ...props }) {
371
+ const [visible, setVisible] = useState3(delay === 0 && spinning);
372
+ useEffect(() => {
373
+ if (!spinning) {
374
+ setVisible(false);
375
+ return;
376
+ }
377
+ const timer = window.setTimeout(() => setVisible(true), delay);
378
+ return () => window.clearTimeout(timer);
379
+ }, [delay, spinning]);
380
+ const spinner = visible ? /* @__PURE__ */ jsxs4("div", { className: `sia-spin sia-spin--${size}`, role: "status", "aria-live": "polite", children: [
381
+ indicator ?? /* @__PURE__ */ jsxs4("span", { className: "sia-spin__indicator", children: [
382
+ /* @__PURE__ */ jsx4("i", {}),
383
+ /* @__PURE__ */ jsx4("i", {}),
384
+ /* @__PURE__ */ jsx4("i", {}),
385
+ /* @__PURE__ */ jsx4("i", {})
386
+ ] }),
387
+ tip ? /* @__PURE__ */ jsx4("span", { className: "sia-spin__tip", children: tip }) : null
388
+ ] }) : null;
389
+ if (fullscreen) return visible && typeof document !== "undefined" ? createPortal(/* @__PURE__ */ jsx4("div", { className: "sia-spin-fullscreen", children: spinner }), document.body) : null;
390
+ if (!children) return /* @__PURE__ */ jsx4("div", { className: `sia-spin-wrap ${className}`.trim(), ...props, children: spinner });
391
+ return /* @__PURE__ */ jsxs4("div", { className: `sia-spin-container${visible ? " is-spinning" : ""} ${className}`.trim(), ...props, children: [
392
+ children,
393
+ visible ? /* @__PURE__ */ jsx4("div", { className: "sia-spin-mask", children: spinner }) : null
394
+ ] });
395
+ }
396
+ function escapeXml(value) {
397
+ return value.replace(/[&<>"']/g, (char) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&apos;" })[char]);
398
+ }
399
+ 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 }) {
400
+ const background = useMemo2(() => {
401
+ const tileWidth = width + gap[0], tileHeight = height + gap[1];
402
+ const lines = Array.isArray(content) ? content : [content];
403
+ const family = font?.fontFamily ?? "sans-serif", size = font?.fontSize ?? 16, weight = font?.fontWeight ?? 400, color = font?.color ?? "rgba(0,0,0,.15)";
404
+ 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("");
405
+ 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>`;
406
+ return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
407
+ }, [content, font?.color, font?.fontFamily, font?.fontSize, font?.fontWeight, gap[0], gap[1], height, image, offset[0], offset[1], rotate, width]);
408
+ return /* @__PURE__ */ jsxs4("div", { className: `sia-watermark ${className}`.trim(), ...props, children: [
409
+ children,
410
+ /* @__PURE__ */ jsx4("div", { className: "sia-watermark__layer", "aria-hidden": "true", style: { zIndex, backgroundImage: background } })
411
+ ] });
412
+ }
413
+ var notificationListeners = /* @__PURE__ */ new Set();
414
+ var notificationEntries = [];
415
+ var notificationSeed = 0;
416
+ var notificationHost = null;
417
+ var notificationTimers = /* @__PURE__ */ new Map();
418
+ function emitNotifications() {
419
+ notificationListeners.forEach((listener) => listener([...notificationEntries]));
420
+ }
421
+ function closeNotification(key) {
422
+ const entry = notificationEntries.find((item) => item.key === key);
423
+ notificationEntries = notificationEntries.filter((item) => item.key !== key);
424
+ window.clearTimeout(notificationTimers.get(key));
425
+ notificationTimers.delete(key);
426
+ emitNotifications();
427
+ entry?.onClose?.();
428
+ }
429
+ function NotificationHost() {
430
+ const [entries, setEntries] = useState3(notificationEntries);
431
+ useEffect(() => {
432
+ notificationListeners.add(setEntries);
433
+ return () => {
434
+ notificationListeners.delete(setEntries);
435
+ };
436
+ }, []);
437
+ const placements = ["topLeft", "topRight", "bottomLeft", "bottomRight"];
438
+ return /* @__PURE__ */ jsx4(Fragment2, { children: placements.map((placement) => /* @__PURE__ */ jsx4("div", { className: `sia-notification sia-notification--${placement}`, children: entries.filter((item) => (item.placement ?? "topRight") === placement).map((item) => /* @__PURE__ */ jsxs4("div", { className: `sia-notification__notice sia-notification__notice--${item.type ?? "info"}`, role: item.role ?? "alert", onClick: item.onClick, children: [
439
+ /* @__PURE__ */ jsx4("span", { className: "sia-notification__icon", children: item.icon ?? /* @__PURE__ */ jsx4(Icon, { name: item.type === "success" ? "circle-check" : item.type === "warning" ? "warning" : item.type === "error" ? "circle-close" : "info", variant: "filled" }) }),
440
+ /* @__PURE__ */ jsxs4("div", { children: [
441
+ /* @__PURE__ */ jsx4("strong", { children: item.message }),
442
+ item.description ? /* @__PURE__ */ jsx4("p", { children: item.description }) : null,
443
+ item.btn
444
+ ] }),
445
+ /* @__PURE__ */ jsx4("button", { type: "button", "aria-label": "\u5173\u95ED\u901A\u77E5", onClick: (event) => {
446
+ event.stopPropagation();
447
+ closeNotification(item.key);
448
+ }, children: item.closeIcon ?? /* @__PURE__ */ jsx4(Icon, { name: "close", size: 14 }) })
449
+ ] }, item.key)) }, placement)) });
450
+ }
451
+ function ensureNotificationHost() {
452
+ if (typeof document === "undefined" || notificationHost) return;
453
+ notificationHost = document.createElement("div");
454
+ notificationHost.dataset.siaNotificationHost = "";
455
+ document.body.appendChild(notificationHost);
456
+ createRoot(notificationHost).render(/* @__PURE__ */ jsx4(NotificationHost, {}));
457
+ }
458
+ function openNotification(config) {
459
+ if (typeof window === "undefined" || typeof document === "undefined") return { key: config.key ?? "ssr", close: () => void 0 };
460
+ ensureNotificationHost();
461
+ const key = config.key ?? `sia-notification-${++notificationSeed}`;
462
+ const entry = { ...config, key };
463
+ const exists = notificationEntries.some((item) => item.key === key);
464
+ notificationEntries = exists ? notificationEntries.map((item) => item.key === key ? entry : item) : [...notificationEntries, entry];
465
+ emitNotifications();
466
+ window.clearTimeout(notificationTimers.get(key));
467
+ if ((config.duration ?? 4.5) > 0) notificationTimers.set(key, window.setTimeout(() => closeNotification(key), (config.duration ?? 4.5) * 1e3));
468
+ return { key, close: () => closeNotification(key) };
469
+ }
470
+ var notification = {
471
+ open: openNotification,
472
+ info: (config) => openNotification({ ...config, type: "info" }),
473
+ success: (config) => openNotification({ ...config, type: "success" }),
474
+ warning: (config) => openNotification({ ...config, type: "warning" }),
475
+ error: (config) => openNotification({ ...config, type: "error" }),
476
+ destroy: (key) => {
477
+ if (key !== void 0) closeNotification(key);
478
+ else {
479
+ [...notificationEntries].forEach((item) => closeNotification(item.key));
480
+ }
481
+ }
482
+ };
483
+ function Tour({ open = false, steps, current, defaultCurrent = 0, mask = true, closable = true, disabledInteraction = false, onChange, onClose, onFinish }) {
484
+ const [index, setIndex] = useControllableState({ value: current, defaultValue: defaultCurrent, onChange });
485
+ const [, force] = useState3(0);
486
+ useEffect(() => {
487
+ if (!open) return;
488
+ const update = () => force((value) => value + 1);
489
+ window.addEventListener("resize", update);
490
+ window.addEventListener("scroll", update, true);
491
+ return () => {
492
+ window.removeEventListener("resize", update);
493
+ window.removeEventListener("scroll", update, true);
494
+ };
495
+ }, [open]);
496
+ if (!open || !steps[index] || typeof document === "undefined") return null;
497
+ const step = steps[index];
498
+ const target = typeof step.target === "function" ? step.target() : step.target;
499
+ const rect = target?.getBoundingClientRect();
500
+ const placement = step.placement ?? (rect ? "bottom" : "center");
501
+ 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%)" };
502
+ return createPortal(/* @__PURE__ */ jsxs4("div", { className: "sia-tour", role: "dialog", "aria-modal": "true", children: [
503
+ mask && !rect ? /* @__PURE__ */ jsx4("div", { className: "sia-tour__mask" }) : null,
504
+ rect ? /* @__PURE__ */ jsx4("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,
505
+ /* @__PURE__ */ jsxs4("div", { className: "sia-tour__panel", style: panelStyle, children: [
506
+ closable ? /* @__PURE__ */ jsx4("button", { className: "sia-tour__close", "aria-label": "\u5173\u95ED\u5F15\u5BFC", onClick: () => onClose?.(index), children: /* @__PURE__ */ jsx4(Icon, { name: "close", size: 14 }) }) : null,
507
+ step.cover,
508
+ /* @__PURE__ */ jsx4("strong", { children: step.title }),
509
+ step.description ? /* @__PURE__ */ jsx4("div", { className: "sia-tour__description", children: step.description }) : null,
510
+ /* @__PURE__ */ jsxs4("footer", { children: [
511
+ /* @__PURE__ */ jsxs4("span", { children: [
512
+ index + 1,
513
+ " / ",
514
+ steps.length
515
+ ] }),
516
+ /* @__PURE__ */ jsxs4("div", { children: [
517
+ index > 0 ? /* @__PURE__ */ jsx4(Button, { size: "small", ...step.prevButtonProps, onClick: () => setIndex(index - 1), children: step.prevButtonProps?.children ?? "\u4E0A\u4E00\u6B65" }) : null,
518
+ /* @__PURE__ */ jsx4(Button, { size: "small", variant: "primary", ...step.nextButtonProps, onClick: () => {
519
+ if (index >= steps.length - 1) onFinish?.();
520
+ else setIndex(index + 1);
521
+ }, children: step.nextButtonProps?.children ?? (index >= steps.length - 1 ? "\u5B8C\u6210" : "\u4E0B\u4E00\u6B65") })
522
+ ] })
523
+ ] })
524
+ ] })
525
+ ] }), document.body);
526
+ }
527
+
528
+ // src/components/DataDisplay.tsx
529
+ import { Children, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "react";
530
+ import { createPortal as createPortal2 } from "react-dom";
531
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
532
+ function Rate({ value, defaultValue = 0, count = 5, allowHalf = false, allowClear = true, disabled = false, character, tooltips, onChange, onHoverChange, className = "", ...props }) {
533
+ const [current, setCurrent] = useControllableState({ value, defaultValue, onChange });
534
+ const [hover, setHover] = useState4(0);
535
+ const shown = hover || current;
536
+ function choose(next) {
537
+ setCurrent(allowClear && next === current ? 0 : next);
538
+ }
539
+ return /* @__PURE__ */ jsx5("div", { className: `sia-rate${disabled ? " is-disabled" : ""} ${className}`.trim(), role: "radiogroup", "aria-label": "\u8BC4\u5206", onMouseLeave: () => {
540
+ setHover(0);
541
+ onHoverChange?.(0);
542
+ }, ...props, children: Array.from({ length: count }, (_, index) => {
543
+ const whole = index + 1;
544
+ const fill = Math.max(0, Math.min(1, shown - index));
545
+ const content = typeof character === "function" ? character(index) : character ?? /* @__PURE__ */ jsx5(Icon, { name: "star", variant: "filled" });
546
+ return /* @__PURE__ */ jsx5("span", { className: "sia-rate__item", title: tooltips?.[index], children: /* @__PURE__ */ jsxs5("button", { type: "button", disabled, role: "radio", "aria-checked": current === whole, "aria-label": `${whole} \u661F`, onMouseMove: (event) => {
547
+ const rect = event.currentTarget.getBoundingClientRect();
548
+ const next = allowHalf && event.clientX - rect.left < rect.width / 2 ? whole - 0.5 : whole;
549
+ setHover(next);
550
+ onHoverChange?.(next);
551
+ }, onClick: (event) => {
552
+ const rect = event.currentTarget.getBoundingClientRect();
553
+ choose(allowHalf && event.clientX - rect.left < rect.width / 2 ? whole - 0.5 : whole);
554
+ }, onKeyDown: (event) => {
555
+ if (event.key === "ArrowRight" || event.key === "ArrowUp") {
556
+ event.preventDefault();
557
+ setCurrent(Math.min(count, current + (allowHalf ? 0.5 : 1)));
558
+ }
559
+ if (event.key === "ArrowLeft" || event.key === "ArrowDown") {
560
+ event.preventDefault();
561
+ setCurrent(Math.max(0, current - (allowHalf ? 0.5 : 1)));
562
+ }
563
+ }, children: [
564
+ /* @__PURE__ */ jsx5("span", { className: "sia-rate__base", children: content }),
565
+ /* @__PURE__ */ jsx5("span", { className: "sia-rate__fill", style: { width: `${fill * 100}%` }, children: content })
566
+ ] }) }, whole);
567
+ }) });
568
+ }
569
+ function BadgeRibbon({ text, color, placement = "end", className = "", children, ...props }) {
570
+ return /* @__PURE__ */ jsxs5("div", { className: `sia-ribbon-wrap ${className}`.trim(), ...props, children: [
571
+ children,
572
+ /* @__PURE__ */ jsx5("span", { className: `sia-ribbon sia-ribbon--${placement}`, style: { backgroundColor: color }, children: text })
573
+ ] });
574
+ }
575
+ function Badge({ count, showZero = false, overflowCount = 99, dot = false, status, text, color, offset = [0, 0], size = "default", className = "", children, style, ...props }) {
576
+ const numeric = typeof count === "number";
577
+ const hidden = !dot && !status && (count === void 0 || count === null || count === 0 && !showZero);
578
+ const display = numeric && count > overflowCount ? `${overflowCount}+` : count;
579
+ const badge = !hidden ? /* @__PURE__ */ jsx5("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;
580
+ if (status && !children) return /* @__PURE__ */ jsxs5("span", { className: `sia-badge sia-badge--status ${className}`.trim(), style, ...props, children: [
581
+ badge,
582
+ text ? /* @__PURE__ */ jsx5("span", { className: "sia-badge__text", children: text }) : null
583
+ ] });
584
+ return /* @__PURE__ */ jsxs5("span", { className: `sia-badge ${className}`.trim(), style, ...props, children: [
585
+ children,
586
+ badge,
587
+ text && !status ? /* @__PURE__ */ jsx5("span", { className: "sia-badge__text", children: text }) : null
588
+ ] });
589
+ }
590
+ Badge.Ribbon = BadgeRibbon;
591
+ function pad(value) {
592
+ return String(value).padStart(2, "0");
593
+ }
594
+ function formatDate(date) {
595
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
596
+ }
597
+ function parseDate(value) {
598
+ const date = value ? /* @__PURE__ */ new Date(`${value}T00:00:00`) : /* @__PURE__ */ new Date();
599
+ return Number.isNaN(date.getTime()) ? /* @__PURE__ */ new Date() : date;
600
+ }
601
+ var WEEK = ["\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u65E5"];
602
+ 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"];
603
+ function Calendar({ value, defaultValue, mode = "month", fullscreen = true, validRange, disabledDate, dateCellRender, fullCellRender, headerRender, onChange, onSelect, onPanelChange, className = "", ...props }) {
604
+ const [selected, setSelected] = useControllableState({ value, defaultValue: defaultValue ?? formatDate(/* @__PURE__ */ new Date()), onChange });
605
+ const [panelMode, setPanelMode] = useState4(mode);
606
+ const [panel, setPanel] = useState4(() => {
607
+ const date = parseDate(value ?? defaultValue);
608
+ return new Date(date.getFullYear(), date.getMonth(), 1);
609
+ });
610
+ useEffect2(() => {
611
+ if (value) {
612
+ const date = parseDate(value);
613
+ setPanel(new Date(date.getFullYear(), date.getMonth(), 1));
614
+ }
615
+ }, [value]);
616
+ const grid = useMemo3(() => {
617
+ const first = new Date(panel.getFullYear(), panel.getMonth(), 1);
618
+ const mondayIndex = (first.getDay() + 6) % 7;
619
+ return Array.from({ length: 42 }, (_, index) => new Date(panel.getFullYear(), panel.getMonth(), index - mondayIndex + 1));
620
+ }, [panel]);
621
+ function setPanelValue(next) {
622
+ setPanel(next);
623
+ onPanelChange?.(formatDate(next), panelMode);
624
+ }
625
+ function setMode(next) {
626
+ setPanelMode(next);
627
+ onPanelChange?.(formatDate(panel), next);
628
+ }
629
+ const headerConfig = { value: formatDate(panel), mode: panelMode, onChange: (next) => setPanelValue(parseDate(next)), onTypeChange: setMode };
630
+ return /* @__PURE__ */ jsxs5("div", { className: `sia-calendar${fullscreen ? " sia-calendar--fullscreen" : " sia-calendar--mini"} ${className}`.trim(), ...props, children: [
631
+ /* @__PURE__ */ jsx5("div", { className: "sia-calendar__header", children: headerRender ? headerRender(headerConfig) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
632
+ /* @__PURE__ */ jsx5("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__ */ jsx5(Icon, { name: "chevron-left" }) }),
633
+ /* @__PURE__ */ jsxs5("strong", { children: [
634
+ panel.getFullYear(),
635
+ " \u5E74",
636
+ panelMode === "month" ? ` ${panel.getMonth() + 1} \u6708` : ""
637
+ ] }),
638
+ /* @__PURE__ */ jsxs5("div", { className: "sia-calendar__modes", children: [
639
+ /* @__PURE__ */ jsx5("button", { className: panelMode === "month" ? "is-active" : "", onClick: () => setMode("month"), children: "\u6708" }),
640
+ /* @__PURE__ */ jsx5("button", { className: panelMode === "year" ? "is-active" : "", onClick: () => setMode("year"), children: "\u5E74" })
641
+ ] }),
642
+ /* @__PURE__ */ jsx5("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__ */ jsx5(Icon, { name: "chevron-right" }) })
643
+ ] }) }),
644
+ panelMode === "year" ? /* @__PURE__ */ jsx5("div", { className: "sia-calendar__months", children: MONTHS.map((month, index) => /* @__PURE__ */ jsx5("button", { className: panel.getMonth() === index ? "is-selected" : "", onClick: () => {
645
+ setPanelValue(new Date(panel.getFullYear(), index, 1));
646
+ setMode("month");
647
+ }, children: month }, month)) }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
648
+ /* @__PURE__ */ jsx5("div", { className: "sia-calendar__week", children: WEEK.map((day) => /* @__PURE__ */ jsx5("span", { children: day }, day)) }),
649
+ /* @__PURE__ */ jsx5("div", { className: "sia-calendar__grid", children: grid.map((date) => {
650
+ const key = formatDate(date);
651
+ const outside = date.getMonth() !== panel.getMonth();
652
+ const disabled = Boolean(disabledDate?.(key) || validRange && (key < validRange[0] || key > validRange[1]));
653
+ const origin = /* @__PURE__ */ jsxs5(Fragment3, { children: [
654
+ /* @__PURE__ */ jsx5("span", { children: date.getDate() }),
655
+ dateCellRender?.(key)
656
+ ] });
657
+ return /* @__PURE__ */ jsx5("button", { disabled, className: `${outside ? "is-outside" : ""}${selected === key ? " is-selected" : ""}${formatDate(/* @__PURE__ */ new Date()) === key ? " is-today" : ""}`, onClick: () => {
658
+ setSelected(key);
659
+ onSelect?.(key);
660
+ if (outside) setPanelValue(new Date(date.getFullYear(), date.getMonth(), 1));
661
+ }, children: fullCellRender?.(key, { originNode: origin, type: "date" }) ?? origin }, key);
662
+ }) })
663
+ ] })
664
+ ] });
665
+ }
666
+ function Carousel({ autoplay = false, autoplaySpeed = 3e3, arrows = false, dots = true, effect = "scroll", infinite = true, initialSlide = 0, pauseOnHover = true, beforeChange, afterChange, className = "", children, ...props }) {
667
+ const slides = Children.toArray(children);
668
+ const [current, setCurrent] = useState4(Math.min(initialSlide, Math.max(0, slides.length - 1)));
669
+ const [paused, setPaused] = useState4(false);
670
+ function go(next) {
671
+ if (!slides.length) return;
672
+ const resolved = infinite ? (next + slides.length) % slides.length : Math.max(0, Math.min(slides.length - 1, next));
673
+ if (resolved === current) return;
674
+ beforeChange?.(current, resolved);
675
+ setCurrent(resolved);
676
+ afterChange?.(resolved);
677
+ }
678
+ useEffect2(() => {
679
+ if (!autoplay || paused || slides.length < 2) return;
680
+ const timer = window.setInterval(() => go(current + 1), autoplaySpeed);
681
+ return () => window.clearInterval(timer);
682
+ }, [autoplay, autoplaySpeed, current, paused, slides.length]);
683
+ return /* @__PURE__ */ jsxs5("div", { className: `sia-carousel sia-carousel--${effect} ${className}`.trim(), onMouseEnter: pauseOnHover ? () => setPaused(true) : void 0, onMouseLeave: pauseOnHover ? () => setPaused(false) : void 0, ...props, children: [
684
+ /* @__PURE__ */ jsx5("div", { className: "sia-carousel__viewport", children: /* @__PURE__ */ jsx5("div", { className: "sia-carousel__track", style: effect === "scroll" ? { transform: `translateX(-${current * 100}%)` } : void 0, children: slides.map((slide, index) => /* @__PURE__ */ jsx5("div", { className: `sia-carousel__slide${index === current ? " is-active" : ""}`, "aria-hidden": index !== current, children: slide }, index)) }) }),
685
+ arrows ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
686
+ /* @__PURE__ */ jsx5("button", { className: "sia-carousel__arrow sia-carousel__arrow--prev", disabled: !infinite && current === 0, "aria-label": "\u4E0A\u4E00\u5F20", onClick: () => go(current - 1), children: /* @__PURE__ */ jsx5(Icon, { name: "chevron-left" }) }),
687
+ /* @__PURE__ */ jsx5("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__ */ jsx5(Icon, { name: "chevron-right" }) })
688
+ ] }) : null,
689
+ dots ? /* @__PURE__ */ jsx5("div", { className: `sia-carousel__dots${typeof dots === "object" && dots.className ? ` ${dots.className}` : ""}`, children: slides.map((_, index) => /* @__PURE__ */ jsx5("button", { "aria-label": `\u5207\u6362\u5230\u7B2C ${index + 1} \u5F20`, "aria-current": index === current, onClick: () => go(index), children: /* @__PURE__ */ jsx5("span", {}) }, index)) }) : null
690
+ ] });
691
+ }
692
+ function CollapsePanel({
693
+ open,
694
+ forceRender = false,
695
+ destroyInactivePanel = false,
696
+ children
697
+ }) {
698
+ const [keepChildren, setKeepChildren] = useState4(open || forceRender || !destroyInactivePanel);
699
+ useEffect2(() => {
700
+ if (open || forceRender || !destroyInactivePanel) {
701
+ setKeepChildren(true);
702
+ return void 0;
703
+ }
704
+ const timer = window.setTimeout(() => setKeepChildren(false), 240);
705
+ return () => window.clearTimeout(timer);
706
+ }, [destroyInactivePanel, forceRender, open]);
707
+ const renderChildren = open || forceRender || !destroyInactivePanel || keepChildren;
708
+ return /* @__PURE__ */ jsx5("div", { className: "sia-collapse__panel", "aria-hidden": !open, children: /* @__PURE__ */ jsx5("div", { className: "sia-collapse__panel-motion", children: /* @__PURE__ */ jsx5("div", { className: "sia-collapse__panel-body", children: renderChildren ? children : null }) }) });
709
+ }
710
+ function Collapse({ items, activeKey, defaultActiveKey = [], accordion = false, bordered = true, ghost = false, destroyInactivePanel = false, expandIconPosition = "start", onChange, className = "", ...props }) {
711
+ const normalize = (key) => Array.isArray(key) ? [...key] : key === void 0 ? [] : [key];
712
+ const controlled = activeKey !== void 0;
713
+ const [internal, setInternal] = useState4(normalize(defaultActiveKey));
714
+ const openKeys = controlled ? normalize(activeKey) : internal;
715
+ function toggle(item) {
716
+ if (item.disabled || item.collapsible === "disabled") return;
717
+ const open = openKeys.includes(item.key);
718
+ const next = accordion ? open ? [] : [item.key] : open ? openKeys.filter((key) => key !== item.key) : [...openKeys, item.key];
719
+ if (!controlled) setInternal(next);
720
+ onChange?.(accordion ? next[0] ?? "" : next);
721
+ }
722
+ const borderClassName = !bordered || ghost ? "sia-collapse--borderless" : "sia-collapse--bordered";
723
+ return /* @__PURE__ */ jsx5("div", { className: `sia-collapse ${borderClassName}${ghost ? " sia-collapse--ghost" : ""} sia-collapse--icon-${expandIconPosition} ${className}`.trim(), ...props, children: items.map((item) => {
724
+ const open = openKeys.includes(item.key);
725
+ const arrow = item.showArrow === false ? null : /* @__PURE__ */ jsx5("button", { type: "button", className: "sia-collapse__arrow", "aria-label": open ? "\u6536\u8D77" : "\u5C55\u5F00", onClick: item.collapsible === "icon" ? () => toggle(item) : void 0, children: /* @__PURE__ */ jsx5(Icon, { name: "chevron-right", size: 14 }) });
726
+ return /* @__PURE__ */ jsxs5("section", { className: `sia-collapse__item${open ? " is-open" : ""}${item.disabled ? " is-disabled" : ""} ${item.className ?? ""}`.trim(), children: [
727
+ /* @__PURE__ */ jsxs5("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) => {
728
+ if (event.key === "Enter" || event.key === " ") {
729
+ event.preventDefault();
730
+ toggle(item);
731
+ }
732
+ }, children: [
733
+ expandIconPosition === "start" ? arrow : null,
734
+ /* @__PURE__ */ jsx5("span", { className: "sia-collapse__label", children: item.label }),
735
+ item.extra ? /* @__PURE__ */ jsx5("span", { className: "sia-collapse__extra", onClick: (event) => event.stopPropagation(), children: item.extra }) : null,
736
+ expandIconPosition === "end" ? arrow : null
737
+ ] }),
738
+ /* @__PURE__ */ jsx5(CollapsePanel, { open, forceRender: item.forceRender, destroyInactivePanel, children: item.children })
739
+ ] }, item.key);
740
+ }) });
741
+ }
742
+ function ImagePreview({ open, src, alt = "", onOpenChange }) {
743
+ const previewRef = useRef2(null);
744
+ useOverlayLifecycle(open, previewRef, () => onOpenChange(false));
745
+ if (!open || !src || typeof document === "undefined") return null;
746
+ return createPortal2(/* @__PURE__ */ jsxs5("div", { ref: previewRef, className: "sia-image-preview", role: "dialog", "aria-modal": "true", "aria-label": "\u56FE\u7247\u9884\u89C8", tabIndex: -1, onClick: () => onOpenChange(false), children: [
747
+ /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "\u5173\u95ED\u9884\u89C8", onClick: () => onOpenChange(false), children: /* @__PURE__ */ jsx5(Icon, { name: "close" }) }),
748
+ /* @__PURE__ */ jsx5("img", { src, alt, onClick: (event) => event.stopPropagation() })
749
+ ] }), document.body);
750
+ }
751
+ function Image({ fallback, placeholder, preview = true, rootClassName = "", className = "", src, alt = "", onError, style, ...props }) {
752
+ const config = typeof preview === "object" ? preview : {};
753
+ const controlled = typeof preview === "object" && preview.open !== void 0;
754
+ const [internalOpen, setInternalOpen] = useState4(false);
755
+ const open = controlled ? config.open : internalOpen;
756
+ const [loaded, setLoaded] = useState4(false);
757
+ const [failed, setFailed] = useState4(false);
758
+ const displaySrc = failed && fallback ? fallback : src;
759
+ const radius = typeof style?.borderRadius === "number" ? `${style.borderRadius}px` : style?.borderRadius;
760
+ const rootStyle = {
761
+ ...style,
762
+ "--sia-image-radius": radius ?? "var(--sia-radius)"
763
+ };
764
+ function setOpen(next) {
765
+ if (!controlled) setInternalOpen(next);
766
+ config.onOpenChange?.(next);
767
+ }
768
+ return /* @__PURE__ */ jsxs5("span", { className: `sia-image ${rootClassName}`.trim(), style: rootStyle, children: [
769
+ !loaded && placeholder ? /* @__PURE__ */ jsx5("span", { className: "sia-image__placeholder", children: placeholder }) : null,
770
+ /* @__PURE__ */ jsx5("img", { ...props, src: displaySrc, alt, className, onLoad: () => setLoaded(true), onError: (event) => {
771
+ if (!failed && fallback) setFailed(true);
772
+ onError?.(event);
773
+ } }),
774
+ preview ? /* @__PURE__ */ jsx5("button", { type: "button", className: "sia-image__mask", "aria-label": "\u9884\u89C8\u56FE\u7247", onClick: () => setOpen(true), children: config.mask ?? /* @__PURE__ */ jsxs5(Fragment3, { children: [
775
+ /* @__PURE__ */ jsx5(Icon, { name: "eye" }),
776
+ "\u9884\u89C8"
777
+ ] }) }) : null,
778
+ /* @__PURE__ */ jsx5(ImagePreview, { open, src: config.src ?? displaySrc, alt, onOpenChange: setOpen })
779
+ ] });
780
+ }
781
+
782
+ // src/components/Upload.tsx
783
+ import { useId as useId2, useRef as useRef3 } from "react";
784
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
785
+ var LIST_IGNORE = /* @__PURE__ */ Symbol("SIA_UPLOAD_LIST_IGNORE");
786
+ function UploadRoot({
787
+ accept,
788
+ multiple = false,
789
+ directory = false,
790
+ disabled = false,
791
+ maxCount: maxCount2,
792
+ fileList,
793
+ defaultFileList = [],
794
+ listType = "text",
795
+ showUploadList = true,
796
+ beforeUpload,
797
+ customRequest,
798
+ onChange,
799
+ onRemove,
800
+ children,
801
+ className = "",
802
+ onDragOver,
803
+ onDrop,
804
+ ...props
805
+ }) {
806
+ const inputRef = useRef3(null);
807
+ const filesRef = useRef3(fileList ?? defaultFileList);
808
+ const id = useId2();
809
+ const [files, setFiles] = useControllableState({ value: fileList, defaultValue: defaultFileList });
810
+ filesRef.current = files;
811
+ function emit(file, nextList) {
812
+ filesRef.current = nextList;
813
+ setFiles(nextList);
814
+ onChange?.({ file, fileList: nextList });
815
+ }
816
+ async function processFile(file, allFiles) {
817
+ const beforeResult = await beforeUpload?.(file, allFiles);
818
+ if (beforeResult === LIST_IGNORE) return;
819
+ if (beforeResult === false) {
820
+ const pending = { uid: `${Date.now()}-${file.name}`, name: file.name, size: file.size, type: file.type, status: "ready", originFileObj: file };
821
+ emit(pending, maxCount2 === 1 ? [pending] : [...filesRef.current, pending].slice(-(maxCount2 ?? Number.POSITIVE_INFINITY)));
822
+ return;
823
+ }
824
+ const uploadFile = beforeResult instanceof File ? beforeResult : file;
825
+ 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 };
826
+ const nextList = maxCount2 === 1 ? [item] : [...filesRef.current, item].slice(-(maxCount2 ?? Number.POSITIVE_INFINITY));
827
+ emit(item, nextList);
828
+ const request = {
829
+ file: uploadFile,
830
+ filename: uploadFile.name,
831
+ onProgress: (percent) => {
832
+ const progressing = { ...item, status: "uploading", percent };
833
+ const progressList = filesRef.current.map((entry) => entry.uid === item.uid ? progressing : entry);
834
+ emit(progressing, progressList);
835
+ },
836
+ onSuccess: (response) => {
837
+ const done = { ...item, status: "done", percent: 100, response };
838
+ const completed = filesRef.current.map((entry) => entry.uid === item.uid ? done : entry);
839
+ emit(done, completed);
840
+ },
841
+ onError: (error) => {
842
+ const failed = { ...item, status: "error", error };
843
+ const completed = filesRef.current.map((entry) => entry.uid === item.uid ? failed : entry);
844
+ emit(failed, completed);
845
+ }
846
+ };
847
+ if (customRequest) customRequest(request);
848
+ else window.setTimeout(() => request.onSuccess({ local: true }), 180);
849
+ }
850
+ function handleFiles(event) {
851
+ const selected = [...event.currentTarget.files ?? []];
852
+ selected.forEach((file) => void processFile(file, selected));
853
+ event.currentTarget.value = "";
854
+ }
855
+ function handleDrop(event) {
856
+ onDrop?.(event);
857
+ if (event.defaultPrevented || disabled) return;
858
+ event.preventDefault();
859
+ const selected = [...event.dataTransfer.files];
860
+ selected.forEach((file) => void processFile(file, selected));
861
+ }
862
+ async function remove(file) {
863
+ if (await onRemove?.(file) === false) return;
864
+ const next = files.filter((item) => item.uid !== file.uid);
865
+ emit({ ...file, status: "ready" }, next);
866
+ }
867
+ return /* @__PURE__ */ jsxs6(
868
+ "div",
869
+ {
870
+ className: `sia-upload sia-upload--${listType} ${className}`.trim(),
871
+ onDragOver: (event) => {
872
+ onDragOver?.(event);
873
+ if (!event.defaultPrevented && !disabled) event.preventDefault();
874
+ },
875
+ onDrop: handleDrop,
876
+ ...props,
877
+ children: [
878
+ /* @__PURE__ */ jsx6(
879
+ "input",
880
+ {
881
+ ref: inputRef,
882
+ id,
883
+ className: "sia-upload__input",
884
+ type: "file",
885
+ accept,
886
+ multiple,
887
+ disabled,
888
+ ...directory ? { webkitdirectory: "", directory: "" } : {},
889
+ onChange: handleFiles
890
+ }
891
+ ),
892
+ /* @__PURE__ */ jsx6("div", { className: "sia-upload__trigger", onClick: () => !disabled && inputRef.current?.click(), children: children ?? /* @__PURE__ */ jsx6(Button, { icon: /* @__PURE__ */ jsx6(Icon, { name: "upload", size: 16 }), disabled, children: "\u9009\u62E9\u6587\u4EF6" }) }),
893
+ showUploadList && files.length ? /* @__PURE__ */ jsx6("div", { className: "sia-upload__list", children: files.map((file) => /* @__PURE__ */ jsxs6("div", { className: `sia-upload__item sia-upload__item--${file.status ?? "ready"}`, children: [
894
+ /* @__PURE__ */ jsx6(Icon, { name: file.status === "done" ? "circle-check" : "file", size: 16 }),
895
+ /* @__PURE__ */ jsx6("span", { className: "sia-upload__name", title: file.name, children: file.name }),
896
+ file.status === "uploading" ? /* @__PURE__ */ jsx6("span", { className: "sia-upload__progress", children: /* @__PURE__ */ jsx6("span", { style: { width: `${file.percent ?? 0}%` } }) }) : null,
897
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": `\u79FB\u9664 ${file.name}`, onClick: () => void remove(file), children: /* @__PURE__ */ jsx6(Icon, { name: "close", size: 14 }) })
898
+ ] }, file.uid)) }) : null
899
+ ]
900
+ }
901
+ );
902
+ }
903
+ function UploadDragger({ hint = "\u652F\u6301\u5355\u4E2A\u6216\u6279\u91CF\u4E0A\u4F20", children, className = "", ...props }) {
904
+ return /* @__PURE__ */ jsx6(UploadRoot, { ...props, className: `sia-upload-dragger ${className}`.trim(), children: children ?? /* @__PURE__ */ jsxs6("div", { className: "sia-upload-dragger__content", children: [
905
+ /* @__PURE__ */ jsx6(Icon, { name: "upload", size: 28 }),
906
+ /* @__PURE__ */ jsx6("strong", { children: "\u70B9\u51FB\u6216\u62D6\u62FD\u6587\u4EF6\u5230\u6B64\u533A\u57DF\u4E0A\u4F20" }),
907
+ /* @__PURE__ */ jsx6("span", { children: hint })
908
+ ] }) });
909
+ }
910
+ var Upload = Object.assign(UploadRoot, { Dragger: UploadDragger, LIST_IGNORE });
911
+
912
+ // src/components/Message.tsx
913
+ import { createRoot as createRoot2 } from "react-dom/client";
914
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
915
+ var messageSeed = 0;
916
+ var messageRoot = null;
917
+ var messageContainer = null;
918
+ var messageItems = [];
919
+ var defaultDuration = 3;
920
+ var maxCount = 5;
921
+ var messageTimers = /* @__PURE__ */ new Map();
922
+ var messageIcons = {
923
+ info: /* @__PURE__ */ jsx7(Icon, { name: "info", size: 18 }),
924
+ success: /* @__PURE__ */ jsx7(Icon, { name: "circle-check", size: 18 }),
925
+ warning: /* @__PURE__ */ jsx7(Icon, { name: "warning", size: 18 }),
926
+ error: /* @__PURE__ */ jsx7(Icon, { name: "circle-close", size: 18 }),
927
+ loading: /* @__PURE__ */ jsx7(Icon, { name: "loader", size: 18, spin: true })
928
+ };
929
+ function ensureMessageRoot() {
930
+ if (typeof document === "undefined") return false;
931
+ if (!messageContainer) {
932
+ messageContainer = document.createElement("div");
933
+ messageContainer.className = "sia-message-root";
934
+ document.body.appendChild(messageContainer);
935
+ messageRoot = createRoot2(messageContainer);
936
+ }
937
+ return true;
938
+ }
939
+ function renderMessages() {
940
+ if (!ensureMessageRoot()) return;
941
+ messageRoot.render(/* @__PURE__ */ jsx7("div", { className: "sia-message-list", "aria-live": "polite", children: messageItems.map((item) => /* @__PURE__ */ jsxs7("div", { className: `sia-message sia-message--${item.type}`, role: item.type === "loading" ? "status" : "alert", children: [
942
+ /* @__PURE__ */ jsx7("span", { className: "sia-message__icon", "aria-hidden": "true", children: messageIcons[item.type] }),
943
+ /* @__PURE__ */ jsx7("span", { className: "sia-message__content", children: item.content }),
944
+ item.closable ? /* @__PURE__ */ jsx7("button", { type: "button", className: "sia-message__close", "aria-label": "\u5173\u95ED\u63D0\u793A", onClick: () => closeMessage(item.key), children: /* @__PURE__ */ jsx7(Icon, { name: "close", size: 14 }) }) : null
945
+ ] }, item.key)) }));
946
+ }
947
+ function closeMessage(key) {
948
+ const item = messageItems.find((candidate) => candidate.key === key);
949
+ const timer = messageTimers.get(key);
950
+ if (timer !== void 0) window.clearTimeout(timer);
951
+ messageTimers.delete(key);
952
+ messageItems = messageItems.filter((candidate) => candidate.key !== key);
953
+ item?.onClose?.();
954
+ renderMessages();
955
+ }
956
+ function scheduleMessage(item) {
957
+ const existingTimer = messageTimers.get(item.key);
958
+ if (existingTimer !== void 0) window.clearTimeout(existingTimer);
959
+ const duration = item.duration ?? (item.type === "loading" ? 0 : defaultDuration);
960
+ if (duration > 0) {
961
+ messageTimers.set(item.key, window.setTimeout(() => closeMessage(item.key), duration * 1e3));
962
+ }
963
+ }
964
+ function openMessage(input) {
965
+ const config = typeof input === "object" && input !== null && "content" in input ? input : { content: input };
966
+ const key = config.key ?? `sia-message-${++messageSeed}`;
967
+ const item = { ...config, key, type: config.type ?? "info" };
968
+ const existingIndex = messageItems.findIndex((candidate) => candidate.key === key);
969
+ if (existingIndex >= 0) messageItems = messageItems.map((candidate, index) => index === existingIndex ? item : candidate);
970
+ else messageItems = [...messageItems, item];
971
+ while (messageItems.length > maxCount) closeMessage(messageItems[0].key);
972
+ renderMessages();
973
+ scheduleMessage(item);
974
+ return {
975
+ close: () => closeMessage(key),
976
+ update(next) {
977
+ const current = messageItems.find((candidate) => candidate.key === key);
978
+ if (!current) return;
979
+ const updated = { ...current, ...next, key, type: next.type ?? current.type };
980
+ messageItems = messageItems.map((candidate) => candidate.key === key ? updated : candidate);
981
+ renderMessages();
982
+ scheduleMessage(updated);
983
+ }
984
+ };
985
+ }
986
+ function shortcut(type) {
987
+ return (content, duration) => openMessage({ content, duration, type });
988
+ }
989
+ var message = {
990
+ open: openMessage,
991
+ info: shortcut("info"),
992
+ success: shortcut("success"),
993
+ warning: shortcut("warning"),
994
+ error: shortcut("error"),
995
+ loading: shortcut("loading"),
996
+ destroy(key) {
997
+ if (key !== void 0) {
998
+ closeMessage(key);
999
+ return;
1000
+ }
1001
+ [...messageItems].forEach((item) => closeMessage(item.key));
1002
+ },
1003
+ config(config) {
1004
+ if (config.duration !== void 0) defaultDuration = config.duration;
1005
+ if (config.maxCount !== void 0) maxCount = Math.max(1, config.maxCount);
1006
+ }
1007
+ };
1008
+
1009
+ // src/components/Breadcrumb.tsx
1010
+ import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1011
+ function Breadcrumb({ items, separator = "/", itemRender, className = "", ...props }) {
1012
+ return /* @__PURE__ */ jsx8("nav", { "aria-label": "\u9762\u5305\u5C51\u5BFC\u822A", ...props, className: `sia-breadcrumb ${className}`.trim(), children: /* @__PURE__ */ jsx8("ol", { className: "sia-breadcrumb__list", children: items.map((item, index) => {
1013
+ const current = index === items.length - 1;
1014
+ const content = /* @__PURE__ */ jsxs8(Fragment4, { children: [
1015
+ item.icon ? /* @__PURE__ */ jsx8("span", { className: "sia-breadcrumb__icon", "aria-hidden": "true", children: item.icon }) : null,
1016
+ /* @__PURE__ */ jsx8("span", { className: "sia-breadcrumb__title", children: item.title })
1017
+ ] });
1018
+ const custom = itemRender?.(item, index, items);
1019
+ const label = item.disabled ? /* @__PURE__ */ jsx8("span", { className: "sia-breadcrumb__label", "aria-disabled": "true", children: content }) : custom !== void 0 ? /* @__PURE__ */ jsx8("span", { className: "sia-breadcrumb__label", children: custom }) : item.href ? /* @__PURE__ */ jsx8("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__ */ jsx8(Button, { className: "sia-breadcrumb__label", variant: "text", onClick: item.onClick, children: content }) : /* @__PURE__ */ jsx8("span", { className: "sia-breadcrumb__label", children: content });
1020
+ return /* @__PURE__ */ jsxs8("li", { className: `sia-breadcrumb__item${current ? " is-current" : ""}${item.disabled ? " is-disabled" : ""}`, children: [
1021
+ /* @__PURE__ */ jsxs8("span", { className: "sia-breadcrumb__entry", "aria-current": current ? "page" : void 0, children: [
1022
+ label,
1023
+ item.menu?.items.length ? /* @__PURE__ */ jsx8(Dropdown, { menu: item.menu, trigger: ["click"], disabled: item.disabled, children: /* @__PURE__ */ jsx8(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__ */ jsx8(Icon, { name: "chevron-down", size: 12 }) }) }) : null
1024
+ ] }),
1025
+ !current ? /* @__PURE__ */ jsx8("span", { className: "sia-breadcrumb__separator", "aria-hidden": "true", children: item.separator === void 0 ? separator : item.separator }) : null
1026
+ ] }, item.key ?? index);
1027
+ }) }) });
1028
+ }
1029
+
1030
+ // src/components/Typography.tsx
1031
+ import { useEffect as useEffect3, useLayoutEffect, useRef as useRef4, useState as useState5 } from "react";
1032
+ import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1033
+ function TypographyContent({
1034
+ as: Tag2 = "span",
1035
+ type,
1036
+ disabled,
1037
+ strong,
1038
+ italic,
1039
+ underline,
1040
+ delete: deleted,
1041
+ mark,
1042
+ code,
1043
+ keyboard,
1044
+ copyable,
1045
+ editable,
1046
+ ellipsis,
1047
+ children,
1048
+ className = "",
1049
+ ...props
1050
+ }) {
1051
+ const contentRef = useRef4(null);
1052
+ const editRef = useRef4(null);
1053
+ const timer = useRef4();
1054
+ const [localText, setLocalText] = useState5();
1055
+ const [draft, setDraft] = useState5("");
1056
+ const [editing, setEditing] = useState5(false);
1057
+ const [copied, setCopied] = useState5(false);
1058
+ const [copyError, setCopyError] = useState5(false);
1059
+ const [expanded, setExpanded] = useState5(false);
1060
+ const [overflow, setOverflow] = useState5(false);
1061
+ const editConfig = typeof editable === "object" ? editable : void 0;
1062
+ const content = editConfig?.text ?? localText ?? children;
1063
+ const requestedRows = typeof ellipsis === "object" ? ellipsis.rows ?? 1 : 1;
1064
+ const rows = Number.isFinite(requestedRows) ? Math.max(1, Math.floor(requestedRows)) : 1;
1065
+ const expandable = typeof ellipsis === "object" && ellipsis.expandable;
1066
+ useEffect3(() => {
1067
+ setLocalText(void 0);
1068
+ }, [children]);
1069
+ useEffect3(() => () => clearTimeout(timer.current), []);
1070
+ useLayoutEffect(() => {
1071
+ const element = contentRef.current;
1072
+ if (!element || !ellipsis || editing || expanded) return;
1073
+ const measure = () => setOverflow(element.scrollHeight > element.clientHeight + 1 || element.scrollWidth > element.clientWidth + 1);
1074
+ measure();
1075
+ const observer = new ResizeObserver(measure);
1076
+ observer.observe(element);
1077
+ return () => observer.disconnect();
1078
+ }, [content, ellipsis, rows, editing, expanded]);
1079
+ async function copy() {
1080
+ try {
1081
+ const text = typeof copyable === "object" ? copyable.text ?? contentRef.current?.textContent ?? "" : contentRef.current?.textContent ?? "";
1082
+ await navigator.clipboard.writeText(text);
1083
+ setCopied(true);
1084
+ setCopyError(false);
1085
+ clearTimeout(timer.current);
1086
+ timer.current = setTimeout(() => setCopied(false), 2e3);
1087
+ if (typeof copyable === "object") copyable.onCopy?.();
1088
+ } catch {
1089
+ setCopyError(true);
1090
+ }
1091
+ }
1092
+ function finish(save) {
1093
+ if (save) {
1094
+ setLocalText(draft);
1095
+ editConfig?.onChange?.(draft);
1096
+ }
1097
+ setEditing(false);
1098
+ requestAnimationFrame(() => editRef.current?.focus());
1099
+ }
1100
+ let formatted = content;
1101
+ if (strong) formatted = /* @__PURE__ */ jsx9("strong", { children: formatted });
1102
+ if (italic) formatted = /* @__PURE__ */ jsx9("em", { children: formatted });
1103
+ if (underline) formatted = /* @__PURE__ */ jsx9("u", { children: formatted });
1104
+ if (deleted) formatted = /* @__PURE__ */ jsx9("del", { children: formatted });
1105
+ if (mark) formatted = /* @__PURE__ */ jsx9("mark", { children: formatted });
1106
+ if (code) formatted = /* @__PURE__ */ jsx9("code", { children: formatted });
1107
+ if (keyboard) formatted = /* @__PURE__ */ jsx9("kbd", { children: formatted });
1108
+ return /* @__PURE__ */ jsx9(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__ */ jsxs9("span", { className: "sia-typography__editor", children: [
1109
+ /* @__PURE__ */ jsx9(
1110
+ TextArea,
1111
+ {
1112
+ autoFocus: true,
1113
+ "aria-label": "\u7F16\u8F91\u6587\u672C",
1114
+ value: draft,
1115
+ maxLength: editConfig?.maxLength,
1116
+ rows: 3,
1117
+ onChange: (event) => setDraft(event.target.value),
1118
+ onKeyDown: (event) => {
1119
+ if (event.nativeEvent.isComposing) return;
1120
+ if (event.key === "Escape") {
1121
+ event.preventDefault();
1122
+ finish(false);
1123
+ }
1124
+ if (event.key === "Enter" && !event.shiftKey) {
1125
+ event.preventDefault();
1126
+ finish(true);
1127
+ }
1128
+ }
1129
+ }
1130
+ ),
1131
+ /* @__PURE__ */ jsxs9("span", { className: "sia-typography__edit-actions", children: [
1132
+ /* @__PURE__ */ jsx9(Button, { size: "small", onClick: () => finish(false), children: "\u53D6\u6D88" }),
1133
+ /* @__PURE__ */ jsx9(Button, { size: "small", variant: "primary", onClick: () => finish(true), children: "\u4FDD\u5B58" })
1134
+ ] })
1135
+ ] }) : /* @__PURE__ */ jsxs9(Fragment5, { children: [
1136
+ /* @__PURE__ */ jsx9("span", { ref: contentRef, className: ellipsis && !expanded ? "sia-typography__ellipsis" : void 0, style: ellipsis && !expanded ? { "--sia-typography-rows": rows } : void 0, children: formatted }),
1137
+ expandable && (overflow || expanded) ? /* @__PURE__ */ jsx9(Button, { variant: "link", size: "small", className: "sia-typography__action", "aria-expanded": expanded, disabled, onClick: () => setExpanded(!expanded), children: expanded ? "\u6536\u8D77" : "\u5C55\u5F00" }) : null,
1138
+ editable ? /* @__PURE__ */ jsx9(Button, { ref: editRef, variant: "text", size: "small", className: "sia-typography__action", "aria-label": "\u7F16\u8F91\u6587\u672C", title: "\u7F16\u8F91", disabled, icon: /* @__PURE__ */ jsx9(Icon, { name: "edit", size: 14 }), onClick: () => {
1139
+ setDraft(contentRef.current?.textContent ?? "");
1140
+ setEditing(true);
1141
+ } }) : null,
1142
+ copyable ? /* @__PURE__ */ jsx9(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__ */ jsx9(Icon, { name: copied ? "check" : "copy", size: 14 }), onClick: () => void copy() }) : null,
1143
+ copyError ? /* @__PURE__ */ jsx9("span", { role: "status", className: "sia-typography--danger", children: "\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u6587\u672C\u590D\u5236\u3002" }) : null
1144
+ ] }) });
1145
+ }
1146
+ function Title({ level = 1, ...props }) {
1147
+ return /* @__PURE__ */ jsx9(TypographyContent, { ...props, as: `h${level}` });
1148
+ }
1149
+ function Text(props) {
1150
+ return /* @__PURE__ */ jsx9(TypographyContent, { ...props });
1151
+ }
1152
+ function Paragraph(props) {
1153
+ return /* @__PURE__ */ jsx9(TypographyContent, { ...props, as: "p" });
1154
+ }
1155
+ function Link({ disabled, className = "", onClick, href, target, rel, ...props }) {
1156
+ return /* @__PURE__ */ jsx9(
1157
+ "a",
1158
+ {
1159
+ ...props,
1160
+ href: disabled ? void 0 : href,
1161
+ target,
1162
+ rel: rel ?? (target === "_blank" ? "noopener noreferrer" : void 0),
1163
+ "aria-disabled": disabled || void 0,
1164
+ tabIndex: disabled ? -1 : props.tabIndex,
1165
+ className: `sia-typography sia-typography--link${disabled ? " is-disabled" : ""} ${className}`.trim(),
1166
+ onClick: (event) => {
1167
+ if (disabled) event.preventDefault();
1168
+ else onClick?.(event);
1169
+ }
1170
+ }
1171
+ );
1172
+ }
1173
+ function TypographyRoot({ className = "", ...props }) {
1174
+ return /* @__PURE__ */ jsx9("div", { ...props, className: `sia-typography ${className}`.trim() });
1175
+ }
1176
+ var Typography = Object.assign(TypographyRoot, { Title, Text, Paragraph, Link });
1177
+
1178
+ // src/components/FloatButton.tsx
1179
+ import { createContext, forwardRef, useContext, useEffect as useEffect4, useId as useId3, useRef as useRef5, useState as useState6 } from "react";
1180
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1181
+ var GroupShape = createContext(void 0);
1182
+ var FloatButtonRoot = forwardRef(function FloatButton({
1183
+ icon,
1184
+ description,
1185
+ tooltip,
1186
+ type = "default",
1187
+ shape = "circle",
1188
+ badge,
1189
+ htmlType = "button",
1190
+ className = "",
1191
+ style,
1192
+ children,
1193
+ ...props
1194
+ }, ref) {
1195
+ const groupShape = useContext(GroupShape);
1196
+ const label = props["aria-label"] ?? (typeof tooltip === "string" ? tooltip : typeof description === "string" ? description : "\u60AC\u6D6E\u64CD\u4F5C");
1197
+ const button = /* @__PURE__ */ jsx10(
1198
+ "button",
1199
+ {
1200
+ ...props,
1201
+ ref,
1202
+ type: htmlType,
1203
+ "aria-label": label,
1204
+ className: `sia-float-button sia-float-button--${groupShape ?? shape} sia-float-button--${type} ${className}`.trim(),
1205
+ children: /* @__PURE__ */ jsx10(Badge, { ...badge, className: "sia-float-button__badge", children: /* @__PURE__ */ jsxs10("span", { className: "sia-float-button__body", children: [
1206
+ icon !== null ? /* @__PURE__ */ jsx10("span", { className: "sia-float-button__icon", children: icon ?? /* @__PURE__ */ jsx10(Icon, { name: "question", size: 20 }) }) : null,
1207
+ description != null || children != null ? /* @__PURE__ */ jsx10("span", { className: "sia-float-button__description", children: description ?? children }) : null
1208
+ ] }) })
1209
+ }
1210
+ );
1211
+ return /* @__PURE__ */ jsx10("span", { className: "sia-float-button-root", style, children: tooltip ? /* @__PURE__ */ jsx10(Tooltip, { title: tooltip, placement: "left", children: button }) : button });
1212
+ });
1213
+ function FloatButtonGroup({
1214
+ shape = "circle",
1215
+ type = "default",
1216
+ icon,
1217
+ closeIcon,
1218
+ tooltip,
1219
+ trigger,
1220
+ placement = "top",
1221
+ open,
1222
+ defaultOpen = false,
1223
+ onOpenChange,
1224
+ children,
1225
+ className = "",
1226
+ onMouseEnter,
1227
+ onMouseLeave,
1228
+ onKeyDown,
1229
+ onBlur,
1230
+ ...props
1231
+ }) {
1232
+ const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
1233
+ const rootRef = useRef5(null);
1234
+ const triggerRef = useRef5(null);
1235
+ const id = useId3();
1236
+ useEffect4(() => {
1237
+ if (!trigger || !visible) return;
1238
+ const close = (event) => {
1239
+ if (!rootRef.current?.contains(event.target)) setVisible(false);
1240
+ };
1241
+ document.addEventListener("pointerdown", close);
1242
+ return () => document.removeEventListener("pointerdown", close);
1243
+ }, [trigger, visible, setVisible]);
1244
+ return /* @__PURE__ */ jsx10(GroupShape.Provider, { value: shape, children: /* @__PURE__ */ jsxs10(
1245
+ "div",
1246
+ {
1247
+ ...props,
1248
+ ref: rootRef,
1249
+ role: "group",
1250
+ className: `sia-float-button-group sia-float-button-group--${shape} sia-float-button-group--${placement}${trigger ? " sia-float-button-group--menu" : ""} ${className}`.trim(),
1251
+ onMouseEnter: (event) => {
1252
+ onMouseEnter?.(event);
1253
+ if (trigger === "hover") setVisible(true);
1254
+ },
1255
+ onMouseLeave: (event) => {
1256
+ onMouseLeave?.(event);
1257
+ if (trigger === "hover" && !event.currentTarget.contains(document.activeElement)) setVisible(false);
1258
+ },
1259
+ onBlur: (event) => {
1260
+ onBlur?.(event);
1261
+ if (trigger === "hover" && !event.currentTarget.contains(event.relatedTarget) && !event.currentTarget.matches(":hover")) setVisible(false);
1262
+ },
1263
+ onKeyDown: (event) => {
1264
+ onKeyDown?.(event);
1265
+ if (!event.defaultPrevented && trigger && event.key === "Escape") {
1266
+ setVisible(false);
1267
+ triggerRef.current?.focus();
1268
+ }
1269
+ },
1270
+ children: [
1271
+ !trigger || visible ? /* @__PURE__ */ jsx10("div", { id, className: "sia-float-button-group__list", children }) : null,
1272
+ trigger ? /* @__PURE__ */ jsx10(
1273
+ FloatButtonRoot,
1274
+ {
1275
+ ref: triggerRef,
1276
+ type,
1277
+ icon: visible ? closeIcon ?? /* @__PURE__ */ jsx10(Icon, { name: "close", size: 20 }) : icon ?? /* @__PURE__ */ jsx10(Icon, { name: "plus", size: 20 }),
1278
+ tooltip,
1279
+ "aria-label": visible ? "\u6536\u8D77\u60AC\u6D6E\u83DC\u5355" : "\u5C55\u5F00\u60AC\u6D6E\u83DC\u5355",
1280
+ "aria-expanded": visible,
1281
+ "aria-controls": visible ? id : void 0,
1282
+ onClick: () => setVisible(!visible)
1283
+ }
1284
+ ) : null
1285
+ ]
1286
+ }
1287
+ ) });
1288
+ }
1289
+ function FloatButtonBackTop({ target, visibilityHeight = 400, behavior = "smooth", onClick, icon, tooltip = "\u8FD4\u56DE\u9876\u90E8", ...props }) {
1290
+ const [visible, setVisible] = useState6(false);
1291
+ useEffect4(() => {
1292
+ const element = target ? target() : window;
1293
+ if (!element) return;
1294
+ const update = () => setVisible((element === window ? window.scrollY : element.scrollTop) >= visibilityHeight);
1295
+ update();
1296
+ element.addEventListener("scroll", update, { passive: true });
1297
+ return () => element.removeEventListener("scroll", update);
1298
+ }, [target, visibilityHeight]);
1299
+ if (!visible) return null;
1300
+ return /* @__PURE__ */ jsx10(FloatButtonRoot, { ...props, tooltip, icon: icon ?? /* @__PURE__ */ jsx10(Icon, { name: "arrow-up", size: 20 }), onClick: (event) => {
1301
+ onClick?.(event);
1302
+ if (event.defaultPrevented) return;
1303
+ const element = target ? target() : window;
1304
+ element?.scrollTo({ top: 0, behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : behavior });
1305
+ } });
1306
+ }
1307
+ var FloatButton2 = Object.assign(FloatButtonRoot, { Group: FloatButtonGroup, BackTop: FloatButtonBackTop });
1308
+
1309
+ export {
1310
+ Card,
1311
+ Tag,
1312
+ Tabs,
1313
+ Popconfirm,
1314
+ Progress,
1315
+ Spin,
1316
+ Watermark,
1317
+ notification,
1318
+ Tour,
1319
+ Rate,
1320
+ Badge,
1321
+ Calendar,
1322
+ Carousel,
1323
+ Collapse,
1324
+ ImagePreview,
1325
+ Image,
1326
+ Upload,
1327
+ message,
1328
+ Breadcrumb,
1329
+ Typography,
1330
+ FloatButton2 as FloatButton
1331
+ };