@ug666/ui-react 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/blocks/index.cjs +238 -0
  2. package/dist/blocks/index.cjs.map +1 -0
  3. package/dist/blocks/index.d.cts +86 -0
  4. package/dist/blocks/index.d.ts +86 -0
  5. package/dist/blocks/index.js +153 -0
  6. package/dist/blocks/index.js.map +1 -0
  7. package/dist/button-CaLZig8j.d.cts +22 -0
  8. package/dist/button-CaLZig8j.d.ts +22 -0
  9. package/dist/chunk-2IVRUJKO.js +377 -0
  10. package/dist/chunk-2IVRUJKO.js.map +1 -0
  11. package/dist/chunk-73WQAE3E.js +3003 -0
  12. package/dist/chunk-73WQAE3E.js.map +1 -0
  13. package/dist/chunk-RUDEZA5Q.js +62 -0
  14. package/dist/chunk-RUDEZA5Q.js.map +1 -0
  15. package/dist/chunk-S45GP6IB.js +254 -0
  16. package/dist/chunk-S45GP6IB.js.map +1 -0
  17. package/dist/components/index.cjs +3993 -0
  18. package/dist/components/index.cjs.map +1 -0
  19. package/dist/components/index.d.cts +1097 -0
  20. package/dist/components/index.d.ts +1097 -0
  21. package/dist/components/index.js +330 -0
  22. package/dist/components/index.js.map +1 -0
  23. package/dist/hooks/index.cjs +1 -0
  24. package/dist/hooks/index.cjs.map +1 -1
  25. package/dist/hooks/index.js +1 -0
  26. package/dist/index.cjs +1410 -710
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +274 -1340
  29. package/dist/index.d.ts +274 -1340
  30. package/dist/index.js +385 -3229
  31. package/dist/index.js.map +1 -1
  32. package/dist/labs/index.cjs +34 -0
  33. package/dist/labs/index.cjs.map +1 -0
  34. package/dist/labs/index.d.cts +12 -0
  35. package/dist/labs/index.d.ts +12 -0
  36. package/dist/labs/index.js +9 -0
  37. package/dist/labs/index.js.map +1 -0
  38. package/dist/patterns/index.cjs +758 -0
  39. package/dist/patterns/index.cjs.map +1 -0
  40. package/dist/patterns/index.d.cts +158 -0
  41. package/dist/patterns/index.d.ts +158 -0
  42. package/dist/patterns/index.js +320 -0
  43. package/dist/patterns/index.js.map +1 -0
  44. package/dist/primitives/index.cjs +384 -0
  45. package/dist/primitives/index.cjs.map +1 -0
  46. package/dist/primitives/index.d.cts +137 -0
  47. package/dist/primitives/index.d.ts +137 -0
  48. package/dist/primitives/index.js +56 -0
  49. package/dist/primitives/index.js.map +1 -0
  50. package/dist/sidebar-vl00Z2o-.d.cts +93 -0
  51. package/dist/sidebar-vl00Z2o-.d.ts +93 -0
  52. package/dist/styles.css +2499 -0
  53. package/dist/tokens.css +86 -9
  54. package/package.json +36 -6
