@ug666/ui-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,3799 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Accordion: () => Accordion,
24
+ AccordionContent: () => AccordionContent,
25
+ AccordionItem: () => AccordionItem,
26
+ AccordionTrigger: () => AccordionTrigger,
27
+ Alert: () => Alert,
28
+ AlertDescription: () => AlertDescription,
29
+ AlertTitle: () => AlertTitle,
30
+ Avatar: () => Avatar,
31
+ AvatarFallback: () => AvatarFallback,
32
+ AvatarGroup: () => AvatarGroup,
33
+ AvatarImage: () => AvatarImage,
34
+ Badge: () => Badge,
35
+ Breadcrumb: () => Breadcrumb,
36
+ BreadcrumbItem: () => BreadcrumbItem,
37
+ BreadcrumbLink: () => BreadcrumbLink,
38
+ BreadcrumbSeparator: () => BreadcrumbSeparator,
39
+ Button: () => Button,
40
+ Card: () => Card,
41
+ CardContent: () => CardContent,
42
+ CardDescription: () => CardDescription,
43
+ CardFooter: () => CardFooter,
44
+ CardHeader: () => CardHeader,
45
+ CardTitle: () => CardTitle,
46
+ Checkbox: () => Checkbox,
47
+ ContextMenu: () => ContextMenu,
48
+ ContextMenuContent: () => ContextMenuContent,
49
+ ContextMenuItem: () => ContextMenuItem,
50
+ ContextMenuSeparator: () => ContextMenuSeparator,
51
+ ContextMenuTrigger: () => ContextMenuTrigger,
52
+ Descriptions: () => Descriptions,
53
+ DescriptionsItem: () => DescriptionsItem,
54
+ Dialog: () => Dialog,
55
+ Drawer: () => Drawer,
56
+ DrawerClose: () => DrawerClose,
57
+ DrawerContent: () => DrawerContent,
58
+ DrawerDescription: () => DrawerDescription,
59
+ DrawerFooter: () => DrawerFooter,
60
+ DrawerHeader: () => DrawerHeader,
61
+ DrawerTitle: () => DrawerTitle,
62
+ DropdownContent: () => DropdownContent,
63
+ DropdownItem: () => DropdownItem,
64
+ DropdownMenu: () => DropdownMenu,
65
+ DropdownSeparator: () => DropdownSeparator,
66
+ DropdownTrigger: () => DropdownTrigger,
67
+ EmptyState: () => EmptyState,
68
+ Form: () => Form,
69
+ FormControl: () => FormControl,
70
+ FormDescription: () => FormDescription,
71
+ FormField: () => FormField,
72
+ FormItem: () => FormItem,
73
+ FormLabel: () => FormLabel,
74
+ FormMessage: () => FormMessage,
75
+ Input: () => Input,
76
+ Label: () => Label,
77
+ Modal: () => Modal,
78
+ ModalCloseButton: () => ModalCloseButton,
79
+ ModalContent: () => ModalContent,
80
+ ModalFooter: () => ModalFooter,
81
+ ModalHeader: () => ModalHeader,
82
+ ModalTitle: () => ModalTitle,
83
+ NavigationMenu: () => NavigationMenu,
84
+ NavigationMenuContent: () => NavigationMenuContent,
85
+ NavigationMenuItem: () => NavigationMenuItem,
86
+ NavigationMenuLink: () => NavigationMenuLink,
87
+ NavigationMenuTrigger: () => NavigationMenuTrigger,
88
+ NumberInput: () => NumberInput,
89
+ OTPInput: () => OTPInput,
90
+ Pagination: () => Pagination,
91
+ Popover: () => Popover,
92
+ PopoverContent: () => PopoverContent,
93
+ PopoverTrigger: () => PopoverTrigger,
94
+ Progress: () => Progress,
95
+ Radio: () => Radio,
96
+ RadioGroup: () => RadioGroup,
97
+ Select: () => Select,
98
+ Separator: () => Separator,
99
+ Sheet: () => Sheet,
100
+ Sidebar: () => Sidebar,
101
+ Skeleton: () => Skeleton,
102
+ Slider: () => Slider,
103
+ Spinner: () => Spinner,
104
+ Statistic: () => Statistic,
105
+ Steps: () => Steps,
106
+ Switch: () => Switch,
107
+ Table: () => Table,
108
+ TableBody: () => TableBody,
109
+ TableCell: () => TableCell,
110
+ TableHead: () => TableHead,
111
+ TableHeader: () => TableHeader,
112
+ TableRow: () => TableRow,
113
+ Tabs: () => Tabs,
114
+ TabsContent: () => TabsContent,
115
+ TabsList: () => TabsList,
116
+ TabsTrigger: () => TabsTrigger,
117
+ Tag: () => Tag,
118
+ Textarea: () => Textarea,
119
+ Toaster: () => Toaster,
120
+ Tooltip: () => Tooltip,
121
+ TooltipContent: () => TooltipContent,
122
+ TooltipTrigger: () => TooltipTrigger,
123
+ badgeVariants: () => badgeVariants,
124
+ buttonVariants: () => buttonVariants,
125
+ checkboxVariants: () => checkboxVariants,
126
+ cn: () => import_ui_utils43.cn,
127
+ numberInputVariants: () => numberInputVariants,
128
+ tagVariants: () => tagVariants,
129
+ theme: () => theme,
130
+ toast: () => toast,
131
+ useClickOutside: () => useClickOutside,
132
+ useCopyToClipboard: () => useCopyToClipboard,
133
+ useDebounce: () => useDebounce,
134
+ useEventListener: () => useEventListener,
135
+ useForm: () => useForm,
136
+ useHotkeys: () => useHotkeys,
137
+ useInterval: () => useInterval,
138
+ useLocalStorage: () => useLocalStorage,
139
+ useMediaQuery: () => useMediaQuery,
140
+ useMounted: () => useMounted,
141
+ usePagination: () => usePagination,
142
+ useTimeout: () => useTimeout,
143
+ useToggle: () => useToggle
144
+ });
145
+ module.exports = __toCommonJS(index_exports);
146
+
147
+ // src/components/button.tsx
148
+ var import_react = require("react");
149
+ var import_lucide_react = require("lucide-react");
150
+ var import_class_variance_authority = require("class-variance-authority");
151
+ var import_ui_utils = require("@ug666/ui-utils");
152
+ var import_jsx_runtime = require("react/jsx-runtime");
153
+ var buttonVariants = (0, import_class_variance_authority.cva)(
154
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
155
+ {
156
+ variants: {
157
+ variant: {
158
+ default: "bg-primary text-primary-fg hover:bg-primary-hover focus-visible:ring-ring",
159
+ destructive: "bg-danger text-danger-fg hover:bg-danger-hover focus-visible:ring-danger",
160
+ outline: "border border-border-strong bg-surface-1 text-text-primary hover:bg-surface-2 focus-visible:ring-ring/30",
161
+ secondary: "bg-surface-2 text-text-primary hover:bg-surface-3 focus-visible:ring-ring/30",
162
+ ghost: "text-text-primary hover:bg-surface-2 focus-visible:ring-ring/30",
163
+ link: "text-text-primary underline-offset-4 hover:underline focus-visible:ring-ring/30"
164
+ },
165
+ size: {
166
+ default: "h-9 px-4 py-2",
167
+ sm: "h-8 rounded-md px-3 text-xs",
168
+ lg: "h-12 rounded-md px-6 text-base",
169
+ icon: "h-9 w-9"
170
+ }
171
+ },
172
+ defaultVariants: {
173
+ variant: "default",
174
+ size: "default"
175
+ }
176
+ }
177
+ );
178
+ var Button = (0, import_react.forwardRef)(
179
+ ({ className, variant, size, loading = false, disabled, children, ...props }, ref) => {
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
181
+ "button",
182
+ {
183
+ ref,
184
+ className: (0, import_ui_utils.cn)(buttonVariants({ variant, size }), className),
185
+ disabled: disabled || loading,
186
+ ...props,
187
+ children: [
188
+ loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "animate-spin", size: 16 }),
189
+ children
190
+ ]
191
+ }
192
+ );
193
+ }
194
+ );
195
+ Button.displayName = "Button";
196
+
197
+ // src/components/input.tsx
198
+ var import_react2 = require("react");
199
+ var import_ui_utils2 = require("@ug666/ui-utils");
200
+ var import_jsx_runtime2 = require("react/jsx-runtime");
201
+ var Input = (0, import_react2.forwardRef)(
202
+ ({ className, label, error, helperText, id, ...props }, ref) => {
203
+ const generatedId = (0, import_react2.useId)();
204
+ const inputId = id ?? generatedId;
205
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-1", children: [
206
+ label && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
207
+ "label",
208
+ {
209
+ htmlFor: inputId,
210
+ className: "text-sm font-medium text-text-primary",
211
+ children: label
212
+ }
213
+ ),
214
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
215
+ "input",
216
+ {
217
+ ref,
218
+ id: inputId,
219
+ className: (0, import_ui_utils2.cn)(
220
+ "flex h-9 w-full rounded-md border bg-surface-1 px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary",
221
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1",
222
+ "disabled:cursor-not-allowed disabled:opacity-50",
223
+ error ? "border-danger focus-visible:ring-danger" : "border-border-strong focus-visible:ring-ring/30",
224
+ className
225
+ ),
226
+ ...props
227
+ }
228
+ ),
229
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-danger", children: error }),
230
+ !error && helperText && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-text-secondary", children: helperText })
231
+ ] });
232
+ }
233
+ );
234
+ Input.displayName = "Input";
235
+
236
+ // src/components/label.tsx
237
+ var import_react3 = require("react");
238
+ var import_ui_utils3 = require("@ug666/ui-utils");
239
+ var import_jsx_runtime3 = require("react/jsx-runtime");
240
+ var Label = (0, import_react3.forwardRef)(({ className, required, children, ...props }, ref) => {
241
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
242
+ "label",
243
+ {
244
+ ref,
245
+ className: (0, import_ui_utils3.cn)(
246
+ "leading-none text-sm font-medium text-text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
247
+ className
248
+ ),
249
+ ...props,
250
+ children: [
251
+ children,
252
+ required && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ml-0.5 text-danger", "aria-hidden": "true", children: "*" })
253
+ ]
254
+ }
255
+ );
256
+ });
257
+ Label.displayName = "Label";
258
+
259
+ // src/components/card.tsx
260
+ var import_react4 = require("react");
261
+ var import_ui_utils4 = require("@ug666/ui-utils");
262
+ var import_jsx_runtime4 = require("react/jsx-runtime");
263
+ var Card = (0, import_react4.forwardRef)(({ className, ...props }, ref) => {
264
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: (0, import_ui_utils4.cn)("rounded-lg border border-border-base bg-surface-1", className), ...props });
265
+ });
266
+ var CardHeader = (0, import_react4.forwardRef)(({ className, ...props }, ref) => {
267
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: (0, import_ui_utils4.cn)("flex flex-col gap-1 px-5 py-4 border-b border-border-base", className), ...props });
268
+ });
269
+ var CardTitle = (0, import_react4.forwardRef)(({ className, ...props }, ref) => {
270
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { ref, className: (0, import_ui_utils4.cn)("leading-none font-semibold tracking-tight text-text-primary", className), ...props });
271
+ });
272
+ var CardDescription = (0, import_react4.forwardRef)(({ className, ...props }, ref) => {
273
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { ref, className: (0, import_ui_utils4.cn)("text-sm text-text-secondary", className), ...props });
274
+ });
275
+ var CardContent = (0, import_react4.forwardRef)(({ className, ...props }, ref) => {
276
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: (0, import_ui_utils4.cn)("px-5 py-4", className), ...props });
277
+ });
278
+ var CardFooter = (0, import_react4.forwardRef)(({ className, ...props }, ref) => {
279
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: (0, import_ui_utils4.cn)("flex items-center px-5 py-4 border-t border-border-base", className), ...props });
280
+ });
281
+ Card.displayName = "Card";
282
+ CardHeader.displayName = "CardHeader";
283
+ CardTitle.displayName = "CardTitle";
284
+ CardDescription.displayName = "CardDescription";
285
+ CardContent.displayName = "CardContent";
286
+ CardFooter.displayName = "CardFooter";
287
+
288
+ // src/components/badge.tsx
289
+ var import_react5 = require("react");
290
+ var import_class_variance_authority2 = require("class-variance-authority");
291
+ var import_ui_utils5 = require("@ug666/ui-utils");
292
+ var import_jsx_runtime5 = require("react/jsx-runtime");
293
+ var badgeVariants = (0, import_class_variance_authority2.cva)(
294
+ "inline-flex items-center rounded-md px-2.5 py-0.5 text-xs font-semibold transition-colors",
295
+ {
296
+ variants: {
297
+ variant: {
298
+ default: "bg-primary text-primary-fg",
299
+ secondary: "bg-surface-3 text-text-primary",
300
+ destructive: "bg-danger-soft text-danger-soft-fg",
301
+ outline: "border border-border-strong text-text-primary bg-transparent",
302
+ success: "bg-success-soft text-success-soft-fg",
303
+ warning: "bg-warning-soft text-warning-soft-fg"
304
+ }
305
+ },
306
+ defaultVariants: {
307
+ variant: "default"
308
+ }
309
+ }
310
+ );
311
+ var Badge = (0, import_react5.forwardRef)(({ className, variant, ...props }, ref) => {
312
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { ref, className: (0, import_ui_utils5.cn)(badgeVariants({ variant }), className), ...props });
313
+ });
314
+ Badge.displayName = "Badge";
315
+
316
+ // src/components/tag.tsx
317
+ var import_react6 = require("react");
318
+ var import_lucide_react2 = require("lucide-react");
319
+ var import_class_variance_authority3 = require("class-variance-authority");
320
+ var import_ui_utils6 = require("@ug666/ui-utils");
321
+ var import_jsx_runtime6 = require("react/jsx-runtime");
322
+ var tagVariants = (0, import_class_variance_authority3.cva)(
323
+ "inline-flex items-center gap-1 rounded font-medium transition-colors",
324
+ {
325
+ variants: {
326
+ variant: {
327
+ default: "bg-surface-3 text-text-primary",
328
+ primary: "bg-success-soft text-success-soft-fg",
329
+ success: "bg-success-soft text-success-soft-fg",
330
+ warning: "bg-warning-soft text-warning-soft-fg",
331
+ destructive: "bg-danger-soft text-danger-soft-fg",
332
+ outline: "border border-border-strong bg-transparent text-text-primary"
333
+ },
334
+ size: {
335
+ sm: "px-1.5 py-0 text-xs",
336
+ default: "px-2 py-0.5 text-xs"
337
+ }
338
+ },
339
+ defaultVariants: {
340
+ variant: "default",
341
+ size: "default"
342
+ }
343
+ }
344
+ );
345
+ var Tag = (0, import_react6.forwardRef)(
346
+ ({ variant, size, closable = false, disabled = false, color, onClose, className, children, style, ...props }, ref) => {
347
+ const customStyle = color ? { backgroundColor: color, color: "#fff", borderColor: color, ...style } : style ?? {};
348
+ function handleClose(event) {
349
+ event.stopPropagation();
350
+ if (!disabled) {
351
+ onClose?.(event);
352
+ }
353
+ }
354
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
355
+ "span",
356
+ {
357
+ ref,
358
+ className: (0, import_ui_utils6.cn)(tagVariants({ variant, size }), disabled && "cursor-not-allowed opacity-50", className),
359
+ style: customStyle,
360
+ ...props,
361
+ children: [
362
+ children,
363
+ closable && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
364
+ "button",
365
+ {
366
+ type: "button",
367
+ onClick: handleClose,
368
+ disabled,
369
+ className: "inline-flex items-center justify-center rounded-sm opacity-60 transition-opacity hover:opacity-100 focus-visible:outline-none disabled:pointer-events-none",
370
+ "aria-label": "\u5173\u95ED\u6807\u7B7E",
371
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.X, { size: 10, strokeWidth: 2.5 })
372
+ }
373
+ )
374
+ ]
375
+ }
376
+ );
377
+ }
378
+ );
379
+ Tag.displayName = "Tag";
380
+
381
+ // src/components/modal.tsx
382
+ var import_react8 = require("react");
383
+ var import_react_dom = require("react-dom");
384
+ var import_lucide_react3 = require("lucide-react");
385
+ var import_ui_utils7 = require("@ug666/ui-utils");
386
+
387
+ // src/hooks/use-escape-key.ts
388
+ var import_react7 = require("react");
389
+ function useEscapeKey(open, onEscape) {
390
+ const handleEscape = (0, import_react7.useCallback)(
391
+ (e) => {
392
+ if (e.key === "Escape") onEscape();
393
+ },
394
+ [onEscape]
395
+ );
396
+ (0, import_react7.useEffect)(() => {
397
+ if (!open) return;
398
+ document.addEventListener("keydown", handleEscape);
399
+ document.body.style.overflow = "hidden";
400
+ return () => {
401
+ document.removeEventListener("keydown", handleEscape);
402
+ document.body.style.overflow = "";
403
+ };
404
+ }, [open, handleEscape]);
405
+ }
406
+
407
+ // src/components/modal.tsx
408
+ var import_jsx_runtime7 = require("react/jsx-runtime");
409
+ var Modal = (0, import_react8.forwardRef)(({ open, onClose, children, className }, ref) => {
410
+ useEscapeKey(open, onClose);
411
+ if (!open) return null;
412
+ return (0, import_react_dom.createPortal)(
413
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
414
+ "div",
415
+ {
416
+ ref,
417
+ className: (0, import_ui_utils7.cn)(
418
+ "fixed inset-0 z-50 flex items-center justify-center",
419
+ className
420
+ ),
421
+ role: "dialog",
422
+ "aria-modal": "true",
423
+ children: [
424
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
425
+ "div",
426
+ {
427
+ className: "absolute inset-0 bg-overlay",
428
+ onClick: onClose,
429
+ "aria-hidden": "true"
430
+ }
431
+ ),
432
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative z-10", children })
433
+ ]
434
+ }
435
+ ),
436
+ document.body
437
+ );
438
+ });
439
+ var ModalContent = (0, import_react8.forwardRef)(({ className, maxWidth = "max-w-lg", children, ...props }, ref) => {
440
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref, className: (0, import_ui_utils7.cn)("w-full rounded-lg bg-surface-1 shadow-lg", maxWidth, className), ...props, children });
441
+ });
442
+ var ModalHeader = (0, import_react8.forwardRef)(({ className, ...props }, ref) => {
443
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref, className: (0, import_ui_utils7.cn)("flex items-center justify-between border-b border-border-base px-6 py-4", className), ...props });
444
+ });
445
+ var ModalTitle = (0, import_react8.forwardRef)(({ className, ...props }, ref) => {
446
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { ref, className: (0, import_ui_utils7.cn)("text-lg font-semibold text-text-primary", className), ...props });
447
+ });
448
+ var ModalFooter = (0, import_react8.forwardRef)(({ className, ...props }, ref) => {
449
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref, className: (0, import_ui_utils7.cn)("flex items-center justify-end gap-2 border-t border-border-base px-6 py-4", className), ...props });
450
+ });
451
+ var ModalCloseButton = (0, import_react8.forwardRef)(({ onClick, className, type = "button", ...props }, ref) => {
452
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
453
+ "button",
454
+ {
455
+ ref,
456
+ type,
457
+ onClick,
458
+ className: (0, import_ui_utils7.cn)(
459
+ "rounded-md p-1 text-text-tertiary transition-colors hover:bg-surface-3 hover:text-text-secondary",
460
+ className
461
+ ),
462
+ "aria-label": "\u5173\u95ED",
463
+ ...props,
464
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.X, { size: 18 })
465
+ }
466
+ );
467
+ });
468
+ Modal.displayName = "Modal";
469
+ ModalContent.displayName = "ModalContent";
470
+ ModalHeader.displayName = "ModalHeader";
471
+ ModalTitle.displayName = "ModalTitle";
472
+ ModalFooter.displayName = "ModalFooter";
473
+ ModalCloseButton.displayName = "ModalCloseButton";
474
+
475
+ // src/components/dialog.tsx
476
+ var import_react9 = require("react");
477
+ var import_react_dom2 = require("react-dom");
478
+ var import_ui_utils8 = require("@ug666/ui-utils");
479
+ var import_jsx_runtime8 = require("react/jsx-runtime");
480
+ var CONFIRM_VARIANT_CLASSES = {
481
+ default: "bg-primary text-primary-fg hover:bg-primary-hover focus-visible:ring-ring",
482
+ destructive: "bg-danger text-danger-fg hover:bg-danger-hover focus-visible:ring-danger"
483
+ };
484
+ var Dialog = (0, import_react9.forwardRef)(
485
+ ({
486
+ open,
487
+ onOpenChange,
488
+ title,
489
+ description,
490
+ variant = "default",
491
+ cancelText = "\u53D6\u6D88",
492
+ confirmText = "\u786E\u8BA4",
493
+ onConfirm,
494
+ onCancel,
495
+ className
496
+ }, ref) => {
497
+ const handleClose = (0, import_react9.useCallback)(() => {
498
+ onOpenChange(false);
499
+ }, [onOpenChange]);
500
+ const handleCancel = (0, import_react9.useCallback)(() => {
501
+ onCancel?.();
502
+ handleClose();
503
+ }, [onCancel, handleClose]);
504
+ const handleConfirm = (0, import_react9.useCallback)(() => {
505
+ onConfirm?.();
506
+ handleClose();
507
+ }, [onConfirm, handleClose]);
508
+ const handleEscape = (0, import_react9.useCallback)(
509
+ (e) => {
510
+ if (e.key === "Escape") handleCancel();
511
+ },
512
+ [handleCancel]
513
+ );
514
+ (0, import_react9.useEffect)(() => {
515
+ if (!open) return;
516
+ document.addEventListener("keydown", handleEscape);
517
+ document.body.style.overflow = "hidden";
518
+ return () => {
519
+ document.removeEventListener("keydown", handleEscape);
520
+ document.body.style.overflow = "";
521
+ };
522
+ }, [open, handleEscape]);
523
+ if (!open) return null;
524
+ return (0, import_react_dom2.createPortal)(
525
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
526
+ "div",
527
+ {
528
+ ref,
529
+ className: (0, import_ui_utils8.cn)(
530
+ "fixed inset-0 z-50 flex items-center justify-center p-4",
531
+ className
532
+ ),
533
+ role: "alertdialog",
534
+ "aria-modal": "true",
535
+ "aria-labelledby": "dialog-title",
536
+ "aria-describedby": description ? "dialog-description" : void 0,
537
+ children: [
538
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
539
+ "div",
540
+ {
541
+ className: "absolute inset-0 bg-overlay",
542
+ onClick: handleCancel,
543
+ "aria-hidden": "true"
544
+ }
545
+ ),
546
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative z-10 w-full max-w-sm rounded-lg bg-surface-1 shadow-lg", children: [
547
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "px-6 pt-6 pb-4", children: [
548
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
549
+ "h2",
550
+ {
551
+ id: "dialog-title",
552
+ className: "text-base font-bold text-text-primary",
553
+ children: title
554
+ }
555
+ ),
556
+ description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
557
+ "p",
558
+ {
559
+ id: "dialog-description",
560
+ className: "mt-2 text-sm text-text-secondary",
561
+ children: description
562
+ }
563
+ )
564
+ ] }),
565
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-end gap-2 border-t border-border-subtle px-6 py-4", children: [
566
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
567
+ "button",
568
+ {
569
+ type: "button",
570
+ onClick: handleCancel,
571
+ className: (0, import_ui_utils8.cn)(
572
+ "inline-flex h-9 items-center justify-center rounded-md border border-border-strong bg-surface-1 px-4 text-sm font-medium text-text-secondary transition-colors",
573
+ "hover:bg-surface-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-ring/30"
574
+ ),
575
+ children: cancelText
576
+ }
577
+ ),
578
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
579
+ "button",
580
+ {
581
+ type: "button",
582
+ onClick: handleConfirm,
583
+ className: (0, import_ui_utils8.cn)(
584
+ "inline-flex h-9 items-center justify-center rounded-md px-4 text-sm font-medium transition-colors",
585
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
586
+ CONFIRM_VARIANT_CLASSES[variant]
587
+ ),
588
+ children: confirmText
589
+ }
590
+ )
591
+ ] })
592
+ ] })
593
+ ]
594
+ }
595
+ ),
596
+ document.body
597
+ );
598
+ }
599
+ );
600
+ Dialog.displayName = "Dialog";
601
+
602
+ // src/components/drawer.tsx
603
+ var import_react10 = require("react");
604
+ var import_react_dom3 = require("react-dom");
605
+ var import_lucide_react4 = require("lucide-react");
606
+ var import_ui_utils9 = require("@ug666/ui-utils");
607
+ var import_jsx_runtime9 = require("react/jsx-runtime");
608
+ var DrawerContext = (0, import_react10.createContext)(null);
609
+ function useDrawerContext() {
610
+ const ctx = (0, import_react10.useContext)(DrawerContext);
611
+ if (!ctx) throw new Error("Drawer \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Drawer> \u5185\u4F7F\u7528");
612
+ return ctx;
613
+ }
614
+ var SIDE_CLASSES = {
615
+ right: "inset-y-0 right-0 h-full w-80 max-w-full translate-x-0",
616
+ left: "inset-y-0 left-0 h-full w-80 max-w-full translate-x-0",
617
+ top: "inset-x-0 top-0 w-full h-auto max-h-[80vh] translate-y-0",
618
+ bottom: "inset-x-0 bottom-0 w-full h-auto max-h-[80vh] translate-y-0"
619
+ };
620
+ var Drawer = ({ open, onOpenChange, side = "right", children }) => {
621
+ useEscapeKey(open, () => onOpenChange(false));
622
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DrawerContext.Provider, { value: { open, onOpenChange, side }, children });
623
+ };
624
+ Drawer.displayName = "Drawer";
625
+ var DrawerContent = (0, import_react10.forwardRef)(({ className, children, ...props }, ref) => {
626
+ const { open, onOpenChange, side } = useDrawerContext();
627
+ if (!open) return null;
628
+ return (0, import_react_dom3.createPortal)(
629
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "fixed inset-0 z-50", role: "dialog", "aria-modal": "true", children: [
630
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
631
+ "div",
632
+ {
633
+ className: "absolute inset-0 bg-overlay transition-opacity",
634
+ onClick: () => onOpenChange(false),
635
+ "aria-hidden": "true"
636
+ }
637
+ ),
638
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
639
+ "div",
640
+ {
641
+ ref,
642
+ className: (0, import_ui_utils9.cn)(
643
+ "absolute flex flex-col bg-surface-1 shadow-xl transition-transform duration-300 ease-in-out",
644
+ SIDE_CLASSES[side],
645
+ className
646
+ ),
647
+ onClick: (e) => e.stopPropagation(),
648
+ ...props,
649
+ children
650
+ }
651
+ )
652
+ ] }),
653
+ document.body
654
+ );
655
+ });
656
+ DrawerContent.displayName = "DrawerContent";
657
+ var DrawerHeader = (0, import_react10.forwardRef)(({ className, ...props }, ref) => {
658
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
659
+ "div",
660
+ {
661
+ ref,
662
+ className: (0, import_ui_utils9.cn)("flex flex-col gap-1.5 border-b border-border-base px-6 py-4", className),
663
+ ...props
664
+ }
665
+ );
666
+ });
667
+ DrawerHeader.displayName = "DrawerHeader";
668
+ var DrawerTitle = (0, import_react10.forwardRef)(({ className, ...props }, ref) => {
669
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { ref, className: (0, import_ui_utils9.cn)("text-lg font-semibold text-text-primary", className), ...props });
670
+ });
671
+ DrawerTitle.displayName = "DrawerTitle";
672
+ var DrawerDescription = (0, import_react10.forwardRef)(({ className, ...props }, ref) => {
673
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { ref, className: (0, import_ui_utils9.cn)("text-sm text-text-secondary", className), ...props });
674
+ });
675
+ DrawerDescription.displayName = "DrawerDescription";
676
+ var DrawerFooter = (0, import_react10.forwardRef)(({ className, ...props }, ref) => {
677
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
678
+ "div",
679
+ {
680
+ ref,
681
+ className: (0, import_ui_utils9.cn)("mt-auto flex items-center justify-end gap-2 border-t border-border-base px-6 py-4", className),
682
+ ...props
683
+ }
684
+ );
685
+ });
686
+ DrawerFooter.displayName = "DrawerFooter";
687
+ var DrawerClose = (0, import_react10.forwardRef)(({ className, children, type = "button", ...props }, ref) => {
688
+ const { onOpenChange } = useDrawerContext();
689
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
690
+ "button",
691
+ {
692
+ ref,
693
+ type,
694
+ onClick: () => onOpenChange(false),
695
+ className: (0, import_ui_utils9.cn)(
696
+ "inline-flex items-center justify-center rounded-md px-4 py-2 text-sm font-medium text-text-secondary transition-colors hover:bg-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30",
697
+ className
698
+ ),
699
+ ...props,
700
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react4.X, { size: 18 })
701
+ }
702
+ );
703
+ });
704
+ DrawerClose.displayName = "DrawerClose";
705
+
706
+ // src/components/table.tsx
707
+ var import_react11 = require("react");
708
+ var import_ui_utils10 = require("@ug666/ui-utils");
709
+ var import_jsx_runtime10 = require("react/jsx-runtime");
710
+ var Table = (0, import_react11.forwardRef)(({ className, ...props }, ref) => {
711
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
712
+ "table",
713
+ {
714
+ ref,
715
+ className: (0, import_ui_utils10.cn)("w-full caption-bottom text-sm", className),
716
+ ...props
717
+ }
718
+ ) });
719
+ });
720
+ var TableHeader = (0, import_react11.forwardRef)(({ className, ...props }, ref) => {
721
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { ref, className: (0, import_ui_utils10.cn)("[&_tr]:border-b border-border-base", className), ...props });
722
+ });
723
+ var TableBody = (0, import_react11.forwardRef)(({ className, ...props }, ref) => {
724
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { ref, className: (0, import_ui_utils10.cn)("[&_tr:last-child]:border-0", className), ...props });
725
+ });
726
+ var TableRow = (0, import_react11.forwardRef)(({ className, ...props }, ref) => {
727
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { ref, className: (0, import_ui_utils10.cn)("border-b border-border-base transition-colors hover:bg-surface-2", className), ...props });
728
+ });
729
+ var TableHead = (0, import_react11.forwardRef)(({ className, ...props }, ref) => {
730
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { ref, className: (0, import_ui_utils10.cn)("h-10 px-4 text-left align-middle font-medium text-text-secondary [&:has([role=checkbox])]:pr-0", className), ...props });
731
+ });
732
+ var TableCell = (0, import_react11.forwardRef)(({ className, ...props }, ref) => {
733
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { ref, className: (0, import_ui_utils10.cn)("px-4 py-3 align-middle text-text-primary [&:has([role=checkbox])]:pr-0", className), ...props });
734
+ });
735
+ Table.displayName = "Table";
736
+ TableHeader.displayName = "TableHeader";
737
+ TableBody.displayName = "TableBody";
738
+ TableRow.displayName = "TableRow";
739
+ TableHead.displayName = "TableHead";
740
+ TableCell.displayName = "TableCell";
741
+
742
+ // src/components/toast.tsx
743
+ var import_react12 = require("react");
744
+ var import_react_dom4 = require("react-dom");
745
+ var import_lucide_react5 = require("lucide-react");
746
+ var import_ui_utils11 = require("@ug666/ui-utils");
747
+ var import_jsx_runtime11 = require("react/jsx-runtime");
748
+ var listeners = /* @__PURE__ */ new Set();
749
+ var toastItems = [];
750
+ var toastTimers = /* @__PURE__ */ new Map();
751
+ function notify() {
752
+ listeners.forEach((fn) => fn([...toastItems]));
753
+ }
754
+ function addToast(message, type) {
755
+ const id = Math.random().toString(36).slice(2);
756
+ toastItems = [...toastItems, { id, message, type }];
757
+ notify();
758
+ const timer = setTimeout(() => removeToast(id), 3e3);
759
+ toastTimers.set(id, timer);
760
+ }
761
+ function removeToast(id) {
762
+ const timer = toastTimers.get(id);
763
+ if (timer) {
764
+ clearTimeout(timer);
765
+ toastTimers.delete(id);
766
+ }
767
+ toastItems = toastItems.filter((t) => t.id !== id);
768
+ notify();
769
+ }
770
+ var toast = {
771
+ success: (message) => addToast(message, "success"),
772
+ error: (message) => addToast(message, "error"),
773
+ info: (message) => addToast(message, "info")
774
+ };
775
+ var typeStyles = {
776
+ success: "bg-success-soft border-success/30 text-success-soft-fg",
777
+ error: "bg-danger-soft border-danger/30 text-danger-soft-fg",
778
+ info: "bg-info-soft border-info/30 text-info-soft-fg"
779
+ };
780
+ var typeLabel = {
781
+ success: "\u6210\u529F",
782
+ error: "\u9519\u8BEF",
783
+ info: "\u63D0\u793A"
784
+ };
785
+ var Toaster = (0, import_react12.forwardRef)(({ className, ...props }, ref) => {
786
+ const [items, setItems] = (0, import_react12.useState)([]);
787
+ const mountedRef = (0, import_react12.useRef)(true);
788
+ const handleUpdate = (0, import_react12.useCallback)((next) => {
789
+ if (mountedRef.current) {
790
+ setItems(next);
791
+ }
792
+ }, []);
793
+ (0, import_react12.useEffect)(() => {
794
+ listeners.add(handleUpdate);
795
+ return () => {
796
+ mountedRef.current = false;
797
+ listeners.delete(handleUpdate);
798
+ };
799
+ }, [handleUpdate]);
800
+ if (items.length === 0) return null;
801
+ return (0, import_react_dom4.createPortal)(
802
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
803
+ "div",
804
+ {
805
+ ref,
806
+ className: (0, import_ui_utils11.cn)("fixed top-4 right-4 z-[9999] flex w-80 flex-col gap-2", className),
807
+ role: "region",
808
+ "aria-label": "\u901A\u77E5",
809
+ ...props,
810
+ children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
811
+ "div",
812
+ {
813
+ className: (0, import_ui_utils11.cn)(
814
+ "flex items-start justify-between gap-2 rounded-md border px-4 py-3 text-sm shadow-md",
815
+ typeStyles[item.type]
816
+ ),
817
+ role: "alert",
818
+ children: [
819
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
820
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-semibold", children: [
821
+ typeLabel[item.type],
822
+ "\uFF1A"
823
+ ] }),
824
+ item.message
825
+ ] }),
826
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
827
+ "button",
828
+ {
829
+ type: "button",
830
+ onClick: () => removeToast(item.id),
831
+ className: "mt-0.5 shrink-0 opacity-60 hover:opacity-100 transition-opacity",
832
+ "aria-label": "\u5173\u95ED\u901A\u77E5",
833
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.X, { size: 14 })
834
+ }
835
+ )
836
+ ]
837
+ },
838
+ item.id
839
+ ))
840
+ }
841
+ ),
842
+ document.body
843
+ );
844
+ });
845
+ Toaster.displayName = "Toaster";
846
+
847
+ // src/components/sidebar.tsx
848
+ var import_react13 = require("react");
849
+ var import_ui_utils12 = require("@ug666/ui-utils");
850
+ var import_jsx_runtime12 = require("react/jsx-runtime");
851
+ var variantStyles = {
852
+ primary: {
853
+ container: "bg-primary text-primary-fg",
854
+ active: "bg-primary-active text-primary-fg",
855
+ inactive: "text-primary-fg/70 hover:bg-primary-hover hover:text-primary-fg",
856
+ divider: "border-primary-active"
857
+ },
858
+ dark: {
859
+ container: "bg-slate-950 text-slate-100",
860
+ active: "bg-slate-800/80 text-white before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:h-5 before:w-[3px] before:rounded-r-full before:bg-primary",
861
+ inactive: "text-slate-400 hover:bg-slate-800/40 hover:text-slate-100",
862
+ divider: "border-slate-800/80"
863
+ }
864
+ };
865
+ var Sidebar = (0, import_react13.forwardRef)(
866
+ ({ items, variant = "primary", collapsed = false, footer, className }, ref) => {
867
+ const styles = variantStyles[variant];
868
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
869
+ "aside",
870
+ {
871
+ ref,
872
+ className: (0, import_ui_utils12.cn)(
873
+ "flex flex-col transition-all duration-300",
874
+ styles.container,
875
+ collapsed ? "w-16" : "w-60",
876
+ className
877
+ ),
878
+ children: [
879
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("nav", { className: "flex-1 overflow-y-auto py-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className: "flex flex-col gap-1 px-2", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
880
+ "a",
881
+ {
882
+ href: item.href,
883
+ className: (0, import_ui_utils12.cn)(
884
+ "relative flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors duration-150",
885
+ item.active ? styles.active : styles.inactive
886
+ ),
887
+ title: collapsed ? item.label : void 0,
888
+ children: [
889
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(item.icon, { size: 17, className: "shrink-0" }),
890
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "truncate", children: item.label })
891
+ ]
892
+ }
893
+ ) }, item.href)) }) }),
894
+ footer && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
895
+ "div",
896
+ {
897
+ className: (0, import_ui_utils12.cn)(
898
+ "border-t px-2 py-4",
899
+ styles.divider,
900
+ collapsed && "flex justify-center"
901
+ ),
902
+ children: footer
903
+ }
904
+ )
905
+ ]
906
+ }
907
+ );
908
+ }
909
+ );
910
+ Sidebar.displayName = "Sidebar";
911
+
912
+ // src/components/pagination.tsx
913
+ var import_react14 = require("react");
914
+ var import_lucide_react6 = require("lucide-react");
915
+ var import_ui_utils13 = require("@ug666/ui-utils");
916
+ var import_jsx_runtime13 = require("react/jsx-runtime");
917
+ var MAX_VISIBLE_PAGES = 5;
918
+ function getPageNumbers(page, totalPages) {
919
+ if (totalPages <= MAX_VISIBLE_PAGES) {
920
+ return Array.from({ length: totalPages }, (_, i) => i + 1);
921
+ }
922
+ const half = Math.floor(MAX_VISIBLE_PAGES / 2);
923
+ let start = Math.max(1, page - half);
924
+ const end = Math.min(totalPages, start + MAX_VISIBLE_PAGES - 1);
925
+ if (end - start < MAX_VISIBLE_PAGES - 1) {
926
+ start = Math.max(1, end - MAX_VISIBLE_PAGES + 1);
927
+ }
928
+ const pages = [];
929
+ if (start > 1) {
930
+ pages.push(1);
931
+ if (start > 2) pages.push("...");
932
+ }
933
+ for (let i = start; i <= end; i++) pages.push(i);
934
+ if (end < totalPages) {
935
+ if (end < totalPages - 1) pages.push("...");
936
+ pages.push(totalPages);
937
+ }
938
+ return pages;
939
+ }
940
+ var Pagination = (0, import_react14.forwardRef)(({ page, totalPages, onPageChange, className }, ref) => {
941
+ const pageNumbers = getPageNumbers(page, totalPages);
942
+ const btnBase = "inline-flex h-8 min-w-8 items-center justify-center rounded-md px-2 text-sm transition-colors disabled:pointer-events-none disabled:opacity-40";
943
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ref, className: (0, import_ui_utils13.cn)("flex items-center gap-1", className), children: [
944
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
945
+ "button",
946
+ {
947
+ type: "button",
948
+ className: (0, import_ui_utils13.cn)(btnBase, "border border-border-strong bg-surface-1 text-text-primary hover:bg-surface-3"),
949
+ disabled: page <= 1,
950
+ onClick: () => onPageChange(page - 1),
951
+ "aria-label": "\u4E0A\u4E00\u9875",
952
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.ChevronLeft, { size: 16 })
953
+ }
954
+ ),
955
+ pageNumbers.map(
956
+ (p, idx) => p === "..." ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "px-1 text-text-tertiary select-none", children: "\u2026" }, `ellipsis-${idx}`) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
957
+ "button",
958
+ {
959
+ type: "button",
960
+ className: (0, import_ui_utils13.cn)(
961
+ btnBase,
962
+ p === page ? "bg-primary text-primary-fg" : "border border-border-strong bg-surface-1 text-text-primary hover:bg-surface-3"
963
+ ),
964
+ onClick: () => onPageChange(p),
965
+ "aria-current": p === page ? "page" : void 0,
966
+ children: p
967
+ },
968
+ p
969
+ )
970
+ ),
971
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
972
+ "button",
973
+ {
974
+ type: "button",
975
+ className: (0, import_ui_utils13.cn)(btnBase, "border border-border-strong bg-surface-1 text-text-primary hover:bg-surface-3"),
976
+ disabled: page >= totalPages,
977
+ onClick: () => onPageChange(page + 1),
978
+ "aria-label": "\u4E0B\u4E00\u9875",
979
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.ChevronRight, { size: 16 })
980
+ }
981
+ )
982
+ ] });
983
+ });
984
+ Pagination.displayName = "Pagination";
985
+
986
+ // src/components/select.tsx
987
+ var import_react15 = require("react");
988
+ var import_ui_utils14 = require("@ug666/ui-utils");
989
+ var import_jsx_runtime14 = require("react/jsx-runtime");
990
+ var Select = (0, import_react15.forwardRef)(
991
+ ({ className, label, error, helperText, options, placeholder, id, ...props }, ref) => {
992
+ const generatedId = (0, import_react15.useId)();
993
+ const selectId = id ?? generatedId;
994
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-1", children: [
995
+ label && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { htmlFor: selectId, className: "text-sm font-medium text-text-primary", children: label }),
996
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
997
+ "select",
998
+ {
999
+ ref,
1000
+ id: selectId,
1001
+ className: (0, import_ui_utils14.cn)(
1002
+ "flex h-9 w-full rounded-md border bg-surface-1 px-3 py-1.5 text-sm text-text-primary",
1003
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1",
1004
+ "disabled:cursor-not-allowed disabled:opacity-50",
1005
+ error ? "border-red-400 focus-visible:ring-red-400" : "border-border-strong focus-visible:ring-ring/30",
1006
+ className
1007
+ ),
1008
+ ...props,
1009
+ children: [
1010
+ placeholder && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: "", disabled: true, children: placeholder }),
1011
+ options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
1012
+ ]
1013
+ }
1014
+ ),
1015
+ error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-xs text-danger", children: error }),
1016
+ !error && helperText && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-xs text-text-secondary", children: helperText })
1017
+ ] });
1018
+ }
1019
+ );
1020
+ Select.displayName = "Select";
1021
+
1022
+ // src/components/spinner.tsx
1023
+ var import_react16 = require("react");
1024
+ var import_lucide_react7 = require("lucide-react");
1025
+ var import_class_variance_authority4 = require("class-variance-authority");
1026
+ var import_ui_utils15 = require("@ug666/ui-utils");
1027
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1028
+ var spinnerVariants = (0, import_class_variance_authority4.cva)("animate-spin text-text-tertiary", {
1029
+ variants: {
1030
+ size: {
1031
+ sm: "h-4 w-4",
1032
+ md: "h-6 w-6",
1033
+ lg: "h-10 w-10"
1034
+ }
1035
+ },
1036
+ defaultVariants: {
1037
+ size: "md"
1038
+ }
1039
+ });
1040
+ var Spinner = (0, import_react16.forwardRef)(({ className, size, label = "\u52A0\u8F7D\u4E2D", ...props }, ref) => {
1041
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1042
+ import_lucide_react7.Loader2,
1043
+ {
1044
+ ref,
1045
+ className: (0, import_ui_utils15.cn)(spinnerVariants({ size }), className),
1046
+ "aria-label": label,
1047
+ role: "status",
1048
+ ...props
1049
+ }
1050
+ );
1051
+ });
1052
+ Spinner.displayName = "Spinner";
1053
+
1054
+ // src/components/checkbox.tsx
1055
+ var import_react17 = require("react");
1056
+ var import_lucide_react8 = require("lucide-react");
1057
+ var import_class_variance_authority5 = require("class-variance-authority");
1058
+ var import_ui_utils16 = require("@ug666/ui-utils");
1059
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1060
+ var checkboxVariants = (0, import_class_variance_authority5.cva)(
1061
+ "peer inline-flex shrink-0 items-center justify-center rounded border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1062
+ {
1063
+ variants: {
1064
+ size: {
1065
+ sm: "h-3.5 w-3.5",
1066
+ default: "h-4 w-4",
1067
+ lg: "h-5 w-5"
1068
+ },
1069
+ state: {
1070
+ unchecked: "border-border-strong bg-surface-1 hover:border-border-strong",
1071
+ checked: "border-primary bg-primary text-primary-fg focus-visible:ring-ring",
1072
+ indeterminate: "border-primary bg-primary text-primary-fg focus-visible:ring-ring"
1073
+ }
1074
+ },
1075
+ defaultVariants: {
1076
+ size: "default",
1077
+ state: "unchecked"
1078
+ }
1079
+ }
1080
+ );
1081
+ var Checkbox = (0, import_react17.forwardRef)(
1082
+ ({
1083
+ className,
1084
+ size,
1085
+ checked,
1086
+ indeterminate = false,
1087
+ disabled,
1088
+ label,
1089
+ labelClassName,
1090
+ onCheckedChange,
1091
+ id,
1092
+ ...props
1093
+ }, ref) => {
1094
+ const innerRef = (0, import_react17.useRef)(null);
1095
+ (0, import_react17.useEffect)(() => {
1096
+ if (innerRef.current) {
1097
+ innerRef.current.indeterminate = indeterminate;
1098
+ }
1099
+ }, [indeterminate]);
1100
+ const state = indeterminate ? "indeterminate" : checked ? "checked" : "unchecked";
1101
+ const iconSize = size === "sm" ? 10 : size === "lg" ? 14 : 12;
1102
+ const control = /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "relative inline-flex", children: [
1103
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1104
+ "input",
1105
+ {
1106
+ ref: (node) => {
1107
+ innerRef.current = node;
1108
+ if (typeof ref === "function") ref(node);
1109
+ else if (ref) ref.current = node;
1110
+ },
1111
+ id,
1112
+ type: "checkbox",
1113
+ className: "peer sr-only",
1114
+ checked: checked ?? false,
1115
+ disabled,
1116
+ onChange: (e) => onCheckedChange?.(e.target.checked),
1117
+ ...props
1118
+ }
1119
+ ),
1120
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1121
+ "span",
1122
+ {
1123
+ "aria-hidden": "true",
1124
+ className: (0, import_ui_utils16.cn)(checkboxVariants({ size, state }), className),
1125
+ children: indeterminate ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react8.Minus, { size: iconSize }) : checked ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react8.Check, { size: iconSize }) : null
1126
+ }
1127
+ )
1128
+ ] });
1129
+ if (label === void 0 || label === null) return control;
1130
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1131
+ "label",
1132
+ {
1133
+ htmlFor: id,
1134
+ className: (0, import_ui_utils16.cn)(
1135
+ "inline-flex cursor-pointer items-center gap-2 text-sm text-text-primary select-none",
1136
+ disabled && "cursor-not-allowed opacity-60",
1137
+ labelClassName
1138
+ ),
1139
+ children: [
1140
+ control,
1141
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: label })
1142
+ ]
1143
+ }
1144
+ );
1145
+ }
1146
+ );
1147
+ Checkbox.displayName = "Checkbox";
1148
+
1149
+ // src/components/radio.tsx
1150
+ var import_react18 = require("react");
1151
+ var import_class_variance_authority6 = require("class-variance-authority");
1152
+ var import_ui_utils17 = require("@ug666/ui-utils");
1153
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1154
+ var RadioGroupContext = (0, import_react18.createContext)(null);
1155
+ function useRadioGroupContext() {
1156
+ return (0, import_react18.useContext)(RadioGroupContext);
1157
+ }
1158
+ var radioVariants = (0, import_class_variance_authority6.cva)(
1159
+ "relative inline-flex shrink-0 items-center justify-center rounded-full border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1160
+ {
1161
+ variants: {
1162
+ size: {
1163
+ sm: "h-3.5 w-3.5",
1164
+ default: "h-4 w-4",
1165
+ lg: "h-5 w-5"
1166
+ },
1167
+ checked: {
1168
+ true: "border-primary bg-primary focus-visible:ring-ring",
1169
+ false: "border-border-strong bg-surface-1 hover:border-border-strong"
1170
+ }
1171
+ },
1172
+ defaultVariants: {
1173
+ size: "default",
1174
+ checked: false
1175
+ }
1176
+ }
1177
+ );
1178
+ var Radio = (0, import_react18.forwardRef)(
1179
+ ({
1180
+ className,
1181
+ size,
1182
+ value,
1183
+ checked: checkedProp,
1184
+ disabled: disabledProp,
1185
+ label,
1186
+ name: nameProp,
1187
+ onChange,
1188
+ id,
1189
+ ...props
1190
+ }, ref) => {
1191
+ const group = useRadioGroupContext();
1192
+ const generatedId = (0, import_react18.useId)();
1193
+ const inputId = id ?? generatedId;
1194
+ const isChecked = group ? group.value === value : checkedProp ?? false;
1195
+ const isDisabled = group ? group.disabled || (disabledProp ?? false) : disabledProp ?? false;
1196
+ const inputName = group ? group.name : nameProp;
1197
+ function handleChange() {
1198
+ if (group) {
1199
+ group.onValueChange(value);
1200
+ } else {
1201
+ onChange?.(value);
1202
+ }
1203
+ }
1204
+ const dotSize = size === "sm" ? "h-1.5 w-1.5" : size === "lg" ? "h-2.5 w-2.5" : "h-2 w-2";
1205
+ const control = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "relative inline-flex", children: [
1206
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1207
+ "input",
1208
+ {
1209
+ ref,
1210
+ id: inputId,
1211
+ type: "radio",
1212
+ className: "peer sr-only",
1213
+ value,
1214
+ checked: isChecked,
1215
+ disabled: isDisabled,
1216
+ name: inputName,
1217
+ onChange: handleChange,
1218
+ ...props
1219
+ }
1220
+ ),
1221
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1222
+ "span",
1223
+ {
1224
+ "aria-hidden": "true",
1225
+ className: (0, import_ui_utils17.cn)(radioVariants({ size, checked: isChecked }), className),
1226
+ children: isChecked && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: (0, import_ui_utils17.cn)("rounded-full bg-white", dotSize) })
1227
+ }
1228
+ )
1229
+ ] });
1230
+ if (label === void 0 || label === null) return control;
1231
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1232
+ "label",
1233
+ {
1234
+ htmlFor: inputId,
1235
+ className: (0, import_ui_utils17.cn)(
1236
+ "inline-flex cursor-pointer items-center gap-2 text-sm text-text-primary select-none",
1237
+ isDisabled && "cursor-not-allowed opacity-60"
1238
+ ),
1239
+ children: [
1240
+ control,
1241
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: label })
1242
+ ]
1243
+ }
1244
+ );
1245
+ }
1246
+ );
1247
+ Radio.displayName = "Radio";
1248
+ var RadioGroup = (0, import_react18.forwardRef)(
1249
+ ({
1250
+ className,
1251
+ value: valueProp,
1252
+ defaultValue,
1253
+ onValueChange,
1254
+ disabled = false,
1255
+ name,
1256
+ orientation = "vertical",
1257
+ children,
1258
+ ...props
1259
+ }, ref) => {
1260
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react18.useState)(defaultValue);
1261
+ const isControlled = valueProp !== void 0;
1262
+ const currentValue = isControlled ? valueProp : uncontrolledValue;
1263
+ function handleValueChange(newValue) {
1264
+ if (!isControlled) {
1265
+ setUncontrolledValue(newValue);
1266
+ }
1267
+ onValueChange?.(newValue);
1268
+ }
1269
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1270
+ RadioGroupContext.Provider,
1271
+ {
1272
+ value: {
1273
+ value: currentValue,
1274
+ onValueChange: handleValueChange,
1275
+ name,
1276
+ disabled
1277
+ },
1278
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1279
+ "div",
1280
+ {
1281
+ ref,
1282
+ role: "radiogroup",
1283
+ className: (0, import_ui_utils17.cn)(
1284
+ "flex",
1285
+ orientation === "vertical" ? "flex-col gap-2" : "flex-row flex-wrap gap-4",
1286
+ className
1287
+ ),
1288
+ ...props,
1289
+ children
1290
+ }
1291
+ )
1292
+ }
1293
+ );
1294
+ }
1295
+ );
1296
+ RadioGroup.displayName = "RadioGroup";
1297
+
1298
+ // src/components/slider.tsx
1299
+ var import_react19 = require("react");
1300
+ var import_ui_utils18 = require("@ug666/ui-utils");
1301
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1302
+ var Slider = (0, import_react19.forwardRef)(
1303
+ ({
1304
+ className,
1305
+ value: valueProp,
1306
+ defaultValue = 0,
1307
+ min = 0,
1308
+ max = 100,
1309
+ step = 1,
1310
+ disabled = false,
1311
+ showValue = false,
1312
+ onValueChange,
1313
+ ...props
1314
+ }, ref) => {
1315
+ const isControlled = valueProp !== void 0;
1316
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react19.useState)(defaultValue);
1317
+ const currentValue = isControlled ? valueProp : uncontrolledValue;
1318
+ const fillPercent = max === min ? 0 : (currentValue - min) / (max - min) * 100;
1319
+ function handleChange(e) {
1320
+ const newValue = Number(e.target.value);
1321
+ if (!isControlled) {
1322
+ setUncontrolledValue(newValue);
1323
+ }
1324
+ onValueChange?.(newValue);
1325
+ }
1326
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: (0, import_ui_utils18.cn)("flex flex-col gap-1", className), children: [
1327
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "self-start text-xs font-medium text-text-primary", children: currentValue }),
1328
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "relative flex h-5 w-full items-center", children: [
1329
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "pointer-events-none absolute h-1.5 w-full overflow-hidden rounded-full bg-surface-3", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1330
+ "div",
1331
+ {
1332
+ className: "h-full rounded-full bg-primary transition-all",
1333
+ style: { width: `${fillPercent}%` }
1334
+ }
1335
+ ) }),
1336
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1337
+ "input",
1338
+ {
1339
+ ref,
1340
+ type: "range",
1341
+ min,
1342
+ max,
1343
+ step,
1344
+ value: currentValue,
1345
+ disabled,
1346
+ onChange: handleChange,
1347
+ className: (0, import_ui_utils18.cn)(
1348
+ "relative h-5 w-full cursor-pointer appearance-none bg-transparent",
1349
+ // thumb 样式
1350
+ "[&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-border-strong [&::-webkit-slider-thumb]:bg-surface-1 [&::-webkit-slider-thumb]:shadow-sm [&::-webkit-slider-thumb]:transition-transform [&::-webkit-slider-thumb]:hover:scale-110",
1351
+ "[&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-border-strong [&::-moz-range-thumb]:bg-surface-1 [&::-moz-range-thumb]:shadow-sm",
1352
+ // track 透明(用自定义 div 代替)
1353
+ "[&::-webkit-slider-runnable-track]:bg-transparent",
1354
+ "[&::-moz-range-track]:bg-transparent",
1355
+ // focus
1356
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
1357
+ // disabled
1358
+ "disabled:cursor-not-allowed disabled:opacity-50"
1359
+ ),
1360
+ ...props
1361
+ }
1362
+ )
1363
+ ] })
1364
+ ] });
1365
+ }
1366
+ );
1367
+ Slider.displayName = "Slider";
1368
+
1369
+ // src/components/number-input.tsx
1370
+ var import_react20 = require("react");
1371
+ var import_lucide_react9 = require("lucide-react");
1372
+ var import_class_variance_authority7 = require("class-variance-authority");
1373
+ var import_ui_utils19 = require("@ug666/ui-utils");
1374
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1375
+ var numberInputVariants = (0, import_class_variance_authority7.cva)(
1376
+ "inline-flex items-center rounded-md border border-border-strong bg-surface-1 transition-colors focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-1 has-[:disabled]:pointer-events-none has-[:disabled]:opacity-50",
1377
+ {
1378
+ variants: {
1379
+ size: {
1380
+ sm: "h-8 text-xs",
1381
+ default: "h-9 text-sm",
1382
+ lg: "h-11 text-base"
1383
+ }
1384
+ },
1385
+ defaultVariants: {
1386
+ size: "default"
1387
+ }
1388
+ }
1389
+ );
1390
+ var NumberInput = (0, import_react20.forwardRef)(
1391
+ ({
1392
+ className,
1393
+ size,
1394
+ value: valueProp,
1395
+ defaultValue = 0,
1396
+ min,
1397
+ max,
1398
+ step = 1,
1399
+ precision = 0,
1400
+ disabled = false,
1401
+ placeholder,
1402
+ onValueChange,
1403
+ ...props
1404
+ }, ref) => {
1405
+ const isControlled = valueProp !== void 0;
1406
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react20.useState)(defaultValue);
1407
+ const currentValue = isControlled ? valueProp : uncontrolledValue;
1408
+ function clamp(val) {
1409
+ let result = val;
1410
+ if (min !== void 0) result = Math.max(min, result);
1411
+ if (max !== void 0) result = Math.min(max, result);
1412
+ return result;
1413
+ }
1414
+ function format(val) {
1415
+ return val.toFixed(precision);
1416
+ }
1417
+ function commit(newVal) {
1418
+ const clamped = clamp(Number(newVal.toFixed(precision)));
1419
+ if (!isControlled) {
1420
+ setUncontrolledValue(clamped);
1421
+ }
1422
+ onValueChange?.(clamped);
1423
+ }
1424
+ function handleDecrement() {
1425
+ commit(currentValue - step);
1426
+ }
1427
+ function handleIncrement() {
1428
+ commit(currentValue + step);
1429
+ }
1430
+ function handleInputChange(e) {
1431
+ const parsed = parseFloat(e.target.value);
1432
+ if (!Number.isNaN(parsed)) {
1433
+ commit(parsed);
1434
+ }
1435
+ }
1436
+ function handleBlur(e) {
1437
+ const parsed = parseFloat(e.target.value);
1438
+ if (!Number.isNaN(parsed)) {
1439
+ commit(parsed);
1440
+ } else {
1441
+ if (!isControlled) {
1442
+ setUncontrolledValue(uncontrolledValue);
1443
+ }
1444
+ }
1445
+ }
1446
+ const atMin = min !== void 0 && currentValue <= min;
1447
+ const atMax = max !== void 0 && currentValue >= max;
1448
+ const btnBase = "inline-flex shrink-0 items-center justify-center text-text-secondary transition-colors hover:bg-surface-3 hover:text-text-primary disabled:pointer-events-none disabled:opacity-40";
1449
+ const btnSizeCls = size === "sm" ? "h-8 w-7" : size === "lg" ? "h-11 w-9" : "h-9 w-8";
1450
+ const iconSize = size === "sm" ? 12 : size === "lg" ? 16 : 14;
1451
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: (0, import_ui_utils19.cn)(numberInputVariants({ size }), className), children: [
1452
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1453
+ "button",
1454
+ {
1455
+ type: "button",
1456
+ "aria-label": "\u51CF\u5C11\u6570\u503C",
1457
+ disabled: disabled || atMin,
1458
+ onClick: handleDecrement,
1459
+ className: (0, import_ui_utils19.cn)(btnBase, btnSizeCls, "rounded-l-md border-r border-border-base"),
1460
+ tabIndex: -1,
1461
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Minus, { size: iconSize })
1462
+ }
1463
+ ),
1464
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1465
+ "input",
1466
+ {
1467
+ ref,
1468
+ type: "number",
1469
+ className: (0, import_ui_utils19.cn)(
1470
+ "min-w-0 flex-1 bg-transparent text-center text-text-primary outline-none",
1471
+ "placeholder:text-text-tertiary",
1472
+ // 隐藏原生 spinner
1473
+ "[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
1474
+ ),
1475
+ value: format(currentValue),
1476
+ disabled,
1477
+ placeholder,
1478
+ min,
1479
+ max,
1480
+ step,
1481
+ onChange: handleInputChange,
1482
+ onBlur: handleBlur,
1483
+ ...props
1484
+ }
1485
+ ),
1486
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1487
+ "button",
1488
+ {
1489
+ type: "button",
1490
+ "aria-label": "\u589E\u52A0\u6570\u503C",
1491
+ disabled: disabled || atMax,
1492
+ onClick: handleIncrement,
1493
+ className: (0, import_ui_utils19.cn)(btnBase, btnSizeCls, "rounded-r-md border-l border-border-base"),
1494
+ tabIndex: -1,
1495
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Plus, { size: iconSize })
1496
+ }
1497
+ )
1498
+ ] });
1499
+ }
1500
+ );
1501
+ NumberInput.displayName = "NumberInput";
1502
+
1503
+ // src/components/otp-input.tsx
1504
+ var import_react21 = require("react");
1505
+ var import_ui_utils20 = require("@ug666/ui-utils");
1506
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1507
+ var OTPInput = (0, import_react21.forwardRef)(
1508
+ ({
1509
+ value,
1510
+ onValueChange,
1511
+ length = 6,
1512
+ disabled = false,
1513
+ onComplete,
1514
+ className
1515
+ }, ref) => {
1516
+ const inputRefs = (0, import_react21.useRef)([]);
1517
+ const focusAt = (0, import_react21.useCallback)((index) => {
1518
+ const el = inputRefs.current[index];
1519
+ if (el) {
1520
+ el.focus();
1521
+ el.setSelectionRange(el.value.length, el.value.length);
1522
+ }
1523
+ }, []);
1524
+ const updateValueAt = (0, import_react21.useCallback)(
1525
+ (index, char) => {
1526
+ const chars = value.padEnd(length, "").split("").slice(0, length);
1527
+ chars[index] = char;
1528
+ const next = chars.join("");
1529
+ onValueChange(next);
1530
+ if (char && next.replace(/\s/g, "").length === length && !next.includes(" ")) {
1531
+ onComplete?.(next);
1532
+ }
1533
+ },
1534
+ [value, length, onValueChange, onComplete]
1535
+ );
1536
+ const handleChange = (0, import_react21.useCallback)(
1537
+ (index, e) => {
1538
+ const raw = e.target.value;
1539
+ const digit = raw.replace(/\D/g, "").slice(-1);
1540
+ updateValueAt(index, digit);
1541
+ if (digit && index < length - 1) {
1542
+ focusAt(index + 1);
1543
+ }
1544
+ },
1545
+ [length, updateValueAt, focusAt]
1546
+ );
1547
+ const handleKeyDown = (0, import_react21.useCallback)(
1548
+ (index, e) => {
1549
+ if (e.key === "ArrowLeft") {
1550
+ e.preventDefault();
1551
+ if (index > 0) focusAt(index - 1);
1552
+ } else if (e.key === "ArrowRight") {
1553
+ e.preventDefault();
1554
+ if (index < length - 1) focusAt(index + 1);
1555
+ } else if (e.key === "Backspace") {
1556
+ e.preventDefault();
1557
+ const current = value[index] ?? "";
1558
+ if (current) {
1559
+ updateValueAt(index, "");
1560
+ } else if (index > 0) {
1561
+ updateValueAt(index - 1, "");
1562
+ focusAt(index - 1);
1563
+ }
1564
+ }
1565
+ },
1566
+ [value, length, focusAt, updateValueAt]
1567
+ );
1568
+ const handlePaste = (0, import_react21.useCallback)(
1569
+ (e) => {
1570
+ e.preventDefault();
1571
+ const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, length);
1572
+ if (!pasted) return;
1573
+ const chars = pasted.padEnd(length, "").split("").slice(0, length);
1574
+ const next = chars.join("");
1575
+ onValueChange(next);
1576
+ const nextFocus = Math.min(pasted.length, length - 1);
1577
+ focusAt(nextFocus);
1578
+ if (pasted.length === length) {
1579
+ onComplete?.(next);
1580
+ }
1581
+ },
1582
+ [length, onValueChange, onComplete, focusAt]
1583
+ );
1584
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1585
+ "div",
1586
+ {
1587
+ ref,
1588
+ className: (0, import_ui_utils20.cn)("flex items-center gap-2", className),
1589
+ role: "group",
1590
+ "aria-label": "\u9A8C\u8BC1\u7801\u8F93\u5165",
1591
+ children: Array.from({ length }, (_, i) => {
1592
+ const char = value[i] ?? "";
1593
+ const isFocused = false;
1594
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1595
+ "input",
1596
+ {
1597
+ ref: (el) => {
1598
+ inputRefs.current[i] = el;
1599
+ },
1600
+ type: "text",
1601
+ inputMode: "numeric",
1602
+ pattern: "[0-9]",
1603
+ maxLength: 1,
1604
+ value: char,
1605
+ disabled,
1606
+ "aria-label": `\u9A8C\u8BC1\u7801\u7B2C ${i + 1} \u4F4D`,
1607
+ className: (0, import_ui_utils20.cn)(
1608
+ "h-10 w-10 rounded-md border text-center text-sm font-medium text-text-primary transition-colors",
1609
+ "outline-none focus:border-primary focus:ring-2 focus:ring-ring/20",
1610
+ "disabled:cursor-not-allowed disabled:opacity-50",
1611
+ char ? "border-border-strong" : "border-border-base"
1612
+ ),
1613
+ onChange: (e) => handleChange(i, e),
1614
+ onKeyDown: (e) => handleKeyDown(i, e),
1615
+ onPaste: handlePaste,
1616
+ onClick: (e) => e.target.select()
1617
+ },
1618
+ i
1619
+ );
1620
+ })
1621
+ }
1622
+ );
1623
+ }
1624
+ );
1625
+ OTPInput.displayName = "OTPInput";
1626
+
1627
+ // src/components/form.tsx
1628
+ var import_react22 = require("react");
1629
+ var import_ui_utils21 = require("@ug666/ui-utils");
1630
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1631
+ var FormFieldContext = (0, import_react22.createContext)(null);
1632
+ function useFormFieldContext() {
1633
+ const ctx = (0, import_react22.useContext)(FormFieldContext);
1634
+ if (!ctx) {
1635
+ throw new Error("FormField \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <FormField> \u5185\u4F7F\u7528");
1636
+ }
1637
+ return ctx;
1638
+ }
1639
+ var Form = (0, import_react22.forwardRef)(
1640
+ ({ className, onSubmit, children, ...props }, ref) => {
1641
+ function handleSubmit(event) {
1642
+ event.preventDefault();
1643
+ onSubmit?.(event);
1644
+ }
1645
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1646
+ "form",
1647
+ {
1648
+ ref,
1649
+ className: (0, import_ui_utils21.cn)(className),
1650
+ onSubmit: handleSubmit,
1651
+ ...props,
1652
+ children
1653
+ }
1654
+ );
1655
+ }
1656
+ );
1657
+ Form.displayName = "Form";
1658
+ var FormField = (0, import_react22.forwardRef)(
1659
+ ({ name, error, className, children, ...props }, ref) => {
1660
+ const generatedId = (0, import_react22.useId)();
1661
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FormFieldContext.Provider, { value: { name, error, id: generatedId }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref, className: (0, import_ui_utils21.cn)(className), ...props, children }) });
1662
+ }
1663
+ );
1664
+ FormField.displayName = "FormField";
1665
+ var FormItem = (0, import_react22.forwardRef)(
1666
+ ({ className, children, ...props }, ref) => {
1667
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1668
+ "div",
1669
+ {
1670
+ ref,
1671
+ className: (0, import_ui_utils21.cn)("flex flex-col gap-1.5", className),
1672
+ ...props,
1673
+ children
1674
+ }
1675
+ );
1676
+ }
1677
+ );
1678
+ FormItem.displayName = "FormItem";
1679
+ var FormLabel = (0, import_react22.forwardRef)(
1680
+ ({ className, required, children, htmlFor, ...props }, ref) => {
1681
+ const ctx = useFormFieldContext();
1682
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1683
+ Label,
1684
+ {
1685
+ ref,
1686
+ htmlFor: htmlFor ?? ctx.id,
1687
+ required,
1688
+ className: (0, import_ui_utils21.cn)(className),
1689
+ ...props,
1690
+ children
1691
+ }
1692
+ );
1693
+ }
1694
+ );
1695
+ FormLabel.displayName = "FormLabel";
1696
+ function FormControl({ children }) {
1697
+ const ctx = useFormFieldContext();
1698
+ const descriptionId = `${ctx.id}-description`;
1699
+ const messageId = `${ctx.id}-message`;
1700
+ return (0, import_react22.cloneElement)(children, {
1701
+ id: ctx.id,
1702
+ "aria-describedby": ctx.error ? `${descriptionId} ${messageId}` : descriptionId,
1703
+ "aria-invalid": ctx.error ? true : void 0
1704
+ });
1705
+ }
1706
+ FormControl.displayName = "FormControl";
1707
+ var FormDescription = (0, import_react22.forwardRef)(
1708
+ ({ className, children, ...props }, ref) => {
1709
+ const ctx = useFormFieldContext();
1710
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1711
+ "p",
1712
+ {
1713
+ ref,
1714
+ id: `${ctx.id}-description`,
1715
+ className: (0, import_ui_utils21.cn)("text-xs text-text-secondary", className),
1716
+ ...props,
1717
+ children
1718
+ }
1719
+ );
1720
+ }
1721
+ );
1722
+ FormDescription.displayName = "FormDescription";
1723
+ var FormMessage = (0, import_react22.forwardRef)(
1724
+ ({ className, children, ...props }, ref) => {
1725
+ const ctx = useFormFieldContext();
1726
+ const message = ctx.error ?? (typeof children === "string" ? children : void 0);
1727
+ if (!message) return null;
1728
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1729
+ "p",
1730
+ {
1731
+ ref,
1732
+ id: `${ctx.id}-message`,
1733
+ className: (0, import_ui_utils21.cn)("text-xs text-danger-soft-fg", className),
1734
+ role: "alert",
1735
+ ...props,
1736
+ children: message
1737
+ }
1738
+ );
1739
+ }
1740
+ );
1741
+ FormMessage.displayName = "FormMessage";
1742
+
1743
+ // src/components/tabs.tsx
1744
+ var import_react23 = require("react");
1745
+ var import_ui_utils22 = require("@ug666/ui-utils");
1746
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1747
+ var TabsContext = (0, import_react23.createContext)(null);
1748
+ function useTabsContext() {
1749
+ const ctx = (0, import_react23.useContext)(TabsContext);
1750
+ if (!ctx) throw new Error("Tabs \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Tabs> \u5185\u4F7F\u7528");
1751
+ return ctx;
1752
+ }
1753
+ var Tabs = (0, import_react23.forwardRef)(({ value, onValueChange, children, className }, ref) => {
1754
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TabsContext.Provider, { value: { value, onValueChange }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { ref, className: (0, import_ui_utils22.cn)("w-full", className), children }) });
1755
+ });
1756
+ var TabsList = (0, import_react23.forwardRef)(({ className, children, ...props }, ref) => {
1757
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1758
+ "div",
1759
+ {
1760
+ ref,
1761
+ role: "tablist",
1762
+ className: (0, import_ui_utils22.cn)("inline-flex w-full items-center gap-0 border-b border-border-base", className),
1763
+ ...props,
1764
+ children
1765
+ }
1766
+ );
1767
+ });
1768
+ var TabsTrigger = (0, import_react23.forwardRef)(({ value, className, children, ...props }, ref) => {
1769
+ const { value: activeValue, onValueChange } = useTabsContext();
1770
+ const isActive = activeValue === value;
1771
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1772
+ "button",
1773
+ {
1774
+ ref,
1775
+ type: "button",
1776
+ role: "tab",
1777
+ "aria-selected": isActive,
1778
+ tabIndex: isActive ? 0 : -1,
1779
+ onClick: () => onValueChange(value),
1780
+ className: (0, import_ui_utils22.cn)(
1781
+ "relative px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:ring-offset-1",
1782
+ "after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-full after:transition-colors",
1783
+ isActive ? "text-text-primary after:bg-primary" : "text-text-secondary hover:text-text-primary after:bg-transparent",
1784
+ className
1785
+ ),
1786
+ ...props,
1787
+ children
1788
+ }
1789
+ );
1790
+ });
1791
+ var TabsContent = (0, import_react23.forwardRef)(({ value, className, children, ...props }, ref) => {
1792
+ const { value: activeValue } = useTabsContext();
1793
+ if (activeValue !== value) return null;
1794
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1795
+ "div",
1796
+ {
1797
+ ref,
1798
+ role: "tabpanel",
1799
+ tabIndex: 0,
1800
+ className: (0, import_ui_utils22.cn)("mt-4 focus-visible:outline-none", className),
1801
+ ...props,
1802
+ children
1803
+ }
1804
+ );
1805
+ });
1806
+ Tabs.displayName = "Tabs";
1807
+ TabsList.displayName = "TabsList";
1808
+ TabsTrigger.displayName = "TabsTrigger";
1809
+ TabsContent.displayName = "TabsContent";
1810
+
1811
+ // src/components/accordion.tsx
1812
+ var import_react24 = require("react");
1813
+ var import_lucide_react10 = require("lucide-react");
1814
+ var import_ui_utils23 = require("@ug666/ui-utils");
1815
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1816
+ var AccordionContext = (0, import_react24.createContext)(null);
1817
+ var AccordionItemContext = (0, import_react24.createContext)(null);
1818
+ function useAccordionContext() {
1819
+ const ctx = (0, import_react24.useContext)(AccordionContext);
1820
+ if (!ctx) throw new Error("Accordion \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Accordion> \u5185\u4F7F\u7528");
1821
+ return ctx;
1822
+ }
1823
+ function useAccordionItemContext() {
1824
+ const ctx = (0, import_react24.useContext)(AccordionItemContext);
1825
+ if (!ctx) throw new Error("AccordionTrigger/AccordionContent \u5FC5\u987B\u5728 <AccordionItem> \u5185\u4F7F\u7528");
1826
+ return ctx;
1827
+ }
1828
+ var Accordion = (0, import_react24.forwardRef)(
1829
+ (props, ref) => {
1830
+ const { type, children, className, ...rest } = props;
1831
+ const isSingle = type === "single";
1832
+ const singleProps = isSingle ? props : null;
1833
+ const multiProps = !isSingle ? props : null;
1834
+ const [internalSingle, setInternalSingle] = (0, import_react24.useState)(singleProps?.defaultValue ?? "");
1835
+ const [internalMulti, setInternalMulti] = (0, import_react24.useState)(multiProps?.defaultValue ?? []);
1836
+ const isControlledSingle = isSingle && singleProps?.value !== void 0;
1837
+ const isControlledMulti = !isSingle && multiProps?.value !== void 0;
1838
+ const value = isSingle ? isControlledSingle ? singleProps.value ?? "" : internalSingle : isControlledMulti ? multiProps.value ?? [] : internalMulti;
1839
+ const collapsible = isSingle ? singleProps?.collapsible ?? false : false;
1840
+ function handleValueChange(itemValue) {
1841
+ if (isSingle) {
1842
+ const current = value;
1843
+ const next = current === itemValue && collapsible ? "" : itemValue;
1844
+ if (!isControlledSingle) setInternalSingle(next);
1845
+ singleProps?.onValueChange?.(next);
1846
+ } else {
1847
+ const current = value;
1848
+ const next = current.includes(itemValue) ? current.filter((v) => v !== itemValue) : [...current, itemValue];
1849
+ if (!isControlledMulti) setInternalMulti(next);
1850
+ multiProps?.onValueChange?.(next);
1851
+ }
1852
+ }
1853
+ const { defaultValue: _dv, onValueChange: _ov, collapsible: _col, ...domRest } = rest;
1854
+ void _dv;
1855
+ void _ov;
1856
+ void _col;
1857
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AccordionContext.Provider, { value: { type, value, onValueChange: handleValueChange, collapsible }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref, className: (0, import_ui_utils23.cn)("w-full divide-y divide-border-base rounded-md border border-border-base", className), ...domRest, children }) });
1858
+ }
1859
+ );
1860
+ Accordion.displayName = "Accordion";
1861
+ var AccordionItem = (0, import_react24.forwardRef)(({ value, className, children, ...props }, ref) => {
1862
+ const { value: activeValue, type } = useAccordionContext();
1863
+ const isOpen = type === "single" ? activeValue === value : activeValue.includes(value);
1864
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AccordionItemContext.Provider, { value: { value, isOpen }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref, className: (0, import_ui_utils23.cn)("", className), ...props, children }) });
1865
+ });
1866
+ AccordionItem.displayName = "AccordionItem";
1867
+ var AccordionTrigger = (0, import_react24.forwardRef)(({ className, children, ...props }, ref) => {
1868
+ const { onValueChange } = useAccordionContext();
1869
+ const { value, isOpen } = useAccordionItemContext();
1870
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1871
+ "button",
1872
+ {
1873
+ ref,
1874
+ type: "button",
1875
+ "aria-expanded": isOpen,
1876
+ onClick: () => onValueChange(value),
1877
+ className: (0, import_ui_utils23.cn)(
1878
+ "flex w-full items-center justify-between px-4 py-3 text-left text-sm font-medium text-text-primary transition-colors hover:bg-surface-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:ring-inset",
1879
+ className
1880
+ ),
1881
+ ...props,
1882
+ children: [
1883
+ children,
1884
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1885
+ import_lucide_react10.ChevronDown,
1886
+ {
1887
+ size: 16,
1888
+ className: (0, import_ui_utils23.cn)("shrink-0 text-text-secondary transition-transform duration-200", isOpen && "rotate-180")
1889
+ }
1890
+ )
1891
+ ]
1892
+ }
1893
+ );
1894
+ });
1895
+ AccordionTrigger.displayName = "AccordionTrigger";
1896
+ var AccordionContent = (0, import_react24.forwardRef)(({ className, children, ...props }, ref) => {
1897
+ const { isOpen } = useAccordionItemContext();
1898
+ if (!isOpen) return null;
1899
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1900
+ "div",
1901
+ {
1902
+ ref,
1903
+ className: (0, import_ui_utils23.cn)("px-4 pb-4 pt-1 text-sm text-text-secondary", className),
1904
+ ...props,
1905
+ children
1906
+ }
1907
+ );
1908
+ });
1909
+ AccordionContent.displayName = "AccordionContent";
1910
+
1911
+ // src/components/steps.tsx
1912
+ var import_react25 = require("react");
1913
+ var import_lucide_react11 = require("lucide-react");
1914
+ var import_ui_utils24 = require("@ug666/ui-utils");
1915
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1916
+ var Steps = (0, import_react25.forwardRef)(
1917
+ ({ current, items, direction = "horizontal", status = "process", className, ...props }, ref) => {
1918
+ const isHorizontal = direction === "horizontal";
1919
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1920
+ "div",
1921
+ {
1922
+ ref,
1923
+ className: (0, import_ui_utils24.cn)(
1924
+ isHorizontal ? "flex items-start" : "flex flex-col",
1925
+ className
1926
+ ),
1927
+ ...props,
1928
+ children: items.map((item, index) => {
1929
+ const isFinished = index < current || index === current && status === "finish";
1930
+ const isCurrent = index === current && status !== "finish";
1931
+ const isError = index === current && status === "error";
1932
+ const isLast = index === items.length - 1;
1933
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
1934
+ "div",
1935
+ {
1936
+ className: (0, import_ui_utils24.cn)(
1937
+ isHorizontal ? "flex flex-1 items-start" : "flex items-start"
1938
+ ),
1939
+ children: [
1940
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: (0, import_ui_utils24.cn)("flex", isHorizontal ? "flex-col items-center" : "items-start"), children: [
1941
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1942
+ "div",
1943
+ {
1944
+ className: (0, import_ui_utils24.cn)(
1945
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold transition-colors",
1946
+ isFinished && "border-primary bg-primary text-primary-fg",
1947
+ isCurrent && !isError && "border-primary bg-surface-1 text-text-primary",
1948
+ isError && "border-red-500 bg-surface-1 text-red-500",
1949
+ !isFinished && !isCurrent && !isError && "border-border-strong bg-surface-1 text-text-tertiary"
1950
+ ),
1951
+ children: isFinished ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react11.Check, { size: 16, strokeWidth: 2.5 }) : item.icon ?? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: index + 1 })
1952
+ }
1953
+ ),
1954
+ !isLast && !isHorizontal && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1955
+ "div",
1956
+ {
1957
+ className: (0, import_ui_utils24.cn)(
1958
+ "ml-[15px] mt-1 w-0.5 flex-1 self-stretch",
1959
+ isFinished ? "bg-primary" : "bg-border-base"
1960
+ ),
1961
+ style: { minHeight: "24px" }
1962
+ }
1963
+ )
1964
+ ] }),
1965
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
1966
+ "div",
1967
+ {
1968
+ className: (0, import_ui_utils24.cn)(
1969
+ isHorizontal ? "mt-2 text-center" : "ml-3 pb-6",
1970
+ isLast && !isHorizontal && "pb-0"
1971
+ ),
1972
+ children: [
1973
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1974
+ "p",
1975
+ {
1976
+ className: (0, import_ui_utils24.cn)(
1977
+ "text-sm font-medium",
1978
+ isFinished && "text-text-primary",
1979
+ isCurrent && !isError && "text-text-primary",
1980
+ isError && "text-red-500",
1981
+ !isFinished && !isCurrent && !isError && "text-text-tertiary"
1982
+ ),
1983
+ children: item.title
1984
+ }
1985
+ ),
1986
+ item.description && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
1987
+ "p",
1988
+ {
1989
+ className: (0, import_ui_utils24.cn)(
1990
+ "mt-0.5 text-xs",
1991
+ isError ? "text-red-400" : "text-text-secondary"
1992
+ ),
1993
+ children: item.description
1994
+ }
1995
+ )
1996
+ ]
1997
+ }
1998
+ ),
1999
+ !isLast && isHorizontal && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2000
+ "div",
2001
+ {
2002
+ className: (0, import_ui_utils24.cn)(
2003
+ "mx-2 mt-4 h-0.5 flex-1",
2004
+ isFinished ? "bg-primary" : "bg-border-base"
2005
+ )
2006
+ }
2007
+ )
2008
+ ]
2009
+ },
2010
+ index
2011
+ );
2012
+ })
2013
+ }
2014
+ );
2015
+ }
2016
+ );
2017
+ Steps.displayName = "Steps";
2018
+
2019
+ // src/components/dropdown.tsx
2020
+ var import_react26 = require("react");
2021
+ var import_react_dom5 = require("react-dom");
2022
+ var import_ui_utils25 = require("@ug666/ui-utils");
2023
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2024
+ var DropdownContext = (0, import_react26.createContext)(null);
2025
+ function assignRef(ref, value) {
2026
+ if (typeof ref === "function") {
2027
+ ref(value);
2028
+ return;
2029
+ }
2030
+ if (ref) {
2031
+ ref.current = value;
2032
+ }
2033
+ }
2034
+ function useDropdownContext() {
2035
+ const ctx = (0, import_react26.useContext)(DropdownContext);
2036
+ if (!ctx) throw new Error("Dropdown \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <DropdownMenu> \u5185\u4F7F\u7528");
2037
+ return ctx;
2038
+ }
2039
+ var DropdownMenu = (0, import_react26.forwardRef)(({ children, className }, ref) => {
2040
+ const [open, setOpen] = (0, import_react26.useState)(false);
2041
+ const triggerRef = (0, import_react26.useRef)(null);
2042
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DropdownContext.Provider, { value: { open, setOpen, triggerRef }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { ref, className: (0, import_ui_utils25.cn)("relative inline-block", className), children }) });
2043
+ });
2044
+ var DropdownTrigger = (0, import_react26.forwardRef)(({ children, className }, ref) => {
2045
+ const { setOpen, open, triggerRef } = useDropdownContext();
2046
+ const handleRef = (0, import_react26.useCallback)(
2047
+ (node) => {
2048
+ triggerRef.current = node;
2049
+ assignRef(ref, node);
2050
+ },
2051
+ [ref, triggerRef]
2052
+ );
2053
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2054
+ "div",
2055
+ {
2056
+ ref: handleRef,
2057
+ className: (0, import_ui_utils25.cn)("inline-flex", className),
2058
+ onClick: () => setOpen(!open),
2059
+ children
2060
+ }
2061
+ );
2062
+ });
2063
+ var DropdownContent = (0, import_react26.forwardRef)(({ children, className, align = "start" }, ref) => {
2064
+ const { open, setOpen, triggerRef } = useDropdownContext();
2065
+ const contentRef = (0, import_react26.useRef)(null);
2066
+ const [position, setPosition] = (0, import_react26.useState)({ top: 0, left: 0 });
2067
+ const handleRef = (0, import_react26.useCallback)(
2068
+ (node) => {
2069
+ contentRef.current = node;
2070
+ assignRef(ref, node);
2071
+ },
2072
+ [ref]
2073
+ );
2074
+ const updatePosition = (0, import_react26.useCallback)(() => {
2075
+ if (!triggerRef.current) return;
2076
+ const rect = triggerRef.current.getBoundingClientRect();
2077
+ const top = rect.bottom + window.scrollY + 4;
2078
+ const left = align === "end" ? rect.right + window.scrollX - (contentRef.current?.offsetWidth ?? 0) : rect.left + window.scrollX;
2079
+ setPosition({ top, left });
2080
+ }, [align, triggerRef]);
2081
+ (0, import_react26.useEffect)(() => {
2082
+ if (!open) return;
2083
+ updatePosition();
2084
+ }, [open, updatePosition]);
2085
+ (0, import_react26.useEffect)(() => {
2086
+ if (!open) return;
2087
+ function handleClickOutside(e) {
2088
+ if (contentRef.current && !contentRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
2089
+ setOpen(false);
2090
+ }
2091
+ }
2092
+ document.addEventListener("mousedown", handleClickOutside);
2093
+ return () => document.removeEventListener("mousedown", handleClickOutside);
2094
+ }, [open, setOpen, triggerRef]);
2095
+ if (!open) return null;
2096
+ return (0, import_react_dom5.createPortal)(
2097
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2098
+ "div",
2099
+ {
2100
+ ref: handleRef,
2101
+ style: { top: position.top, left: position.left },
2102
+ className: (0, import_ui_utils25.cn)(
2103
+ "absolute z-50 min-w-40 rounded-md border border-border-base bg-surface-1 py-1 shadow-lg",
2104
+ className
2105
+ ),
2106
+ children
2107
+ }
2108
+ ),
2109
+ document.body
2110
+ );
2111
+ });
2112
+ var DropdownItem = (0, import_react26.forwardRef)(({ children, className, destructive = false, onClick, ...props }, ref) => {
2113
+ const { setOpen } = useDropdownContext();
2114
+ function handleClick(e) {
2115
+ setOpen(false);
2116
+ onClick?.(e);
2117
+ }
2118
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2119
+ "button",
2120
+ {
2121
+ ref,
2122
+ type: "button",
2123
+ className: (0, import_ui_utils25.cn)(
2124
+ "w-full px-3 py-1.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:bg-surface-3",
2125
+ destructive ? "text-red-600 hover:bg-red-50" : "text-text-primary hover:bg-surface-3",
2126
+ className
2127
+ ),
2128
+ onClick: handleClick,
2129
+ ...props,
2130
+ children
2131
+ }
2132
+ );
2133
+ });
2134
+ var DropdownSeparator = (0, import_react26.forwardRef)(({ className, ...props }, ref) => {
2135
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { ref, className: (0, import_ui_utils25.cn)("my-1 h-px bg-border-base", className), ...props });
2136
+ });
2137
+ DropdownMenu.displayName = "DropdownMenu";
2138
+ DropdownTrigger.displayName = "DropdownTrigger";
2139
+ DropdownContent.displayName = "DropdownContent";
2140
+ DropdownItem.displayName = "DropdownItem";
2141
+ DropdownSeparator.displayName = "DropdownSeparator";
2142
+
2143
+ // src/components/popover.tsx
2144
+ var import_react27 = require("react");
2145
+ var import_react_dom6 = require("react-dom");
2146
+ var import_ui_utils26 = require("@ug666/ui-utils");
2147
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2148
+ var PopoverContext = (0, import_react27.createContext)(null);
2149
+ function usePopoverContext() {
2150
+ const ctx = (0, import_react27.useContext)(PopoverContext);
2151
+ if (!ctx) throw new Error("Popover \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Popover> \u5185\u4F7F\u7528");
2152
+ return ctx;
2153
+ }
2154
+ function assignRef2(ref, value) {
2155
+ if (typeof ref === "function") {
2156
+ ref(value);
2157
+ return;
2158
+ }
2159
+ if (ref) {
2160
+ ref.current = value;
2161
+ }
2162
+ }
2163
+ var Popover = ({ open: controlledOpen, defaultOpen = false, onOpenChange, children }) => {
2164
+ const [internalOpen, setInternalOpen] = (0, import_react27.useState)(defaultOpen);
2165
+ const triggerRef = (0, import_react27.useRef)(null);
2166
+ const isControlled = controlledOpen !== void 0;
2167
+ const open = isControlled ? controlledOpen : internalOpen;
2168
+ const setOpen = (0, import_react27.useCallback)(
2169
+ (value) => {
2170
+ if (!isControlled) setInternalOpen(value);
2171
+ onOpenChange?.(value);
2172
+ },
2173
+ [isControlled, onOpenChange]
2174
+ );
2175
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(PopoverContext.Provider, { value: { open, setOpen, triggerRef }, children });
2176
+ };
2177
+ Popover.displayName = "Popover";
2178
+ var PopoverTrigger = (0, import_react27.forwardRef)(({ children, className }, ref) => {
2179
+ const { setOpen, open, triggerRef } = usePopoverContext();
2180
+ const handleRef = (0, import_react27.useCallback)(
2181
+ (node) => {
2182
+ triggerRef.current = node;
2183
+ assignRef2(ref, node);
2184
+ },
2185
+ [ref, triggerRef]
2186
+ );
2187
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2188
+ "div",
2189
+ {
2190
+ ref: handleRef,
2191
+ className: (0, import_ui_utils26.cn)("inline-flex", className),
2192
+ onClick: () => setOpen(!open),
2193
+ children
2194
+ }
2195
+ );
2196
+ });
2197
+ PopoverTrigger.displayName = "PopoverTrigger";
2198
+ function calcPosition(triggerRect, contentEl, side, align, sideOffset) {
2199
+ const cw = contentEl.offsetWidth;
2200
+ const ch = contentEl.offsetHeight;
2201
+ let top = 0;
2202
+ let left = 0;
2203
+ if (side === "bottom") {
2204
+ top = triggerRect.bottom + window.scrollY + sideOffset;
2205
+ } else if (side === "top") {
2206
+ top = triggerRect.top + window.scrollY - ch - sideOffset;
2207
+ } else if (side === "left") {
2208
+ top = triggerRect.top + window.scrollY + triggerRect.height / 2 - ch / 2;
2209
+ left = triggerRect.left + window.scrollX - cw - sideOffset;
2210
+ return { top, left };
2211
+ } else {
2212
+ top = triggerRect.top + window.scrollY + triggerRect.height / 2 - ch / 2;
2213
+ left = triggerRect.right + window.scrollX + sideOffset;
2214
+ return { top, left };
2215
+ }
2216
+ if (align === "start") {
2217
+ left = triggerRect.left + window.scrollX;
2218
+ } else if (align === "end") {
2219
+ left = triggerRect.right + window.scrollX - cw;
2220
+ } else {
2221
+ left = triggerRect.left + window.scrollX + triggerRect.width / 2 - cw / 2;
2222
+ }
2223
+ return { top, left };
2224
+ }
2225
+ var PopoverContent = (0, import_react27.forwardRef)(
2226
+ ({ children, className, side = "bottom", align = "center", sideOffset = 4, ...props }, ref) => {
2227
+ const { open, setOpen, triggerRef } = usePopoverContext();
2228
+ const contentRef = (0, import_react27.useRef)(null);
2229
+ const [pos, setPos] = (0, import_react27.useState)({ top: 0, left: 0 });
2230
+ const handleRef = (0, import_react27.useCallback)(
2231
+ (node) => {
2232
+ contentRef.current = node;
2233
+ assignRef2(ref, node);
2234
+ },
2235
+ [ref]
2236
+ );
2237
+ const updatePos = (0, import_react27.useCallback)(() => {
2238
+ if (!triggerRef.current || !contentRef.current) return;
2239
+ const rect = triggerRef.current.getBoundingClientRect();
2240
+ setPos(calcPosition(rect, contentRef.current, side, align, sideOffset));
2241
+ }, [side, align, sideOffset, triggerRef]);
2242
+ (0, import_react27.useEffect)(() => {
2243
+ if (open) updatePos();
2244
+ }, [open, updatePos]);
2245
+ (0, import_react27.useEffect)(() => {
2246
+ if (!open) return;
2247
+ function handleMouseDown(e) {
2248
+ if (contentRef.current && !contentRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
2249
+ setOpen(false);
2250
+ }
2251
+ }
2252
+ document.addEventListener("mousedown", handleMouseDown);
2253
+ return () => document.removeEventListener("mousedown", handleMouseDown);
2254
+ }, [open, setOpen, triggerRef]);
2255
+ if (!open) return null;
2256
+ return (0, import_react_dom6.createPortal)(
2257
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2258
+ "div",
2259
+ {
2260
+ ref: handleRef,
2261
+ style: { top: pos.top, left: pos.left },
2262
+ className: (0, import_ui_utils26.cn)(
2263
+ "absolute z-50 min-w-40 rounded-md border border-border-base bg-surface-1 p-3 shadow-lg",
2264
+ className
2265
+ ),
2266
+ ...props,
2267
+ children
2268
+ }
2269
+ ),
2270
+ document.body
2271
+ );
2272
+ }
2273
+ );
2274
+ PopoverContent.displayName = "PopoverContent";
2275
+
2276
+ // src/components/context-menu.tsx
2277
+ var import_react28 = require("react");
2278
+ var import_react_dom7 = require("react-dom");
2279
+ var import_ui_utils27 = require("@ug666/ui-utils");
2280
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2281
+ var ContextMenuContext = (0, import_react28.createContext)(null);
2282
+ function useContextMenuContext() {
2283
+ const ctx = (0, import_react28.useContext)(ContextMenuContext);
2284
+ if (!ctx) throw new Error("ContextMenu \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <ContextMenu> \u5185\u4F7F\u7528");
2285
+ return ctx;
2286
+ }
2287
+ function assignRef3(ref, value) {
2288
+ if (typeof ref === "function") {
2289
+ ref(value);
2290
+ return;
2291
+ }
2292
+ if (ref) {
2293
+ ref.current = value;
2294
+ }
2295
+ }
2296
+ var ContextMenu = (0, import_react28.forwardRef)(
2297
+ ({ children, className }, ref) => {
2298
+ const [open, setOpen] = (0, import_react28.useState)(false);
2299
+ const [position, setPosition] = (0, import_react28.useState)({ x: 0, y: 0 });
2300
+ const openAt = (0, import_react28.useCallback)((pos) => {
2301
+ setPosition(pos);
2302
+ setOpen(true);
2303
+ }, []);
2304
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ContextMenuContext.Provider, { value: { open, position, setOpen, openAt }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { ref, className: (0, import_ui_utils27.cn)("relative", className), children }) });
2305
+ }
2306
+ );
2307
+ var ContextMenuTrigger = (0, import_react28.forwardRef)(
2308
+ ({ children, className, ...props }, ref) => {
2309
+ const { openAt } = useContextMenuContext();
2310
+ function handleContextMenu(e) {
2311
+ e.preventDefault();
2312
+ openAt({ x: e.clientX, y: e.clientY });
2313
+ }
2314
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2315
+ "div",
2316
+ {
2317
+ ref,
2318
+ className: (0, import_ui_utils27.cn)(className),
2319
+ onContextMenu: handleContextMenu,
2320
+ ...props,
2321
+ children
2322
+ }
2323
+ );
2324
+ }
2325
+ );
2326
+ var ContextMenuContent = (0, import_react28.forwardRef)(
2327
+ ({ children, className, ...props }, ref) => {
2328
+ const { open, position, setOpen } = useContextMenuContext();
2329
+ const contentRef = (0, import_react28.useRef)(null);
2330
+ const handleRef = (0, import_react28.useCallback)(
2331
+ (node) => {
2332
+ contentRef.current = node;
2333
+ assignRef3(ref, node);
2334
+ },
2335
+ [ref]
2336
+ );
2337
+ (0, import_react28.useEffect)(() => {
2338
+ if (!open) return;
2339
+ function handleMouseDown(e) {
2340
+ if (contentRef.current && !contentRef.current.contains(e.target)) {
2341
+ setOpen(false);
2342
+ }
2343
+ }
2344
+ function handleKeyDown(e) {
2345
+ if (e.key === "Escape") {
2346
+ setOpen(false);
2347
+ }
2348
+ }
2349
+ document.addEventListener("mousedown", handleMouseDown);
2350
+ document.addEventListener("keydown", handleKeyDown);
2351
+ return () => {
2352
+ document.removeEventListener("mousedown", handleMouseDown);
2353
+ document.removeEventListener("keydown", handleKeyDown);
2354
+ };
2355
+ }, [open, setOpen]);
2356
+ if (!open) return null;
2357
+ return (0, import_react_dom7.createPortal)(
2358
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2359
+ "div",
2360
+ {
2361
+ ref: handleRef,
2362
+ style: { top: position.y, left: position.x },
2363
+ className: (0, import_ui_utils27.cn)(
2364
+ "fixed z-50 min-w-40 rounded-md border border-border-base bg-surface-1 py-1 shadow-lg",
2365
+ className
2366
+ ),
2367
+ ...props,
2368
+ children
2369
+ }
2370
+ ),
2371
+ document.body
2372
+ );
2373
+ }
2374
+ );
2375
+ var ContextMenuItem = (0, import_react28.forwardRef)(
2376
+ ({ children, className, destructive = false, onClick, ...props }, ref) => {
2377
+ const { setOpen } = useContextMenuContext();
2378
+ function handleClick(e) {
2379
+ setOpen(false);
2380
+ onClick?.(e);
2381
+ }
2382
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
2383
+ "button",
2384
+ {
2385
+ ref,
2386
+ type: "button",
2387
+ className: (0, import_ui_utils27.cn)(
2388
+ "w-full px-3 py-1.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:bg-surface-3",
2389
+ destructive ? "text-red-600 hover:bg-red-50" : "text-text-primary hover:bg-surface-3",
2390
+ className
2391
+ ),
2392
+ onClick: handleClick,
2393
+ ...props,
2394
+ children
2395
+ }
2396
+ );
2397
+ }
2398
+ );
2399
+ var ContextMenuSeparator = (0, import_react28.forwardRef)(
2400
+ ({ className, ...props }, ref) => {
2401
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { ref, className: (0, import_ui_utils27.cn)("my-1 h-px bg-border-base", className), ...props });
2402
+ }
2403
+ );
2404
+ ContextMenu.displayName = "ContextMenu";
2405
+ ContextMenuTrigger.displayName = "ContextMenuTrigger";
2406
+ ContextMenuContent.displayName = "ContextMenuContent";
2407
+ ContextMenuItem.displayName = "ContextMenuItem";
2408
+ ContextMenuSeparator.displayName = "ContextMenuSeparator";
2409
+
2410
+ // src/components/navigation-menu.tsx
2411
+ var import_react29 = require("react");
2412
+ var import_lucide_react12 = require("lucide-react");
2413
+ var import_ui_utils28 = require("@ug666/ui-utils");
2414
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2415
+ var NavigationMenuContext = (0, import_react29.createContext)(null);
2416
+ function useNavigationMenuContext() {
2417
+ const ctx = (0, import_react29.useContext)(NavigationMenuContext);
2418
+ if (!ctx) throw new Error("NavigationMenu \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <NavigationMenu> \u5185\u4F7F\u7528");
2419
+ return ctx;
2420
+ }
2421
+ var NavigationMenuItemContext = (0, import_react29.createContext)(null);
2422
+ function useNavigationMenuItemContext() {
2423
+ const ctx = (0, import_react29.useContext)(NavigationMenuItemContext);
2424
+ if (!ctx) throw new Error("NavigationMenuTrigger/Content \u5FC5\u987B\u5728 <NavigationMenuItem> \u5185\u4F7F\u7528");
2425
+ return ctx;
2426
+ }
2427
+ var _idCounter = 0;
2428
+ var NavigationMenu = (0, import_react29.forwardRef)(
2429
+ ({ className, children, ...props }, ref) => {
2430
+ const [activeItem, setActiveItem] = (0, import_react29.useState)(null);
2431
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(NavigationMenuContext.Provider, { value: { activeItem, setActiveItem }, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2432
+ "nav",
2433
+ {
2434
+ ref,
2435
+ className: (0, import_ui_utils28.cn)("relative flex items-center gap-1", className),
2436
+ ...props,
2437
+ children
2438
+ }
2439
+ ) });
2440
+ }
2441
+ );
2442
+ var NavigationMenuItem = (0, import_react29.forwardRef)(
2443
+ ({ className, children, ...props }, ref) => {
2444
+ const itemIdRef = (0, import_react29.useRef)(`nav-item-${++_idCounter}`);
2445
+ const { activeItem, setActiveItem } = useNavigationMenuContext();
2446
+ const isOpen = activeItem === itemIdRef.current;
2447
+ const handleMouseEnter = (0, import_react29.useCallback)(() => {
2448
+ setActiveItem(itemIdRef.current);
2449
+ }, [setActiveItem]);
2450
+ const handleMouseLeave = (0, import_react29.useCallback)(() => {
2451
+ setActiveItem(null);
2452
+ }, [setActiveItem]);
2453
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(NavigationMenuItemContext.Provider, { value: { itemId: itemIdRef.current }, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2454
+ "div",
2455
+ {
2456
+ ref,
2457
+ className: (0, import_ui_utils28.cn)("relative", className),
2458
+ onMouseEnter: handleMouseEnter,
2459
+ onMouseLeave: handleMouseLeave,
2460
+ "data-state": isOpen ? "open" : "closed",
2461
+ ...props,
2462
+ children
2463
+ }
2464
+ ) });
2465
+ }
2466
+ );
2467
+ var NavigationMenuLink = (0, import_react29.forwardRef)(
2468
+ ({ className, active = false, children, ...props }, ref) => {
2469
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2470
+ "a",
2471
+ {
2472
+ ref,
2473
+ className: (0, import_ui_utils28.cn)(
2474
+ "inline-flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:ring-offset-1",
2475
+ active ? "bg-surface-3 text-text-primary" : "text-text-secondary hover:bg-surface-3 hover:text-text-primary",
2476
+ className
2477
+ ),
2478
+ ...props,
2479
+ children
2480
+ }
2481
+ );
2482
+ }
2483
+ );
2484
+ var NavigationMenuTrigger = (0, import_react29.forwardRef)(
2485
+ ({ className, children, ...props }, ref) => {
2486
+ const { activeItem } = useNavigationMenuContext();
2487
+ const { itemId } = useNavigationMenuItemContext();
2488
+ const isOpen = activeItem === itemId;
2489
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
2490
+ "button",
2491
+ {
2492
+ ref,
2493
+ type: "button",
2494
+ "aria-expanded": isOpen,
2495
+ className: (0, import_ui_utils28.cn)(
2496
+ "inline-flex items-center gap-1 rounded-md px-3 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:ring-offset-1",
2497
+ isOpen ? "bg-surface-3 text-text-primary" : "text-text-secondary hover:bg-surface-3 hover:text-text-primary",
2498
+ className
2499
+ ),
2500
+ ...props,
2501
+ children: [
2502
+ children,
2503
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2504
+ import_lucide_react12.ChevronDown,
2505
+ {
2506
+ size: 14,
2507
+ className: (0, import_ui_utils28.cn)("transition-transform duration-200", isOpen && "rotate-180")
2508
+ }
2509
+ )
2510
+ ]
2511
+ }
2512
+ );
2513
+ }
2514
+ );
2515
+ var NavigationMenuContent = (0, import_react29.forwardRef)(
2516
+ ({ className, children, ...props }, ref) => {
2517
+ const { activeItem } = useNavigationMenuContext();
2518
+ const { itemId } = useNavigationMenuItemContext();
2519
+ const isOpen = activeItem === itemId;
2520
+ if (!isOpen) return null;
2521
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
2522
+ "div",
2523
+ {
2524
+ ref,
2525
+ className: (0, import_ui_utils28.cn)(
2526
+ "absolute left-0 top-full z-50 mt-1 min-w-40 rounded-md border border-border-base bg-surface-1 py-1 shadow-lg",
2527
+ className
2528
+ ),
2529
+ ...props,
2530
+ children
2531
+ }
2532
+ );
2533
+ }
2534
+ );
2535
+ NavigationMenu.displayName = "NavigationMenu";
2536
+ NavigationMenuItem.displayName = "NavigationMenuItem";
2537
+ NavigationMenuLink.displayName = "NavigationMenuLink";
2538
+ NavigationMenuTrigger.displayName = "NavigationMenuTrigger";
2539
+ NavigationMenuContent.displayName = "NavigationMenuContent";
2540
+
2541
+ // src/components/avatar.tsx
2542
+ var import_react30 = require("react");
2543
+ var import_lucide_react13 = require("lucide-react");
2544
+ var import_class_variance_authority8 = require("class-variance-authority");
2545
+ var import_ui_utils29 = require("@ug666/ui-utils");
2546
+ var import_jsx_runtime29 = require("react/jsx-runtime");
2547
+ var AvatarContext = (0, import_react30.createContext)(null);
2548
+ function useAvatarContext(componentName) {
2549
+ const ctx = (0, import_react30.useContext)(AvatarContext);
2550
+ if (!ctx) {
2551
+ throw new Error(`<${componentName}> \u5FC5\u987B\u5728 <Avatar> \u5185\u4F7F\u7528`);
2552
+ }
2553
+ return ctx;
2554
+ }
2555
+ var avatarVariants = (0, import_class_variance_authority8.cva)(
2556
+ "relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-surface-3",
2557
+ {
2558
+ variants: {
2559
+ size: {
2560
+ sm: "h-8 w-8 text-xs",
2561
+ md: "h-10 w-10 text-sm",
2562
+ lg: "h-14 w-14 text-base",
2563
+ xl: "h-20 w-20 text-xl"
2564
+ }
2565
+ },
2566
+ defaultVariants: { size: "md" }
2567
+ }
2568
+ );
2569
+ var Avatar = (0, import_react30.forwardRef)(
2570
+ ({ size, className, children, ...props }, ref) => {
2571
+ const [imageLoadingStatus, setImageLoadingStatus] = (0, import_react30.useState)("idle");
2572
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AvatarContext.Provider, { value: { imageLoadingStatus, setImageLoadingStatus }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { ref, className: (0, import_ui_utils29.cn)(avatarVariants({ size }), className), ...props, children }) });
2573
+ }
2574
+ );
2575
+ var AvatarImage = (0, import_react30.forwardRef)(
2576
+ ({ src, alt = "", className, onLoad, onError, ...props }, ref) => {
2577
+ const { imageLoadingStatus, setImageLoadingStatus } = useAvatarContext("AvatarImage");
2578
+ (0, import_react30.useEffect)(() => {
2579
+ if (!src) {
2580
+ setImageLoadingStatus("error");
2581
+ return;
2582
+ }
2583
+ setImageLoadingStatus("loading");
2584
+ }, [src, setImageLoadingStatus]);
2585
+ if (imageLoadingStatus !== "loaded" && imageLoadingStatus !== "loading") {
2586
+ return null;
2587
+ }
2588
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2589
+ "img",
2590
+ {
2591
+ ref,
2592
+ src,
2593
+ alt,
2594
+ onLoad: (event) => {
2595
+ setImageLoadingStatus("loaded");
2596
+ onLoad?.(event);
2597
+ },
2598
+ onError: (event) => {
2599
+ setImageLoadingStatus("error");
2600
+ onError?.(event);
2601
+ },
2602
+ className: (0, import_ui_utils29.cn)(
2603
+ "h-full w-full object-cover",
2604
+ imageLoadingStatus === "loading" && "invisible",
2605
+ className
2606
+ ),
2607
+ ...props
2608
+ }
2609
+ );
2610
+ }
2611
+ );
2612
+ var AvatarFallback = (0, import_react30.forwardRef)(
2613
+ ({ className, children, ...props }, ref) => {
2614
+ const { imageLoadingStatus } = useAvatarContext("AvatarFallback");
2615
+ if (imageLoadingStatus === "loaded") return null;
2616
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
2617
+ "span",
2618
+ {
2619
+ ref,
2620
+ className: (0, import_ui_utils29.cn)(
2621
+ "absolute inset-0 flex items-center justify-center font-medium text-text-secondary",
2622
+ className
2623
+ ),
2624
+ ...props,
2625
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react13.User, { size: 16 })
2626
+ }
2627
+ );
2628
+ }
2629
+ );
2630
+ Avatar.displayName = "Avatar";
2631
+ AvatarImage.displayName = "AvatarImage";
2632
+ AvatarFallback.displayName = "AvatarFallback";
2633
+
2634
+ // src/components/avatar-group.tsx
2635
+ var import_react31 = require("react");
2636
+ var import_ui_utils30 = require("@ug666/ui-utils");
2637
+ var import_jsx_runtime30 = require("react/jsx-runtime");
2638
+ var SIZE_CLASSES = {
2639
+ sm: "h-8 w-8 text-xs",
2640
+ default: "h-10 w-10 text-sm",
2641
+ lg: "h-14 w-14 text-base"
2642
+ };
2643
+ var RING_SIZE_CLASSES = {
2644
+ sm: "ring-2",
2645
+ default: "ring-2",
2646
+ lg: "ring-[3px]"
2647
+ };
2648
+ var OVERLAP_CLASSES = {
2649
+ sm: "-ml-2",
2650
+ default: "-ml-3",
2651
+ lg: "-ml-4"
2652
+ };
2653
+ var AvatarGroup = (0, import_react31.forwardRef)(
2654
+ ({ max = 5, size = "default", className, children, ...props }, ref) => {
2655
+ const allItems = import_react31.Children.toArray(children).filter(import_react31.isValidElement);
2656
+ const visibleItems = allItems.slice(0, max);
2657
+ const overflowCount = allItems.length - max;
2658
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
2659
+ "div",
2660
+ {
2661
+ ref,
2662
+ className: (0, import_ui_utils30.cn)("flex items-center", className),
2663
+ ...props,
2664
+ children: [
2665
+ visibleItems.map((child, idx) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2666
+ "span",
2667
+ {
2668
+ className: (0, import_ui_utils30.cn)(
2669
+ "relative inline-flex shrink-0 overflow-hidden rounded-full ring-surface-1",
2670
+ SIZE_CLASSES[size],
2671
+ RING_SIZE_CLASSES[size],
2672
+ idx > 0 && OVERLAP_CLASSES[size]
2673
+ ),
2674
+ children: child
2675
+ },
2676
+ idx
2677
+ )),
2678
+ overflowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
2679
+ "span",
2680
+ {
2681
+ className: (0, import_ui_utils30.cn)(
2682
+ "relative inline-flex shrink-0 items-center justify-center rounded-full bg-surface-3 font-medium text-text-secondary ring-surface-1",
2683
+ SIZE_CLASSES[size],
2684
+ RING_SIZE_CLASSES[size],
2685
+ OVERLAP_CLASSES[size]
2686
+ ),
2687
+ "aria-label": `\u8FD8\u6709 ${overflowCount} \u4EBA`,
2688
+ children: [
2689
+ "+",
2690
+ overflowCount
2691
+ ]
2692
+ }
2693
+ )
2694
+ ]
2695
+ }
2696
+ );
2697
+ }
2698
+ );
2699
+ AvatarGroup.displayName = "AvatarGroup";
2700
+
2701
+ // src/components/tooltip.tsx
2702
+ var import_react32 = require("react");
2703
+ var import_react_dom8 = require("react-dom");
2704
+ var import_ui_utils31 = require("@ug666/ui-utils");
2705
+ var import_jsx_runtime31 = require("react/jsx-runtime");
2706
+ var TooltipContext = (0, import_react32.createContext)(null);
2707
+ function assignRef4(ref, value) {
2708
+ if (typeof ref === "function") {
2709
+ ref(value);
2710
+ return;
2711
+ }
2712
+ if (ref) {
2713
+ ref.current = value;
2714
+ }
2715
+ }
2716
+ function useTooltipContext() {
2717
+ const ctx = (0, import_react32.useContext)(TooltipContext);
2718
+ if (!ctx) throw new Error("Tooltip \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Tooltip> \u5185\u4F7F\u7528");
2719
+ return ctx;
2720
+ }
2721
+ var Tooltip = (0, import_react32.forwardRef)(({ children, className }, ref) => {
2722
+ const [open, setOpen] = (0, import_react32.useState)(false);
2723
+ const triggerRef = (0, import_react32.useRef)(null);
2724
+ const delayRef = (0, import_react32.useRef)(null);
2725
+ (0, import_react32.useEffect)(() => {
2726
+ return () => {
2727
+ if (delayRef.current) {
2728
+ clearTimeout(delayRef.current);
2729
+ }
2730
+ };
2731
+ }, []);
2732
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(TooltipContext.Provider, { value: { open, setOpen, triggerRef, delayRef }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { ref, className: (0, import_ui_utils31.cn)("relative inline-flex", className), children }) });
2733
+ });
2734
+ var TooltipTrigger = (0, import_react32.forwardRef)(({ children, className }, ref) => {
2735
+ const { setOpen, triggerRef, delayRef } = useTooltipContext();
2736
+ const handleRef = (0, import_react32.useCallback)(
2737
+ (node) => {
2738
+ triggerRef.current = node;
2739
+ assignRef4(ref, node);
2740
+ },
2741
+ [ref, triggerRef]
2742
+ );
2743
+ function handleMouseEnter() {
2744
+ delayRef.current = setTimeout(() => setOpen(true), 200);
2745
+ }
2746
+ function handleMouseLeave() {
2747
+ if (delayRef.current) clearTimeout(delayRef.current);
2748
+ setOpen(false);
2749
+ }
2750
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2751
+ "span",
2752
+ {
2753
+ ref: handleRef,
2754
+ className: (0, import_ui_utils31.cn)("inline-flex", className),
2755
+ onMouseEnter: handleMouseEnter,
2756
+ onMouseLeave: handleMouseLeave,
2757
+ children
2758
+ }
2759
+ );
2760
+ });
2761
+ var arrowPositionClasses = {
2762
+ top: "after:absolute after:top-full after:left-1/2 after:-translate-x-1/2 after:border-4 after:border-transparent after:border-t-text-primary",
2763
+ bottom: "after:absolute after:bottom-full after:left-1/2 after:-translate-x-1/2 after:border-4 after:border-transparent after:border-b-text-primary",
2764
+ left: "after:absolute after:left-full after:top-1/2 after:-translate-y-1/2 after:border-4 after:border-transparent after:border-l-text-primary",
2765
+ right: "after:absolute after:right-full after:top-1/2 after:-translate-y-1/2 after:border-4 after:border-transparent after:border-r-text-primary"
2766
+ };
2767
+ var TooltipContent = (0, import_react32.forwardRef)(({ children, side = "top", className }, ref) => {
2768
+ const { open, triggerRef } = useTooltipContext();
2769
+ const contentRef = (0, import_react32.useRef)(null);
2770
+ const [pos, setPos] = (0, import_react32.useState)({ top: 0, left: 0 });
2771
+ const handleRef = (0, import_react32.useCallback)(
2772
+ (node) => {
2773
+ contentRef.current = node;
2774
+ assignRef4(ref, node);
2775
+ },
2776
+ [ref]
2777
+ );
2778
+ const updatePos = (0, import_react32.useCallback)(() => {
2779
+ if (!triggerRef.current || !contentRef.current) return;
2780
+ const rect = triggerRef.current.getBoundingClientRect();
2781
+ const cw = contentRef.current.offsetWidth;
2782
+ const ch = contentRef.current.offsetHeight;
2783
+ const gap = 8;
2784
+ let top = 0;
2785
+ let left = 0;
2786
+ if (side === "top") {
2787
+ top = rect.top + window.scrollY - ch - gap;
2788
+ left = rect.left + window.scrollX + rect.width / 2 - cw / 2;
2789
+ } else if (side === "bottom") {
2790
+ top = rect.bottom + window.scrollY + gap;
2791
+ left = rect.left + window.scrollX + rect.width / 2 - cw / 2;
2792
+ } else if (side === "left") {
2793
+ top = rect.top + window.scrollY + rect.height / 2 - ch / 2;
2794
+ left = rect.left + window.scrollX - cw - gap;
2795
+ } else {
2796
+ top = rect.top + window.scrollY + rect.height / 2 - ch / 2;
2797
+ left = rect.right + window.scrollX + gap;
2798
+ }
2799
+ setPos({ top, left });
2800
+ }, [side, triggerRef]);
2801
+ (0, import_react32.useEffect)(() => {
2802
+ if (open) updatePos();
2803
+ }, [open, updatePos]);
2804
+ if (!open) return null;
2805
+ return (0, import_react_dom8.createPortal)(
2806
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
2807
+ "div",
2808
+ {
2809
+ ref: handleRef,
2810
+ style: { top: pos.top, left: pos.left },
2811
+ className: (0, import_ui_utils31.cn)(
2812
+ "absolute z-50 rounded-md bg-text-primary px-2.5 py-1.5 text-xs text-surface-1 shadow-md",
2813
+ arrowPositionClasses[side],
2814
+ className
2815
+ ),
2816
+ children
2817
+ }
2818
+ ),
2819
+ document.body
2820
+ );
2821
+ });
2822
+ Tooltip.displayName = "Tooltip";
2823
+ TooltipTrigger.displayName = "TooltipTrigger";
2824
+ TooltipContent.displayName = "TooltipContent";
2825
+
2826
+ // src/components/alert.tsx
2827
+ var import_react33 = require("react");
2828
+ var import_lucide_react14 = require("lucide-react");
2829
+ var import_class_variance_authority9 = require("class-variance-authority");
2830
+ var import_ui_utils32 = require("@ug666/ui-utils");
2831
+ var import_jsx_runtime32 = require("react/jsx-runtime");
2832
+ var alertVariants = (0, import_class_variance_authority9.cva)(
2833
+ "relative flex gap-3 rounded-md border-l-4 p-4",
2834
+ {
2835
+ variants: {
2836
+ variant: {
2837
+ default: "border-l-primary bg-info-soft text-info-soft-fg",
2838
+ info: "border-l-info bg-info-soft text-info-soft-fg",
2839
+ success: "border-l-success bg-success-soft text-success-soft-fg",
2840
+ warning: "border-l-warning bg-warning-soft text-warning-soft-fg",
2841
+ destructive: "border-l-danger bg-danger-soft text-danger-soft-fg"
2842
+ }
2843
+ },
2844
+ defaultVariants: { variant: "default" }
2845
+ }
2846
+ );
2847
+ var iconMap = {
2848
+ default: import_lucide_react14.AlertCircle,
2849
+ info: import_lucide_react14.Info,
2850
+ success: import_lucide_react14.CheckCircle,
2851
+ warning: import_lucide_react14.AlertTriangle,
2852
+ destructive: import_lucide_react14.AlertCircle
2853
+ };
2854
+ var iconColorMap = {
2855
+ default: "text-info",
2856
+ info: "text-info",
2857
+ success: "text-success",
2858
+ warning: "text-warning",
2859
+ destructive: "text-danger"
2860
+ };
2861
+ var Alert = (0, import_react33.forwardRef)(
2862
+ ({ variant = "default", className, children, ...props }, ref) => {
2863
+ const Icon = iconMap[variant ?? "default"];
2864
+ const iconColor = iconColorMap[variant ?? "default"];
2865
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
2866
+ "div",
2867
+ {
2868
+ ref,
2869
+ role: "alert",
2870
+ className: (0, import_ui_utils32.cn)(alertVariants({ variant }), className),
2871
+ ...props,
2872
+ children: [
2873
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Icon, { size: 18, className: (0, import_ui_utils32.cn)("mt-0.5 shrink-0", iconColor) }),
2874
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex flex-col gap-0.5", children })
2875
+ ]
2876
+ }
2877
+ );
2878
+ }
2879
+ );
2880
+ var AlertTitle = (0, import_react33.forwardRef)(({ className, ...props }, ref) => {
2881
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { ref, className: (0, import_ui_utils32.cn)("text-sm font-semibold leading-5", className), ...props });
2882
+ });
2883
+ var AlertDescription = (0, import_react33.forwardRef)(({ className, ...props }, ref) => {
2884
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { ref, className: (0, import_ui_utils32.cn)("text-sm leading-5 opacity-90", className), ...props });
2885
+ });
2886
+ Alert.displayName = "Alert";
2887
+ AlertTitle.displayName = "AlertTitle";
2888
+ AlertDescription.displayName = "AlertDescription";
2889
+
2890
+ // src/components/breadcrumb.tsx
2891
+ var import_react34 = require("react");
2892
+ var import_lucide_react15 = require("lucide-react");
2893
+ var import_ui_utils33 = require("@ug666/ui-utils");
2894
+ var import_jsx_runtime33 = require("react/jsx-runtime");
2895
+ var Breadcrumb = (0, import_react34.forwardRef)(({ className, children, ...props }, ref) => {
2896
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("nav", { ref, "aria-label": "\u9762\u5305\u5C51\u5BFC\u822A", className: (0, import_ui_utils33.cn)(className), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ol", { className: "flex flex-wrap items-center gap-0 text-sm text-text-secondary", children }) });
2897
+ });
2898
+ var BreadcrumbItem = (0, import_react34.forwardRef)(({ className, ...props }, ref) => {
2899
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("li", { ref, className: (0, import_ui_utils33.cn)("flex items-center gap-1", className), ...props });
2900
+ });
2901
+ var BreadcrumbLink = (0, import_react34.forwardRef)(
2902
+ ({ current = false, className, children, href, ...props }, ref) => {
2903
+ if (current) {
2904
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { "aria-current": "page", className: (0, import_ui_utils33.cn)("font-medium text-text-primary", className), children });
2905
+ }
2906
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2907
+ "a",
2908
+ {
2909
+ ref,
2910
+ href,
2911
+ className: (0, import_ui_utils33.cn)("transition-colors hover:text-text-primary", className),
2912
+ ...props,
2913
+ children
2914
+ }
2915
+ );
2916
+ }
2917
+ );
2918
+ var BreadcrumbSeparator = (0, import_react34.forwardRef)(
2919
+ ({ className, children, ...props }, ref) => {
2920
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
2921
+ "li",
2922
+ {
2923
+ ref,
2924
+ role: "presentation",
2925
+ "aria-hidden": "true",
2926
+ className: (0, import_ui_utils33.cn)("text-text-tertiary", className),
2927
+ ...props,
2928
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react15.ChevronRight, { size: 14 })
2929
+ }
2930
+ );
2931
+ }
2932
+ );
2933
+ Breadcrumb.displayName = "Breadcrumb";
2934
+ BreadcrumbItem.displayName = "BreadcrumbItem";
2935
+ BreadcrumbLink.displayName = "BreadcrumbLink";
2936
+ BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
2937
+
2938
+ // src/components/switch.tsx
2939
+ var import_react35 = require("react");
2940
+ var import_ui_utils34 = require("@ug666/ui-utils");
2941
+ var import_jsx_runtime34 = require("react/jsx-runtime");
2942
+ var Switch = (0, import_react35.forwardRef)(
2943
+ ({
2944
+ checked,
2945
+ onCheckedChange,
2946
+ disabled = false,
2947
+ label,
2948
+ labelPlacement = "right",
2949
+ className,
2950
+ id,
2951
+ ...props
2952
+ }, ref) => {
2953
+ const generatedId = (0, import_react35.useId)();
2954
+ const switchId = id ?? generatedId;
2955
+ const track = /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2956
+ "button",
2957
+ {
2958
+ ref,
2959
+ id: switchId,
2960
+ type: "button",
2961
+ role: "switch",
2962
+ "aria-checked": checked,
2963
+ disabled,
2964
+ onClick: () => !disabled && onCheckedChange(!checked),
2965
+ className: (0, import_ui_utils34.cn)(
2966
+ "relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200",
2967
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2968
+ "disabled:cursor-not-allowed disabled:opacity-50",
2969
+ checked ? "bg-primary" : "bg-surface-3",
2970
+ className
2971
+ ),
2972
+ ...props,
2973
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
2974
+ "span",
2975
+ {
2976
+ className: (0, import_ui_utils34.cn)(
2977
+ "pointer-events-none block h-5 w-5 rounded-full bg-white shadow-sm ring-0 transition-transform duration-200",
2978
+ checked ? "translate-x-5" : "translate-x-0"
2979
+ )
2980
+ }
2981
+ )
2982
+ }
2983
+ );
2984
+ if (!label) return track;
2985
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
2986
+ "label",
2987
+ {
2988
+ htmlFor: switchId,
2989
+ className: (0, import_ui_utils34.cn)(
2990
+ "inline-flex items-center gap-2 cursor-pointer",
2991
+ disabled && "cursor-not-allowed opacity-50"
2992
+ ),
2993
+ children: [
2994
+ labelPlacement === "left" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-sm font-medium text-text-primary", children: label }),
2995
+ track,
2996
+ labelPlacement === "right" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-sm font-medium text-text-primary", children: label })
2997
+ ]
2998
+ }
2999
+ );
3000
+ }
3001
+ );
3002
+ Switch.displayName = "Switch";
3003
+
3004
+ // src/components/textarea.tsx
3005
+ var import_react36 = require("react");
3006
+ var import_ui_utils35 = require("@ug666/ui-utils");
3007
+ var import_jsx_runtime35 = require("react/jsx-runtime");
3008
+ var Textarea = (0, import_react36.forwardRef)(
3009
+ ({ className, label, error, helperText, id, rows = 3, ...props }, ref) => {
3010
+ const generatedId = (0, import_react36.useId)();
3011
+ const textareaId = id ?? generatedId;
3012
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col gap-1", children: [
3013
+ label && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("label", { htmlFor: textareaId, className: "text-sm font-medium text-text-primary", children: label }),
3014
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3015
+ "textarea",
3016
+ {
3017
+ ref,
3018
+ id: textareaId,
3019
+ rows,
3020
+ className: (0, import_ui_utils35.cn)(
3021
+ "w-full rounded-md border bg-surface-1 px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary",
3022
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1",
3023
+ "disabled:cursor-not-allowed disabled:opacity-50",
3024
+ "resize-y",
3025
+ error ? "border-danger focus-visible:ring-danger" : "border-border-strong focus-visible:ring-ring/30",
3026
+ className
3027
+ ),
3028
+ ...props
3029
+ }
3030
+ ),
3031
+ error && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-xs text-danger", children: error }),
3032
+ !error && helperText && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-xs text-text-secondary", children: helperText })
3033
+ ] });
3034
+ }
3035
+ );
3036
+ Textarea.displayName = "Textarea";
3037
+
3038
+ // src/components/skeleton.tsx
3039
+ var import_react37 = require("react");
3040
+ var import_class_variance_authority10 = require("class-variance-authority");
3041
+ var import_ui_utils36 = require("@ug666/ui-utils");
3042
+ var import_jsx_runtime36 = require("react/jsx-runtime");
3043
+ var skeletonVariants = (0, import_class_variance_authority10.cva)(
3044
+ "animate-pulse bg-surface-3",
3045
+ {
3046
+ variants: {
3047
+ variant: {
3048
+ text: "h-4 w-full rounded",
3049
+ circle: "rounded-full",
3050
+ rect: "rounded-md"
3051
+ }
3052
+ },
3053
+ defaultVariants: { variant: "rect" }
3054
+ }
3055
+ );
3056
+ var Skeleton = (0, import_react37.forwardRef)(({ variant, className, ...props }, ref) => {
3057
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { ref, className: (0, import_ui_utils36.cn)(skeletonVariants({ variant }), className), "aria-hidden": "true", ...props });
3058
+ });
3059
+ Skeleton.displayName = "Skeleton";
3060
+
3061
+ // src/components/progress.tsx
3062
+ var import_react38 = require("react");
3063
+ var import_ui_utils37 = require("@ug666/ui-utils");
3064
+ var import_jsx_runtime37 = require("react/jsx-runtime");
3065
+ var Progress = (0, import_react38.forwardRef)(({
3066
+ value,
3067
+ max = 100,
3068
+ showLabel = false,
3069
+ color = "bg-indigo-500",
3070
+ className,
3071
+ ...props
3072
+ }, ref) => {
3073
+ const clamped = Math.min(Math.max(value, 0), max);
3074
+ const percent = Math.round(clamped / max * 100);
3075
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { ref, className: (0, import_ui_utils37.cn)("flex items-center gap-3", className), ...props, children: [
3076
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3077
+ "div",
3078
+ {
3079
+ role: "progressbar",
3080
+ "aria-valuenow": clamped,
3081
+ "aria-valuemin": 0,
3082
+ "aria-valuemax": max,
3083
+ className: "h-2 w-full overflow-hidden rounded-full bg-surface-2",
3084
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3085
+ "div",
3086
+ {
3087
+ className: (0, import_ui_utils37.cn)("h-full rounded-full transition-all duration-500 ease-out", color),
3088
+ style: { width: `${percent}%` }
3089
+ }
3090
+ )
3091
+ }
3092
+ ),
3093
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "shrink-0 text-xs font-medium text-text-secondary tabular-nums w-9 text-right", children: [
3094
+ percent,
3095
+ "%"
3096
+ ] })
3097
+ ] });
3098
+ });
3099
+ Progress.displayName = "Progress";
3100
+
3101
+ // src/components/sheet.tsx
3102
+ var import_react39 = require("react");
3103
+ var import_react_dom9 = require("react-dom");
3104
+ var import_lucide_react16 = require("lucide-react");
3105
+ var import_ui_utils38 = require("@ug666/ui-utils");
3106
+ var import_jsx_runtime38 = require("react/jsx-runtime");
3107
+ var Sheet = (0, import_react39.forwardRef)(({ open, onClose, side = "right", title, children, className }, ref) => {
3108
+ useEscapeKey(open, onClose);
3109
+ if (!open) return null;
3110
+ return (0, import_react_dom9.createPortal)(
3111
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "fixed inset-0 z-50 flex", role: "dialog", "aria-modal": "true", children: [
3112
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3113
+ "div",
3114
+ {
3115
+ className: "absolute inset-0 bg-overlay transition-opacity",
3116
+ onClick: onClose,
3117
+ "aria-hidden": "true"
3118
+ }
3119
+ ),
3120
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
3121
+ "div",
3122
+ {
3123
+ ref,
3124
+ className: (0, import_ui_utils38.cn)(
3125
+ "relative flex h-full w-80 max-w-full flex-col bg-surface-1 shadow-xl",
3126
+ "transition-transform duration-300 ease-in-out",
3127
+ side === "right" ? "ml-auto translate-x-0" : "mr-auto translate-x-0",
3128
+ className
3129
+ ),
3130
+ children: [
3131
+ title && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center justify-between border-b border-border-base px-5 py-4", children: [
3132
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("h2", { className: "text-base font-semibold text-text-primary", children: title }),
3133
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3134
+ "button",
3135
+ {
3136
+ type: "button",
3137
+ onClick: onClose,
3138
+ className: "rounded-md p-1 text-text-tertiary hover:bg-surface-3 hover:text-text-secondary transition-colors",
3139
+ "aria-label": "\u5173\u95ED",
3140
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react16.X, { size: 18 })
3141
+ }
3142
+ )
3143
+ ] }),
3144
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex-1 overflow-y-auto px-5 py-4", children })
3145
+ ]
3146
+ }
3147
+ )
3148
+ ] }),
3149
+ document.body
3150
+ );
3151
+ });
3152
+ Sheet.displayName = "Sheet";
3153
+
3154
+ // src/components/empty-state.tsx
3155
+ var import_react40 = require("react");
3156
+ var import_ui_utils39 = require("@ug666/ui-utils");
3157
+ var import_jsx_runtime39 = require("react/jsx-runtime");
3158
+ var EmptyState = (0, import_react40.forwardRef)(
3159
+ ({ icon: Icon, title, description, action, className, ...props }, ref) => {
3160
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
3161
+ "div",
3162
+ {
3163
+ ref,
3164
+ className: (0, import_ui_utils39.cn)(
3165
+ "flex flex-col items-center justify-center gap-3 py-16 text-center",
3166
+ className
3167
+ ),
3168
+ ...props,
3169
+ children: [
3170
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-surface-2", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Icon, { size: 28, className: "text-text-tertiary" }) }),
3171
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-1", children: [
3172
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-base font-semibold text-text-primary", children: title }),
3173
+ description && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "max-w-xs text-sm text-text-secondary", children: description })
3174
+ ] }),
3175
+ action && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "mt-1", children: action })
3176
+ ]
3177
+ }
3178
+ );
3179
+ }
3180
+ );
3181
+ EmptyState.displayName = "EmptyState";
3182
+
3183
+ // src/components/separator.tsx
3184
+ var import_react41 = require("react");
3185
+ var import_ui_utils40 = require("@ug666/ui-utils");
3186
+ var import_jsx_runtime40 = require("react/jsx-runtime");
3187
+ var ORIENTATION_CLASSES = {
3188
+ horizontal: "h-px w-full bg-border-base",
3189
+ vertical: "w-px h-full bg-border-base"
3190
+ };
3191
+ var Separator = (0, import_react41.forwardRef)(
3192
+ ({ orientation = "horizontal", className, ...props }, ref) => {
3193
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3194
+ "div",
3195
+ {
3196
+ ref,
3197
+ role: "separator",
3198
+ "aria-orientation": orientation,
3199
+ className: (0, import_ui_utils40.cn)(ORIENTATION_CLASSES[orientation], className),
3200
+ ...props
3201
+ }
3202
+ );
3203
+ }
3204
+ );
3205
+ Separator.displayName = "Separator";
3206
+
3207
+ // src/components/descriptions.tsx
3208
+ var import_react42 = require("react");
3209
+ var import_ui_utils41 = require("@ug666/ui-utils");
3210
+ var import_jsx_runtime41 = require("react/jsx-runtime");
3211
+ var SIZE_LABEL_CLASSES = {
3212
+ sm: "text-xs py-1 px-2",
3213
+ default: "text-sm py-2 px-3",
3214
+ lg: "text-base py-3 px-4"
3215
+ };
3216
+ var SIZE_VALUE_CLASSES = {
3217
+ sm: "text-xs py-1 px-2",
3218
+ default: "text-sm py-2 px-3",
3219
+ lg: "text-base py-3 px-4"
3220
+ };
3221
+ var DescriptionsItem = (0, import_react42.forwardRef)(
3222
+ ({ label, children, className, span: _span, ...props }, ref) => {
3223
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ref, className, ...props, children: [
3224
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "text-text-secondary", children: label }),
3225
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "text-text-primary", children })
3226
+ ] });
3227
+ }
3228
+ );
3229
+ DescriptionsItem.displayName = "DescriptionsItem";
3230
+ var Descriptions = (0, import_react42.forwardRef)(
3231
+ ({ column = 2, bordered = false, size = "default", title, className, children, ...props }, ref) => {
3232
+ const items = import_react42.Children.toArray(children).filter(
3233
+ (child) => (0, import_react42.isValidElement)(child) && child.type.displayName === "DescriptionsItem"
3234
+ );
3235
+ if (bordered) {
3236
+ const rows = [];
3237
+ let currentRow = [];
3238
+ let currentColCount = 0;
3239
+ for (const item of items) {
3240
+ const span = item.props.span ?? 1;
3241
+ if (currentColCount + span > column) {
3242
+ rows.push(currentRow);
3243
+ currentRow = [];
3244
+ currentColCount = 0;
3245
+ }
3246
+ currentRow.push({ label: item.props.label, value: item.props.children, span });
3247
+ currentColCount += span;
3248
+ }
3249
+ if (currentRow.length > 0) rows.push(currentRow);
3250
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ref, className: (0, import_ui_utils41.cn)("w-full", className), ...props, children: [
3251
+ title && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "mb-3 text-base font-semibold text-text-primary", children: title }),
3252
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("table", { className: "w-full border-collapse border border-border-base", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("tbody", { children: rows.map((row, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("tr", { children: row.map((cell, cellIdx) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
3253
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3254
+ "td",
3255
+ {
3256
+ className: (0, import_ui_utils41.cn)(
3257
+ "border border-border-base bg-surface-2 font-medium text-text-secondary",
3258
+ SIZE_LABEL_CLASSES[size]
3259
+ ),
3260
+ style: { width: `${1 / (column * 2) * 100}%` },
3261
+ children: cell.label
3262
+ },
3263
+ `label-${cellIdx}`
3264
+ ),
3265
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3266
+ "td",
3267
+ {
3268
+ className: (0, import_ui_utils41.cn)(
3269
+ "border border-border-base text-text-primary",
3270
+ SIZE_VALUE_CLASSES[size]
3271
+ ),
3272
+ colSpan: cell.span > 1 ? cell.span * 2 - 1 : 1,
3273
+ children: cell.value
3274
+ },
3275
+ `value-${cellIdx}`
3276
+ )
3277
+ ] })) }, rowIdx)) }) })
3278
+ ] });
3279
+ }
3280
+ const GRID_COLS = {
3281
+ 1: "grid-cols-1",
3282
+ 2: "grid-cols-2",
3283
+ 3: "grid-cols-3",
3284
+ 4: "grid-cols-4"
3285
+ };
3286
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ref, className: (0, import_ui_utils41.cn)("w-full", className), ...props, children: [
3287
+ title && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "mb-3 text-base font-semibold text-text-primary", children: title }),
3288
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: (0, import_ui_utils41.cn)("grid gap-x-6 gap-y-4", GRID_COLS[column]), children: items.map((item, idx) => {
3289
+ const span = item.props.span ?? 1;
3290
+ const colSpanClass = span === 2 ? "col-span-2" : span === 3 ? "col-span-3" : span === 4 ? "col-span-4" : "";
3291
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: (0, import_ui_utils41.cn)("flex flex-col gap-0.5", colSpanClass, item.props.className), children: [
3292
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: (0, import_ui_utils41.cn)("font-medium text-text-secondary", size === "sm" ? "text-xs" : size === "lg" ? "text-sm" : "text-xs"), children: item.props.label }),
3293
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: (0, import_ui_utils41.cn)("text-text-primary", size === "sm" ? "text-sm" : size === "lg" ? "text-base" : "text-sm"), children: item.props.children })
3294
+ ] }, idx);
3295
+ }) })
3296
+ ] });
3297
+ }
3298
+ );
3299
+ Descriptions.displayName = "Descriptions";
3300
+
3301
+ // src/components/statistic.tsx
3302
+ var import_react43 = require("react");
3303
+ var import_lucide_react17 = require("lucide-react");
3304
+ var import_ui_utils42 = require("@ug666/ui-utils");
3305
+ var import_jsx_runtime42 = require("react/jsx-runtime");
3306
+ var SIZE_TITLE_CLASSES = {
3307
+ sm: "text-xs",
3308
+ default: "text-sm",
3309
+ lg: "text-base"
3310
+ };
3311
+ var SIZE_VALUE_CLASSES2 = {
3312
+ sm: "text-2xl",
3313
+ default: "text-3xl",
3314
+ lg: "text-4xl"
3315
+ };
3316
+ var SIZE_SUFFIX_CLASSES = {
3317
+ sm: "text-xs",
3318
+ default: "text-sm",
3319
+ lg: "text-base"
3320
+ };
3321
+ var TREND_ICON_COLOR = {
3322
+ up: "text-success",
3323
+ down: "text-danger",
3324
+ flat: "text-text-secondary"
3325
+ };
3326
+ var TREND_TEXT_COLOR = {
3327
+ up: "text-success",
3328
+ down: "text-danger",
3329
+ flat: "text-text-secondary"
3330
+ };
3331
+ function formatValue(value, precision) {
3332
+ if (typeof value === "string") return value;
3333
+ return new Intl.NumberFormat("zh-CN", {
3334
+ minimumFractionDigits: precision ?? 0,
3335
+ maximumFractionDigits: precision ?? 0
3336
+ }).format(value);
3337
+ }
3338
+ var Statistic = (0, import_react43.forwardRef)(
3339
+ ({ title, value, precision, prefix, suffix, trend, change, size = "default", className, ...props }, ref) => {
3340
+ const TrendIcon = trend === "up" ? import_lucide_react17.TrendingUp : trend === "down" ? import_lucide_react17.TrendingDown : trend === "flat" ? import_lucide_react17.Minus : null;
3341
+ const iconSize = size === "sm" ? 14 : size === "lg" ? 18 : 16;
3342
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { ref, className: (0, import_ui_utils42.cn)("flex flex-col gap-1", className), ...props, children: [
3343
+ title && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: (0, import_ui_utils42.cn)("font-medium text-text-secondary", SIZE_TITLE_CLASSES[size]), children: title }),
3344
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-baseline gap-1", children: [
3345
+ prefix && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: (0, import_ui_utils42.cn)("text-text-primary", SIZE_SUFFIX_CLASSES[size]), children: prefix }),
3346
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: (0, import_ui_utils42.cn)("font-bold tabular-nums text-text-primary", SIZE_VALUE_CLASSES2[size]), children: formatValue(value, precision) }),
3347
+ suffix && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: (0, import_ui_utils42.cn)("text-text-secondary", SIZE_SUFFIX_CLASSES[size]), children: suffix })
3348
+ ] }),
3349
+ (trend || change) && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1", children: [
3350
+ TrendIcon && trend && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(TrendIcon, { size: iconSize, className: TREND_ICON_COLOR[trend] }),
3351
+ change && trend && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: (0, import_ui_utils42.cn)("text-xs font-medium", TREND_TEXT_COLOR[trend]), children: change })
3352
+ ] })
3353
+ ] });
3354
+ }
3355
+ );
3356
+ Statistic.displayName = "Statistic";
3357
+
3358
+ // src/theme.ts
3359
+ var theme = {
3360
+ colors: {
3361
+ primary: { DEFAULT: "#6366f1", hover: "#4f46e5", light: "#eef2ff" },
3362
+ secondary: { DEFAULT: "#64748b", hover: "#475569", light: "#f1f5f9" },
3363
+ destructive: { DEFAULT: "#ef4444", hover: "#dc2626", light: "#fef2f2" },
3364
+ success: { DEFAULT: "#22c55e", hover: "#16a34a", light: "#f0fdf4" },
3365
+ warning: { DEFAULT: "#f59e0b", hover: "#d97706", light: "#fffbeb" },
3366
+ background: "#ffffff",
3367
+ foreground: "#0f172a",
3368
+ muted: "#f1f5f9",
3369
+ border: "#e2e8f0",
3370
+ ring: "#6366f1"
3371
+ },
3372
+ radius: { sm: "0.375rem", md: "0.5rem", lg: "0.75rem", full: "9999px" },
3373
+ fontFamily: { sans: "system-ui, -apple-system, sans-serif", mono: "ui-monospace, monospace" }
3374
+ };
3375
+
3376
+ // src/index.ts
3377
+ var import_ui_utils43 = require("@ug666/ui-utils");
3378
+
3379
+ // src/hooks/use-debounce.ts
3380
+ var import_react44 = require("react");
3381
+ function useDebounce(value, delay = 300) {
3382
+ const [debounced, setDebounced] = (0, import_react44.useState)(value);
3383
+ (0, import_react44.useEffect)(() => {
3384
+ const timer = setTimeout(() => setDebounced(value), delay);
3385
+ return () => clearTimeout(timer);
3386
+ }, [value, delay]);
3387
+ return debounced;
3388
+ }
3389
+
3390
+ // src/hooks/use-local-storage.ts
3391
+ var import_react45 = require("react");
3392
+ function useLocalStorage(key, initialValue) {
3393
+ const [storedValue, setStoredValue] = (0, import_react45.useState)(() => {
3394
+ if (typeof window === "undefined") return initialValue;
3395
+ try {
3396
+ const item = window.localStorage.getItem(key);
3397
+ return item ? JSON.parse(item) : initialValue;
3398
+ } catch {
3399
+ return initialValue;
3400
+ }
3401
+ });
3402
+ const setValue = (0, import_react45.useCallback)((value) => {
3403
+ setStoredValue((prev) => {
3404
+ const next = value instanceof Function ? value(prev) : value;
3405
+ if (typeof window !== "undefined") {
3406
+ window.localStorage.setItem(key, JSON.stringify(next));
3407
+ }
3408
+ return next;
3409
+ });
3410
+ }, [key]);
3411
+ const removeValue = (0, import_react45.useCallback)(() => {
3412
+ setStoredValue(initialValue);
3413
+ if (typeof window !== "undefined") {
3414
+ window.localStorage.removeItem(key);
3415
+ }
3416
+ }, [key, initialValue]);
3417
+ return [storedValue, setValue, removeValue];
3418
+ }
3419
+
3420
+ // src/hooks/use-media-query.ts
3421
+ var import_react46 = require("react");
3422
+ function useMediaQuery(query) {
3423
+ const [matches, setMatches] = (0, import_react46.useState)(() => {
3424
+ if (typeof window === "undefined") return false;
3425
+ return window.matchMedia(query).matches;
3426
+ });
3427
+ (0, import_react46.useEffect)(() => {
3428
+ if (typeof window === "undefined") return;
3429
+ const mediaQueryList = window.matchMedia(query);
3430
+ setMatches(mediaQueryList.matches);
3431
+ const handleChange = (event) => {
3432
+ setMatches(event.matches);
3433
+ };
3434
+ mediaQueryList.addEventListener("change", handleChange);
3435
+ return () => mediaQueryList.removeEventListener("change", handleChange);
3436
+ }, [query]);
3437
+ return matches;
3438
+ }
3439
+
3440
+ // src/hooks/use-click-outside.ts
3441
+ var import_react47 = require("react");
3442
+ function useClickOutside(ref, handler) {
3443
+ (0, import_react47.useEffect)(() => {
3444
+ const handleMouseDown = (event) => {
3445
+ if (ref.current && !ref.current.contains(event.target)) {
3446
+ handler();
3447
+ }
3448
+ };
3449
+ const handleTouchStart = (event) => {
3450
+ if (ref.current && !ref.current.contains(event.target)) {
3451
+ handler();
3452
+ }
3453
+ };
3454
+ document.addEventListener("mousedown", handleMouseDown);
3455
+ document.addEventListener("touchstart", handleTouchStart);
3456
+ return () => {
3457
+ document.removeEventListener("mousedown", handleMouseDown);
3458
+ document.removeEventListener("touchstart", handleTouchStart);
3459
+ };
3460
+ }, [ref, handler]);
3461
+ }
3462
+
3463
+ // src/hooks/use-copy-to-clipboard.ts
3464
+ var import_react48 = require("react");
3465
+ function useCopyToClipboard() {
3466
+ const [copied, setCopied] = (0, import_react48.useState)(false);
3467
+ const timerRef = (0, import_react48.useRef)(null);
3468
+ (0, import_react48.useEffect)(() => {
3469
+ return () => {
3470
+ if (timerRef.current) {
3471
+ clearTimeout(timerRef.current);
3472
+ }
3473
+ };
3474
+ }, []);
3475
+ const copy = (0, import_react48.useCallback)(async (text) => {
3476
+ if (typeof navigator === "undefined" || !navigator.clipboard) {
3477
+ console.error("\u526A\u8D34\u677F API \u4E0D\u53EF\u7528");
3478
+ return;
3479
+ }
3480
+ try {
3481
+ await navigator.clipboard.writeText(text);
3482
+ setCopied(true);
3483
+ if (timerRef.current) {
3484
+ clearTimeout(timerRef.current);
3485
+ }
3486
+ timerRef.current = setTimeout(() => setCopied(false), 2e3);
3487
+ } catch (error) {
3488
+ console.error("\u590D\u5236\u5230\u526A\u8D34\u677F\u5931\u8D25:", error);
3489
+ }
3490
+ }, []);
3491
+ return { copied, copy };
3492
+ }
3493
+
3494
+ // src/hooks/use-toggle.ts
3495
+ var import_react49 = require("react");
3496
+ function useToggle(initial = false) {
3497
+ const [value, setValue] = (0, import_react49.useState)(initial);
3498
+ const toggle = (0, import_react49.useCallback)(() => {
3499
+ setValue((prev) => !prev);
3500
+ }, []);
3501
+ return [value, toggle, setValue];
3502
+ }
3503
+
3504
+ // src/hooks/use-pagination.ts
3505
+ var import_react50 = require("react");
3506
+ function usePagination({
3507
+ total,
3508
+ pageSize = 10,
3509
+ initialPage = 1
3510
+ }) {
3511
+ const totalPages = (0, import_react50.useMemo)(
3512
+ () => Math.max(1, Math.ceil(total / pageSize)),
3513
+ [total, pageSize]
3514
+ );
3515
+ const [page, setPageState] = (0, import_react50.useState)(
3516
+ () => Math.min(Math.max(1, initialPage), Math.max(1, Math.ceil(total / pageSize)))
3517
+ );
3518
+ (0, import_react50.useEffect)(() => {
3519
+ setPageState((prev) => Math.min(prev, totalPages));
3520
+ }, [totalPages]);
3521
+ const setPage = (0, import_react50.useCallback)(
3522
+ (p) => {
3523
+ setPageState(Math.min(Math.max(1, p), totalPages));
3524
+ },
3525
+ [totalPages]
3526
+ );
3527
+ const nextPage = (0, import_react50.useCallback)(() => {
3528
+ setPageState((prev) => Math.min(prev + 1, totalPages));
3529
+ }, [totalPages]);
3530
+ const prevPage = (0, import_react50.useCallback)(() => {
3531
+ setPageState((prev) => Math.max(prev - 1, 1));
3532
+ }, []);
3533
+ const startIndex = (page - 1) * pageSize;
3534
+ const endIndex = Math.min(startIndex + pageSize, total);
3535
+ return {
3536
+ page,
3537
+ totalPages,
3538
+ setPage,
3539
+ nextPage,
3540
+ prevPage,
3541
+ hasNext: page < totalPages,
3542
+ hasPrev: page > 1,
3543
+ startIndex,
3544
+ endIndex
3545
+ };
3546
+ }
3547
+
3548
+ // src/hooks/use-form.ts
3549
+ var import_react51 = require("react");
3550
+ function useForm(initialValues) {
3551
+ const [values, setValues] = (0, import_react51.useState)(initialValues);
3552
+ const [errors, setErrors] = (0, import_react51.useState)({});
3553
+ const isDirty = (0, import_react51.useMemo)(
3554
+ () => Object.keys(initialValues).some(
3555
+ (key) => values[key] !== initialValues[key]
3556
+ ),
3557
+ [values, initialValues]
3558
+ );
3559
+ const handleChange = (0, import_react51.useCallback)((name, value) => {
3560
+ setValues((prev) => ({ ...prev, [name]: value }));
3561
+ setErrors((prev) => {
3562
+ if (!prev[name]) return prev;
3563
+ const next = { ...prev };
3564
+ delete next[name];
3565
+ return next;
3566
+ });
3567
+ }, []);
3568
+ const setError = (0, import_react51.useCallback)((name, message) => {
3569
+ setErrors((prev) => ({ ...prev, [name]: message }));
3570
+ }, []);
3571
+ const clearErrors = (0, import_react51.useCallback)(() => {
3572
+ setErrors({});
3573
+ }, []);
3574
+ const reset = (0, import_react51.useCallback)(() => {
3575
+ setValues(initialValues);
3576
+ setErrors({});
3577
+ }, [initialValues]);
3578
+ return { values, errors, handleChange, setError, clearErrors, reset, isDirty };
3579
+ }
3580
+
3581
+ // src/hooks/use-mounted.ts
3582
+ var import_react52 = require("react");
3583
+ function useMounted() {
3584
+ const [mounted, setMounted] = (0, import_react52.useState)(false);
3585
+ (0, import_react52.useEffect)(() => {
3586
+ setMounted(true);
3587
+ }, []);
3588
+ return mounted;
3589
+ }
3590
+
3591
+ // src/hooks/use-interval.ts
3592
+ var import_react53 = require("react");
3593
+ function useInterval(callback, delay) {
3594
+ const savedCallback = (0, import_react53.useRef)(callback);
3595
+ (0, import_react53.useEffect)(() => {
3596
+ savedCallback.current = callback;
3597
+ }, [callback]);
3598
+ (0, import_react53.useEffect)(() => {
3599
+ if (delay === null) return;
3600
+ const id = setInterval(() => savedCallback.current(), delay);
3601
+ return () => clearInterval(id);
3602
+ }, [delay]);
3603
+ }
3604
+
3605
+ // src/hooks/use-timeout.ts
3606
+ var import_react54 = require("react");
3607
+ function useTimeout(callback, delay) {
3608
+ const savedCallback = (0, import_react54.useRef)(callback);
3609
+ (0, import_react54.useEffect)(() => {
3610
+ savedCallback.current = callback;
3611
+ }, [callback]);
3612
+ (0, import_react54.useEffect)(() => {
3613
+ if (delay === null) return;
3614
+ const id = setTimeout(() => savedCallback.current(), delay);
3615
+ return () => clearTimeout(id);
3616
+ }, [delay]);
3617
+ }
3618
+
3619
+ // src/hooks/use-hotkeys.ts
3620
+ var import_react55 = require("react");
3621
+ function parseHotkey(keys) {
3622
+ const parts = keys.toLowerCase().split("+").map((s) => s.trim());
3623
+ const ctrl = parts.includes("ctrl");
3624
+ const meta = parts.includes("cmd") || parts.includes("meta");
3625
+ const alt = parts.includes("alt");
3626
+ const shift = parts.includes("shift");
3627
+ const key = parts.find(
3628
+ (p) => !["ctrl", "cmd", "meta", "alt", "shift"].includes(p)
3629
+ ) ?? "";
3630
+ return { ctrl, meta, alt, shift, key };
3631
+ }
3632
+ function useHotkeys(keys, callback, options = {}) {
3633
+ const { preventDefault = false, target = null } = options;
3634
+ const savedCallback = (0, import_react55.useRef)(callback);
3635
+ (0, import_react55.useEffect)(() => {
3636
+ savedCallback.current = callback;
3637
+ }, [callback]);
3638
+ (0, import_react55.useEffect)(() => {
3639
+ const parsed = parseHotkey(keys);
3640
+ const eventTarget = target ?? window;
3641
+ function handler(event) {
3642
+ const eventKey = event.key.toLowerCase();
3643
+ const match = eventKey === parsed.key && event.ctrlKey === parsed.ctrl && event.metaKey === parsed.meta && event.altKey === parsed.alt && event.shiftKey === parsed.shift;
3644
+ if (match) {
3645
+ if (preventDefault) event.preventDefault();
3646
+ savedCallback.current(event);
3647
+ }
3648
+ }
3649
+ eventTarget.addEventListener("keydown", handler);
3650
+ return () => {
3651
+ eventTarget.removeEventListener("keydown", handler);
3652
+ };
3653
+ }, [keys, preventDefault, target]);
3654
+ }
3655
+
3656
+ // src/hooks/use-event-listener.ts
3657
+ var import_react56 = require("react");
3658
+ function useEventListener(event, handler, target) {
3659
+ const savedHandler = (0, import_react56.useRef)(handler);
3660
+ (0, import_react56.useEffect)(() => {
3661
+ savedHandler.current = handler;
3662
+ }, [handler]);
3663
+ (0, import_react56.useEffect)(() => {
3664
+ if (target === null) return;
3665
+ const eventTarget = target ?? window;
3666
+ function listener(event2) {
3667
+ savedHandler.current(event2);
3668
+ }
3669
+ eventTarget.addEventListener(event, listener);
3670
+ return () => {
3671
+ eventTarget.removeEventListener(event, listener);
3672
+ };
3673
+ }, [event, target]);
3674
+ }
3675
+ // Annotate the CommonJS export names for ESM import in node:
3676
+ 0 && (module.exports = {
3677
+ Accordion,
3678
+ AccordionContent,
3679
+ AccordionItem,
3680
+ AccordionTrigger,
3681
+ Alert,
3682
+ AlertDescription,
3683
+ AlertTitle,
3684
+ Avatar,
3685
+ AvatarFallback,
3686
+ AvatarGroup,
3687
+ AvatarImage,
3688
+ Badge,
3689
+ Breadcrumb,
3690
+ BreadcrumbItem,
3691
+ BreadcrumbLink,
3692
+ BreadcrumbSeparator,
3693
+ Button,
3694
+ Card,
3695
+ CardContent,
3696
+ CardDescription,
3697
+ CardFooter,
3698
+ CardHeader,
3699
+ CardTitle,
3700
+ Checkbox,
3701
+ ContextMenu,
3702
+ ContextMenuContent,
3703
+ ContextMenuItem,
3704
+ ContextMenuSeparator,
3705
+ ContextMenuTrigger,
3706
+ Descriptions,
3707
+ DescriptionsItem,
3708
+ Dialog,
3709
+ Drawer,
3710
+ DrawerClose,
3711
+ DrawerContent,
3712
+ DrawerDescription,
3713
+ DrawerFooter,
3714
+ DrawerHeader,
3715
+ DrawerTitle,
3716
+ DropdownContent,
3717
+ DropdownItem,
3718
+ DropdownMenu,
3719
+ DropdownSeparator,
3720
+ DropdownTrigger,
3721
+ EmptyState,
3722
+ Form,
3723
+ FormControl,
3724
+ FormDescription,
3725
+ FormField,
3726
+ FormItem,
3727
+ FormLabel,
3728
+ FormMessage,
3729
+ Input,
3730
+ Label,
3731
+ Modal,
3732
+ ModalCloseButton,
3733
+ ModalContent,
3734
+ ModalFooter,
3735
+ ModalHeader,
3736
+ ModalTitle,
3737
+ NavigationMenu,
3738
+ NavigationMenuContent,
3739
+ NavigationMenuItem,
3740
+ NavigationMenuLink,
3741
+ NavigationMenuTrigger,
3742
+ NumberInput,
3743
+ OTPInput,
3744
+ Pagination,
3745
+ Popover,
3746
+ PopoverContent,
3747
+ PopoverTrigger,
3748
+ Progress,
3749
+ Radio,
3750
+ RadioGroup,
3751
+ Select,
3752
+ Separator,
3753
+ Sheet,
3754
+ Sidebar,
3755
+ Skeleton,
3756
+ Slider,
3757
+ Spinner,
3758
+ Statistic,
3759
+ Steps,
3760
+ Switch,
3761
+ Table,
3762
+ TableBody,
3763
+ TableCell,
3764
+ TableHead,
3765
+ TableHeader,
3766
+ TableRow,
3767
+ Tabs,
3768
+ TabsContent,
3769
+ TabsList,
3770
+ TabsTrigger,
3771
+ Tag,
3772
+ Textarea,
3773
+ Toaster,
3774
+ Tooltip,
3775
+ TooltipContent,
3776
+ TooltipTrigger,
3777
+ badgeVariants,
3778
+ buttonVariants,
3779
+ checkboxVariants,
3780
+ cn,
3781
+ numberInputVariants,
3782
+ tagVariants,
3783
+ theme,
3784
+ toast,
3785
+ useClickOutside,
3786
+ useCopyToClipboard,
3787
+ useDebounce,
3788
+ useEventListener,
3789
+ useForm,
3790
+ useHotkeys,
3791
+ useInterval,
3792
+ useLocalStorage,
3793
+ useMediaQuery,
3794
+ useMounted,
3795
+ usePagination,
3796
+ useTimeout,
3797
+ useToggle
3798
+ });
3799
+ //# sourceMappingURL=index.cjs.map