@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
@@ -0,0 +1,758 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/patterns/index.ts
22
+ var patterns_exports = {};
23
+ __export(patterns_exports, {
24
+ AdminShell: () => AdminShell,
25
+ ConfirmDialog: () => ConfirmDialog,
26
+ CopyField: () => CopyField,
27
+ PageHeader: () => PageHeader,
28
+ UGAdminShell: () => AdminShell,
29
+ UGConfirmDialog: () => ConfirmDialog,
30
+ UGCopyField: () => CopyField,
31
+ UGPageHeader: () => PageHeader
32
+ });
33
+ module.exports = __toCommonJS(patterns_exports);
34
+
35
+ // src/patterns/admin-shell.tsx
36
+ var import_react3 = require("react");
37
+ var import_lucide_react3 = require("lucide-react");
38
+
39
+ // src/components/button.tsx
40
+ var import_react = require("react");
41
+ var import_lucide_react = require("lucide-react");
42
+ var import_class_variance_authority = require("class-variance-authority");
43
+
44
+ // src/internal/cn.ts
45
+ var import_clsx = require("clsx");
46
+ var import_tailwind_merge = require("tailwind-merge");
47
+ function cn(...inputs) {
48
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
49
+ }
50
+
51
+ // src/components/button.tsx
52
+ var import_jsx_runtime = require("react/jsx-runtime");
53
+ var buttonVariants = (0, import_class_variance_authority.cva)(
54
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-[background,border-color,color,box-shadow,transform] duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
55
+ {
56
+ variants: {
57
+ variant: {
58
+ default: "bg-primary text-primary-fg shadow-sm hover:bg-primary-hover hover:shadow-md focus-visible:ring-ring",
59
+ destructive: "bg-danger text-danger-fg shadow-sm hover:bg-danger-hover hover:shadow-md focus-visible:ring-danger",
60
+ outline: "border border-border-strong bg-surface-1 text-text-primary shadow-sm hover:border-primary/55 hover:bg-surface-2 focus-visible:ring-ring/30",
61
+ secondary: "border border-border-base bg-surface-2 text-text-primary shadow-sm hover:bg-surface-3 focus-visible:ring-ring/30",
62
+ ghost: "text-text-primary hover:bg-surface-2 focus-visible:ring-ring/30",
63
+ link: "text-text-primary underline-offset-4 hover:underline focus-visible:ring-ring/30"
64
+ },
65
+ size: {
66
+ default: "h-9 px-4 py-2",
67
+ sm: "h-8 px-3 text-xs",
68
+ lg: "h-11 px-5 text-base",
69
+ icon: "h-9 w-9"
70
+ }
71
+ },
72
+ defaultVariants: {
73
+ variant: "default",
74
+ size: "default"
75
+ }
76
+ }
77
+ );
78
+ var Button = (0, import_react.forwardRef)(
79
+ ({ className, variant, size, loading = false, disabled, children, ...props }, ref) => {
80
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
81
+ "button",
82
+ {
83
+ ref,
84
+ className: cn(buttonVariants({ variant, size }), className),
85
+ disabled: disabled || loading,
86
+ ...props,
87
+ children: [
88
+ loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "animate-spin", size: 16 }),
89
+ children
90
+ ]
91
+ }
92
+ );
93
+ }
94
+ );
95
+ Button.displayName = "Button";
96
+
97
+ // src/components/sidebar.tsx
98
+ var import_react2 = require("react");
99
+ var import_lucide_react2 = require("lucide-react");
100
+ var import_jsx_runtime2 = require("react/jsx-runtime");
101
+ var variantStyles = {
102
+ primary: {
103
+ container: "border-r border-border-base bg-surface-1 text-text-primary shadow-sm",
104
+ active: "bg-primary/10 text-primary shadow-sm ring-1 ring-primary/20 before:absolute before:left-0 before:top-1/2 before:h-6 before:w-[3px] before:-translate-y-1/2 before:rounded-r-full before:bg-primary",
105
+ inactive: "text-text-secondary hover:bg-surface-2 hover:text-text-primary",
106
+ divider: "border-border-base",
107
+ icon: "bg-transparent text-text-tertiary group-hover:bg-surface-3 group-hover:text-primary",
108
+ activeIcon: "bg-primary/15 text-primary"
109
+ },
110
+ dark: {
111
+ container: "border-r border-border-base bg-surface-1 text-text-primary shadow-sm",
112
+ active: "bg-primary/10 text-primary shadow-sm ring-1 ring-primary/20 before:absolute before:left-0 before:top-1/2 before:h-6 before:w-[3px] before:-translate-y-1/2 before:rounded-r-full before:bg-primary",
113
+ inactive: "text-text-secondary hover:bg-surface-2 hover:text-text-primary",
114
+ divider: "border-border-base",
115
+ icon: "bg-transparent text-text-tertiary group-hover:bg-surface-3 group-hover:text-primary",
116
+ activeIcon: "bg-primary/15 text-primary"
117
+ }
118
+ };
119
+ function getItemKey(item, index, parentKey) {
120
+ return item.id ?? item.href ?? `${parentKey}-${index}-${item.label}`;
121
+ }
122
+ function itemHasActiveChild(item) {
123
+ return Boolean(item.children?.some((child) => child.active || itemHasActiveChild(child)));
124
+ }
125
+ function normalizeSearch(value) {
126
+ return value.toLowerCase().replace(/\s+/g, "");
127
+ }
128
+ function filterSidebarItems(items, query) {
129
+ if (!query) return items;
130
+ return items.reduce((result, item) => {
131
+ const children = item.children ? filterSidebarItems(item.children, query) : [];
132
+ const matched = normalizeSearch(item.label).includes(query);
133
+ if (matched || children.length > 0) {
134
+ result.push({ ...item, children });
135
+ }
136
+ return result;
137
+ }, []);
138
+ }
139
+ var Sidebar = (0, import_react2.forwardRef)(
140
+ ({
141
+ items,
142
+ variant = "primary",
143
+ collapsed,
144
+ defaultCollapsed = false,
145
+ onCollapsedChange,
146
+ collapsible = false,
147
+ searchable = false,
148
+ searchPlaceholder = "\u641C\u7D22\u83DC\u5355...",
149
+ responsive = false,
150
+ mobileOpen = false,
151
+ onMobileOpenChange,
152
+ header,
153
+ footer,
154
+ className
155
+ }, ref) => {
156
+ const styles = variantStyles[variant];
157
+ const [internalCollapsed, setInternalCollapsed] = (0, import_react2.useState)(defaultCollapsed);
158
+ const [expandedKeys, setExpandedKeys] = (0, import_react2.useState)(() => /* @__PURE__ */ new Set());
159
+ const [query, setQuery] = (0, import_react2.useState)("");
160
+ const effectiveCollapsed = collapsed ?? internalCollapsed;
161
+ const normalizedQuery = normalizeSearch(query);
162
+ const visibleItems = (0, import_react2.useMemo)(() => filterSidebarItems(items, normalizedQuery), [items, normalizedQuery]);
163
+ function setCollapsedState(nextCollapsed) {
164
+ setInternalCollapsed(nextCollapsed);
165
+ onCollapsedChange?.(nextCollapsed);
166
+ }
167
+ function toggleExpanded(key) {
168
+ setExpandedKeys((current) => {
169
+ const next = new Set(current);
170
+ if (next.has(key)) {
171
+ next.delete(key);
172
+ } else {
173
+ next.add(key);
174
+ }
175
+ return next;
176
+ });
177
+ }
178
+ function closeMobile() {
179
+ onMobileOpenChange?.(false);
180
+ }
181
+ function renderItems(list, depth = 0, parentKey = "root") {
182
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: cn("flex flex-col gap-1", depth === 0 ? "px-2.5" : "ml-6 mt-1 border-l border-border-base pl-2"), children: list.map((item, index) => {
183
+ const key = getItemKey(item, index, parentKey);
184
+ const hasChildren = Boolean(item.children?.length);
185
+ const active = Boolean(item.active || itemHasActiveChild(item));
186
+ const expanded = !effectiveCollapsed && hasChildren && (normalizedQuery.length > 0 || active || expandedKeys.has(key));
187
+ const itemContent = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
188
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
189
+ "span",
190
+ {
191
+ className: cn(
192
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg transition-colors",
193
+ active ? styles.activeIcon : styles.icon
194
+ ),
195
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(item.icon, { size: 16 })
196
+ }
197
+ ),
198
+ !effectiveCollapsed && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "min-w-0 flex-1 truncate text-left", children: item.label }),
199
+ !effectiveCollapsed && hasChildren && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
200
+ import_lucide_react2.ChevronDown,
201
+ {
202
+ size: 15,
203
+ className: cn("shrink-0 text-text-tertiary transition-transform", expanded && "rotate-180"),
204
+ "aria-hidden": "true"
205
+ }
206
+ )
207
+ ] });
208
+ const itemClassName = cn(
209
+ "group relative flex min-w-0 items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm font-medium outline-none transition-all duration-150 focus-visible:ring-2 focus-visible:ring-primary/35",
210
+ effectiveCollapsed && "justify-center px-2",
211
+ active ? styles.active : styles.inactive
212
+ );
213
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { children: [
214
+ hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
215
+ "button",
216
+ {
217
+ type: "button",
218
+ className: cn("w-full", itemClassName),
219
+ "aria-expanded": expanded,
220
+ title: effectiveCollapsed ? item.label : void 0,
221
+ onClick: () => toggleExpanded(key),
222
+ children: itemContent
223
+ }
224
+ ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
225
+ "a",
226
+ {
227
+ href: item.href ?? "#",
228
+ "aria-current": item.active ? "page" : void 0,
229
+ className: itemClassName,
230
+ title: effectiveCollapsed ? item.label : void 0,
231
+ onClick: closeMobile,
232
+ children: itemContent
233
+ }
234
+ ),
235
+ expanded && item.children ? renderItems(item.children, depth + 1, key) : null
236
+ ] }, key);
237
+ }) });
238
+ }
239
+ const sidebar = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
240
+ "aside",
241
+ {
242
+ ref,
243
+ className: cn(
244
+ "flex flex-col overflow-hidden transition-all duration-300",
245
+ styles.container,
246
+ effectiveCollapsed ? "w-[72px]" : "w-64",
247
+ responsive && [
248
+ "fixed inset-y-0 left-0 z-50 md:relative md:inset-auto md:z-auto",
249
+ mobileOpen ? "translate-x-0" : "-translate-x-full md:translate-x-0"
250
+ ],
251
+ className
252
+ ),
253
+ children: [
254
+ (header || collapsible || responsive && mobileOpen) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
255
+ "div",
256
+ {
257
+ className: cn(
258
+ "flex border-b px-3 py-3",
259
+ styles.divider,
260
+ effectiveCollapsed ? "justify-center" : "items-center gap-2"
261
+ ),
262
+ children: [
263
+ !effectiveCollapsed && header ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "min-w-0 flex-1", children: header }) : null,
264
+ collapsible && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
265
+ "button",
266
+ {
267
+ type: "button",
268
+ className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-border-base bg-surface-2 text-text-secondary transition-colors hover:border-primary/40 hover:text-text-primary",
269
+ "aria-label": effectiveCollapsed ? "\u5C55\u5F00\u4FA7\u8FB9\u680F" : "\u6298\u53E0\u4FA7\u8FB9\u680F",
270
+ onClick: () => setCollapsedState(!effectiveCollapsed),
271
+ children: effectiveCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.PanelLeftOpen, { size: 17 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.PanelLeftClose, { size: 17 })
272
+ }
273
+ ),
274
+ responsive && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
275
+ "button",
276
+ {
277
+ type: "button",
278
+ className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-border-base bg-surface-2 text-text-secondary transition-colors hover:border-primary/40 hover:text-text-primary md:hidden",
279
+ "aria-label": "\u5173\u95ED\u4FA7\u8FB9\u680F",
280
+ onClick: closeMobile,
281
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.X, { size: 17 })
282
+ }
283
+ )
284
+ ]
285
+ }
286
+ ),
287
+ searchable && !effectiveCollapsed && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: cn("border-b px-3 py-3", styles.divider), children: [
288
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "sr-only", htmlFor: "ug-sidebar-search", children: "\u641C\u7D22\u83DC\u5355" }),
289
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative", children: [
290
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.Search, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary", "aria-hidden": "true" }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
292
+ "input",
293
+ {
294
+ id: "ug-sidebar-search",
295
+ value: query,
296
+ onChange: (event) => setQuery(event.target.value),
297
+ placeholder: searchPlaceholder,
298
+ autoComplete: "off",
299
+ className: "h-10 w-full rounded-lg border border-border-base bg-surface-0 px-3 pl-9 pr-9 text-sm text-text-primary outline-none transition-colors placeholder:text-text-tertiary focus:border-primary focus:ring-2 focus:ring-primary/20",
300
+ type: "text",
301
+ role: "searchbox"
302
+ }
303
+ ),
304
+ query ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
305
+ "button",
306
+ {
307
+ type: "button",
308
+ className: "absolute right-1 top-1/2 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-md text-text-tertiary transition-colors hover:bg-surface-2 hover:text-text-primary",
309
+ "aria-label": "\u6E05\u7A7A\u641C\u7D22",
310
+ onClick: () => setQuery(""),
311
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.X, { size: 14 })
312
+ }
313
+ ) : null
314
+ ] })
315
+ ] }),
316
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("nav", { className: "flex-1 overflow-y-auto py-3.5", children: visibleItems.length > 0 ? renderItems(visibleItems) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mx-3 rounded-lg border border-dashed border-border-base bg-surface-0 px-3 py-3 text-sm text-text-tertiary", children: "\u6CA1\u6709\u5339\u914D\u7684\u83DC\u5355" }) }),
317
+ footer && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
318
+ "div",
319
+ {
320
+ className: cn(
321
+ "border-t px-2.5 py-3",
322
+ styles.divider,
323
+ effectiveCollapsed && "flex justify-center"
324
+ ),
325
+ children: footer
326
+ }
327
+ )
328
+ ]
329
+ }
330
+ );
331
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
332
+ responsive && mobileOpen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
333
+ "button",
334
+ {
335
+ type: "button",
336
+ className: "fixed inset-0 z-40 bg-overlay md:hidden",
337
+ "aria-label": "\u5173\u95ED\u4FA7\u8FB9\u680F\u906E\u7F69",
338
+ onClick: closeMobile
339
+ }
340
+ ) : null,
341
+ sidebar
342
+ ] });
343
+ }
344
+ );
345
+ Sidebar.displayName = "Sidebar";
346
+
347
+ // src/patterns/admin-shell.tsx
348
+ var import_jsx_runtime3 = require("react/jsx-runtime");
349
+ var AdminShell = (0, import_react3.forwardRef)(
350
+ ({
351
+ navItems,
352
+ sidebarHeader,
353
+ sidebarFooter,
354
+ sidebarVariant = "dark",
355
+ sidebarSearchable = false,
356
+ sidebarCollapsible = true,
357
+ sidebarCollapsed,
358
+ defaultSidebarCollapsed = false,
359
+ onSidebarCollapsedChange,
360
+ mobileSidebarOpen,
361
+ onMobileSidebarOpenChange,
362
+ topbarStart,
363
+ topbarEnd,
364
+ topbar,
365
+ mainClassName,
366
+ contentClassName,
367
+ children,
368
+ className,
369
+ ...props
370
+ }, ref) => {
371
+ const [internalMobileOpen, setInternalMobileOpen] = (0, import_react3.useState)(false);
372
+ const effectiveMobileOpen = mobileSidebarOpen ?? internalMobileOpen;
373
+ function setMobileOpen(open) {
374
+ if (mobileSidebarOpen === void 0) {
375
+ setInternalMobileOpen(open);
376
+ }
377
+ onMobileSidebarOpenChange?.(open);
378
+ }
379
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
380
+ "div",
381
+ {
382
+ ref,
383
+ className: cn("min-h-screen bg-surface-0 text-text-primary", className),
384
+ ...props,
385
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex min-h-screen min-w-0", children: [
386
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
387
+ Sidebar,
388
+ {
389
+ items: navItems,
390
+ variant: sidebarVariant,
391
+ header: sidebarHeader,
392
+ footer: sidebarFooter,
393
+ searchable: sidebarSearchable,
394
+ collapsible: sidebarCollapsible,
395
+ collapsed: sidebarCollapsed,
396
+ defaultCollapsed: defaultSidebarCollapsed,
397
+ onCollapsedChange: onSidebarCollapsedChange,
398
+ responsive: true,
399
+ mobileOpen: effectiveMobileOpen,
400
+ onMobileOpenChange: setMobileOpen,
401
+ className: "shrink-0"
402
+ }
403
+ ),
404
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col", children: [
405
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("header", { className: "sticky top-0 z-30 flex min-h-14 items-center gap-3 border-b border-border-base bg-surface-0/95 px-4 backdrop-blur sm:px-6 lg:px-8", children: [
406
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
407
+ Button,
408
+ {
409
+ type: "button",
410
+ variant: "ghost",
411
+ size: "icon",
412
+ className: "md:hidden",
413
+ "aria-label": "\u6253\u5F00\u4FA7\u8FB9\u680F",
414
+ onClick: () => setMobileOpen(true),
415
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.Menu, { size: 18 })
416
+ }
417
+ ),
418
+ topbar ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "min-w-0 flex-1", children: topbar }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
419
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "min-w-0 flex-1", children: topbarStart }),
420
+ topbarEnd ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex shrink-0 items-center gap-2", children: topbarEnd }) : null
421
+ ] })
422
+ ] }),
423
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("main", { className: cn("min-w-0 flex-1 overflow-x-hidden", mainClassName), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: cn("mx-auto w-full max-w-7xl px-4 py-6 sm:px-6 lg:px-8", contentClassName), children }) })
424
+ ] })
425
+ ] })
426
+ }
427
+ );
428
+ }
429
+ );
430
+ AdminShell.displayName = "AdminShell";
431
+
432
+ // src/patterns/confirm-dialog.tsx
433
+ var import_react7 = require("react");
434
+ var import_lucide_react5 = require("lucide-react");
435
+
436
+ // src/components/modal.tsx
437
+ var import_react6 = require("react");
438
+ var import_react_dom = require("react-dom");
439
+ var import_lucide_react4 = require("lucide-react");
440
+
441
+ // src/hooks/use-escape-key.ts
442
+ var import_react4 = require("react");
443
+ function useEscapeKey(open, onEscape) {
444
+ const handleEscape = (0, import_react4.useCallback)(
445
+ (e) => {
446
+ if (e.key === "Escape") onEscape();
447
+ },
448
+ [onEscape]
449
+ );
450
+ (0, import_react4.useEffect)(() => {
451
+ if (!open || typeof document === "undefined") return;
452
+ document.addEventListener("keydown", handleEscape);
453
+ document.body.style.overflow = "hidden";
454
+ return () => {
455
+ document.removeEventListener("keydown", handleEscape);
456
+ document.body.style.overflow = "";
457
+ };
458
+ }, [open, handleEscape]);
459
+ }
460
+
461
+ // src/internal/use-portal-container.ts
462
+ var import_react5 = require("react");
463
+ function usePortalContainer() {
464
+ const [container, setContainer] = (0, import_react5.useState)(null);
465
+ (0, import_react5.useEffect)(() => {
466
+ if (typeof document === "undefined") return;
467
+ setContainer(document.body);
468
+ }, []);
469
+ return container;
470
+ }
471
+
472
+ // src/components/modal.tsx
473
+ var import_jsx_runtime4 = require("react/jsx-runtime");
474
+ var Modal = (0, import_react6.forwardRef)(({ open, onClose, children, className }, ref) => {
475
+ useEscapeKey(open, onClose);
476
+ const portalContainer = usePortalContainer();
477
+ if (!open || !portalContainer) return null;
478
+ return (0, import_react_dom.createPortal)(
479
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
480
+ "div",
481
+ {
482
+ ref,
483
+ className: cn(
484
+ "fixed inset-0 z-[80] flex items-center justify-center p-4",
485
+ className
486
+ ),
487
+ role: "dialog",
488
+ "aria-modal": "true",
489
+ children: [
490
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
491
+ "div",
492
+ {
493
+ className: "absolute inset-0 bg-overlay",
494
+ onClick: onClose,
495
+ "aria-hidden": "true"
496
+ }
497
+ ),
498
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "relative z-10", children })
499
+ ]
500
+ }
501
+ ),
502
+ portalContainer
503
+ );
504
+ });
505
+ var ModalContent = (0, import_react6.forwardRef)(({ className, maxWidth = "max-w-lg", children, ...props }, ref) => {
506
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cn("flex max-h-[85vh] w-full flex-col rounded-lg border border-border-base bg-surface-1 shadow-xl", maxWidth, className), ...props, children });
507
+ });
508
+ var ModalHeader = (0, import_react6.forwardRef)(({ className, ...props }, ref) => {
509
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cn("flex shrink-0 items-center justify-between border-b border-border-base px-6 py-4", className), ...props });
510
+ });
511
+ var ModalTitle = (0, import_react6.forwardRef)(({ className, ...props }, ref) => {
512
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { ref, className: cn("text-lg font-semibold text-text-primary", className), ...props });
513
+ });
514
+ var ModalFooter = (0, import_react6.forwardRef)(({ className, ...props }, ref) => {
515
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cn("flex shrink-0 items-center justify-end gap-2 border-t border-border-base px-6 py-4", className), ...props });
516
+ });
517
+ var ModalCloseButton = (0, import_react6.forwardRef)(({ onClick, className, type = "button", ...props }, ref) => {
518
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
519
+ "button",
520
+ {
521
+ ref,
522
+ type,
523
+ onClick,
524
+ className: cn(
525
+ "rounded-md p-1 text-text-tertiary transition-colors hover:bg-surface-3 hover:text-text-secondary",
526
+ className
527
+ ),
528
+ "aria-label": "\u5173\u95ED",
529
+ ...props,
530
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react4.X, { size: 18 })
531
+ }
532
+ );
533
+ });
534
+ Modal.displayName = "Modal";
535
+ ModalContent.displayName = "ModalContent";
536
+ ModalHeader.displayName = "ModalHeader";
537
+ ModalTitle.displayName = "ModalTitle";
538
+ ModalFooter.displayName = "ModalFooter";
539
+ ModalCloseButton.displayName = "ModalCloseButton";
540
+
541
+ // src/patterns/confirm-dialog.tsx
542
+ var import_jsx_runtime5 = require("react/jsx-runtime");
543
+ var ConfirmDialog = (0, import_react7.forwardRef)(
544
+ ({
545
+ open,
546
+ onOpenChange,
547
+ title,
548
+ description,
549
+ children,
550
+ variant = "destructive",
551
+ icon,
552
+ cancelText = "\u53D6\u6D88",
553
+ confirmText = "\u786E\u8BA4",
554
+ loading = false,
555
+ disabled = false,
556
+ closeOnConfirm = true,
557
+ onCancel,
558
+ onConfirm,
559
+ className,
560
+ ...props
561
+ }, ref) => {
562
+ const Icon = icon ?? (variant === "destructive" ? import_lucide_react5.AlertTriangle : import_lucide_react5.HelpCircle);
563
+ function handleCancel() {
564
+ onCancel?.();
565
+ onOpenChange(false);
566
+ }
567
+ function handleConfirm() {
568
+ const result = onConfirm?.();
569
+ if (closeOnConfirm) onOpenChange(false);
570
+ return result;
571
+ }
572
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Modal, { open, onClose: handleCancel, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
573
+ ModalContent,
574
+ {
575
+ ref,
576
+ className: cn("max-w-md", className),
577
+ ...props,
578
+ children: [
579
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ModalHeader, { className: "items-start gap-3", children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
581
+ "div",
582
+ {
583
+ className: cn(
584
+ "flex h-10 w-10 shrink-0 items-center justify-center rounded-md",
585
+ variant === "destructive" ? "bg-danger-soft text-danger-soft-fg" : "bg-primary-soft text-primary-soft-fg"
586
+ ),
587
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { size: 20, "aria-hidden": "true" })
588
+ }
589
+ ),
590
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "min-w-0 flex-1 space-y-1", children: [
591
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ModalTitle, { className: "break-words text-base", children: title }),
592
+ description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-sm leading-6 text-text-secondary", children: description }) : null
593
+ ] })
594
+ ] }),
595
+ children ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "px-6 py-4 text-sm text-text-secondary", children }) : null,
596
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ModalFooter, { className: "flex-col-reverse gap-2 sm:flex-row", children: [
597
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { type: "button", variant: "outline", disabled: loading, onClick: handleCancel, children: cancelText }),
598
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
599
+ Button,
600
+ {
601
+ type: "button",
602
+ variant: variant === "destructive" ? "destructive" : "default",
603
+ loading,
604
+ disabled,
605
+ onClick: handleConfirm,
606
+ children: confirmText
607
+ }
608
+ )
609
+ ] })
610
+ ]
611
+ }
612
+ ) });
613
+ }
614
+ );
615
+ ConfirmDialog.displayName = "ConfirmDialog";
616
+
617
+ // src/patterns/copy-field.tsx
618
+ var import_react8 = require("react");
619
+ var import_lucide_react6 = require("lucide-react");
620
+ var import_jsx_runtime6 = require("react/jsx-runtime");
621
+ var CopyField = (0, import_react8.forwardRef)(
622
+ ({
623
+ value,
624
+ label,
625
+ displayValue,
626
+ monospace = true,
627
+ disabled = false,
628
+ copyLabel = "\u590D\u5236",
629
+ copiedLabel = "\u5DF2\u590D\u5236",
630
+ onCopied,
631
+ onCopyError,
632
+ className,
633
+ ...props
634
+ }, ref) => {
635
+ const [copied, setCopied] = (0, import_react8.useState)(false);
636
+ const timeoutRef = (0, import_react8.useRef)(null);
637
+ (0, import_react8.useEffect)(() => {
638
+ return () => {
639
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
640
+ };
641
+ }, []);
642
+ async function handleCopy() {
643
+ if (disabled) return;
644
+ try {
645
+ if (!navigator.clipboard?.writeText) {
646
+ throw new Error("Clipboard API is not available");
647
+ }
648
+ await navigator.clipboard.writeText(value);
649
+ setCopied(true);
650
+ onCopied?.(value);
651
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
652
+ timeoutRef.current = setTimeout(() => setCopied(false), 1400);
653
+ } catch (error) {
654
+ onCopyError?.(error);
655
+ }
656
+ }
657
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref, className: cn("space-y-2", className), ...props, children: [
658
+ label ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-xs font-medium text-text-secondary", children: label }) : null,
659
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
660
+ "div",
661
+ {
662
+ className: cn(
663
+ "flex min-w-0 items-stretch overflow-hidden rounded-md border border-border-base bg-surface-1",
664
+ disabled && "opacity-60"
665
+ ),
666
+ children: [
667
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
668
+ "div",
669
+ {
670
+ className: cn(
671
+ "min-w-0 flex-1 truncate px-3 py-2 text-sm text-text-primary",
672
+ monospace && "font-mono"
673
+ ),
674
+ title: typeof displayValue === "string" ? displayValue : value,
675
+ children: displayValue ?? value
676
+ }
677
+ ),
678
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex shrink-0 items-center border-l border-border-base bg-surface-2 px-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
679
+ Button,
680
+ {
681
+ type: "button",
682
+ variant: "ghost",
683
+ size: "sm",
684
+ disabled,
685
+ onClick: handleCopy,
686
+ "aria-live": "polite",
687
+ children: [
688
+ copied ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Check, { size: 15 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Copy, { size: 15 }),
689
+ copied ? copiedLabel : copyLabel
690
+ ]
691
+ }
692
+ ) })
693
+ ]
694
+ }
695
+ )
696
+ ] });
697
+ }
698
+ );
699
+ CopyField.displayName = "CopyField";
700
+
701
+ // src/patterns/page-header.tsx
702
+ var import_react9 = require("react");
703
+ var import_jsx_runtime7 = require("react/jsx-runtime");
704
+ var PageHeader = (0, import_react9.forwardRef)(
705
+ ({
706
+ eyebrow,
707
+ title,
708
+ description,
709
+ badge,
710
+ breadcrumb,
711
+ actions,
712
+ meta,
713
+ children,
714
+ className,
715
+ ...props
716
+ }, ref) => {
717
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
718
+ "header",
719
+ {
720
+ ref,
721
+ className: cn(
722
+ "flex min-w-0 flex-col gap-5 border-b border-border-base pb-6",
723
+ className
724
+ ),
725
+ ...props,
726
+ children: [
727
+ breadcrumb ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-w-0", children: breadcrumb }) : null,
728
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 flex-col gap-4 lg:flex-row lg:items-start lg:justify-between", children: [
729
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "min-w-0 space-y-3", children: [
730
+ eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-xs font-semibold uppercase text-primary", children: eyebrow }) : null,
731
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 flex-wrap items-center gap-2.5", children: [
732
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { className: "min-w-0 break-words text-2xl font-bold leading-tight text-text-primary sm:text-3xl", children: title }),
733
+ badge ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "shrink-0", children: badge }) : null
734
+ ] }),
735
+ description ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "max-w-3xl text-sm leading-6 text-text-secondary", children: description }) : null,
736
+ meta ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex min-w-0 flex-wrap items-center gap-x-4 gap-y-2 text-xs text-text-tertiary", children: meta }) : null
737
+ ] }),
738
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex shrink-0 flex-wrap items-center gap-2 lg:justify-end", children: actions }) : null
739
+ ] }),
740
+ children ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-w-0", children }) : null
741
+ ]
742
+ }
743
+ );
744
+ }
745
+ );
746
+ PageHeader.displayName = "PageHeader";
747
+ // Annotate the CommonJS export names for ESM import in node:
748
+ 0 && (module.exports = {
749
+ AdminShell,
750
+ ConfirmDialog,
751
+ CopyField,
752
+ PageHeader,
753
+ UGAdminShell,
754
+ UGConfirmDialog,
755
+ UGCopyField,
756
+ UGPageHeader
757
+ });
758
+ //# sourceMappingURL=index.cjs.map