package/dist/index.js CHANGED
@@ -1,3 +1,89 @@
1
+ "use client";
2
+ import {
3
+ Accordion,
4
+ AccordionContent,
5
+ AccordionItem,
6
+ AccordionTrigger,
7
+ Alert,
8
+ AlertDescription,
9
+ AlertTitle,
10
+ Avatar,
11
+ AvatarFallback,
12
+ AvatarGroup,
13
+ AvatarImage,
14
+ Breadcrumb,
15
+ BreadcrumbItem,
16
+ BreadcrumbLink,
17
+ BreadcrumbSeparator,
18
+ Checkbox,
19
+ ContextMenu,
20
+ ContextMenuContent,
21
+ ContextMenuItem,
22
+ ContextMenuSeparator,
23
+ ContextMenuTrigger,
24
+ Descriptions,
25
+ DescriptionsItem,
26
+ Dialog,
27
+ Drawer,
28
+ DrawerClose,
29
+ DrawerContent,
30
+ DrawerDescription,
31
+ DrawerFooter,
32
+ DrawerHeader,
33
+ DrawerTitle,
34
+ DropdownContent,
35
+ DropdownItem,
36
+ DropdownMenu,
37
+ DropdownSeparator,
38
+ DropdownTrigger,
39
+ EmptyState,
40
+ Form,
41
+ FormControl,
42
+ FormDescription,
43
+ FormField,
44
+ FormItem,
45
+ FormLabel,
46
+ FormMessage,
47
+ NavigationMenu,
48
+ NavigationMenuContent,
49
+ NavigationMenuItem,
50
+ NavigationMenuLink,
51
+ NavigationMenuTrigger,
52
+ NumberInput,
53
+ OTPInput,
54
+ Pagination,
55
+ Popover,
56
+ PopoverContent,
57
+ PopoverTrigger,
58
+ Progress,
59
+ Radio,
60
+ RadioGroup,
61
+ Select,
62
+ Sheet,
63
+ Skeleton,
64
+ Slider,
65
+ Statistic,
66
+ Steps,
67
+ Switch,
68
+ Table,
69
+ TableBody,
70
+ TableCell,
71
+ TableHead,
72
+ TableHeader,
73
+ TableRow,
74
+ Tabs,
75
+ TabsContent,
76
+ TabsList,
77
+ TabsTrigger,
78
+ Textarea,
79
+ Toaster,
80
+ Tooltip,
81
+ TooltipContent,
82
+ TooltipTrigger,
83
+ checkboxVariants,
84
+ numberInputVariants,
85
+ toast
86
+ } from "./chunk-73WQAE3E.js";
1
87
  import {
2
88
  useClickOutside,
3
89
  useCopyToClipboard,
@@ -13,3250 +99,213 @@ import {
13
99
  useTimeout,
14
100
  useToggle
15
101
  } from "./chunk-MGXIF756.js";
102
+ import {
103
+ Modal,
104
+ ModalCloseButton,
105
+ ModalContent,
106
+ ModalFooter,
107
+ ModalHeader,
108
+ ModalTitle,
109
+ Sidebar
110
+ } from "./chunk-2IVRUJKO.js";
111
+ import {
112
+ Badge,
113
+ Card,
114
+ CardContent,
115
+ CardDescription,
116
+ CardFooter,
117
+ CardHeader,
118
+ CardTitle,
119
+ Input,
120
+ Label,
121
+ Separator,
122
+ Spinner,
123
+ Tag,
124
+ badgeVariants,
125
+ tagVariants
126
+ } from "./chunk-S45GP6IB.js";
127
+ import {
128
+ Button,
129
+ buttonVariants,
130
+ cn
131
+ } from "./chunk-RUDEZA5Q.js";
16
132
 
17
- // src/components/button.tsx
18
- import { forwardRef } from "react";
19
- import { Loader2 } from "lucide-react";
20
- import { cva } from "class-variance-authority";
21
- import { cn } from "@ug666/ui-utils";
22
- import { jsx, jsxs } from "react/jsx-runtime";
23
- var buttonVariants = cva(
24
- "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",
25
- {
26
- variants: {
27
- variant: {
28
- default: "bg-primary text-primary-fg hover:bg-primary-hover focus-visible:ring-ring",
29
- destructive: "bg-danger text-danger-fg hover:bg-danger-hover focus-visible:ring-danger",
30
- outline: "border border-border-strong bg-surface-1 text-text-primary hover:bg-surface-2 focus-visible:ring-ring/30",
31
- secondary: "bg-surface-2 text-text-primary hover:bg-surface-3 focus-visible:ring-ring/30",
32
- ghost: "text-text-primary hover:bg-surface-2 focus-visible:ring-ring/30",
33
- link: "text-text-primary underline-offset-4 hover:underline focus-visible:ring-ring/30"
34
- },
35
- size: {
36
- default: "h-9 px-4 py-2",
37
- sm: "h-8 rounded-md px-3 text-xs",
38
- lg: "h-12 rounded-md px-6 text-base",
39
- icon: "h-9 w-9"
40
- }
133
+ // src/theme.ts
134
+ var theme = {
135
+ colors: {
136
+ primary: {
137
+ DEFAULT: "hsl(var(--primary))",
138
+ hover: "hsl(var(--primary-hover))",
139
+ active: "hsl(var(--primary-active))",
140
+ foreground: "hsl(var(--primary-fg))",
141
+ soft: "hsl(var(--primary-soft) / 0.12)",
142
+ softForeground: "hsl(var(--primary-soft-fg))"
41
143
  },
42
- defaultVariants: {
43
- variant: "default",
44
- size: "default"
45
- }
46
- }
47
- );
48
- var Button = forwardRef(
49
- ({ className, variant, size, loading = false, disabled, children, ...props }, ref) => {
50
- return /* @__PURE__ */ jsxs(
51
- "button",
52
- {
53
- ref,
54
- className: cn(buttonVariants({ variant, size }), className),
55
- disabled: disabled || loading,
56
- ...props,
57
- children: [
58
- loading && /* @__PURE__ */ jsx(Loader2, { className: "animate-spin", size: 16 }),
59
- children
60
- ]
61
- }
62
- );
63
- }
64
- );
65
- Button.displayName = "Button";
66
-
67
- // src/components/input.tsx
68
- import { forwardRef as forwardRef2, useId } from "react";
69
- import { cn as cn2 } from "@ug666/ui-utils";
70
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
71
- var Input = forwardRef2(
72
- ({ className, label, error, helperText, id, ...props }, ref) => {
73
- const generatedId = useId();
74
- const inputId = id ?? generatedId;
75
- return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-1", children: [
76
- label && /* @__PURE__ */ jsx2(
77
- "label",
78
- {
79
- htmlFor: inputId,
80
- className: "text-sm font-medium text-text-primary",
81
- children: label
82
- }
83
- ),
84
- /* @__PURE__ */ jsx2(
85
- "input",
86
- {
87
- ref,
88
- id: inputId,
89
- className: cn2(
90
- "flex h-9 w-full rounded-md border bg-surface-1 px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary",
91
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1",
92
- "disabled:cursor-not-allowed disabled:opacity-50",
93
- error ? "border-danger focus-visible:ring-danger" : "border-border-strong focus-visible:ring-ring/30",
94
- className
95
- ),
96
- ...props
97
- }
98
- ),
99
- error && /* @__PURE__ */ jsx2("p", { className: "text-xs text-danger", children: error }),
100
- !error && helperText && /* @__PURE__ */ jsx2("p", { className: "text-xs text-text-secondary", children: helperText })
101
- ] });
102
- }
103
- );
104
- Input.displayName = "Input";
105
-
106
- // src/components/label.tsx
107
- import { forwardRef as forwardRef3 } from "react";
108
- import { cn as cn3 } from "@ug666/ui-utils";
109
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
110
- var Label = forwardRef3(({ className, required, children, ...props }, ref) => {
111
- return /* @__PURE__ */ jsxs3(
112
- "label",
113
- {
114
- ref,
115
- className: cn3(
116
- "leading-none text-sm font-medium text-text-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
117
- className
118
- ),
119
- ...props,
120
- children: [
121
- children,
122
- required && /* @__PURE__ */ jsx3("span", { className: "ml-0.5 text-danger", "aria-hidden": "true", children: "*" })
123
- ]
124
- }
125
- );
126
- });
127
- Label.displayName = "Label";
128
-
129
- // src/components/card.tsx
130
- import { forwardRef as forwardRef4 } from "react";
131
- import { cn as cn4 } from "@ug666/ui-utils";
132
- import { jsx as jsx4 } from "react/jsx-runtime";
133
- var Card = forwardRef4(({ className, ...props }, ref) => {
134
- return /* @__PURE__ */ jsx4("div", { ref, className: cn4("rounded-lg border border-border-base bg-surface-1", className), ...props });
135
- });
136
- var CardHeader = forwardRef4(({ className, ...props }, ref) => {
137
- return /* @__PURE__ */ jsx4("div", { ref, className: cn4("flex flex-col gap-1 px-5 py-4 border-b border-border-base", className), ...props });
138
- });
139
- var CardTitle = forwardRef4(({ className, ...props }, ref) => {
140
- return /* @__PURE__ */ jsx4("h3", { ref, className: cn4("leading-none font-semibold tracking-tight text-text-primary", className), ...props });
141
- });
142
- var CardDescription = forwardRef4(({ className, ...props }, ref) => {
143
- return /* @__PURE__ */ jsx4("p", { ref, className: cn4("text-sm text-text-secondary", className), ...props });
144
- });
145
- var CardContent = forwardRef4(({ className, ...props }, ref) => {
146
- return /* @__PURE__ */ jsx4("div", { ref, className: cn4("px-5 py-4", className), ...props });
147
- });
148
- var CardFooter = forwardRef4(({ className, ...props }, ref) => {
149
- return /* @__PURE__ */ jsx4("div", { ref, className: cn4("flex items-center px-5 py-4 border-t border-border-base", className), ...props });
150
- });
151
- Card.displayName = "Card";
152
- CardHeader.displayName = "CardHeader";
153
- CardTitle.displayName = "CardTitle";
154
- CardDescription.displayName = "CardDescription";
155
- CardContent.displayName = "CardContent";
156
- CardFooter.displayName = "CardFooter";
157
-
158
- // src/components/badge.tsx
159
- import { forwardRef as forwardRef5 } from "react";
160
- import { cva as cva2 } from "class-variance-authority";
161
- import { cn as cn5 } from "@ug666/ui-utils";
162
- import { jsx as jsx5 } from "react/jsx-runtime";
163
- var badgeVariants = cva2(
164
- "inline-flex items-center rounded-md px-2.5 py-0.5 text-xs font-semibold transition-colors",
165
- {
166
- variants: {
167
- variant: {
168
- default: "bg-primary text-primary-fg",
169
- secondary: "bg-surface-3 text-text-primary",
170
- destructive: "bg-danger-soft text-danger-soft-fg",
171
- outline: "border border-border-strong text-text-primary bg-transparent",
172
- success: "bg-success-soft text-success-soft-fg",
173
- warning: "bg-warning-soft text-warning-soft-fg"
174
- }
144
+ success: {
145
+ DEFAULT: "hsl(var(--success))",
146
+ hover: "hsl(var(--success-hover))",
147
+ foreground: "hsl(var(--success-fg))",
148
+ soft: "hsl(var(--success-soft) / 0.12)",
149
+ softForeground: "hsl(var(--success-soft-fg))"
175
150
  },
176
- defaultVariants: {
177
- variant: "default"
178
- }
179
- }
180
- );
181
- var Badge = forwardRef5(({ className, variant, ...props }, ref) => {
182
- return /* @__PURE__ */ jsx5("span", { ref, className: cn5(badgeVariants({ variant }), className), ...props });
183
- });
184
- Badge.displayName = "Badge";
185
-
186
- // src/components/tag.tsx
187
- import { forwardRef as forwardRef6 } from "react";
188
- import { X } from "lucide-react";
189
- import { cva as cva3 } from "class-variance-authority";
190
- import { cn as cn6 } from "@ug666/ui-utils";
191
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
192
- var tagVariants = cva3(
193
- "inline-flex items-center gap-1 rounded font-medium transition-colors",
194
- {
195
- variants: {
196
- variant: {
197
- default: "bg-surface-3 text-text-primary",
198
- primary: "bg-success-soft text-success-soft-fg",
199
- success: "bg-success-soft text-success-soft-fg",
200
- warning: "bg-warning-soft text-warning-soft-fg",
201
- destructive: "bg-danger-soft text-danger-soft-fg",
202
- outline: "border border-border-strong bg-transparent text-text-primary"
203
- },
204
- size: {
205
- sm: "px-1.5 py-0 text-xs",
206
- default: "px-2 py-0.5 text-xs"
207
- }
151
+ warning: {
152
+ DEFAULT: "hsl(var(--warning))",
153
+ hover: "hsl(var(--warning-hover))",
154
+ foreground: "hsl(var(--warning-fg))",
155
+ soft: "hsl(var(--warning-soft) / 0.12)",
156
+ softForeground: "hsl(var(--warning-soft-fg))"
208
157
  },
209
- defaultVariants: {
210
- variant: "default",
211
- size: "default"
212
- }
213
- }
214
- );
215
- var Tag = forwardRef6(
216
- ({ variant, size, closable = false, disabled = false, color, onClose, className, children, style, ...props }, ref) => {
217
- const customStyle = color ? { backgroundColor: color, color: "#fff", borderColor: color, ...style } : style ?? {};
218
- function handleClose(event) {
219
- event.stopPropagation();
220
- if (!disabled) {
221
- onClose?.(event);
222
- }
223
- }
224
- return /* @__PURE__ */ jsxs4(
225
- "span",
226
- {
227
- ref,
228
- className: cn6(tagVariants({ variant, size }), disabled && "cursor-not-allowed opacity-50", className),
229
- style: customStyle,
230
- ...props,
231
- children: [
232
- children,
233
- closable && /* @__PURE__ */ jsx6(
234
- "button",
235
- {
236
- type: "button",
237
- onClick: handleClose,
238
- disabled,
239
- className: "inline-flex items-center justify-center rounded-sm opacity-60 transition-opacity hover:opacity-100 focus-visible:outline-none disabled:pointer-events-none",
240
- "aria-label": "\u5173\u95ED\u6807\u7B7E",
241
- children: /* @__PURE__ */ jsx6(X, { size: 10, strokeWidth: 2.5 })
242
- }
243
- )
244
- ]
245
- }
246
- );
247
- }
248
- );
249
- Tag.displayName = "Tag";
250
-
251
- // src/components/modal.tsx
252
- import { forwardRef as forwardRef7 } from "react";
253
- import { createPortal } from "react-dom";
254
- import { X as X2 } from "lucide-react";
255
- import { cn as cn7 } from "@ug666/ui-utils";
256
-
257
- // src/hooks/use-escape-key.ts
258
- import { useCallback, useEffect } from "react";
259
- function useEscapeKey(open, onEscape) {
260
- const handleEscape = useCallback(
261
- (e) => {
262
- if (e.key === "Escape") onEscape();
158
+ danger: {
159
+ DEFAULT: "hsl(var(--danger))",
160
+ hover: "hsl(var(--danger-hover))",
161
+ foreground: "hsl(var(--danger-fg))",
162
+ soft: "hsl(var(--danger-soft) / 0.12)",
163
+ softForeground: "hsl(var(--danger-soft-fg))"
263
164
  },
264
- [onEscape]
265
- );
266
- useEffect(() => {
267
- if (!open) return;
268
- document.addEventListener("keydown", handleEscape);
269
- document.body.style.overflow = "hidden";
270
- return () => {
271
- document.removeEventListener("keydown", handleEscape);
272
- document.body.style.overflow = "";
273
- };
274
- }, [open, handleEscape]);
275
- }
276
-
277
- // src/components/modal.tsx
278
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
279
- var Modal = forwardRef7(({ open, onClose, children, className }, ref) => {
280
- useEscapeKey(open, onClose);
281
- if (!open) return null;
282
- return createPortal(
283
- /* @__PURE__ */ jsxs5(
284
- "div",
285
- {
286
- ref,
287
- className: cn7(
288
- "fixed inset-0 z-50 flex items-center justify-center",
289
- className
290
- ),
291
- role: "dialog",
292
- "aria-modal": "true",
293
- children: [
294
- /* @__PURE__ */ jsx7(
295
- "div",
296
- {
297
- className: "absolute inset-0 bg-overlay",
298
- onClick: onClose,
299
- "aria-hidden": "true"
300
- }
301
- ),
302
- /* @__PURE__ */ jsx7("div", { className: "relative z-10", children })
303
- ]
304
- }
305
- ),
306
- document.body
307
- );
308
- });
309
- var ModalContent = forwardRef7(({ className, maxWidth = "max-w-lg", children, ...props }, ref) => {
310
- return /* @__PURE__ */ jsx7("div", { ref, className: cn7("w-full rounded-lg bg-surface-1 shadow-lg", maxWidth, className), ...props, children });
311
- });
312
- var ModalHeader = forwardRef7(({ className, ...props }, ref) => {
313
- return /* @__PURE__ */ jsx7("div", { ref, className: cn7("flex items-center justify-between border-b border-border-base px-6 py-4", className), ...props });
314
- });
315
- var ModalTitle = forwardRef7(({ className, ...props }, ref) => {
316
- return /* @__PURE__ */ jsx7("h2", { ref, className: cn7("text-lg font-semibold text-text-primary", className), ...props });
317
- });
318
- var ModalFooter = forwardRef7(({ className, ...props }, ref) => {
319
- return /* @__PURE__ */ jsx7("div", { ref, className: cn7("flex items-center justify-end gap-2 border-t border-border-base px-6 py-4", className), ...props });
320
- });
321
- var ModalCloseButton = forwardRef7(({ onClick, className, type = "button", ...props }, ref) => {
322
- return /* @__PURE__ */ jsx7(
323
- "button",
324
- {
325
- ref,
326
- type,
327
- onClick,
328
- className: cn7(
329
- "rounded-md p-1 text-text-tertiary transition-colors hover:bg-surface-3 hover:text-text-secondary",
330
- className
331
- ),
332
- "aria-label": "\u5173\u95ED",
333
- ...props,
334
- children: /* @__PURE__ */ jsx7(X2, { size: 18 })
335
- }
336
- );
337
- });
338
- Modal.displayName = "Modal";
339
- ModalContent.displayName = "ModalContent";
340
- ModalHeader.displayName = "ModalHeader";
341
- ModalTitle.displayName = "ModalTitle";
342
- ModalFooter.displayName = "ModalFooter";
343
- ModalCloseButton.displayName = "ModalCloseButton";
344
-
345
- // src/components/dialog.tsx
346
- import { forwardRef as forwardRef8, useCallback as useCallback2, useEffect as useEffect2 } from "react";
347
- import { createPortal as createPortal2 } from "react-dom";
348
- import { cn as cn8 } from "@ug666/ui-utils";
349
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
350
- var CONFIRM_VARIANT_CLASSES = {
351
- default: "bg-primary text-primary-fg hover:bg-primary-hover focus-visible:ring-ring",
352
- destructive: "bg-danger text-danger-fg hover:bg-danger-hover focus-visible:ring-danger"
353
- };
354
- var Dialog = forwardRef8(
355
- ({
356
- open,
357
- onOpenChange,
358
- title,
359
- description,
360
- variant = "default",
361
- cancelText = "\u53D6\u6D88",
362
- confirmText = "\u786E\u8BA4",
363
- onConfirm,
364
- onCancel,
365
- className
366
- }, ref) => {
367
- const handleClose = useCallback2(() => {
368
- onOpenChange(false);
369
- }, [onOpenChange]);
370
- const handleCancel = useCallback2(() => {
371
- onCancel?.();
372
- handleClose();
373
- }, [onCancel, handleClose]);
374
- const handleConfirm = useCallback2(() => {
375
- onConfirm?.();
376
- handleClose();
377
- }, [onConfirm, handleClose]);
378
- const handleEscape = useCallback2(
379
- (e) => {
380
- if (e.key === "Escape") handleCancel();
381
- },
382
- [handleCancel]
383
- );
384
- useEffect2(() => {
385
- if (!open) return;
386
- document.addEventListener("keydown", handleEscape);
387
- document.body.style.overflow = "hidden";
388
- return () => {
389
- document.removeEventListener("keydown", handleEscape);
390
- document.body.style.overflow = "";
391
- };
392
- }, [open, handleEscape]);
393
- if (!open) return null;
394
- return createPortal2(
395
- /* @__PURE__ */ jsxs6(
396
- "div",
397
- {
398
- ref,
399
- className: cn8(
400
- "fixed inset-0 z-50 flex items-center justify-center p-4",
401
- className
402
- ),
403
- role: "alertdialog",
404
- "aria-modal": "true",
405
- "aria-labelledby": "dialog-title",
406
- "aria-describedby": description ? "dialog-description" : void 0,
407
- children: [
408
- /* @__PURE__ */ jsx8(
409
- "div",
410
- {
411
- className: "absolute inset-0 bg-overlay",
412
- onClick: handleCancel,
413
- "aria-hidden": "true"
414
- }
415
- ),
416
- /* @__PURE__ */ jsxs6("div", { className: "relative z-10 w-full max-w-sm rounded-lg bg-surface-1 shadow-lg", children: [
417
- /* @__PURE__ */ jsxs6("div", { className: "px-6 pt-6 pb-4", children: [
418
- /* @__PURE__ */ jsx8(
419
- "h2",
420
- {
421
- id: "dialog-title",
422
- className: "text-base font-bold text-text-primary",
423
- children: title
424
- }
425
- ),
426
- description && /* @__PURE__ */ jsx8(
427
- "p",
428
- {
429
- id: "dialog-description",
430
- className: "mt-2 text-sm text-text-secondary",
431
- children: description
432
- }
433
- )
434
- ] }),
435
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-end gap-2 border-t border-border-subtle px-6 py-4", children: [
436
- /* @__PURE__ */ jsx8(
437
- "button",
438
- {
439
- type: "button",
440
- onClick: handleCancel,
441
- className: cn8(
442
- "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",
443
- "hover:bg-surface-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-ring/30"
444
- ),
445
- children: cancelText
446
- }
447
- ),
448
- /* @__PURE__ */ jsx8(
449
- "button",
450
- {
451
- type: "button",
452
- onClick: handleConfirm,
453
- className: cn8(
454
- "inline-flex h-9 items-center justify-center rounded-md px-4 text-sm font-medium transition-colors",
455
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
456
- CONFIRM_VARIANT_CLASSES[variant]
457
- ),
458
- children: confirmText
459
- }
460
- )
461
- ] })
462
- ] })
463
- ]
464
- }
465
- ),
466
- document.body
467
- );
468
- }
469
- );
470
- Dialog.displayName = "Dialog";
471
-
472
- // src/components/drawer.tsx
473
- import { createContext, forwardRef as forwardRef9, useContext } from "react";
474
- import { createPortal as createPortal3 } from "react-dom";
475
- import { X as X3 } from "lucide-react";
476
- import { cn as cn9 } from "@ug666/ui-utils";
477
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
478
- var DrawerContext = createContext(null);
479
- function useDrawerContext() {
480
- const ctx = useContext(DrawerContext);
481
- if (!ctx) throw new Error("Drawer \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Drawer> \u5185\u4F7F\u7528");
482
- return ctx;
483
- }
484
- var SIDE_CLASSES = {
485
- right: "inset-y-0 right-0 h-full w-80 max-w-full translate-x-0",
486
- left: "inset-y-0 left-0 h-full w-80 max-w-full translate-x-0",
487
- top: "inset-x-0 top-0 w-full h-auto max-h-[80vh] translate-y-0",
488
- bottom: "inset-x-0 bottom-0 w-full h-auto max-h-[80vh] translate-y-0"
489
- };
490
- var Drawer = ({ open, onOpenChange, side = "right", children }) => {
491
- useEscapeKey(open, () => onOpenChange(false));
492
- return /* @__PURE__ */ jsx9(DrawerContext.Provider, { value: { open, onOpenChange, side }, children });
493
- };
494
- Drawer.displayName = "Drawer";
495
- var DrawerContent = forwardRef9(({ className, children, ...props }, ref) => {
496
- const { open, onOpenChange, side } = useDrawerContext();
497
- if (!open) return null;
498
- return createPortal3(
499
- /* @__PURE__ */ jsxs7("div", { className: "fixed inset-0 z-50", role: "dialog", "aria-modal": "true", children: [
500
- /* @__PURE__ */ jsx9(
501
- "div",
502
- {
503
- className: "absolute inset-0 bg-overlay transition-opacity",
504
- onClick: () => onOpenChange(false),
505
- "aria-hidden": "true"
506
- }
507
- ),
508
- /* @__PURE__ */ jsx9(
509
- "div",
510
- {
511
- ref,
512
- className: cn9(
513
- "absolute flex flex-col bg-surface-1 shadow-xl transition-transform duration-300 ease-in-out",
514
- SIDE_CLASSES[side],
515
- className
516
- ),
517
- onClick: (e) => e.stopPropagation(),
518
- ...props,
519
- children
520
- }
521
- )
522
- ] }),
523
- document.body
524
- );
525
- });
526
- DrawerContent.displayName = "DrawerContent";
527
- var DrawerHeader = forwardRef9(({ className, ...props }, ref) => {
528
- return /* @__PURE__ */ jsx9(
529
- "div",
530
- {
531
- ref,
532
- className: cn9("flex flex-col gap-1.5 border-b border-border-base px-6 py-4", className),
533
- ...props
534
- }
535
- );
536
- });
537
- DrawerHeader.displayName = "DrawerHeader";
538
- var DrawerTitle = forwardRef9(({ className, ...props }, ref) => {
539
- return /* @__PURE__ */ jsx9("h2", { ref, className: cn9("text-lg font-semibold text-text-primary", className), ...props });
540
- });
541
- DrawerTitle.displayName = "DrawerTitle";
542
- var DrawerDescription = forwardRef9(({ className, ...props }, ref) => {
543
- return /* @__PURE__ */ jsx9("p", { ref, className: cn9("text-sm text-text-secondary", className), ...props });
544
- });
545
- DrawerDescription.displayName = "DrawerDescription";
546
- var DrawerFooter = forwardRef9(({ className, ...props }, ref) => {
547
- return /* @__PURE__ */ jsx9(
548
- "div",
549
- {
550
- ref,
551
- className: cn9("mt-auto flex items-center justify-end gap-2 border-t border-border-base px-6 py-4", className),
552
- ...props
553
- }
554
- );
555
- });
556
- DrawerFooter.displayName = "DrawerFooter";
557
- var DrawerClose = forwardRef9(({ className, children, type = "button", ...props }, ref) => {
558
- const { onOpenChange } = useDrawerContext();
559
- return /* @__PURE__ */ jsx9(
560
- "button",
561
- {
562
- ref,
563
- type,
564
- onClick: () => onOpenChange(false),
565
- className: cn9(
566
- "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",
567
- className
568
- ),
569
- ...props,
570
- children: children ?? /* @__PURE__ */ jsx9(X3, { size: 18 })
571
- }
572
- );
573
- });
574
- DrawerClose.displayName = "DrawerClose";
575
-
576
- // src/components/table.tsx
577
- import { forwardRef as forwardRef10 } from "react";
578
- import { cn as cn10 } from "@ug666/ui-utils";
579
- import { jsx as jsx10 } from "react/jsx-runtime";
580
- var Table = forwardRef10(({ className, ...props }, ref) => {
581
- return /* @__PURE__ */ jsx10("div", { className: "w-full overflow-auto", children: /* @__PURE__ */ jsx10(
582
- "table",
583
- {
584
- ref,
585
- className: cn10("w-full caption-bottom text-sm", className),
586
- ...props
587
- }
588
- ) });
589
- });
590
- var TableHeader = forwardRef10(({ className, ...props }, ref) => {
591
- return /* @__PURE__ */ jsx10("thead", { ref, className: cn10("[&_tr]:border-b border-border-base", className), ...props });
592
- });
593
- var TableBody = forwardRef10(({ className, ...props }, ref) => {
594
- return /* @__PURE__ */ jsx10("tbody", { ref, className: cn10("[&_tr:last-child]:border-0", className), ...props });
595
- });
596
- var TableRow = forwardRef10(({ className, ...props }, ref) => {
597
- return /* @__PURE__ */ jsx10("tr", { ref, className: cn10("border-b border-border-base transition-colors hover:bg-surface-2", className), ...props });
598
- });
599
- var TableHead = forwardRef10(({ className, ...props }, ref) => {
600
- return /* @__PURE__ */ jsx10("th", { ref, className: cn10("h-10 px-4 text-left align-middle font-medium text-text-secondary [&:has([role=checkbox])]:pr-0", className), ...props });
601
- });
602
- var TableCell = forwardRef10(({ className, ...props }, ref) => {
603
- return /* @__PURE__ */ jsx10("td", { ref, className: cn10("px-4 py-3 align-middle text-text-primary [&:has([role=checkbox])]:pr-0", className), ...props });
604
- });
605
- Table.displayName = "Table";
606
- TableHeader.displayName = "TableHeader";
607
- TableBody.displayName = "TableBody";
608
- TableRow.displayName = "TableRow";
609
- TableHead.displayName = "TableHead";
610
- TableCell.displayName = "TableCell";
611
-
612
- // src/components/toast.tsx
613
- import { forwardRef as forwardRef11, useCallback as useCallback3, useEffect as useEffect3, useRef, useState } from "react";
614
- import { createPortal as createPortal4 } from "react-dom";
615
- import { X as X4 } from "lucide-react";
616
- import { cn as cn11 } from "@ug666/ui-utils";
617
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
618
- var listeners = /* @__PURE__ */ new Set();
619
- var toastItems = [];
620
- var toastTimers = /* @__PURE__ */ new Map();
621
- function notify() {
622
- listeners.forEach((fn) => fn([...toastItems]));
623
- }
624
- function addToast(message, type) {
625
- const id = Math.random().toString(36).slice(2);
626
- toastItems = [...toastItems, { id, message, type }];
627
- notify();
628
- const timer = setTimeout(() => removeToast(id), 3e3);
629
- toastTimers.set(id, timer);
630
- }
631
- function removeToast(id) {
632
- const timer = toastTimers.get(id);
633
- if (timer) {
634
- clearTimeout(timer);
635
- toastTimers.delete(id);
636
- }
637
- toastItems = toastItems.filter((t) => t.id !== id);
638
- notify();
639
- }
640
- var toast = {
641
- success: (message) => addToast(message, "success"),
642
- error: (message) => addToast(message, "error"),
643
- info: (message) => addToast(message, "info")
644
- };
645
- var typeStyles = {
646
- success: "bg-success-soft border-success/30 text-success-soft-fg",
647
- error: "bg-danger-soft border-danger/30 text-danger-soft-fg",
648
- info: "bg-info-soft border-info/30 text-info-soft-fg"
649
- };
650
- var typeLabel = {
651
- success: "\u6210\u529F",
652
- error: "\u9519\u8BEF",
653
- info: "\u63D0\u793A"
654
- };
655
- var Toaster = forwardRef11(({ className, ...props }, ref) => {
656
- const [items, setItems] = useState([]);
657
- const mountedRef = useRef(true);
658
- const handleUpdate = useCallback3((next) => {
659
- if (mountedRef.current) {
660
- setItems(next);
661
- }
662
- }, []);
663
- useEffect3(() => {
664
- listeners.add(handleUpdate);
665
- return () => {
666
- mountedRef.current = false;
667
- listeners.delete(handleUpdate);
668
- };
669
- }, [handleUpdate]);
670
- if (items.length === 0) return null;
671
- return createPortal4(
672
- /* @__PURE__ */ jsx11(
673
- "div",
674
- {
675
- ref,
676
- className: cn11("fixed top-4 right-4 z-[9999] flex w-80 flex-col gap-2", className),
677
- role: "region",
678
- "aria-label": "\u901A\u77E5",
679
- ...props,
680
- children: items.map((item) => /* @__PURE__ */ jsxs8(
681
- "div",
682
- {
683
- className: cn11(
684
- "flex items-start justify-between gap-2 rounded-md border px-4 py-3 text-sm shadow-md",
685
- typeStyles[item.type]
686
- ),
687
- role: "alert",
688
- children: [
689
- /* @__PURE__ */ jsxs8("div", { children: [
690
- /* @__PURE__ */ jsxs8("span", { className: "font-semibold", children: [
691
- typeLabel[item.type],
692
- "\uFF1A"
693
- ] }),
694
- item.message
695
- ] }),
696
- /* @__PURE__ */ jsx11(
697
- "button",
698
- {
699
- type: "button",
700
- onClick: () => removeToast(item.id),
701
- className: "mt-0.5 shrink-0 opacity-60 hover:opacity-100 transition-opacity",
702
- "aria-label": "\u5173\u95ED\u901A\u77E5",
703
- children: /* @__PURE__ */ jsx11(X4, { size: 14 })
704
- }
705
- )
706
- ]
707
- },
708
- item.id
709
- ))
710
- }
711
- ),
712
- document.body
713
- );
714
- });
715
- Toaster.displayName = "Toaster";
716
-
717
- // src/components/sidebar.tsx
718
- import { forwardRef as forwardRef12 } from "react";
719
- import { cn as cn12 } from "@ug666/ui-utils";
720
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
721
- var variantStyles = {
722
- primary: {
723
- container: "bg-primary text-primary-fg",
724
- active: "bg-primary-active text-primary-fg",
725
- inactive: "text-primary-fg/70 hover:bg-primary-hover hover:text-primary-fg",
726
- divider: "border-primary-active"
165
+ info: {
166
+ DEFAULT: "hsl(var(--info))",
167
+ hover: "hsl(var(--info-hover))",
168
+ foreground: "hsl(var(--info-fg))",
169
+ soft: "hsl(var(--info-soft) / 0.12)",
170
+ softForeground: "hsl(var(--info-soft-fg))"
171
+ },
172
+ surface: {
173
+ 0: "hsl(var(--surface-0))",
174
+ 1: "hsl(var(--surface-1))",
175
+ 2: "hsl(var(--surface-2))",
176
+ 3: "hsl(var(--surface-3))"
177
+ },
178
+ text: {
179
+ primary: "hsl(var(--text-primary))",
180
+ secondary: "hsl(var(--text-secondary))",
181
+ tertiary: "hsl(var(--text-tertiary))",
182
+ inverted: "hsl(var(--text-inverted))"
183
+ },
184
+ border: {
185
+ strong: "hsl(var(--border-strong))",
186
+ base: "hsl(var(--border-base))",
187
+ subtle: "hsl(var(--border-subtle))"
188
+ },
189
+ ring: "hsl(var(--ring))",
190
+ overlay: "hsl(var(--overlay) / var(--overlay-alpha))"
727
191
  },
728
- dark: {
729
- container: "bg-slate-950 text-slate-100",
730
- 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",
731
- inactive: "text-slate-400 hover:bg-slate-800/40 hover:text-slate-100",
732
- divider: "border-slate-800/80"
733
- }
192
+ radius: { sm: "var(--radius-sm)", md: "var(--radius-md)", lg: "var(--radius-lg)", xl: "var(--radius-xl)", full: "9999px" },
193
+ fontFamily: { sans: "var(--font-sans)", mono: "var(--font-mono)" }
734
194
  };
735
- var Sidebar = forwardRef12(
736
- ({ items, variant = "primary", collapsed = false, footer, className }, ref) => {
737
- const styles = variantStyles[variant];
738
- return /* @__PURE__ */ jsxs9(
739
- "aside",
740
- {
741
- ref,
742
- className: cn12(
743
- "flex flex-col transition-all duration-300",
744
- styles.container,
745
- collapsed ? "w-16" : "w-60",
746
- className
747
- ),
748
- children: [
749
- /* @__PURE__ */ jsx12("nav", { className: "flex-1 overflow-y-auto py-4", children: /* @__PURE__ */ jsx12("ul", { className: "flex flex-col gap-1 px-2", children: items.map((item) => /* @__PURE__ */ jsx12("li", { children: /* @__PURE__ */ jsxs9(
750
- "a",
751
- {
752
- href: item.href,
753
- className: cn12(
754
- "relative flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors duration-150",
755
- item.active ? styles.active : styles.inactive
756
- ),
757
- title: collapsed ? item.label : void 0,
758
- children: [
759
- /* @__PURE__ */ jsx12(item.icon, { size: 17, className: "shrink-0" }),
760
- !collapsed && /* @__PURE__ */ jsx12("span", { className: "truncate", children: item.label })
761
- ]
762
- }
763
- ) }, item.href)) }) }),
764
- footer && /* @__PURE__ */ jsx12(
765
- "div",
766
- {
767
- className: cn12(
768
- "border-t px-2 py-4",
769
- styles.divider,
770
- collapsed && "flex justify-center"
771
- ),
772
- children: footer
773
- }
774
- )
775
- ]
776
- }
777
- );
778
- }
779
- );
780
- Sidebar.displayName = "Sidebar";
781
-
782
- // src/components/pagination.tsx
783
- import { forwardRef as forwardRef13 } from "react";
784
- import { ChevronLeft, ChevronRight } from "lucide-react";
785
- import { cn as cn13 } from "@ug666/ui-utils";
786
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
787
- var MAX_VISIBLE_PAGES = 5;
788
- function getPageNumbers(page, totalPages) {
789
- if (totalPages <= MAX_VISIBLE_PAGES) {
790
- return Array.from({ length: totalPages }, (_, i) => i + 1);
791
- }
792
- const half = Math.floor(MAX_VISIBLE_PAGES / 2);
793
- let start = Math.max(1, page - half);
794
- const end = Math.min(totalPages, start + MAX_VISIBLE_PAGES - 1);
795
- if (end - start < MAX_VISIBLE_PAGES - 1) {
796
- start = Math.max(1, end - MAX_VISIBLE_PAGES + 1);
797
- }
798
- const pages = [];
799
- if (start > 1) {
800
- pages.push(1);
801
- if (start > 2) pages.push("...");
802
- }
803
- for (let i = start; i <= end; i++) pages.push(i);
804
- if (end < totalPages) {
805
- if (end < totalPages - 1) pages.push("...");
806
- pages.push(totalPages);
807
- }
808
- return pages;
809
- }
810
- var Pagination = forwardRef13(({ page, totalPages, onPageChange, className }, ref) => {
811
- const pageNumbers = getPageNumbers(page, totalPages);
812
- 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";
813
- return /* @__PURE__ */ jsxs10("div", { ref, className: cn13("flex items-center gap-1", className), children: [
814
- /* @__PURE__ */ jsx13(
815
- "button",
816
- {
817
- type: "button",
818
- className: cn13(btnBase, "border border-border-strong bg-surface-1 text-text-primary hover:bg-surface-3"),
819
- disabled: page <= 1,
820
- onClick: () => onPageChange(page - 1),
821
- "aria-label": "\u4E0A\u4E00\u9875",
822
- children: /* @__PURE__ */ jsx13(ChevronLeft, { size: 16 })
823
- }
824
- ),
825
- pageNumbers.map(
826
- (p, idx) => p === "..." ? /* @__PURE__ */ jsx13("span", { className: "px-1 text-text-tertiary select-none", children: "\u2026" }, `ellipsis-${idx}`) : /* @__PURE__ */ jsx13(
827
- "button",
828
- {
829
- type: "button",
830
- className: cn13(
831
- btnBase,
832
- p === page ? "bg-primary text-primary-fg" : "border border-border-strong bg-surface-1 text-text-primary hover:bg-surface-3"
833
- ),
834
- onClick: () => onPageChange(p),
835
- "aria-current": p === page ? "page" : void 0,
836
- children: p
837
- },
838
- p
839
- )
840
- ),
841
- /* @__PURE__ */ jsx13(
842
- "button",
843
- {
844
- type: "button",
845
- className: cn13(btnBase, "border border-border-strong bg-surface-1 text-text-primary hover:bg-surface-3"),
846
- disabled: page >= totalPages,
847
- onClick: () => onPageChange(page + 1),
848
- "aria-label": "\u4E0B\u4E00\u9875",
849
- children: /* @__PURE__ */ jsx13(ChevronRight, { size: 16 })
850
- }
851
- )
852
- ] });
853
- });
854
- Pagination.displayName = "Pagination";
855
-
856
- // src/components/select.tsx
857
- import { forwardRef as forwardRef14, useId as useId2 } from "react";
858
- import { cn as cn14 } from "@ug666/ui-utils";
859
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
860
- var Select = forwardRef14(
861
- ({ className, label, error, helperText, options, placeholder, id, ...props }, ref) => {
862
- const generatedId = useId2();
863
- const selectId = id ?? generatedId;
864
- return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-1", children: [
865
- label && /* @__PURE__ */ jsx14("label", { htmlFor: selectId, className: "text-sm font-medium text-text-primary", children: label }),
866
- /* @__PURE__ */ jsxs11(
867
- "select",
868
- {
869
- ref,
870
- id: selectId,
871
- className: cn14(
872
- "flex h-9 w-full rounded-md border bg-surface-1 px-3 py-1.5 text-sm text-text-primary",
873
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1",
874
- "disabled:cursor-not-allowed disabled:opacity-50",
875
- error ? "border-red-400 focus-visible:ring-red-400" : "border-border-strong focus-visible:ring-ring/30",
876
- className
877
- ),
878
- ...props,
879
- children: [
880
- placeholder && /* @__PURE__ */ jsx14("option", { value: "", disabled: true, children: placeholder }),
881
- options.map((opt) => /* @__PURE__ */ jsx14("option", { value: opt.value, children: opt.label }, opt.value))
882
- ]
883
- }
884
- ),
885
- error && /* @__PURE__ */ jsx14("p", { className: "text-xs text-danger", children: error }),
886
- !error && helperText && /* @__PURE__ */ jsx14("p", { className: "text-xs text-text-secondary", children: helperText })
887
- ] });
888
- }
889
- );
890
- Select.displayName = "Select";
891
195
 
892
- // src/components/spinner.tsx
893
- import { forwardRef as forwardRef15 } from "react";
894
- import { Loader2 as Loader22 } from "lucide-react";
895
- import { cva as cva4 } from "class-variance-authority";
896
- import { cn as cn15 } from "@ug666/ui-utils";
897
- import { jsx as jsx15 } from "react/jsx-runtime";
898
- var spinnerVariants = cva4("animate-spin text-text-tertiary", {
899
- variants: {
900
- size: {
901
- sm: "h-4 w-4",
902
- md: "h-6 w-6",
903
- lg: "h-10 w-10"
904
- }
196
+ // src/component-layers.ts
197
+ var reactComponentLayers = [
198
+ {
199
+ id: "primitives",
200
+ label: "\u57FA\u7840\u7EC4\u4EF6",
201
+ description: "\u6700\u5C0F\u53EF\u590D\u7528\u89C6\u89C9\u5355\u5143\uFF0C\u8D1F\u8D23\u6309\u94AE\u3001\u5BB9\u5668\u3001\u6807\u7B7E\u3001\u5206\u9694\u548C\u52A0\u8F7D\u57FA\u7840\u72B6\u6001\u3002",
202
+ components: [
203
+ { name: "UGButton", route: "/react/components/button" },
204
+ { name: "UGInput", route: "/react/components/input" },
205
+ { name: "UGLabel", route: "/react/components/label" },
206
+ { name: "UGCard", route: "/react/components/card" },
207
+ { name: "UGBadge", route: "/react/components/badge" },
208
+ { name: "UGTag", route: "/react/components/tag" },
209
+ { name: "UGSeparator", route: "/react/components/separator" },
210
+ { name: "UGSpinner", route: "/react/components/spinner" }
211
+ ]
905
212
  },
906
- defaultVariants: {
907
- size: "md"
908
- }
909
- });
910
- var Spinner = forwardRef15(({ className, size, label = "\u52A0\u8F7D\u4E2D", ...props }, ref) => {
911
- return /* @__PURE__ */ jsx15(
912
- Loader22,
913
- {
914
- ref,
915
- className: cn15(spinnerVariants({ size }), className),
916
- "aria-label": label,
917
- role: "status",
918
- ...props
919
- }
920
- );
921
- });
922
- Spinner.displayName = "Spinner";
923
-
924
- // src/components/checkbox.tsx
925
- import { forwardRef as forwardRef16, useEffect as useEffect4, useRef as useRef2 } from "react";
926
- import { Check, Minus } from "lucide-react";
927
- import { cva as cva5 } from "class-variance-authority";
928
- import { cn as cn16 } from "@ug666/ui-utils";
929
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
930
- var checkboxVariants = cva5(
931
- "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",
932
213
  {
933
- variants: {
934
- size: {
935
- sm: "h-3.5 w-3.5",
936
- default: "h-4 w-4",
937
- lg: "h-5 w-5"
938
- },
939
- state: {
940
- unchecked: "border-border-strong bg-surface-1 hover:border-border-strong",
941
- checked: "border-primary bg-primary text-primary-fg focus-visible:ring-ring",
942
- indeterminate: "border-primary bg-primary text-primary-fg focus-visible:ring-ring"
943
- }
944
- },
945
- defaultVariants: {
946
- size: "default",
947
- state: "unchecked"
948
- }
949
- }
950
- );
951
- var Checkbox = forwardRef16(
952
- ({
953
- className,
954
- size,
955
- checked,
956
- indeterminate = false,
957
- disabled,
958
- label,
959
- labelClassName,
960
- onCheckedChange,
961
- id,
962
- ...props
963
- }, ref) => {
964
- const innerRef = useRef2(null);
965
- useEffect4(() => {
966
- if (innerRef.current) {
967
- innerRef.current.indeterminate = indeterminate;
968
- }
969
- }, [indeterminate]);
970
- const state = indeterminate ? "indeterminate" : checked ? "checked" : "unchecked";
971
- const iconSize = size === "sm" ? 10 : size === "lg" ? 14 : 12;
972
- const control = /* @__PURE__ */ jsxs12("span", { className: "relative inline-flex", children: [
973
- /* @__PURE__ */ jsx16(
974
- "input",
975
- {
976
- ref: (node) => {
977
- innerRef.current = node;
978
- if (typeof ref === "function") ref(node);
979
- else if (ref) ref.current = node;
980
- },
981
- id,
982
- type: "checkbox",
983
- className: "peer sr-only",
984
- checked: checked ?? false,
985
- disabled,
986
- onChange: (e) => onCheckedChange?.(e.target.checked),
987
- ...props
988
- }
989
- ),
990
- /* @__PURE__ */ jsx16(
991
- "span",
992
- {
993
- "aria-hidden": "true",
994
- className: cn16(checkboxVariants({ size, state }), className),
995
- children: indeterminate ? /* @__PURE__ */ jsx16(Minus, { size: iconSize }) : checked ? /* @__PURE__ */ jsx16(Check, { size: iconSize }) : null
996
- }
997
- )
998
- ] });
999
- if (label === void 0 || label === null) return control;
1000
- return /* @__PURE__ */ jsxs12(
1001
- "label",
1002
- {
1003
- htmlFor: id,
1004
- className: cn16(
1005
- "inline-flex cursor-pointer items-center gap-2 text-sm text-text-primary select-none",
1006
- disabled && "cursor-not-allowed opacity-60",
1007
- labelClassName
1008
- ),
1009
- children: [
1010
- control,
1011
- /* @__PURE__ */ jsx16("span", { children: label })
1012
- ]
1013
- }
1014
- );
1015
- }
1016
- );
1017
- Checkbox.displayName = "Checkbox";
1018
-
1019
- // src/components/radio.tsx
1020
- import { createContext as createContext2, forwardRef as forwardRef17, useContext as useContext2, useId as useId3, useState as useState2 } from "react";
1021
- import { cva as cva6 } from "class-variance-authority";
1022
- import { cn as cn17 } from "@ug666/ui-utils";
1023
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1024
- var RadioGroupContext = createContext2(null);
1025
- function useRadioGroupContext() {
1026
- return useContext2(RadioGroupContext);
1027
- }
1028
- var radioVariants = cva6(
1029
- "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",
214
+ id: "forms",
215
+ label: "\u8868\u5355\u8F93\u5165",
216
+ description: "\u6536\u96C6\u3001\u6821\u9A8C\u548C\u7F16\u8F91\u7528\u6237\u8F93\u5165\uFF0C\u8981\u6C42\u6807\u7B7E\u3001\u5E2E\u52A9\u6587\u672C\u3001\u9519\u8BEF\u72B6\u6001\u7A33\u5B9A\u5BF9\u9F50\u3002",
217
+ components: [
218
+ { name: "UGTextarea", route: "/react/components/textarea" },
219
+ { name: "UGSelect", route: "/react/components/select" },
220
+ { name: "UGCheckbox", route: "/react/components/checkbox" },
221
+ { name: "UGRadio", route: "/react/components/radio" },
222
+ { name: "UGSwitch", route: "/react/components/switch" },
223
+ { name: "UGSlider", route: "/react/components/slider" },
224
+ { name: "UGNumberInput", route: "/react/components/number-input" },
225
+ { name: "UGOTPInput", route: "/react/components/otp-input" },
226
+ { name: "UGForm", route: "/react/components/form" }
227
+ ]
228
+ },
1030
229
  {
1031
- variants: {
1032
- size: {
1033
- sm: "h-3.5 w-3.5",
1034
- default: "h-4 w-4",
1035
- lg: "h-5 w-5"
1036
- },
1037
- checked: {
1038
- true: "border-primary bg-primary focus-visible:ring-ring",
1039
- false: "border-border-strong bg-surface-1 hover:border-border-strong"
1040
- }
1041
- },
1042
- defaultVariants: {
1043
- size: "default",
1044
- checked: false
1045
- }
1046
- }
1047
- );
1048
- var Radio = forwardRef17(
1049
- ({
1050
- className,
1051
- size,
1052
- value,
1053
- checked: checkedProp,
1054
- disabled: disabledProp,
1055
- label,
1056
- name: nameProp,
1057
- onChange,
1058
- id,
1059
- ...props
1060
- }, ref) => {
1061
- const group = useRadioGroupContext();
1062
- const generatedId = useId3();
1063
- const inputId = id ?? generatedId;
1064
- const isChecked = group ? group.value === value : checkedProp ?? false;
1065
- const isDisabled = group ? group.disabled || (disabledProp ?? false) : disabledProp ?? false;
1066
- const inputName = group ? group.name : nameProp;
1067
- function handleChange() {
1068
- if (group) {
1069
- group.onValueChange(value);
1070
- } else {
1071
- onChange?.(value);
1072
- }
1073
- }
1074
- const dotSize = size === "sm" ? "h-1.5 w-1.5" : size === "lg" ? "h-2.5 w-2.5" : "h-2 w-2";
1075
- const control = /* @__PURE__ */ jsxs13("span", { className: "relative inline-flex", children: [
1076
- /* @__PURE__ */ jsx17(
1077
- "input",
1078
- {
1079
- ref,
1080
- id: inputId,
1081
- type: "radio",
1082
- className: "peer sr-only",
1083
- value,
1084
- checked: isChecked,
1085
- disabled: isDisabled,
1086
- name: inputName,
1087
- onChange: handleChange,
1088
- ...props
1089
- }
1090
- ),
1091
- /* @__PURE__ */ jsx17(
1092
- "span",
1093
- {
1094
- "aria-hidden": "true",
1095
- className: cn17(radioVariants({ size, checked: isChecked }), className),
1096
- children: isChecked && /* @__PURE__ */ jsx17("span", { className: cn17("rounded-full bg-white", dotSize) })
1097
- }
1098
- )
1099
- ] });
1100
- if (label === void 0 || label === null) return control;
1101
- return /* @__PURE__ */ jsxs13(
1102
- "label",
1103
- {
1104
- htmlFor: inputId,
1105
- className: cn17(
1106
- "inline-flex cursor-pointer items-center gap-2 text-sm text-text-primary select-none",
1107
- isDisabled && "cursor-not-allowed opacity-60"
1108
- ),
1109
- children: [
1110
- control,
1111
- /* @__PURE__ */ jsx17("span", { children: label })
1112
- ]
1113
- }
1114
- );
1115
- }
1116
- );
1117
- Radio.displayName = "Radio";
1118
- var RadioGroup = forwardRef17(
1119
- ({
1120
- className,
1121
- value: valueProp,
1122
- defaultValue,
1123
- onValueChange,
1124
- disabled = false,
1125
- name,
1126
- orientation = "vertical",
1127
- children,
1128
- ...props
1129
- }, ref) => {
1130
- const [uncontrolledValue, setUncontrolledValue] = useState2(defaultValue);
1131
- const isControlled = valueProp !== void 0;
1132
- const currentValue = isControlled ? valueProp : uncontrolledValue;
1133
- function handleValueChange(newValue) {
1134
- if (!isControlled) {
1135
- setUncontrolledValue(newValue);
1136
- }
1137
- onValueChange?.(newValue);
1138
- }
1139
- return /* @__PURE__ */ jsx17(
1140
- RadioGroupContext.Provider,
1141
- {
1142
- value: {
1143
- value: currentValue,
1144
- onValueChange: handleValueChange,
1145
- name,
1146
- disabled
1147
- },
1148
- children: /* @__PURE__ */ jsx17(
1149
- "div",
1150
- {
1151
- ref,
1152
- role: "radiogroup",
1153
- className: cn17(
1154
- "flex",
1155
- orientation === "vertical" ? "flex-col gap-2" : "flex-row flex-wrap gap-4",
1156
- className
1157
- ),
1158
- ...props,
1159
- children
1160
- }
1161
- )
1162
- }
1163
- );
1164
- }
1165
- );
1166
- RadioGroup.displayName = "RadioGroup";
1167
-
1168
- // src/components/slider.tsx
1169
- import { forwardRef as forwardRef18, useState as useState3 } from "react";
1170
- import { cn as cn18 } from "@ug666/ui-utils";
1171
- import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1172
- var Slider = forwardRef18(
1173
- ({
1174
- className,
1175
- value: valueProp,
1176
- defaultValue = 0,
1177
- min = 0,
1178
- max = 100,
1179
- step = 1,
1180
- disabled = false,
1181
- showValue = false,
1182
- onValueChange,
1183
- ...props
1184
- }, ref) => {
1185
- const isControlled = valueProp !== void 0;
1186
- const [uncontrolledValue, setUncontrolledValue] = useState3(defaultValue);
1187
- const currentValue = isControlled ? valueProp : uncontrolledValue;
1188
- const fillPercent = max === min ? 0 : (currentValue - min) / (max - min) * 100;
1189
- function handleChange(e) {
1190
- const newValue = Number(e.target.value);
1191
- if (!isControlled) {
1192
- setUncontrolledValue(newValue);
1193
- }
1194
- onValueChange?.(newValue);
1195
- }
1196
- return /* @__PURE__ */ jsxs14("div", { className: cn18("flex flex-col gap-1", className), children: [
1197
- showValue && /* @__PURE__ */ jsx18("span", { className: "self-start text-xs font-medium text-text-primary", children: currentValue }),
1198
- /* @__PURE__ */ jsxs14("div", { className: "relative flex h-5 w-full items-center", children: [
1199
- /* @__PURE__ */ jsx18("div", { className: "pointer-events-none absolute h-1.5 w-full overflow-hidden rounded-full bg-surface-3", children: /* @__PURE__ */ jsx18(
1200
- "div",
1201
- {
1202
- className: "h-full rounded-full bg-primary transition-all",
1203
- style: { width: `${fillPercent}%` }
1204
- }
1205
- ) }),
1206
- /* @__PURE__ */ jsx18(
1207
- "input",
1208
- {
1209
- ref,
1210
- type: "range",
1211
- min,
1212
- max,
1213
- step,
1214
- value: currentValue,
1215
- disabled,
1216
- onChange: handleChange,
1217
- className: cn18(
1218
- "relative h-5 w-full cursor-pointer appearance-none bg-transparent",
1219
- // thumb 样式
1220
- "[&::-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",
1221
- "[&::-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",
1222
- // track 透明(用自定义 div 代替)
1223
- "[&::-webkit-slider-runnable-track]:bg-transparent",
1224
- "[&::-moz-range-track]:bg-transparent",
1225
- // focus
1226
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
1227
- // disabled
1228
- "disabled:cursor-not-allowed disabled:opacity-50"
1229
- ),
1230
- ...props
1231
- }
1232
- )
1233
- ] })
1234
- ] });
1235
- }
1236
- );
1237
- Slider.displayName = "Slider";
1238
-
1239
- // src/components/number-input.tsx
1240
- import { forwardRef as forwardRef19, useState as useState4 } from "react";
1241
- import { Minus as Minus2, Plus } from "lucide-react";
1242
- import { cva as cva7 } from "class-variance-authority";
1243
- import { cn as cn19 } from "@ug666/ui-utils";
1244
- import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
1245
- var numberInputVariants = cva7(
1246
- "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",
230
+ id: "navigation",
231
+ label: "\u5BFC\u822A\u6D41\u7A0B",
232
+ description: "\u9875\u9762\u5B9A\u4F4D\u3001\u533A\u57DF\u5207\u6362\u3001\u5206\u9875\u548C\u6D41\u7A0B\u8868\u8FBE\uFF0C\u8981\u6C42\u9009\u4E2D\u6001\u660E\u786E\u4E14\u79FB\u52A8\u7AEF\u4E0D\u6EA2\u51FA\u3002",
233
+ components: [
234
+ { name: "UGTabs", route: "/react/components/tabs" },
235
+ { name: "UGBreadcrumb", route: "/react/components/breadcrumb" },
236
+ { name: "UGPagination", route: "/react/components/pagination" },
237
+ { name: "UGNavigationMenu", route: "/react/components/navigation-menu" },
238
+ { name: "UGSidebar", route: "/react/components/sidebar" },
239
+ { name: "UGSteps", route: "/react/components/steps" }
240
+ ]
241
+ },
1247
242
  {
1248
- variants: {
1249
- size: {
1250
- sm: "h-8 text-xs",
1251
- default: "h-9 text-sm",
1252
- lg: "h-11 text-base"
1253
- }
1254
- },
1255
- defaultVariants: {
1256
- size: "default"
1257
- }
1258
- }
1259
- );
1260
- var NumberInput = forwardRef19(
1261
- ({
1262
- className,
1263
- size,
1264
- value: valueProp,
1265
- defaultValue = 0,
1266
- min,
1267
- max,
1268
- step = 1,
1269
- precision = 0,
1270
- disabled = false,
1271
- placeholder,
1272
- onValueChange,
1273
- ...props
1274
- }, ref) => {
1275
- const isControlled = valueProp !== void 0;
1276
- const [uncontrolledValue, setUncontrolledValue] = useState4(defaultValue);
1277
- const currentValue = isControlled ? valueProp : uncontrolledValue;
1278
- function clamp(val) {
1279
- let result = val;
1280
- if (min !== void 0) result = Math.max(min, result);
1281
- if (max !== void 0) result = Math.min(max, result);
1282
- return result;
1283
- }
1284
- function format(val) {
1285
- return val.toFixed(precision);
1286
- }
1287
- function commit(newVal) {
1288
- const clamped = clamp(Number(newVal.toFixed(precision)));
1289
- if (!isControlled) {
1290
- setUncontrolledValue(clamped);
1291
- }
1292
- onValueChange?.(clamped);
1293
- }
1294
- function handleDecrement() {
1295
- commit(currentValue - step);
1296
- }
1297
- function handleIncrement() {
1298
- commit(currentValue + step);
1299
- }
1300
- function handleInputChange(e) {
1301
- const parsed = parseFloat(e.target.value);
1302
- if (!Number.isNaN(parsed)) {
1303
- commit(parsed);
1304
- }
1305
- }
1306
- function handleBlur(e) {
1307
- const parsed = parseFloat(e.target.value);
1308
- if (!Number.isNaN(parsed)) {
1309
- commit(parsed);
1310
- } else {
1311
- if (!isControlled) {
1312
- setUncontrolledValue(uncontrolledValue);
1313
- }
1314
- }
1315
- }
1316
- const atMin = min !== void 0 && currentValue <= min;
1317
- const atMax = max !== void 0 && currentValue >= max;
1318
- 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";
1319
- const btnSizeCls = size === "sm" ? "h-8 w-7" : size === "lg" ? "h-11 w-9" : "h-9 w-8";
1320
- const iconSize = size === "sm" ? 12 : size === "lg" ? 16 : 14;
1321
- return /* @__PURE__ */ jsxs15("div", { className: cn19(numberInputVariants({ size }), className), children: [
1322
- /* @__PURE__ */ jsx19(
1323
- "button",
1324
- {
1325
- type: "button",
1326
- "aria-label": "\u51CF\u5C11\u6570\u503C",
1327
- disabled: disabled || atMin,
1328
- onClick: handleDecrement,
1329
- className: cn19(btnBase, btnSizeCls, "rounded-l-md border-r border-border-base"),
1330
- tabIndex: -1,
1331
- children: /* @__PURE__ */ jsx19(Minus2, { size: iconSize })
1332
- }
1333
- ),
1334
- /* @__PURE__ */ jsx19(
1335
- "input",
1336
- {
1337
- ref,
1338
- type: "number",
1339
- className: cn19(
1340
- "min-w-0 flex-1 bg-transparent text-center text-text-primary outline-none",
1341
- "placeholder:text-text-tertiary",
1342
- // 隐藏原生 spinner
1343
- "[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
1344
- ),
1345
- value: format(currentValue),
1346
- disabled,
1347
- placeholder,
1348
- min,
1349
- max,
1350
- step,
1351
- onChange: handleInputChange,
1352
- onBlur: handleBlur,
1353
- ...props
1354
- }
1355
- ),
1356
- /* @__PURE__ */ jsx19(
1357
- "button",
1358
- {
1359
- type: "button",
1360
- "aria-label": "\u589E\u52A0\u6570\u503C",
1361
- disabled: disabled || atMax,
1362
- onClick: handleIncrement,
1363
- className: cn19(btnBase, btnSizeCls, "rounded-r-md border-l border-border-base"),
1364
- tabIndex: -1,
1365
- children: /* @__PURE__ */ jsx19(Plus, { size: iconSize })
1366
- }
1367
- )
1368
- ] });
1369
- }
1370
- );
1371
- NumberInput.displayName = "NumberInput";
1372
-
1373
- // src/components/otp-input.tsx
1374
- import { forwardRef as forwardRef20, useRef as useRef3, useCallback as useCallback4 } from "react";
1375
- import { cn as cn20 } from "@ug666/ui-utils";
1376
- import { jsx as jsx20 } from "react/jsx-runtime";
1377
- var OTPInput = forwardRef20(
1378
- ({
1379
- value,
1380
- onValueChange,
1381
- length = 6,
1382
- disabled = false,
1383
- onComplete,
1384
- className
1385
- }, ref) => {
1386
- const inputRefs = useRef3([]);
1387
- const focusAt = useCallback4((index) => {
1388
- const el = inputRefs.current[index];
1389
- if (el) {
1390
- el.focus();
1391
- el.setSelectionRange(el.value.length, el.value.length);
1392
- }
1393
- }, []);
1394
- const updateValueAt = useCallback4(
1395
- (index, char) => {
1396
- const chars = value.padEnd(length, "").split("").slice(0, length);
1397
- chars[index] = char;
1398
- const next = chars.join("");
1399
- onValueChange(next);
1400
- if (char && next.replace(/\s/g, "").length === length && !next.includes(" ")) {
1401
- onComplete?.(next);
1402
- }
1403
- },
1404
- [value, length, onValueChange, onComplete]
1405
- );
1406
- const handleChange = useCallback4(
1407
- (index, e) => {
1408
- const raw = e.target.value;
1409
- const digit = raw.replace(/\D/g, "").slice(-1);
1410
- updateValueAt(index, digit);
1411
- if (digit && index < length - 1) {
1412
- focusAt(index + 1);
1413
- }
1414
- },
1415
- [length, updateValueAt, focusAt]
1416
- );
1417
- const handleKeyDown = useCallback4(
1418
- (index, e) => {
1419
- if (e.key === "ArrowLeft") {
1420
- e.preventDefault();
1421
- if (index > 0) focusAt(index - 1);
1422
- } else if (e.key === "ArrowRight") {
1423
- e.preventDefault();
1424
- if (index < length - 1) focusAt(index + 1);
1425
- } else if (e.key === "Backspace") {
1426
- e.preventDefault();
1427
- const current = value[index] ?? "";
1428
- if (current) {
1429
- updateValueAt(index, "");
1430
- } else if (index > 0) {
1431
- updateValueAt(index - 1, "");
1432
- focusAt(index - 1);
1433
- }
1434
- }
1435
- },
1436
- [value, length, focusAt, updateValueAt]
1437
- );
1438
- const handlePaste = useCallback4(
1439
- (e) => {
1440
- e.preventDefault();
1441
- const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, length);
1442
- if (!pasted) return;
1443
- const chars = pasted.padEnd(length, "").split("").slice(0, length);
1444
- const next = chars.join("");
1445
- onValueChange(next);
1446
- const nextFocus = Math.min(pasted.length, length - 1);
1447
- focusAt(nextFocus);
1448
- if (pasted.length === length) {
1449
- onComplete?.(next);
1450
- }
1451
- },
1452
- [length, onValueChange, onComplete, focusAt]
1453
- );
1454
- return /* @__PURE__ */ jsx20(
1455
- "div",
1456
- {
1457
- ref,
1458
- className: cn20("flex items-center gap-2", className),
1459
- role: "group",
1460
- "aria-label": "\u9A8C\u8BC1\u7801\u8F93\u5165",
1461
- children: Array.from({ length }, (_, i) => {
1462
- const char = value[i] ?? "";
1463
- const isFocused = false;
1464
- return /* @__PURE__ */ jsx20(
1465
- "input",
1466
- {
1467
- ref: (el) => {
1468
- inputRefs.current[i] = el;
1469
- },
1470
- type: "text",
1471
- inputMode: "numeric",
1472
- pattern: "[0-9]",
1473
- maxLength: 1,
1474
- value: char,
1475
- disabled,
1476
- "aria-label": `\u9A8C\u8BC1\u7801\u7B2C ${i + 1} \u4F4D`,
1477
- className: cn20(
1478
- "h-10 w-10 rounded-md border text-center text-sm font-medium text-text-primary transition-colors",
1479
- "outline-none focus:border-primary focus:ring-2 focus:ring-ring/20",
1480
- "disabled:cursor-not-allowed disabled:opacity-50",
1481
- char ? "border-border-strong" : "border-border-base"
1482
- ),
1483
- onChange: (e) => handleChange(i, e),
1484
- onKeyDown: (e) => handleKeyDown(i, e),
1485
- onPaste: handlePaste,
1486
- onClick: (e) => e.target.select()
1487
- },
1488
- i
1489
- );
1490
- })
1491
- }
1492
- );
1493
- }
1494
- );
1495
- OTPInput.displayName = "OTPInput";
1496
-
1497
- // src/components/form.tsx
1498
- import {
1499
- createContext as createContext3,
1500
- forwardRef as forwardRef21,
1501
- useContext as useContext3,
1502
- useId as useId4,
1503
- cloneElement
1504
- } from "react";
1505
- import { cn as cn21 } from "@ug666/ui-utils";
1506
- import { jsx as jsx21 } from "react/jsx-runtime";
1507
- var FormFieldContext = createContext3(null);
1508
- function useFormFieldContext() {
1509
- const ctx = useContext3(FormFieldContext);
1510
- if (!ctx) {
1511
- throw new Error("FormField \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <FormField> \u5185\u4F7F\u7528");
1512
- }
1513
- return ctx;
1514
- }
1515
- var Form = forwardRef21(
1516
- ({ className, onSubmit, children, ...props }, ref) => {
1517
- function handleSubmit(event) {
1518
- event.preventDefault();
1519
- onSubmit?.(event);
1520
- }
1521
- return /* @__PURE__ */ jsx21(
1522
- "form",
1523
- {
1524
- ref,
1525
- className: cn21(className),
1526
- onSubmit: handleSubmit,
1527
- ...props,
1528
- children
1529
- }
1530
- );
1531
- }
1532
- );
1533
- Form.displayName = "Form";
1534
- var FormField = forwardRef21(
1535
- ({ name, error, className, children, ...props }, ref) => {
1536
- const generatedId = useId4();
1537
- return /* @__PURE__ */ jsx21(FormFieldContext.Provider, { value: { name, error, id: generatedId }, children: /* @__PURE__ */ jsx21("div", { ref, className: cn21(className), ...props, children }) });
1538
- }
1539
- );
1540
- FormField.displayName = "FormField";
1541
- var FormItem = forwardRef21(
1542
- ({ className, children, ...props }, ref) => {
1543
- return /* @__PURE__ */ jsx21(
1544
- "div",
1545
- {
1546
- ref,
1547
- className: cn21("flex flex-col gap-1.5", className),
1548
- ...props,
1549
- children
1550
- }
1551
- );
1552
- }
1553
- );
1554
- FormItem.displayName = "FormItem";
1555
- var FormLabel = forwardRef21(
1556
- ({ className, required, children, htmlFor, ...props }, ref) => {
1557
- const ctx = useFormFieldContext();
1558
- return /* @__PURE__ */ jsx21(
1559
- Label,
1560
- {
1561
- ref,
1562
- htmlFor: htmlFor ?? ctx.id,
1563
- required,
1564
- className: cn21(className),
1565
- ...props,
1566
- children
1567
- }
1568
- );
1569
- }
1570
- );
1571
- FormLabel.displayName = "FormLabel";
1572
- function FormControl({ children }) {
1573
- const ctx = useFormFieldContext();
1574
- const descriptionId = `${ctx.id}-description`;
1575
- const messageId = `${ctx.id}-message`;
1576
- return cloneElement(children, {
1577
- id: ctx.id,
1578
- "aria-describedby": ctx.error ? `${descriptionId} ${messageId}` : descriptionId,
1579
- "aria-invalid": ctx.error ? true : void 0
1580
- });
1581
- }
1582
- FormControl.displayName = "FormControl";
1583
- var FormDescription = forwardRef21(
1584
- ({ className, children, ...props }, ref) => {
1585
- const ctx = useFormFieldContext();
1586
- return /* @__PURE__ */ jsx21(
1587
- "p",
1588
- {
1589
- ref,
1590
- id: `${ctx.id}-description`,
1591
- className: cn21("text-xs text-text-secondary", className),
1592
- ...props,
1593
- children
1594
- }
1595
- );
1596
- }
1597
- );
1598
- FormDescription.displayName = "FormDescription";
1599
- var FormMessage = forwardRef21(
1600
- ({ className, children, ...props }, ref) => {
1601
- const ctx = useFormFieldContext();
1602
- const message = ctx.error ?? (typeof children === "string" ? children : void 0);
1603
- if (!message) return null;
1604
- return /* @__PURE__ */ jsx21(
1605
- "p",
1606
- {
1607
- ref,
1608
- id: `${ctx.id}-message`,
1609
- className: cn21("text-xs text-danger-soft-fg", className),
1610
- role: "alert",
1611
- ...props,
1612
- children: message
1613
- }
1614
- );
1615
- }
1616
- );
1617
- FormMessage.displayName = "FormMessage";
1618
-
1619
- // src/components/tabs.tsx
1620
- import { createContext as createContext4, forwardRef as forwardRef22, useContext as useContext4 } from "react";
1621
- import { cn as cn22 } from "@ug666/ui-utils";
1622
- import { jsx as jsx22 } from "react/jsx-runtime";
1623
- var TabsContext = createContext4(null);
1624
- function useTabsContext() {
1625
- const ctx = useContext4(TabsContext);
1626
- if (!ctx) throw new Error("Tabs \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Tabs> \u5185\u4F7F\u7528");
1627
- return ctx;
1628
- }
1629
- var Tabs = forwardRef22(({ value, onValueChange, children, className }, ref) => {
1630
- return /* @__PURE__ */ jsx22(TabsContext.Provider, { value: { value, onValueChange }, children: /* @__PURE__ */ jsx22("div", { ref, className: cn22("w-full", className), children }) });
1631
- });
1632
- var TabsList = forwardRef22(({ className, children, ...props }, ref) => {
1633
- return /* @__PURE__ */ jsx22(
1634
- "div",
1635
- {
1636
- ref,
1637
- role: "tablist",
1638
- className: cn22("inline-flex w-full items-center gap-0 border-b border-border-base", className),
1639
- ...props,
1640
- children
1641
- }
1642
- );
1643
- });
1644
- var TabsTrigger = forwardRef22(({ value, className, children, ...props }, ref) => {
1645
- const { value: activeValue, onValueChange } = useTabsContext();
1646
- const isActive = activeValue === value;
1647
- return /* @__PURE__ */ jsx22(
1648
- "button",
1649
- {
1650
- ref,
1651
- type: "button",
1652
- role: "tab",
1653
- "aria-selected": isActive,
1654
- tabIndex: isActive ? 0 : -1,
1655
- onClick: () => onValueChange(value),
1656
- className: cn22(
1657
- "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",
1658
- "after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-full after:transition-colors",
1659
- isActive ? "text-text-primary after:bg-primary" : "text-text-secondary hover:text-text-primary after:bg-transparent",
1660
- className
1661
- ),
1662
- ...props,
1663
- children
1664
- }
1665
- );
1666
- });
1667
- var TabsContent = forwardRef22(({ value, className, children, ...props }, ref) => {
1668
- const { value: activeValue } = useTabsContext();
1669
- if (activeValue !== value) return null;
1670
- return /* @__PURE__ */ jsx22(
1671
- "div",
1672
- {
1673
- ref,
1674
- role: "tabpanel",
1675
- tabIndex: 0,
1676
- className: cn22("mt-4 focus-visible:outline-none", className),
1677
- ...props,
1678
- children
1679
- }
1680
- );
1681
- });
1682
- Tabs.displayName = "Tabs";
1683
- TabsList.displayName = "TabsList";
1684
- TabsTrigger.displayName = "TabsTrigger";
1685
- TabsContent.displayName = "TabsContent";
1686
-
1687
- // src/components/accordion.tsx
1688
- import { createContext as createContext5, forwardRef as forwardRef23, useContext as useContext5, useState as useState5 } from "react";
1689
- import { ChevronDown } from "lucide-react";
1690
- import { cn as cn23 } from "@ug666/ui-utils";
1691
- import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1692
- var AccordionContext = createContext5(null);
1693
- var AccordionItemContext = createContext5(null);
1694
- function useAccordionContext() {
1695
- const ctx = useContext5(AccordionContext);
1696
- if (!ctx) throw new Error("Accordion \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Accordion> \u5185\u4F7F\u7528");
1697
- return ctx;
1698
- }
1699
- function useAccordionItemContext() {
1700
- const ctx = useContext5(AccordionItemContext);
1701
- if (!ctx) throw new Error("AccordionTrigger/AccordionContent \u5FC5\u987B\u5728 <AccordionItem> \u5185\u4F7F\u7528");
1702
- return ctx;
1703
- }
1704
- var Accordion = forwardRef23(
1705
- (props, ref) => {
1706
- const { type, children, className, ...rest } = props;
1707
- const isSingle = type === "single";
1708
- const singleProps = isSingle ? props : null;
1709
- const multiProps = !isSingle ? props : null;
1710
- const [internalSingle, setInternalSingle] = useState5(singleProps?.defaultValue ?? "");
1711
- const [internalMulti, setInternalMulti] = useState5(multiProps?.defaultValue ?? []);
1712
- const isControlledSingle = isSingle && singleProps?.value !== void 0;
1713
- const isControlledMulti = !isSingle && multiProps?.value !== void 0;
1714
- const value = isSingle ? isControlledSingle ? singleProps.value ?? "" : internalSingle : isControlledMulti ? multiProps.value ?? [] : internalMulti;
1715
- const collapsible = isSingle ? singleProps?.collapsible ?? false : false;
1716
- function handleValueChange(itemValue) {
1717
- if (isSingle) {
1718
- const current = value;
1719
- const next = current === itemValue && collapsible ? "" : itemValue;
1720
- if (!isControlledSingle) setInternalSingle(next);
1721
- singleProps?.onValueChange?.(next);
1722
- } else {
1723
- const current = value;
1724
- const next = current.includes(itemValue) ? current.filter((v) => v !== itemValue) : [...current, itemValue];
1725
- if (!isControlledMulti) setInternalMulti(next);
1726
- multiProps?.onValueChange?.(next);
1727
- }
1728
- }
1729
- const { defaultValue: _dv, onValueChange: _ov, collapsible: _col, ...domRest } = rest;
1730
- void _dv;
1731
- void _ov;
1732
- void _col;
1733
- return /* @__PURE__ */ jsx23(AccordionContext.Provider, { value: { type, value, onValueChange: handleValueChange, collapsible }, children: /* @__PURE__ */ jsx23("div", { ref, className: cn23("w-full divide-y divide-border-base rounded-md border border-border-base", className), ...domRest, children }) });
1734
- }
1735
- );
1736
- Accordion.displayName = "Accordion";
1737
- var AccordionItem = forwardRef23(({ value, className, children, ...props }, ref) => {
1738
- const { value: activeValue, type } = useAccordionContext();
1739
- const isOpen = type === "single" ? activeValue === value : activeValue.includes(value);
1740
- return /* @__PURE__ */ jsx23(AccordionItemContext.Provider, { value: { value, isOpen }, children: /* @__PURE__ */ jsx23("div", { ref, className: cn23("", className), ...props, children }) });
1741
- });
1742
- AccordionItem.displayName = "AccordionItem";
1743
- var AccordionTrigger = forwardRef23(({ className, children, ...props }, ref) => {
1744
- const { onValueChange } = useAccordionContext();
1745
- const { value, isOpen } = useAccordionItemContext();
1746
- return /* @__PURE__ */ jsxs16(
1747
- "button",
1748
- {
1749
- ref,
1750
- type: "button",
1751
- "aria-expanded": isOpen,
1752
- onClick: () => onValueChange(value),
1753
- className: cn23(
1754
- "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",
1755
- className
1756
- ),
1757
- ...props,
1758
- children: [
1759
- children,
1760
- /* @__PURE__ */ jsx23(
1761
- ChevronDown,
1762
- {
1763
- size: 16,
1764
- className: cn23("shrink-0 text-text-secondary transition-transform duration-200", isOpen && "rotate-180")
1765
- }
1766
- )
1767
- ]
1768
- }
1769
- );
1770
- });
1771
- AccordionTrigger.displayName = "AccordionTrigger";
1772
- var AccordionContent = forwardRef23(({ className, children, ...props }, ref) => {
1773
- const { isOpen } = useAccordionItemContext();
1774
- if (!isOpen) return null;
1775
- return /* @__PURE__ */ jsx23(
1776
- "div",
1777
- {
1778
- ref,
1779
- className: cn23("px-4 pb-4 pt-1 text-sm text-text-secondary", className),
1780
- ...props,
1781
- children
1782
- }
1783
- );
1784
- });
1785
- AccordionContent.displayName = "AccordionContent";
1786
-
1787
- // src/components/steps.tsx
1788
- import { forwardRef as forwardRef24 } from "react";
1789
- import { Check as Check2 } from "lucide-react";
1790
- import { cn as cn24 } from "@ug666/ui-utils";
1791
- import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1792
- var Steps = forwardRef24(
1793
- ({ current, items, direction = "horizontal", status = "process", className, ...props }, ref) => {
1794
- const isHorizontal = direction === "horizontal";
1795
- return /* @__PURE__ */ jsx24(
1796
- "div",
1797
- {
1798
- ref,
1799
- className: cn24(
1800
- isHorizontal ? "flex items-start" : "flex flex-col",
1801
- className
1802
- ),
1803
- ...props,
1804
- children: items.map((item, index) => {
1805
- const isFinished = index < current || index === current && status === "finish";
1806
- const isCurrent = index === current && status !== "finish";
1807
- const isError = index === current && status === "error";
1808
- const isLast = index === items.length - 1;
1809
- return /* @__PURE__ */ jsxs17(
1810
- "div",
1811
- {
1812
- className: cn24(
1813
- isHorizontal ? "flex flex-1 items-start" : "flex items-start"
1814
- ),
1815
- children: [
1816
- /* @__PURE__ */ jsxs17("div", { className: cn24("flex", isHorizontal ? "flex-col items-center" : "items-start"), children: [
1817
- /* @__PURE__ */ jsx24(
1818
- "div",
1819
- {
1820
- className: cn24(
1821
- "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold transition-colors",
1822
- isFinished && "border-primary bg-primary text-primary-fg",
1823
- isCurrent && !isError && "border-primary bg-surface-1 text-text-primary",
1824
- isError && "border-red-500 bg-surface-1 text-red-500",
1825
- !isFinished && !isCurrent && !isError && "border-border-strong bg-surface-1 text-text-tertiary"
1826
- ),
1827
- children: isFinished ? /* @__PURE__ */ jsx24(Check2, { size: 16, strokeWidth: 2.5 }) : item.icon ?? /* @__PURE__ */ jsx24("span", { children: index + 1 })
1828
- }
1829
- ),
1830
- !isLast && !isHorizontal && /* @__PURE__ */ jsx24(
1831
- "div",
1832
- {
1833
- className: cn24(
1834
- "ml-[15px] mt-1 w-0.5 flex-1 self-stretch",
1835
- isFinished ? "bg-primary" : "bg-border-base"
1836
- ),
1837
- style: { minHeight: "24px" }
1838
- }
1839
- )
1840
- ] }),
1841
- /* @__PURE__ */ jsxs17(
1842
- "div",
1843
- {
1844
- className: cn24(
1845
- isHorizontal ? "mt-2 text-center" : "ml-3 pb-6",
1846
- isLast && !isHorizontal && "pb-0"
1847
- ),
1848
- children: [
1849
- /* @__PURE__ */ jsx24(
1850
- "p",
1851
- {
1852
- className: cn24(
1853
- "text-sm font-medium",
1854
- isFinished && "text-text-primary",
1855
- isCurrent && !isError && "text-text-primary",
1856
- isError && "text-red-500",
1857
- !isFinished && !isCurrent && !isError && "text-text-tertiary"
1858
- ),
1859
- children: item.title
1860
- }
1861
- ),
1862
- item.description && /* @__PURE__ */ jsx24(
1863
- "p",
1864
- {
1865
- className: cn24(
1866
- "mt-0.5 text-xs",
1867
- isError ? "text-red-400" : "text-text-secondary"
1868
- ),
1869
- children: item.description
1870
- }
1871
- )
1872
- ]
1873
- }
1874
- ),
1875
- !isLast && isHorizontal && /* @__PURE__ */ jsx24(
1876
- "div",
1877
- {
1878
- className: cn24(
1879
- "mx-2 mt-4 h-0.5 flex-1",
1880
- isFinished ? "bg-primary" : "bg-border-base"
1881
- )
1882
- }
1883
- )
1884
- ]
1885
- },
1886
- index
1887
- );
1888
- })
1889
- }
1890
- );
1891
- }
1892
- );
1893
- Steps.displayName = "Steps";
1894
-
1895
- // src/components/dropdown.tsx
1896
- import { createContext as createContext6, forwardRef as forwardRef25, useCallback as useCallback5, useContext as useContext6, useEffect as useEffect5, useRef as useRef4, useState as useState6 } from "react";
1897
- import { createPortal as createPortal5 } from "react-dom";
1898
- import { cn as cn25 } from "@ug666/ui-utils";
1899
- import { jsx as jsx25 } from "react/jsx-runtime";
1900
- var DropdownContext = createContext6(null);
1901
- function assignRef(ref, value) {
1902
- if (typeof ref === "function") {
1903
- ref(value);
1904
- return;
1905
- }
1906
- if (ref) {
1907
- ref.current = value;
1908
- }
1909
- }
1910
- function useDropdownContext() {
1911
- const ctx = useContext6(DropdownContext);
1912
- if (!ctx) throw new Error("Dropdown \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <DropdownMenu> \u5185\u4F7F\u7528");
1913
- return ctx;
1914
- }
1915
- var DropdownMenu = forwardRef25(({ children, className }, ref) => {
1916
- const [open, setOpen] = useState6(false);
1917
- const triggerRef = useRef4(null);
1918
- return /* @__PURE__ */ jsx25(DropdownContext.Provider, { value: { open, setOpen, triggerRef }, children: /* @__PURE__ */ jsx25("div", { ref, className: cn25("relative inline-block", className), children }) });
1919
- });
1920
- var DropdownTrigger = forwardRef25(({ children, className }, ref) => {
1921
- const { setOpen, open, triggerRef } = useDropdownContext();
1922
- const handleRef = useCallback5(
1923
- (node) => {
1924
- triggerRef.current = node;
1925
- assignRef(ref, node);
1926
- },
1927
- [ref, triggerRef]
1928
- );
1929
- return /* @__PURE__ */ jsx25(
1930
- "div",
1931
- {
1932
- ref: handleRef,
1933
- className: cn25("inline-flex", className),
1934
- onClick: () => setOpen(!open),
1935
- children
1936
- }
1937
- );
1938
- });
1939
- var DropdownContent = forwardRef25(({ children, className, align = "start" }, ref) => {
1940
- const { open, setOpen, triggerRef } = useDropdownContext();
1941
- const contentRef = useRef4(null);
1942
- const [position, setPosition] = useState6({ top: 0, left: 0 });
1943
- const handleRef = useCallback5(
1944
- (node) => {
1945
- contentRef.current = node;
1946
- assignRef(ref, node);
1947
- },
1948
- [ref]
1949
- );
1950
- const updatePosition = useCallback5(() => {
1951
- if (!triggerRef.current) return;
1952
- const rect = triggerRef.current.getBoundingClientRect();
1953
- const top = rect.bottom + window.scrollY + 4;
1954
- const left = align === "end" ? rect.right + window.scrollX - (contentRef.current?.offsetWidth ?? 0) : rect.left + window.scrollX;
1955
- setPosition({ top, left });
1956
- }, [align, triggerRef]);
1957
- useEffect5(() => {
1958
- if (!open) return;
1959
- updatePosition();
1960
- }, [open, updatePosition]);
1961
- useEffect5(() => {
1962
- if (!open) return;
1963
- function handleClickOutside(e) {
1964
- if (contentRef.current && !contentRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
1965
- setOpen(false);
1966
- }
1967
- }
1968
- document.addEventListener("mousedown", handleClickOutside);
1969
- return () => document.removeEventListener("mousedown", handleClickOutside);
1970
- }, [open, setOpen, triggerRef]);
1971
- if (!open) return null;
1972
- return createPortal5(
1973
- /* @__PURE__ */ jsx25(
1974
- "div",
1975
- {
1976
- ref: handleRef,
1977
- style: { top: position.top, left: position.left },
1978
- className: cn25(
1979
- "absolute z-50 min-w-40 rounded-md border border-border-base bg-surface-1 py-1 shadow-lg",
1980
- className
1981
- ),
1982
- children
1983
- }
1984
- ),
1985
- document.body
1986
- );
1987
- });
1988
- var DropdownItem = forwardRef25(({ children, className, destructive = false, onClick, ...props }, ref) => {
1989
- const { setOpen } = useDropdownContext();
1990
- function handleClick(e) {
1991
- setOpen(false);
1992
- onClick?.(e);
1993
- }
1994
- return /* @__PURE__ */ jsx25(
1995
- "button",
1996
- {
1997
- ref,
1998
- type: "button",
1999
- className: cn25(
2000
- "w-full px-3 py-1.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:bg-surface-3",
2001
- destructive ? "text-red-600 hover:bg-red-50" : "text-text-primary hover:bg-surface-3",
2002
- className
2003
- ),
2004
- onClick: handleClick,
2005
- ...props,
2006
- children
2007
- }
2008
- );
2009
- });
2010
- var DropdownSeparator = forwardRef25(({ className, ...props }, ref) => {
2011
- return /* @__PURE__ */ jsx25("div", { ref, className: cn25("my-1 h-px bg-border-base", className), ...props });
2012
- });
2013
- DropdownMenu.displayName = "DropdownMenu";
2014
- DropdownTrigger.displayName = "DropdownTrigger";
2015
- DropdownContent.displayName = "DropdownContent";
2016
- DropdownItem.displayName = "DropdownItem";
2017
- DropdownSeparator.displayName = "DropdownSeparator";
2018
-
2019
- // src/components/popover.tsx
2020
- import { createContext as createContext7, forwardRef as forwardRef26, useCallback as useCallback6, useContext as useContext7, useEffect as useEffect6, useRef as useRef5, useState as useState7 } from "react";
2021
- import { createPortal as createPortal6 } from "react-dom";
2022
- import { cn as cn26 } from "@ug666/ui-utils";
2023
- import { jsx as jsx26 } from "react/jsx-runtime";
2024
- var PopoverContext = createContext7(null);
2025
- function usePopoverContext() {
2026
- const ctx = useContext7(PopoverContext);
2027
- if (!ctx) throw new Error("Popover \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Popover> \u5185\u4F7F\u7528");
2028
- return ctx;
2029
- }
2030
- function assignRef2(ref, value) {
2031
- if (typeof ref === "function") {
2032
- ref(value);
2033
- return;
2034
- }
2035
- if (ref) {
2036
- ref.current = value;
2037
- }
2038
- }
2039
- var Popover = ({ open: controlledOpen, defaultOpen = false, onOpenChange, children }) => {
2040
- const [internalOpen, setInternalOpen] = useState7(defaultOpen);
2041
- const triggerRef = useRef5(null);
2042
- const isControlled = controlledOpen !== void 0;
2043
- const open = isControlled ? controlledOpen : internalOpen;
2044
- const setOpen = useCallback6(
2045
- (value) => {
2046
- if (!isControlled) setInternalOpen(value);
2047
- onOpenChange?.(value);
2048
- },
2049
- [isControlled, onOpenChange]
2050
- );
2051
- return /* @__PURE__ */ jsx26(PopoverContext.Provider, { value: { open, setOpen, triggerRef }, children });
2052
- };
2053
- Popover.displayName = "Popover";
2054
- var PopoverTrigger = forwardRef26(({ children, className }, ref) => {
2055
- const { setOpen, open, triggerRef } = usePopoverContext();
2056
- const handleRef = useCallback6(
2057
- (node) => {
2058
- triggerRef.current = node;
2059
- assignRef2(ref, node);
2060
- },
2061
- [ref, triggerRef]
2062
- );
2063
- return /* @__PURE__ */ jsx26(
2064
- "div",
2065
- {
2066
- ref: handleRef,
2067
- className: cn26("inline-flex", className),
2068
- onClick: () => setOpen(!open),
2069
- children
2070
- }
2071
- );
2072
- });
2073
- PopoverTrigger.displayName = "PopoverTrigger";
2074
- function calcPosition(triggerRect, contentEl, side, align, sideOffset) {
2075
- const cw = contentEl.offsetWidth;
2076
- const ch = contentEl.offsetHeight;
2077
- let top = 0;
2078
- let left = 0;
2079
- if (side === "bottom") {
2080
- top = triggerRect.bottom + window.scrollY + sideOffset;
2081
- } else if (side === "top") {
2082
- top = triggerRect.top + window.scrollY - ch - sideOffset;
2083
- } else if (side === "left") {
2084
- top = triggerRect.top + window.scrollY + triggerRect.height / 2 - ch / 2;
2085
- left = triggerRect.left + window.scrollX - cw - sideOffset;
2086
- return { top, left };
2087
- } else {
2088
- top = triggerRect.top + window.scrollY + triggerRect.height / 2 - ch / 2;
2089
- left = triggerRect.right + window.scrollX + sideOffset;
2090
- return { top, left };
2091
- }
2092
- if (align === "start") {
2093
- left = triggerRect.left + window.scrollX;
2094
- } else if (align === "end") {
2095
- left = triggerRect.right + window.scrollX - cw;
2096
- } else {
2097
- left = triggerRect.left + window.scrollX + triggerRect.width / 2 - cw / 2;
2098
- }
2099
- return { top, left };
2100
- }
2101
- var PopoverContent = forwardRef26(
2102
- ({ children, className, side = "bottom", align = "center", sideOffset = 4, ...props }, ref) => {
2103
- const { open, setOpen, triggerRef } = usePopoverContext();
2104
- const contentRef = useRef5(null);
2105
- const [pos, setPos] = useState7({ top: 0, left: 0 });
2106
- const handleRef = useCallback6(
2107
- (node) => {
2108
- contentRef.current = node;
2109
- assignRef2(ref, node);
2110
- },
2111
- [ref]
2112
- );
2113
- const updatePos = useCallback6(() => {
2114
- if (!triggerRef.current || !contentRef.current) return;
2115
- const rect = triggerRef.current.getBoundingClientRect();
2116
- setPos(calcPosition(rect, contentRef.current, side, align, sideOffset));
2117
- }, [side, align, sideOffset, triggerRef]);
2118
- useEffect6(() => {
2119
- if (open) updatePos();
2120
- }, [open, updatePos]);
2121
- useEffect6(() => {
2122
- if (!open) return;
2123
- function handleMouseDown(e) {
2124
- if (contentRef.current && !contentRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
2125
- setOpen(false);
2126
- }
2127
- }
2128
- document.addEventListener("mousedown", handleMouseDown);
2129
- return () => document.removeEventListener("mousedown", handleMouseDown);
2130
- }, [open, setOpen, triggerRef]);
2131
- if (!open) return null;
2132
- return createPortal6(
2133
- /* @__PURE__ */ jsx26(
2134
- "div",
2135
- {
2136
- ref: handleRef,
2137
- style: { top: pos.top, left: pos.left },
2138
- className: cn26(
2139
- "absolute z-50 min-w-40 rounded-md border border-border-base bg-surface-1 p-3 shadow-lg",
2140
- className
2141
- ),
2142
- ...props,
2143
- children
2144
- }
2145
- ),
2146
- document.body
2147
- );
2148
- }
2149
- );
2150
- PopoverContent.displayName = "PopoverContent";
2151
-
2152
- // src/components/context-menu.tsx
2153
- import { createContext as createContext8, forwardRef as forwardRef27, useCallback as useCallback7, useContext as useContext8, useEffect as useEffect7, useRef as useRef6, useState as useState8 } from "react";
2154
- import { createPortal as createPortal7 } from "react-dom";
2155
- import { cn as cn27 } from "@ug666/ui-utils";
2156
- import { jsx as jsx27 } from "react/jsx-runtime";
2157
- var ContextMenuContext = createContext8(null);
2158
- function useContextMenuContext() {
2159
- const ctx = useContext8(ContextMenuContext);
2160
- if (!ctx) throw new Error("ContextMenu \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <ContextMenu> \u5185\u4F7F\u7528");
2161
- return ctx;
2162
- }
2163
- function assignRef3(ref, value) {
2164
- if (typeof ref === "function") {
2165
- ref(value);
2166
- return;
2167
- }
2168
- if (ref) {
2169
- ref.current = value;
2170
- }
2171
- }
2172
- var ContextMenu = forwardRef27(
2173
- ({ children, className }, ref) => {
2174
- const [open, setOpen] = useState8(false);
2175
- const [position, setPosition] = useState8({ x: 0, y: 0 });
2176
- const openAt = useCallback7((pos) => {
2177
- setPosition(pos);
2178
- setOpen(true);
2179
- }, []);
2180
- return /* @__PURE__ */ jsx27(ContextMenuContext.Provider, { value: { open, position, setOpen, openAt }, children: /* @__PURE__ */ jsx27("div", { ref, className: cn27("relative", className), children }) });
2181
- }
2182
- );
2183
- var ContextMenuTrigger = forwardRef27(
2184
- ({ children, className, ...props }, ref) => {
2185
- const { openAt } = useContextMenuContext();
2186
- function handleContextMenu(e) {
2187
- e.preventDefault();
2188
- openAt({ x: e.clientX, y: e.clientY });
2189
- }
2190
- return /* @__PURE__ */ jsx27(
2191
- "div",
2192
- {
2193
- ref,
2194
- className: cn27(className),
2195
- onContextMenu: handleContextMenu,
2196
- ...props,
2197
- children
2198
- }
2199
- );
2200
- }
2201
- );
2202
- var ContextMenuContent = forwardRef27(
2203
- ({ children, className, ...props }, ref) => {
2204
- const { open, position, setOpen } = useContextMenuContext();
2205
- const contentRef = useRef6(null);
2206
- const handleRef = useCallback7(
2207
- (node) => {
2208
- contentRef.current = node;
2209
- assignRef3(ref, node);
2210
- },
2211
- [ref]
2212
- );
2213
- useEffect7(() => {
2214
- if (!open) return;
2215
- function handleMouseDown(e) {
2216
- if (contentRef.current && !contentRef.current.contains(e.target)) {
2217
- setOpen(false);
2218
- }
2219
- }
2220
- function handleKeyDown(e) {
2221
- if (e.key === "Escape") {
2222
- setOpen(false);
2223
- }
2224
- }
2225
- document.addEventListener("mousedown", handleMouseDown);
2226
- document.addEventListener("keydown", handleKeyDown);
2227
- return () => {
2228
- document.removeEventListener("mousedown", handleMouseDown);
2229
- document.removeEventListener("keydown", handleKeyDown);
2230
- };
2231
- }, [open, setOpen]);
2232
- if (!open) return null;
2233
- return createPortal7(
2234
- /* @__PURE__ */ jsx27(
2235
- "div",
2236
- {
2237
- ref: handleRef,
2238
- style: { top: position.y, left: position.x },
2239
- className: cn27(
2240
- "fixed z-50 min-w-40 rounded-md border border-border-base bg-surface-1 py-1 shadow-lg",
2241
- className
2242
- ),
2243
- ...props,
2244
- children
2245
- }
2246
- ),
2247
- document.body
2248
- );
2249
- }
2250
- );
2251
- var ContextMenuItem = forwardRef27(
2252
- ({ children, className, destructive = false, onClick, ...props }, ref) => {
2253
- const { setOpen } = useContextMenuContext();
2254
- function handleClick(e) {
2255
- setOpen(false);
2256
- onClick?.(e);
2257
- }
2258
- return /* @__PURE__ */ jsx27(
2259
- "button",
2260
- {
2261
- ref,
2262
- type: "button",
2263
- className: cn27(
2264
- "w-full px-3 py-1.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:bg-surface-3",
2265
- destructive ? "text-red-600 hover:bg-red-50" : "text-text-primary hover:bg-surface-3",
2266
- className
2267
- ),
2268
- onClick: handleClick,
2269
- ...props,
2270
- children
2271
- }
2272
- );
2273
- }
2274
- );
2275
- var ContextMenuSeparator = forwardRef27(
2276
- ({ className, ...props }, ref) => {
2277
- return /* @__PURE__ */ jsx27("div", { ref, className: cn27("my-1 h-px bg-border-base", className), ...props });
2278
- }
2279
- );
2280
- ContextMenu.displayName = "ContextMenu";
2281
- ContextMenuTrigger.displayName = "ContextMenuTrigger";
2282
- ContextMenuContent.displayName = "ContextMenuContent";
2283
- ContextMenuItem.displayName = "ContextMenuItem";
2284
- ContextMenuSeparator.displayName = "ContextMenuSeparator";
2285
-
2286
- // src/components/navigation-menu.tsx
2287
- import { createContext as createContext9, forwardRef as forwardRef28, useCallback as useCallback8, useContext as useContext9, useRef as useRef7, useState as useState9 } from "react";
2288
- import { ChevronDown as ChevronDown2 } from "lucide-react";
2289
- import { cn as cn28 } from "@ug666/ui-utils";
2290
- import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
2291
- var NavigationMenuContext = createContext9(null);
2292
- function useNavigationMenuContext() {
2293
- const ctx = useContext9(NavigationMenuContext);
2294
- if (!ctx) throw new Error("NavigationMenu \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <NavigationMenu> \u5185\u4F7F\u7528");
2295
- return ctx;
2296
- }
2297
- var NavigationMenuItemContext = createContext9(null);
2298
- function useNavigationMenuItemContext() {
2299
- const ctx = useContext9(NavigationMenuItemContext);
2300
- if (!ctx) throw new Error("NavigationMenuTrigger/Content \u5FC5\u987B\u5728 <NavigationMenuItem> \u5185\u4F7F\u7528");
2301
- return ctx;
2302
- }
2303
- var _idCounter = 0;
2304
- var NavigationMenu = forwardRef28(
2305
- ({ className, children, ...props }, ref) => {
2306
- const [activeItem, setActiveItem] = useState9(null);
2307
- return /* @__PURE__ */ jsx28(NavigationMenuContext.Provider, { value: { activeItem, setActiveItem }, children: /* @__PURE__ */ jsx28(
2308
- "nav",
2309
- {
2310
- ref,
2311
- className: cn28("relative flex items-center gap-1", className),
2312
- ...props,
2313
- children
2314
- }
2315
- ) });
2316
- }
2317
- );
2318
- var NavigationMenuItem = forwardRef28(
2319
- ({ className, children, ...props }, ref) => {
2320
- const itemIdRef = useRef7(`nav-item-${++_idCounter}`);
2321
- const { activeItem, setActiveItem } = useNavigationMenuContext();
2322
- const isOpen = activeItem === itemIdRef.current;
2323
- const handleMouseEnter = useCallback8(() => {
2324
- setActiveItem(itemIdRef.current);
2325
- }, [setActiveItem]);
2326
- const handleMouseLeave = useCallback8(() => {
2327
- setActiveItem(null);
2328
- }, [setActiveItem]);
2329
- return /* @__PURE__ */ jsx28(NavigationMenuItemContext.Provider, { value: { itemId: itemIdRef.current }, children: /* @__PURE__ */ jsx28(
2330
- "div",
2331
- {
2332
- ref,
2333
- className: cn28("relative", className),
2334
- onMouseEnter: handleMouseEnter,
2335
- onMouseLeave: handleMouseLeave,
2336
- "data-state": isOpen ? "open" : "closed",
2337
- ...props,
2338
- children
2339
- }
2340
- ) });
2341
- }
2342
- );
2343
- var NavigationMenuLink = forwardRef28(
2344
- ({ className, active = false, children, ...props }, ref) => {
2345
- return /* @__PURE__ */ jsx28(
2346
- "a",
2347
- {
2348
- ref,
2349
- className: cn28(
2350
- "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",
2351
- active ? "bg-surface-3 text-text-primary" : "text-text-secondary hover:bg-surface-3 hover:text-text-primary",
2352
- className
2353
- ),
2354
- ...props,
2355
- children
2356
- }
2357
- );
2358
- }
2359
- );
2360
- var NavigationMenuTrigger = forwardRef28(
2361
- ({ className, children, ...props }, ref) => {
2362
- const { activeItem } = useNavigationMenuContext();
2363
- const { itemId } = useNavigationMenuItemContext();
2364
- const isOpen = activeItem === itemId;
2365
- return /* @__PURE__ */ jsxs18(
2366
- "button",
2367
- {
2368
- ref,
2369
- type: "button",
2370
- "aria-expanded": isOpen,
2371
- className: cn28(
2372
- "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",
2373
- isOpen ? "bg-surface-3 text-text-primary" : "text-text-secondary hover:bg-surface-3 hover:text-text-primary",
2374
- className
2375
- ),
2376
- ...props,
2377
- children: [
2378
- children,
2379
- /* @__PURE__ */ jsx28(
2380
- ChevronDown2,
2381
- {
2382
- size: 14,
2383
- className: cn28("transition-transform duration-200", isOpen && "rotate-180")
2384
- }
2385
- )
2386
- ]
2387
- }
2388
- );
2389
- }
2390
- );
2391
- var NavigationMenuContent = forwardRef28(
2392
- ({ className, children, ...props }, ref) => {
2393
- const { activeItem } = useNavigationMenuContext();
2394
- const { itemId } = useNavigationMenuItemContext();
2395
- const isOpen = activeItem === itemId;
2396
- if (!isOpen) return null;
2397
- return /* @__PURE__ */ jsx28(
2398
- "div",
2399
- {
2400
- ref,
2401
- className: cn28(
2402
- "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",
2403
- className
2404
- ),
2405
- ...props,
2406
- children
2407
- }
2408
- );
2409
- }
2410
- );
2411
- NavigationMenu.displayName = "NavigationMenu";
2412
- NavigationMenuItem.displayName = "NavigationMenuItem";
2413
- NavigationMenuLink.displayName = "NavigationMenuLink";
2414
- NavigationMenuTrigger.displayName = "NavigationMenuTrigger";
2415
- NavigationMenuContent.displayName = "NavigationMenuContent";
2416
-
2417
- // src/components/avatar.tsx
2418
- import {
2419
- createContext as createContext10,
2420
- forwardRef as forwardRef29,
2421
- useContext as useContext10,
2422
- useEffect as useEffect8,
2423
- useState as useState10
2424
- } from "react";
2425
- import { User } from "lucide-react";
2426
- import { cva as cva8 } from "class-variance-authority";
2427
- import { cn as cn29 } from "@ug666/ui-utils";
2428
- import { jsx as jsx29 } from "react/jsx-runtime";
2429
- var AvatarContext = createContext10(null);
2430
- function useAvatarContext(componentName) {
2431
- const ctx = useContext10(AvatarContext);
2432
- if (!ctx) {
2433
- throw new Error(`<${componentName}> \u5FC5\u987B\u5728 <Avatar> \u5185\u4F7F\u7528`);
2434
- }
2435
- return ctx;
2436
- }
2437
- var avatarVariants = cva8(
2438
- "relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-surface-3",
243
+ id: "overlays",
244
+ label: "\u6D6E\u5C42\u5F39\u5C42",
245
+ description: "\u4E34\u65F6\u627F\u8F7D\u64CD\u4F5C\u548C\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF0C\u8981\u6C42\u5B9A\u4F4D\u3001\u5173\u95ED\u3001\u7126\u70B9\u548C\u906E\u7F69\u884C\u4E3A\u53EF\u9760\u3002",
246
+ components: [
247
+ { name: "UGModal", route: "/react/components/modal" },
248
+ { name: "UGDialog", route: "/react/components/dialog" },
249
+ { name: "UGDrawer", route: "/react/components/drawer" },
250
+ { name: "UGSheet", route: "/react/components/sheet" },
251
+ { name: "UGDropdownMenu", route: "/react/components/dropdown" },
252
+ { name: "UGContextMenu", route: "/react/components/context-menu" },
253
+ { name: "UGPopover", route: "/react/components/popover" },
254
+ { name: "UGTooltip", route: "/react/components/tooltip" }
255
+ ]
256
+ },
2439
257
  {
2440
- variants: {
2441
- size: {
2442
- sm: "h-8 w-8 text-xs",
2443
- md: "h-10 w-10 text-sm",
2444
- lg: "h-14 w-14 text-base",
2445
- xl: "h-20 w-20 text-xl"
2446
- }
2447
- },
2448
- defaultVariants: { size: "md" }
2449
- }
2450
- );
2451
- var Avatar = forwardRef29(
2452
- ({ size, className, children, ...props }, ref) => {
2453
- const [imageLoadingStatus, setImageLoadingStatus] = useState10("idle");
2454
- return /* @__PURE__ */ jsx29(AvatarContext.Provider, { value: { imageLoadingStatus, setImageLoadingStatus }, children: /* @__PURE__ */ jsx29("span", { ref, className: cn29(avatarVariants({ size }), className), ...props, children }) });
2455
- }
2456
- );
2457
- var AvatarImage = forwardRef29(
2458
- ({ src, alt = "", className, onLoad, onError, ...props }, ref) => {
2459
- const { imageLoadingStatus, setImageLoadingStatus } = useAvatarContext("AvatarImage");
2460
- useEffect8(() => {
2461
- if (!src) {
2462
- setImageLoadingStatus("error");
2463
- return;
2464
- }
2465
- setImageLoadingStatus("loading");
2466
- }, [src, setImageLoadingStatus]);
2467
- if (imageLoadingStatus !== "loaded" && imageLoadingStatus !== "loading") {
2468
- return null;
2469
- }
2470
- return /* @__PURE__ */ jsx29(
2471
- "img",
2472
- {
2473
- ref,
2474
- src,
2475
- alt,
2476
- onLoad: (event) => {
2477
- setImageLoadingStatus("loaded");
2478
- onLoad?.(event);
2479
- },
2480
- onError: (event) => {
2481
- setImageLoadingStatus("error");
2482
- onError?.(event);
2483
- },
2484
- className: cn29(
2485
- "h-full w-full object-cover",
2486
- imageLoadingStatus === "loading" && "invisible",
2487
- className
2488
- ),
2489
- ...props
2490
- }
2491
- );
2492
- }
2493
- );
2494
- var AvatarFallback = forwardRef29(
2495
- ({ className, children, ...props }, ref) => {
2496
- const { imageLoadingStatus } = useAvatarContext("AvatarFallback");
2497
- if (imageLoadingStatus === "loaded") return null;
2498
- return /* @__PURE__ */ jsx29(
2499
- "span",
2500
- {
2501
- ref,
2502
- className: cn29(
2503
- "absolute inset-0 flex items-center justify-center font-medium text-text-secondary",
2504
- className
2505
- ),
2506
- ...props,
2507
- children: children ?? /* @__PURE__ */ jsx29(User, { size: 16 })
2508
- }
2509
- );
2510
- }
2511
- );
2512
- Avatar.displayName = "Avatar";
2513
- AvatarImage.displayName = "AvatarImage";
2514
- AvatarFallback.displayName = "AvatarFallback";
2515
-
2516
- // src/components/avatar-group.tsx
2517
- import { forwardRef as forwardRef30, Children, isValidElement } from "react";
2518
- import { cn as cn30 } from "@ug666/ui-utils";
2519
- import { jsx as jsx30, jsxs as jsxs19 } from "react/jsx-runtime";
2520
- var SIZE_CLASSES = {
2521
- sm: "h-8 w-8 text-xs",
2522
- default: "h-10 w-10 text-sm",
2523
- lg: "h-14 w-14 text-base"
2524
- };
2525
- var RING_SIZE_CLASSES = {
2526
- sm: "ring-2",
2527
- default: "ring-2",
2528
- lg: "ring-[3px]"
2529
- };
2530
- var OVERLAP_CLASSES = {
2531
- sm: "-ml-2",
2532
- default: "-ml-3",
2533
- lg: "-ml-4"
2534
- };
2535
- var AvatarGroup = forwardRef30(
2536
- ({ max = 5, size = "default", className, children, ...props }, ref) => {
2537
- const allItems = Children.toArray(children).filter(isValidElement);
2538
- const visibleItems = allItems.slice(0, max);
2539
- const overflowCount = allItems.length - max;
2540
- return /* @__PURE__ */ jsxs19(
2541
- "div",
2542
- {
2543
- ref,
2544
- className: cn30("flex items-center", className),
2545
- ...props,
2546
- children: [
2547
- visibleItems.map((child, idx) => /* @__PURE__ */ jsx30(
2548
- "span",
2549
- {
2550
- className: cn30(
2551
- "relative inline-flex shrink-0 overflow-hidden rounded-full ring-surface-1",
2552
- SIZE_CLASSES[size],
2553
- RING_SIZE_CLASSES[size],
2554
- idx > 0 && OVERLAP_CLASSES[size]
2555
- ),
2556
- children: child
2557
- },
2558
- idx
2559
- )),
2560
- overflowCount > 0 && /* @__PURE__ */ jsxs19(
2561
- "span",
2562
- {
2563
- className: cn30(
2564
- "relative inline-flex shrink-0 items-center justify-center rounded-full bg-surface-3 font-medium text-text-secondary ring-surface-1",
2565
- SIZE_CLASSES[size],
2566
- RING_SIZE_CLASSES[size],
2567
- OVERLAP_CLASSES[size]
2568
- ),
2569
- "aria-label": `\u8FD8\u6709 ${overflowCount} \u4EBA`,
2570
- children: [
2571
- "+",
2572
- overflowCount
2573
- ]
2574
- }
2575
- )
2576
- ]
2577
- }
2578
- );
2579
- }
2580
- );
2581
- AvatarGroup.displayName = "AvatarGroup";
2582
-
2583
- // src/components/tooltip.tsx
2584
- import { createContext as createContext11, forwardRef as forwardRef31, useCallback as useCallback9, useContext as useContext11, useEffect as useEffect9, useRef as useRef8, useState as useState11 } from "react";
2585
- import { createPortal as createPortal8 } from "react-dom";
2586
- import { cn as cn31 } from "@ug666/ui-utils";
2587
- import { jsx as jsx31 } from "react/jsx-runtime";
2588
- var TooltipContext = createContext11(null);
2589
- function assignRef4(ref, value) {
2590
- if (typeof ref === "function") {
2591
- ref(value);
2592
- return;
2593
- }
2594
- if (ref) {
2595
- ref.current = value;
2596
- }
2597
- }
2598
- function useTooltipContext() {
2599
- const ctx = useContext11(TooltipContext);
2600
- if (!ctx) throw new Error("Tooltip \u5B50\u7EC4\u4EF6\u5FC5\u987B\u5728 <Tooltip> \u5185\u4F7F\u7528");
2601
- return ctx;
2602
- }
2603
- var Tooltip = forwardRef31(({ children, className }, ref) => {
2604
- const [open, setOpen] = useState11(false);
2605
- const triggerRef = useRef8(null);
2606
- const delayRef = useRef8(null);
2607
- useEffect9(() => {
2608
- return () => {
2609
- if (delayRef.current) {
2610
- clearTimeout(delayRef.current);
2611
- }
2612
- };
2613
- }, []);
2614
- return /* @__PURE__ */ jsx31(TooltipContext.Provider, { value: { open, setOpen, triggerRef, delayRef }, children: /* @__PURE__ */ jsx31("span", { ref, className: cn31("relative inline-flex", className), children }) });
2615
- });
2616
- var TooltipTrigger = forwardRef31(({ children, className }, ref) => {
2617
- const { setOpen, triggerRef, delayRef } = useTooltipContext();
2618
- const handleRef = useCallback9(
2619
- (node) => {
2620
- triggerRef.current = node;
2621
- assignRef4(ref, node);
2622
- },
2623
- [ref, triggerRef]
2624
- );
2625
- function handleMouseEnter() {
2626
- delayRef.current = setTimeout(() => setOpen(true), 200);
2627
- }
2628
- function handleMouseLeave() {
2629
- if (delayRef.current) clearTimeout(delayRef.current);
2630
- setOpen(false);
2631
- }
2632
- return /* @__PURE__ */ jsx31(
2633
- "span",
2634
- {
2635
- ref: handleRef,
2636
- className: cn31("inline-flex", className),
2637
- onMouseEnter: handleMouseEnter,
2638
- onMouseLeave: handleMouseLeave,
2639
- children
2640
- }
2641
- );
2642
- });
2643
- var arrowPositionClasses = {
2644
- 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",
2645
- 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",
2646
- 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",
2647
- 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"
2648
- };
2649
- var TooltipContent = forwardRef31(({ children, side = "top", className }, ref) => {
2650
- const { open, triggerRef } = useTooltipContext();
2651
- const contentRef = useRef8(null);
2652
- const [pos, setPos] = useState11({ top: 0, left: 0 });
2653
- const handleRef = useCallback9(
2654
- (node) => {
2655
- contentRef.current = node;
2656
- assignRef4(ref, node);
2657
- },
2658
- [ref]
2659
- );
2660
- const updatePos = useCallback9(() => {
2661
- if (!triggerRef.current || !contentRef.current) return;
2662
- const rect = triggerRef.current.getBoundingClientRect();
2663
- const cw = contentRef.current.offsetWidth;
2664
- const ch = contentRef.current.offsetHeight;
2665
- const gap = 8;
2666
- let top = 0;
2667
- let left = 0;
2668
- if (side === "top") {
2669
- top = rect.top + window.scrollY - ch - gap;
2670
- left = rect.left + window.scrollX + rect.width / 2 - cw / 2;
2671
- } else if (side === "bottom") {
2672
- top = rect.bottom + window.scrollY + gap;
2673
- left = rect.left + window.scrollX + rect.width / 2 - cw / 2;
2674
- } else if (side === "left") {
2675
- top = rect.top + window.scrollY + rect.height / 2 - ch / 2;
2676
- left = rect.left + window.scrollX - cw - gap;
2677
- } else {
2678
- top = rect.top + window.scrollY + rect.height / 2 - ch / 2;
2679
- left = rect.right + window.scrollX + gap;
2680
- }
2681
- setPos({ top, left });
2682
- }, [side, triggerRef]);
2683
- useEffect9(() => {
2684
- if (open) updatePos();
2685
- }, [open, updatePos]);
2686
- if (!open) return null;
2687
- return createPortal8(
2688
- /* @__PURE__ */ jsx31(
2689
- "div",
2690
- {
2691
- ref: handleRef,
2692
- style: { top: pos.top, left: pos.left },
2693
- className: cn31(
2694
- "absolute z-50 rounded-md bg-text-primary px-2.5 py-1.5 text-xs text-surface-1 shadow-md",
2695
- arrowPositionClasses[side],
2696
- className
2697
- ),
2698
- children
2699
- }
2700
- ),
2701
- document.body
2702
- );
2703
- });
2704
- Tooltip.displayName = "Tooltip";
2705
- TooltipTrigger.displayName = "TooltipTrigger";
2706
- TooltipContent.displayName = "TooltipContent";
2707
-
2708
- // src/components/alert.tsx
2709
- import { forwardRef as forwardRef32 } from "react";
2710
- import { Info, CheckCircle, AlertTriangle, AlertCircle } from "lucide-react";
2711
- import { cva as cva9 } from "class-variance-authority";
2712
- import { cn as cn32 } from "@ug666/ui-utils";
2713
- import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
2714
- var alertVariants = cva9(
2715
- "relative flex gap-3 rounded-md border-l-4 p-4",
258
+ id: "feedback",
259
+ label: "\u53CD\u9988\u72B6\u6001",
260
+ description: "\u8868\u8FBE\u6210\u529F\u3001\u8B66\u544A\u3001\u9519\u8BEF\u3001\u7A7A\u72B6\u6001\u548C\u52A0\u8F7D\u8FC7\u7A0B\uFF0C\u8981\u6C42\u8BED\u4E49\u6587\u6848\u548C\u89C6\u89C9\u72B6\u6001\u4E00\u81F4\u3002",
261
+ components: [
262
+ { name: "UGAlert", route: "/react/components/alert" },
263
+ { name: "UGToaster", route: "/react/components/toast" },
264
+ { name: "UGProgress", route: "/react/components/progress" },
265
+ { name: "UGSkeleton", route: "/react/components/skeleton" },
266
+ { name: "UGEmptyState", route: "/react/components/empty-state" }
267
+ ]
268
+ },
2716
269
  {
2717
- variants: {
2718
- variant: {
2719
- default: "border-l-primary bg-info-soft text-info-soft-fg",
2720
- info: "border-l-info bg-info-soft text-info-soft-fg",
2721
- success: "border-l-success bg-success-soft text-success-soft-fg",
2722
- warning: "border-l-warning bg-warning-soft text-warning-soft-fg",
2723
- destructive: "border-l-danger bg-danger-soft text-danger-soft-fg"
2724
- }
2725
- },
2726
- defaultVariants: { variant: "default" }
2727
- }
2728
- );
2729
- var iconMap = {
2730
- default: AlertCircle,
2731
- info: Info,
2732
- success: CheckCircle,
2733
- warning: AlertTriangle,
2734
- destructive: AlertCircle
2735
- };
2736
- var iconColorMap = {
2737
- default: "text-info",
2738
- info: "text-info",
2739
- success: "text-success",
2740
- warning: "text-warning",
2741
- destructive: "text-danger"
2742
- };
2743
- var Alert = forwardRef32(
2744
- ({ variant = "default", className, children, ...props }, ref) => {
2745
- const Icon = iconMap[variant ?? "default"];
2746
- const iconColor = iconColorMap[variant ?? "default"];
2747
- return /* @__PURE__ */ jsxs20(
2748
- "div",
2749
- {
2750
- ref,
2751
- role: "alert",
2752
- className: cn32(alertVariants({ variant }), className),
2753
- ...props,
2754
- children: [
2755
- /* @__PURE__ */ jsx32(Icon, { size: 18, className: cn32("mt-0.5 shrink-0", iconColor) }),
2756
- /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-0.5", children })
2757
- ]
2758
- }
2759
- );
2760
- }
2761
- );
2762
- var AlertTitle = forwardRef32(({ className, ...props }, ref) => {
2763
- return /* @__PURE__ */ jsx32("p", { ref, className: cn32("text-sm font-semibold leading-5", className), ...props });
2764
- });
2765
- var AlertDescription = forwardRef32(({ className, ...props }, ref) => {
2766
- return /* @__PURE__ */ jsx32("p", { ref, className: cn32("text-sm leading-5 opacity-90", className), ...props });
2767
- });
2768
- Alert.displayName = "Alert";
2769
- AlertTitle.displayName = "AlertTitle";
2770
- AlertDescription.displayName = "AlertDescription";
2771
-
2772
- // src/components/breadcrumb.tsx
2773
- import { forwardRef as forwardRef33 } from "react";
2774
- import { ChevronRight as ChevronRight2 } from "lucide-react";
2775
- import { cn as cn33 } from "@ug666/ui-utils";
2776
- import { jsx as jsx33 } from "react/jsx-runtime";
2777
- var Breadcrumb = forwardRef33(({ className, children, ...props }, ref) => {
2778
- return /* @__PURE__ */ jsx33("nav", { ref, "aria-label": "\u9762\u5305\u5C51\u5BFC\u822A", className: cn33(className), ...props, children: /* @__PURE__ */ jsx33("ol", { className: "flex flex-wrap items-center gap-0 text-sm text-text-secondary", children }) });
2779
- });
2780
- var BreadcrumbItem = forwardRef33(({ className, ...props }, ref) => {
2781
- return /* @__PURE__ */ jsx33("li", { ref, className: cn33("flex items-center gap-1", className), ...props });
2782
- });
2783
- var BreadcrumbLink = forwardRef33(
2784
- ({ current = false, className, children, href, ...props }, ref) => {
2785
- if (current) {
2786
- return /* @__PURE__ */ jsx33("span", { "aria-current": "page", className: cn33("font-medium text-text-primary", className), children });
2787
- }
2788
- return /* @__PURE__ */ jsx33(
2789
- "a",
2790
- {
2791
- ref,
2792
- href,
2793
- className: cn33("transition-colors hover:text-text-primary", className),
2794
- ...props,
2795
- children
2796
- }
2797
- );
2798
- }
2799
- );
2800
- var BreadcrumbSeparator = forwardRef33(
2801
- ({ className, children, ...props }, ref) => {
2802
- return /* @__PURE__ */ jsx33(
2803
- "li",
2804
- {
2805
- ref,
2806
- role: "presentation",
2807
- "aria-hidden": "true",
2808
- className: cn33("text-text-tertiary", className),
2809
- ...props,
2810
- children: children ?? /* @__PURE__ */ jsx33(ChevronRight2, { size: 14 })
2811
- }
2812
- );
2813
- }
2814
- );
2815
- Breadcrumb.displayName = "Breadcrumb";
2816
- BreadcrumbItem.displayName = "BreadcrumbItem";
2817
- BreadcrumbLink.displayName = "BreadcrumbLink";
2818
- BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
2819
-
2820
- // src/components/switch.tsx
2821
- import { forwardRef as forwardRef34, useId as useId5 } from "react";
2822
- import { cn as cn34 } from "@ug666/ui-utils";
2823
- import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
2824
- var Switch = forwardRef34(
2825
- ({
2826
- checked,
2827
- onCheckedChange,
2828
- disabled = false,
2829
- label,
2830
- labelPlacement = "right",
2831
- className,
2832
- id,
2833
- ...props
2834
- }, ref) => {
2835
- const generatedId = useId5();
2836
- const switchId = id ?? generatedId;
2837
- const track = /* @__PURE__ */ jsx34(
2838
- "button",
2839
- {
2840
- ref,
2841
- id: switchId,
2842
- type: "button",
2843
- role: "switch",
2844
- "aria-checked": checked,
2845
- disabled,
2846
- onClick: () => !disabled && onCheckedChange(!checked),
2847
- className: cn34(
2848
- "relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200",
2849
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2850
- "disabled:cursor-not-allowed disabled:opacity-50",
2851
- checked ? "bg-primary" : "bg-surface-3",
2852
- className
2853
- ),
2854
- ...props,
2855
- children: /* @__PURE__ */ jsx34(
2856
- "span",
2857
- {
2858
- className: cn34(
2859
- "pointer-events-none block h-5 w-5 rounded-full bg-white shadow-sm ring-0 transition-transform duration-200",
2860
- checked ? "translate-x-5" : "translate-x-0"
2861
- )
2862
- }
2863
- )
2864
- }
2865
- );
2866
- if (!label) return track;
2867
- return /* @__PURE__ */ jsxs21(
2868
- "label",
2869
- {
2870
- htmlFor: switchId,
2871
- className: cn34(
2872
- "inline-flex items-center gap-2 cursor-pointer",
2873
- disabled && "cursor-not-allowed opacity-50"
2874
- ),
2875
- children: [
2876
- labelPlacement === "left" && /* @__PURE__ */ jsx34("span", { className: "text-sm font-medium text-text-primary", children: label }),
2877
- track,
2878
- labelPlacement === "right" && /* @__PURE__ */ jsx34("span", { className: "text-sm font-medium text-text-primary", children: label })
2879
- ]
2880
- }
2881
- );
2882
- }
2883
- );
2884
- Switch.displayName = "Switch";
2885
-
2886
- // src/components/textarea.tsx
2887
- import { forwardRef as forwardRef35, useId as useId6 } from "react";
2888
- import { cn as cn35 } from "@ug666/ui-utils";
2889
- import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
2890
- var Textarea = forwardRef35(
2891
- ({ className, label, error, helperText, id, rows = 3, ...props }, ref) => {
2892
- const generatedId = useId6();
2893
- const textareaId = id ?? generatedId;
2894
- return /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-1", children: [
2895
- label && /* @__PURE__ */ jsx35("label", { htmlFor: textareaId, className: "text-sm font-medium text-text-primary", children: label }),
2896
- /* @__PURE__ */ jsx35(
2897
- "textarea",
2898
- {
2899
- ref,
2900
- id: textareaId,
2901
- rows,
2902
- className: cn35(
2903
- "w-full rounded-md border bg-surface-1 px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary",
2904
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1",
2905
- "disabled:cursor-not-allowed disabled:opacity-50",
2906
- "resize-y",
2907
- error ? "border-danger focus-visible:ring-danger" : "border-border-strong focus-visible:ring-ring/30",
2908
- className
2909
- ),
2910
- ...props
2911
- }
2912
- ),
2913
- error && /* @__PURE__ */ jsx35("p", { className: "text-xs text-danger", children: error }),
2914
- !error && helperText && /* @__PURE__ */ jsx35("p", { className: "text-xs text-text-secondary", children: helperText })
2915
- ] });
2916
- }
2917
- );
2918
- Textarea.displayName = "Textarea";
2919
-
2920
- // src/components/skeleton.tsx
2921
- import { forwardRef as forwardRef36 } from "react";
2922
- import { cva as cva10 } from "class-variance-authority";
2923
- import { cn as cn36 } from "@ug666/ui-utils";
2924
- import { jsx as jsx36 } from "react/jsx-runtime";
2925
- var skeletonVariants = cva10(
2926
- "animate-pulse bg-surface-3",
270
+ id: "data",
271
+ label: "\u6570\u636E\u5C55\u793A",
272
+ description: "\u5C55\u793A\u5217\u8868\u3001\u5BF9\u8C61\u8BE6\u60C5\u3001\u5934\u50CF\u3001\u6307\u6807\u548C\u6298\u53E0\u4FE1\u606F\uFF0C\u8981\u6C42\u5BC6\u5EA6\u6E05\u6670\u4E14\u6587\u672C\u4E0D\u6324\u51FA\u3002",
273
+ components: [
274
+ { name: "UGTable", route: "/react/components/table" },
275
+ { name: "UGDescriptions", route: "/react/components/descriptions" },
276
+ { name: "UGStatistic", route: "/react/components/statistic" },
277
+ { name: "UGAvatar", route: "/react/components/avatar" },
278
+ { name: "UGAvatarGroup", route: "/react/components/avatar-group" },
279
+ { name: "UGAccordion", route: "/react/components/accordion" }
280
+ ]
281
+ },
2927
282
  {
2928
- variants: {
2929
- variant: {
2930
- text: "h-4 w-full rounded",
2931
- circle: "rounded-full",
2932
- rect: "rounded-md"
2933
- }
2934
- },
2935
- defaultVariants: { variant: "rect" }
2936
- }
2937
- );
2938
- var Skeleton = forwardRef36(({ variant, className, ...props }, ref) => {
2939
- return /* @__PURE__ */ jsx36("div", { ref, className: cn36(skeletonVariants({ variant }), className), "aria-hidden": "true", ...props });
2940
- });
2941
- Skeleton.displayName = "Skeleton";
2942
-
2943
- // src/components/progress.tsx
2944
- import { forwardRef as forwardRef37 } from "react";
2945
- import { cn as cn37 } from "@ug666/ui-utils";
2946
- import { jsx as jsx37, jsxs as jsxs23 } from "react/jsx-runtime";
2947
- var Progress = forwardRef37(({
2948
- value,
2949
- max = 100,
2950
- showLabel = false,
2951
- color = "bg-indigo-500",
2952
- className,
2953
- ...props
2954
- }, ref) => {
2955
- const clamped = Math.min(Math.max(value, 0), max);
2956
- const percent = Math.round(clamped / max * 100);
2957
- return /* @__PURE__ */ jsxs23("div", { ref, className: cn37("flex items-center gap-3", className), ...props, children: [
2958
- /* @__PURE__ */ jsx37(
2959
- "div",
2960
- {
2961
- role: "progressbar",
2962
- "aria-valuenow": clamped,
2963
- "aria-valuemin": 0,
2964
- "aria-valuemax": max,
2965
- className: "h-2 w-full overflow-hidden rounded-full bg-surface-2",
2966
- children: /* @__PURE__ */ jsx37(
2967
- "div",
2968
- {
2969
- className: cn37("h-full rounded-full transition-all duration-500 ease-out", color),
2970
- style: { width: `${percent}%` }
2971
- }
2972
- )
2973
- }
2974
- ),
2975
- showLabel && /* @__PURE__ */ jsxs23("span", { className: "shrink-0 text-xs font-medium text-text-secondary tabular-nums w-9 text-right", children: [
2976
- percent,
2977
- "%"
2978
- ] })
2979
- ] });
2980
- });
2981
- Progress.displayName = "Progress";
2982
-
2983
- // src/components/sheet.tsx
2984
- import { forwardRef as forwardRef38 } from "react";
2985
- import { createPortal as createPortal9 } from "react-dom";
2986
- import { X as X5 } from "lucide-react";
2987
- import { cn as cn38 } from "@ug666/ui-utils";
2988
- import { jsx as jsx38, jsxs as jsxs24 } from "react/jsx-runtime";
2989
- var Sheet = forwardRef38(({ open, onClose, side = "right", title, children, className }, ref) => {
2990
- useEscapeKey(open, onClose);
2991
- if (!open) return null;
2992
- return createPortal9(
2993
- /* @__PURE__ */ jsxs24("div", { className: "fixed inset-0 z-50 flex", role: "dialog", "aria-modal": "true", children: [
2994
- /* @__PURE__ */ jsx38(
2995
- "div",
2996
- {
2997
- className: "absolute inset-0 bg-overlay transition-opacity",
2998
- onClick: onClose,
2999
- "aria-hidden": "true"
3000
- }
3001
- ),
3002
- /* @__PURE__ */ jsxs24(
3003
- "div",
3004
- {
3005
- ref,
3006
- className: cn38(
3007
- "relative flex h-full w-80 max-w-full flex-col bg-surface-1 shadow-xl",
3008
- "transition-transform duration-300 ease-in-out",
3009
- side === "right" ? "ml-auto translate-x-0" : "mr-auto translate-x-0",
3010
- className
3011
- ),
3012
- children: [
3013
- title && /* @__PURE__ */ jsxs24("div", { className: "flex items-center justify-between border-b border-border-base px-5 py-4", children: [
3014
- /* @__PURE__ */ jsx38("h2", { className: "text-base font-semibold text-text-primary", children: title }),
3015
- /* @__PURE__ */ jsx38(
3016
- "button",
3017
- {
3018
- type: "button",
3019
- onClick: onClose,
3020
- className: "rounded-md p-1 text-text-tertiary hover:bg-surface-3 hover:text-text-secondary transition-colors",
3021
- "aria-label": "\u5173\u95ED",
3022
- children: /* @__PURE__ */ jsx38(X5, { size: 18 })
3023
- }
3024
- )
3025
- ] }),
3026
- /* @__PURE__ */ jsx38("div", { className: "flex-1 overflow-y-auto px-5 py-4", children })
3027
- ]
3028
- }
3029
- )
3030
- ] }),
3031
- document.body
3032
- );
3033
- });
3034
- Sheet.displayName = "Sheet";
3035
-
3036
- // src/components/empty-state.tsx
3037
- import { forwardRef as forwardRef39 } from "react";
3038
- import { cn as cn39 } from "@ug666/ui-utils";
3039
- import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
3040
- var EmptyState = forwardRef39(
3041
- ({ icon: Icon, title, description, action, className, ...props }, ref) => {
3042
- return /* @__PURE__ */ jsxs25(
3043
- "div",
3044
- {
3045
- ref,
3046
- className: cn39(
3047
- "flex flex-col items-center justify-center gap-3 py-16 text-center",
3048
- className
3049
- ),
3050
- ...props,
3051
- children: [
3052
- Icon && /* @__PURE__ */ jsx39("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-surface-2", children: /* @__PURE__ */ jsx39(Icon, { size: 28, className: "text-text-tertiary" }) }),
3053
- /* @__PURE__ */ jsxs25("div", { className: "flex flex-col gap-1", children: [
3054
- /* @__PURE__ */ jsx39("p", { className: "text-base font-semibold text-text-primary", children: title }),
3055
- description && /* @__PURE__ */ jsx39("p", { className: "max-w-xs text-sm text-text-secondary", children: description })
3056
- ] }),
3057
- action && /* @__PURE__ */ jsx39("div", { className: "mt-1", children: action })
3058
- ]
3059
- }
3060
- );
3061
- }
3062
- );
3063
- EmptyState.displayName = "EmptyState";
3064
-
3065
- // src/components/separator.tsx
3066
- import { forwardRef as forwardRef40 } from "react";
3067
- import { cn as cn40 } from "@ug666/ui-utils";
3068
- import { jsx as jsx40 } from "react/jsx-runtime";
3069
- var ORIENTATION_CLASSES = {
3070
- horizontal: "h-px w-full bg-border-base",
3071
- vertical: "w-px h-full bg-border-base"
3072
- };
3073
- var Separator = forwardRef40(
3074
- ({ orientation = "horizontal", className, ...props }, ref) => {
3075
- return /* @__PURE__ */ jsx40(
3076
- "div",
3077
- {
3078
- ref,
3079
- role: "separator",
3080
- "aria-orientation": orientation,
3081
- className: cn40(ORIENTATION_CLASSES[orientation], className),
3082
- ...props
3083
- }
3084
- );
3085
- }
3086
- );
3087
- Separator.displayName = "Separator";
3088
-
3089
- // src/components/descriptions.tsx
3090
- import { forwardRef as forwardRef41, Children as Children2, isValidElement as isValidElement2 } from "react";
3091
- import { cn as cn41 } from "@ug666/ui-utils";
3092
- import { Fragment, jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
3093
- var SIZE_LABEL_CLASSES = {
3094
- sm: "text-xs py-1 px-2",
3095
- default: "text-sm py-2 px-3",
3096
- lg: "text-base py-3 px-4"
3097
- };
3098
- var SIZE_VALUE_CLASSES = {
3099
- sm: "text-xs py-1 px-2",
3100
- default: "text-sm py-2 px-3",
3101
- lg: "text-base py-3 px-4"
3102
- };
3103
- var DescriptionsItem = forwardRef41(
3104
- ({ label, children, className, span: _span, ...props }, ref) => {
3105
- return /* @__PURE__ */ jsxs26("div", { ref, className, ...props, children: [
3106
- /* @__PURE__ */ jsx41("span", { className: "text-text-secondary", children: label }),
3107
- /* @__PURE__ */ jsx41("span", { className: "text-text-primary", children })
3108
- ] });
3109
- }
3110
- );
3111
- DescriptionsItem.displayName = "DescriptionsItem";
3112
- var Descriptions = forwardRef41(
3113
- ({ column = 2, bordered = false, size = "default", title, className, children, ...props }, ref) => {
3114
- const items = Children2.toArray(children).filter(
3115
- (child) => isValidElement2(child) && child.type.displayName === "DescriptionsItem"
3116
- );
3117
- if (bordered) {
3118
- const rows = [];
3119
- let currentRow = [];
3120
- let currentColCount = 0;
3121
- for (const item of items) {
3122
- const span = item.props.span ?? 1;
3123
- if (currentColCount + span > column) {
3124
- rows.push(currentRow);
3125
- currentRow = [];
3126
- currentColCount = 0;
3127
- }
3128
- currentRow.push({ label: item.props.label, value: item.props.children, span });
3129
- currentColCount += span;
3130
- }
3131
- if (currentRow.length > 0) rows.push(currentRow);
3132
- return /* @__PURE__ */ jsxs26("div", { ref, className: cn41("w-full", className), ...props, children: [
3133
- title && /* @__PURE__ */ jsx41("div", { className: "mb-3 text-base font-semibold text-text-primary", children: title }),
3134
- /* @__PURE__ */ jsx41("table", { className: "w-full border-collapse border border-border-base", children: /* @__PURE__ */ jsx41("tbody", { children: rows.map((row, rowIdx) => /* @__PURE__ */ jsx41("tr", { children: row.map((cell, cellIdx) => /* @__PURE__ */ jsxs26(Fragment, { children: [
3135
- /* @__PURE__ */ jsx41(
3136
- "td",
3137
- {
3138
- className: cn41(
3139
- "border border-border-base bg-surface-2 font-medium text-text-secondary",
3140
- SIZE_LABEL_CLASSES[size]
3141
- ),
3142
- style: { width: `${1 / (column * 2) * 100}%` },
3143
- children: cell.label
3144
- },
3145
- `label-${cellIdx}`
3146
- ),
3147
- /* @__PURE__ */ jsx41(
3148
- "td",
3149
- {
3150
- className: cn41(
3151
- "border border-border-base text-text-primary",
3152
- SIZE_VALUE_CLASSES[size]
3153
- ),
3154
- colSpan: cell.span > 1 ? cell.span * 2 - 1 : 1,
3155
- children: cell.value
3156
- },
3157
- `value-${cellIdx}`
3158
- )
3159
- ] })) }, rowIdx)) }) })
3160
- ] });
3161
- }
3162
- const GRID_COLS = {
3163
- 1: "grid-cols-1",
3164
- 2: "grid-cols-2",
3165
- 3: "grid-cols-3",
3166
- 4: "grid-cols-4"
3167
- };
3168
- return /* @__PURE__ */ jsxs26("div", { ref, className: cn41("w-full", className), ...props, children: [
3169
- title && /* @__PURE__ */ jsx41("div", { className: "mb-3 text-base font-semibold text-text-primary", children: title }),
3170
- /* @__PURE__ */ jsx41("div", { className: cn41("grid gap-x-6 gap-y-4", GRID_COLS[column]), children: items.map((item, idx) => {
3171
- const span = item.props.span ?? 1;
3172
- const colSpanClass = span === 2 ? "col-span-2" : span === 3 ? "col-span-3" : span === 4 ? "col-span-4" : "";
3173
- return /* @__PURE__ */ jsxs26("div", { className: cn41("flex flex-col gap-0.5", colSpanClass, item.props.className), children: [
3174
- /* @__PURE__ */ jsx41("span", { className: cn41("font-medium text-text-secondary", size === "sm" ? "text-xs" : size === "lg" ? "text-sm" : "text-xs"), children: item.props.label }),
3175
- /* @__PURE__ */ jsx41("span", { className: cn41("text-text-primary", size === "sm" ? "text-sm" : size === "lg" ? "text-base" : "text-sm"), children: item.props.children })
3176
- ] }, idx);
3177
- }) })
3178
- ] });
3179
- }
3180
- );
3181
- Descriptions.displayName = "Descriptions";
3182
-
3183
- // src/components/statistic.tsx
3184
- import { forwardRef as forwardRef42 } from "react";
3185
- import { TrendingUp, TrendingDown, Minus as Minus3 } from "lucide-react";
3186
- import { cn as cn42 } from "@ug666/ui-utils";
3187
- import { jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
3188
- var SIZE_TITLE_CLASSES = {
3189
- sm: "text-xs",
3190
- default: "text-sm",
3191
- lg: "text-base"
3192
- };
3193
- var SIZE_VALUE_CLASSES2 = {
3194
- sm: "text-2xl",
3195
- default: "text-3xl",
3196
- lg: "text-4xl"
3197
- };
3198
- var SIZE_SUFFIX_CLASSES = {
3199
- sm: "text-xs",
3200
- default: "text-sm",
3201
- lg: "text-base"
3202
- };
3203
- var TREND_ICON_COLOR = {
3204
- up: "text-success",
3205
- down: "text-danger",
3206
- flat: "text-text-secondary"
3207
- };
3208
- var TREND_TEXT_COLOR = {
3209
- up: "text-success",
3210
- down: "text-danger",
3211
- flat: "text-text-secondary"
3212
- };
3213
- function formatValue(value, precision) {
3214
- if (typeof value === "string") return value;
3215
- return new Intl.NumberFormat("zh-CN", {
3216
- minimumFractionDigits: precision ?? 0,
3217
- maximumFractionDigits: precision ?? 0
3218
- }).format(value);
3219
- }
3220
- var Statistic = forwardRef42(
3221
- ({ title, value, precision, prefix, suffix, trend, change, size = "default", className, ...props }, ref) => {
3222
- const TrendIcon = trend === "up" ? TrendingUp : trend === "down" ? TrendingDown : trend === "flat" ? Minus3 : null;
3223
- const iconSize = size === "sm" ? 14 : size === "lg" ? 18 : 16;
3224
- return /* @__PURE__ */ jsxs27("div", { ref, className: cn42("flex flex-col gap-1", className), ...props, children: [
3225
- title && /* @__PURE__ */ jsx42("span", { className: cn42("font-medium text-text-secondary", SIZE_TITLE_CLASSES[size]), children: title }),
3226
- /* @__PURE__ */ jsxs27("div", { className: "flex items-baseline gap-1", children: [
3227
- prefix && /* @__PURE__ */ jsx42("span", { className: cn42("text-text-primary", SIZE_SUFFIX_CLASSES[size]), children: prefix }),
3228
- /* @__PURE__ */ jsx42("span", { className: cn42("font-bold tabular-nums text-text-primary", SIZE_VALUE_CLASSES2[size]), children: formatValue(value, precision) }),
3229
- suffix && /* @__PURE__ */ jsx42("span", { className: cn42("text-text-secondary", SIZE_SUFFIX_CLASSES[size]), children: suffix })
3230
- ] }),
3231
- (trend || change) && /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-1", children: [
3232
- TrendIcon && trend && /* @__PURE__ */ jsx42(TrendIcon, { size: iconSize, className: TREND_ICON_COLOR[trend] }),
3233
- change && trend && /* @__PURE__ */ jsx42("span", { className: cn42("text-xs font-medium", TREND_TEXT_COLOR[trend]), children: change })
3234
- ] })
3235
- ] });
3236
- }
3237
- );
3238
- Statistic.displayName = "Statistic";
3239
-
3240
- // src/theme.ts
3241
- var theme = {
3242
- colors: {
3243
- primary: { DEFAULT: "#6366f1", hover: "#4f46e5", light: "#eef2ff" },
3244
- secondary: { DEFAULT: "#64748b", hover: "#475569", light: "#f1f5f9" },
3245
- destructive: { DEFAULT: "#ef4444", hover: "#dc2626", light: "#fef2f2" },
3246
- success: { DEFAULT: "#22c55e", hover: "#16a34a", light: "#f0fdf4" },
3247
- warning: { DEFAULT: "#f59e0b", hover: "#d97706", light: "#fffbeb" },
3248
- background: "#ffffff",
3249
- foreground: "#0f172a",
3250
- muted: "#f1f5f9",
3251
- border: "#e2e8f0",
3252
- ring: "#6366f1"
283
+ id: "patterns",
284
+ label: "\u6846\u67B6\u6A21\u5F0F",
285
+ description: "\u540E\u53F0\u3001\u5DE5\u5177\u578B\u548C\u8DE8\u4E1A\u52A1\u901A\u7528\u6A21\u5F0F\uFF0C\u901A\u8FC7\u5B50\u5165\u53E3 @ug666/ui-react/patterns \u4F7F\u7528\u3002",
286
+ components: [
287
+ { name: "UGAdminShell", route: "/react/patterns#adminshell" },
288
+ { name: "UGPageHeader", route: "/react/patterns#pageheader" },
289
+ { name: "UGCopyField", route: "/react/patterns#copyfield" },
290
+ { name: "UGConfirmDialog", route: "/react/patterns#confirmdialog" }
291
+ ]
3253
292
  },
3254
- radius: { sm: "0.375rem", md: "0.5rem", lg: "0.75rem", full: "9999px" },
3255
- fontFamily: { sans: "system-ui, -apple-system, sans-serif", mono: "ui-monospace, monospace" }
3256
- };
3257
-
3258
- // src/index.ts
3259
- import { cn as cn43 } from "@ug666/ui-utils";
293
+ {
294
+ id: "blocks",
295
+ label: "\u5C55\u793A\u533A\u5757",
296
+ description: "\u5C55\u793A\u9875\u3001\u4EA7\u54C1\u9875\u548C\u4ECB\u7ECD\u9875\u533A\u5757\uFF0C\u901A\u8FC7\u5B50\u5165\u53E3 @ug666/ui-react/blocks \u4F7F\u7528\u3002",
297
+ components: [
298
+ { name: "UGLandingHero", route: "/react/blocks#landinghero" },
299
+ { name: "UGFeatureGrid", route: "/react/blocks#featuregrid" }
300
+ ]
301
+ },
302
+ {
303
+ id: "labs",
304
+ label: "\u5B9E\u9A8C\u7EC4\u4EF6",
305
+ description: "\u5C1A\u672A\u7A33\u5B9A\u627F\u8BFA\u7684\u5B9E\u9A8C\u7EC4\u4EF6\uFF0C\u901A\u8FC7\u5B50\u5165\u53E3 @ug666/ui-react/labs \u4F7F\u7528\u3002",
306
+ components: []
307
+ }
308
+ ];
3260
309
  export {
3261
310
  Accordion,
3262
311
  AccordionContent,
@@ -3358,14 +407,121 @@ export {
3358
407
  Tooltip,
3359
408
  TooltipContent,
3360
409
  TooltipTrigger,
410
+ Accordion as UGAccordion,
411
+ AccordionContent as UGAccordionContent,
412
+ AccordionItem as UGAccordionItem,
413
+ AccordionTrigger as UGAccordionTrigger,
414
+ Alert as UGAlert,
415
+ AlertDescription as UGAlertDescription,
416
+ AlertTitle as UGAlertTitle,
417
+ Avatar as UGAvatar,
418
+ AvatarFallback as UGAvatarFallback,
419
+ AvatarGroup as UGAvatarGroup,
420
+ AvatarImage as UGAvatarImage,
421
+ Badge as UGBadge,
422
+ Breadcrumb as UGBreadcrumb,
423
+ BreadcrumbItem as UGBreadcrumbItem,
424
+ BreadcrumbLink as UGBreadcrumbLink,
425
+ BreadcrumbSeparator as UGBreadcrumbSeparator,
426
+ Button as UGButton,
427
+ Card as UGCard,
428
+ CardContent as UGCardContent,
429
+ CardDescription as UGCardDescription,
430
+ CardFooter as UGCardFooter,
431
+ CardHeader as UGCardHeader,
432
+ CardTitle as UGCardTitle,
433
+ Checkbox as UGCheckbox,
434
+ ContextMenu as UGContextMenu,
435
+ ContextMenuContent as UGContextMenuContent,
436
+ ContextMenuItem as UGContextMenuItem,
437
+ ContextMenuSeparator as UGContextMenuSeparator,
438
+ ContextMenuTrigger as UGContextMenuTrigger,
439
+ Descriptions as UGDescriptions,
440
+ DescriptionsItem as UGDescriptionsItem,
441
+ Dialog as UGDialog,
442
+ Drawer as UGDrawer,
443
+ DrawerClose as UGDrawerClose,
444
+ DrawerContent as UGDrawerContent,
445
+ DrawerDescription as UGDrawerDescription,
446
+ DrawerFooter as UGDrawerFooter,
447
+ DrawerHeader as UGDrawerHeader,
448
+ DrawerTitle as UGDrawerTitle,
449
+ DropdownMenu as UGDropdown,
450
+ DropdownContent as UGDropdownContent,
451
+ DropdownItem as UGDropdownItem,
452
+ DropdownMenu as UGDropdownMenu,
453
+ DropdownSeparator as UGDropdownSeparator,
454
+ DropdownTrigger as UGDropdownTrigger,
455
+ EmptyState as UGEmptyState,
456
+ Form as UGForm,
457
+ FormControl as UGFormControl,
458
+ FormDescription as UGFormDescription,
459
+ FormField as UGFormField,
460
+ FormItem as UGFormItem,
461
+ FormLabel as UGFormLabel,
462
+ FormMessage as UGFormMessage,
463
+ Input as UGInput,
464
+ Label as UGLabel,
465
+ Modal as UGModal,
466
+ ModalCloseButton as UGModalCloseButton,
467
+ ModalContent as UGModalContent,
468
+ ModalFooter as UGModalFooter,
469
+ ModalHeader as UGModalHeader,
470
+ ModalTitle as UGModalTitle,
471
+ NavigationMenu as UGNavigationMenu,
472
+ NavigationMenuContent as UGNavigationMenuContent,
473
+ NavigationMenuItem as UGNavigationMenuItem,
474
+ NavigationMenuLink as UGNavigationMenuLink,
475
+ NavigationMenuTrigger as UGNavigationMenuTrigger,
476
+ NumberInput as UGNumberInput,
477
+ OTPInput as UGOTPInput,
478
+ Pagination as UGPagination,
479
+ Popover as UGPopover,
480
+ PopoverContent as UGPopoverContent,
481
+ PopoverTrigger as UGPopoverTrigger,
482
+ Progress as UGProgress,
483
+ Radio as UGRadio,
484
+ RadioGroup as UGRadioGroup,
485
+ Select as UGSelect,
486
+ Separator as UGSeparator,
487
+ Sheet as UGSheet,
488
+ Sidebar as UGSidebar,
489
+ Skeleton as UGSkeleton,
490
+ Slider as UGSlider,
491
+ Spinner as UGSpinner,
492
+ Statistic as UGStatistic,
493
+ Steps as UGSteps,
494
+ Switch as UGSwitch,
495
+ Table as UGTable,
496
+ TableBody as UGTableBody,
497
+ TableCell as UGTableCell,
498
+ TableHead as UGTableHead,
499
+ TableHeader as UGTableHeader,
500
+ TableRow as UGTableRow,
501
+ Tabs as UGTabs,
502
+ TabsContent as UGTabsContent,
503
+ TabsList as UGTabsList,
504
+ TabsTrigger as UGTabsTrigger,
505
+ Tag as UGTag,
506
+ Textarea as UGTextarea,
507
+ Toaster as UGToaster,
508
+ Tooltip as UGTooltip,
509
+ TooltipContent as UGTooltipContent,
510
+ TooltipTrigger as UGTooltipTrigger,
3361
511
  badgeVariants,
3362
512
  buttonVariants,
3363
513
  checkboxVariants,
3364
- cn43 as cn,
514
+ cn,
3365
515
  numberInputVariants,
516
+ reactComponentLayers,
3366
517
  tagVariants,
3367
518
  theme,
3368
519
  toast,
520
+ badgeVariants as ugBadgeVariants,
521
+ buttonVariants as ugButtonVariants,
522
+ checkboxVariants as ugCheckboxVariants,
523
+ numberInputVariants as ugNumberInputVariants,
524
+ tagVariants as ugTagVariants,
3369
525
  useClickOutside,
3370
526
  useCopyToClipboard,
3371
527
  useDebounce,