@camstack/ui-library 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2086 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ AppShell: () => AppShell,
24
+ Badge: () => Badge,
25
+ Button: () => Button,
26
+ Card: () => Card,
27
+ Checkbox: () => Checkbox,
28
+ CodeBlock: () => CodeBlock,
29
+ ConfirmDialog: () => ConfirmDialog,
30
+ DataTable: () => DataTable,
31
+ DeviceCard: () => DeviceCard,
32
+ DeviceGrid: () => DeviceGrid,
33
+ Dialog: () => Dialog,
34
+ DialogContent: () => DialogContent,
35
+ DialogDescription: () => DialogDescription,
36
+ DialogFooter: () => DialogFooter,
37
+ DialogHeader: () => DialogHeader,
38
+ DialogTitle: () => DialogTitle,
39
+ DialogTrigger: () => DialogTrigger,
40
+ Dropdown: () => Dropdown,
41
+ DropdownContent: () => DropdownContent,
42
+ DropdownItem: () => DropdownItem,
43
+ DropdownTrigger: () => DropdownTrigger,
44
+ EmptyState: () => EmptyState,
45
+ FilterBar: () => FilterBar,
46
+ FloatingPanel: () => FloatingPanel,
47
+ FormField: () => FormField,
48
+ IconButton: () => IconButton,
49
+ Input: () => Input,
50
+ KeyValueList: () => KeyValueList,
51
+ Label: () => Label,
52
+ PageHeader: () => PageHeader,
53
+ Popover: () => Popover,
54
+ PopoverContent: () => PopoverContent,
55
+ PopoverTrigger: () => PopoverTrigger,
56
+ ProviderBadge: () => ProviderBadge,
57
+ ScrollArea: () => ScrollArea,
58
+ Select: () => Select,
59
+ Separator: () => Separator,
60
+ Sidebar: () => Sidebar,
61
+ SidebarItem: () => SidebarItem,
62
+ Skeleton: () => Skeleton,
63
+ StatCard: () => StatCard,
64
+ StatusBadge: () => StatusBadge,
65
+ Switch: () => Switch,
66
+ Tabs: () => Tabs,
67
+ TabsContent: () => TabsContent,
68
+ TabsList: () => TabsList,
69
+ TabsTrigger: () => TabsTrigger,
70
+ ThemeProvider: () => ThemeProvider,
71
+ Tooltip: () => Tooltip,
72
+ TooltipContent: () => TooltipContent,
73
+ TooltipTrigger: () => TooltipTrigger,
74
+ cn: () => cn,
75
+ createTheme: () => createTheme,
76
+ darkColors: () => darkColors,
77
+ defaultTheme: () => defaultTheme,
78
+ lightColors: () => lightColors,
79
+ providerIcons: () => providerIcons,
80
+ statusIcons: () => statusIcons,
81
+ themeToCss: () => themeToCss,
82
+ useThemeMode: () => useThemeMode
83
+ });
84
+ module.exports = __toCommonJS(src_exports);
85
+
86
+ // src/theme/defaults.ts
87
+ var providerColors = {
88
+ frigate: "#3b82f6",
89
+ scrypted: "#a855f7",
90
+ reolink: "#06b6d4",
91
+ homeAssistant: "#22d3ee",
92
+ rtsp: "#78716c"
93
+ };
94
+ var darkColors = {
95
+ primary: "#f59e42",
96
+ primaryForeground: "#0c0a09",
97
+ background: "#0c0a09",
98
+ backgroundElevated: "#1c1917",
99
+ surface: "#1c1917",
100
+ surfaceHover: "#292524",
101
+ border: "#292524",
102
+ borderSubtle: "#1c1917",
103
+ foreground: "#fafaf9",
104
+ foregroundMuted: "#a8a29e",
105
+ foregroundSubtle: "#78716c",
106
+ foregroundDisabled: "#57534e",
107
+ success: "#4ade80",
108
+ warning: "#fbbf24",
109
+ danger: "#f87171",
110
+ info: "#60a5fa",
111
+ provider: providerColors
112
+ };
113
+ var lightColors = {
114
+ primary: "#e67e22",
115
+ primaryForeground: "#ffffff",
116
+ background: "#fafaf9",
117
+ backgroundElevated: "#ffffff",
118
+ surface: "#f5f5f4",
119
+ surfaceHover: "#e7e5e4",
120
+ border: "#d6d3d1",
121
+ borderSubtle: "#e7e5e4",
122
+ foreground: "#1c1917",
123
+ foregroundMuted: "#57534e",
124
+ foregroundSubtle: "#78716c",
125
+ foregroundDisabled: "#a8a29e",
126
+ success: "#16a34a",
127
+ warning: "#d97706",
128
+ danger: "#dc2626",
129
+ info: "#2563eb",
130
+ provider: providerColors
131
+ };
132
+ var defaultTheme = {
133
+ colors: {
134
+ dark: darkColors,
135
+ light: lightColors
136
+ },
137
+ spacing: {
138
+ xs: 2,
139
+ sm: 4,
140
+ md: 8,
141
+ lg: 12,
142
+ xl: 16,
143
+ "2xl": 24,
144
+ "3xl": 32
145
+ },
146
+ radius: {
147
+ sm: 4,
148
+ md: 6,
149
+ lg: 8,
150
+ xl: 12
151
+ },
152
+ typography: {
153
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
154
+ sizes: {
155
+ xs: { fontSize: 10, lineHeight: 14 },
156
+ sm: { fontSize: 11, lineHeight: 16 },
157
+ base: { fontSize: 12, lineHeight: 18 },
158
+ lg: { fontSize: 13, lineHeight: 18 },
159
+ xl: { fontSize: 14, lineHeight: 20 },
160
+ "2xl": { fontSize: 16, lineHeight: 22 },
161
+ "3xl": { fontSize: 20, lineHeight: 28 }
162
+ },
163
+ weights: {
164
+ regular: 400,
165
+ medium: 500,
166
+ semibold: 600,
167
+ bold: 700
168
+ }
169
+ },
170
+ table: {
171
+ rowHeight: 28,
172
+ headerHeight: 24,
173
+ cellPaddingX: 8,
174
+ cellPaddingY: 6
175
+ },
176
+ sidebar: {
177
+ width: 176,
178
+ itemHeight: 28,
179
+ iconSize: 14
180
+ }
181
+ };
182
+
183
+ // src/theme/create-theme.ts
184
+ function deepMerge(target, source) {
185
+ const result = { ...target };
186
+ for (const key in source) {
187
+ const sourceVal = source[key];
188
+ const targetVal = target[key];
189
+ if (sourceVal !== void 0 && typeof sourceVal === "object" && sourceVal !== null && !Array.isArray(sourceVal) && typeof targetVal === "object" && targetVal !== null) {
190
+ result[key] = deepMerge(
191
+ targetVal,
192
+ sourceVal
193
+ );
194
+ } else if (sourceVal !== void 0) {
195
+ result[key] = sourceVal;
196
+ }
197
+ }
198
+ return result;
199
+ }
200
+ function createTheme(overrides) {
201
+ if (!overrides) return structuredClone(defaultTheme);
202
+ return deepMerge(structuredClone(defaultTheme), overrides);
203
+ }
204
+
205
+ // src/theme/theme-to-css.ts
206
+ function camelToKebab(str) {
207
+ return str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
208
+ }
209
+ function colorTokenToCssVar(key) {
210
+ return `--color-${camelToKebab(key)}`;
211
+ }
212
+ function generateColorBlock(colors) {
213
+ const lines = [];
214
+ for (const [key, value] of Object.entries(colors)) {
215
+ if (key === "provider") continue;
216
+ lines.push(` ${colorTokenToCssVar(key)}: ${value};`);
217
+ }
218
+ return lines.join("\n");
219
+ }
220
+ function generateProviderColors(provider) {
221
+ const lines = [];
222
+ for (const [key, value] of Object.entries(provider)) {
223
+ lines.push(` --color-provider-${camelToKebab(key)}: ${value};`);
224
+ }
225
+ return lines.join("\n");
226
+ }
227
+ function generateSpacingTokens(spacing) {
228
+ const lines = [];
229
+ for (const [key, value] of Object.entries(spacing)) {
230
+ lines.push(` --spacing-${key}: ${value}px;`);
231
+ }
232
+ return lines.join("\n");
233
+ }
234
+ function generateRadiusTokens(radius) {
235
+ const lines = [];
236
+ for (const [key, value] of Object.entries(radius)) {
237
+ lines.push(` --radius-${key}: ${value}px;`);
238
+ }
239
+ return lines.join("\n");
240
+ }
241
+ function themeToCss(theme) {
242
+ const darkColorBlock = generateColorBlock(theme.colors.dark);
243
+ const lightColorBlock = generateColorBlock(theme.colors.light);
244
+ const providerBlock = generateProviderColors(theme.colors.dark.provider);
245
+ const spacingBlock = generateSpacingTokens(theme.spacing);
246
+ const radiusBlock = generateRadiusTokens(theme.radius);
247
+ return `@theme {
248
+ ${providerBlock}
249
+ ${spacingBlock}
250
+ ${radiusBlock}
251
+ }
252
+
253
+ .dark {
254
+ ${darkColorBlock}
255
+ }
256
+
257
+ .light {
258
+ ${lightColorBlock}
259
+ }
260
+
261
+ @media (prefers-color-scheme: dark) {
262
+ :root {
263
+ ${darkColorBlock.replace(/^ /gm, " ")}
264
+ }
265
+ }
266
+
267
+ @media (prefers-color-scheme: light) {
268
+ :root {
269
+ ${lightColorBlock.replace(/^ /gm, " ")}
270
+ }
271
+ }
272
+ `;
273
+ }
274
+
275
+ // src/theme/theme-provider.tsx
276
+ var import_react = require("react");
277
+ var import_jsx_runtime = require("react/jsx-runtime");
278
+ var ThemeContext = (0, import_react.createContext)(null);
279
+ var TOGGLE_ORDER = ["dark", "light", "system"];
280
+ function getSystemPreference() {
281
+ if (typeof window === "undefined") return "dark";
282
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
283
+ }
284
+ function getInitialMode(storageKey, defaultMode) {
285
+ if (typeof window === "undefined") return defaultMode;
286
+ const stored = localStorage.getItem(storageKey);
287
+ if (stored === "dark" || stored === "light" || stored === "system") {
288
+ return stored;
289
+ }
290
+ return defaultMode;
291
+ }
292
+ function resolveMode(mode) {
293
+ if (mode === "system") return getSystemPreference();
294
+ return mode;
295
+ }
296
+ function ThemeProvider({
297
+ children,
298
+ defaultMode = "system",
299
+ storageKey = "camstack-theme-mode"
300
+ }) {
301
+ const [mode, setModeState] = (0, import_react.useState)(() => getInitialMode(storageKey, defaultMode));
302
+ const [resolvedMode, setResolvedMode] = (0, import_react.useState)(() => resolveMode(mode));
303
+ const setMode = (0, import_react.useCallback)(
304
+ (newMode) => {
305
+ setModeState(newMode);
306
+ setResolvedMode(resolveMode(newMode));
307
+ if (typeof window !== "undefined") {
308
+ localStorage.setItem(storageKey, newMode);
309
+ }
310
+ },
311
+ [storageKey]
312
+ );
313
+ const toggleMode = (0, import_react.useCallback)(() => {
314
+ const currentIndex = TOGGLE_ORDER.indexOf(mode);
315
+ const nextIndex = (currentIndex + 1) % TOGGLE_ORDER.length;
316
+ setMode(TOGGLE_ORDER[nextIndex] ?? "dark");
317
+ }, [mode, setMode]);
318
+ (0, import_react.useEffect)(() => {
319
+ if (typeof document === "undefined") return;
320
+ const root = document.documentElement;
321
+ root.classList.remove("dark", "light");
322
+ root.classList.add(resolvedMode);
323
+ }, [mode, resolvedMode]);
324
+ (0, import_react.useEffect)(() => {
325
+ if (typeof window === "undefined" || mode !== "system") return;
326
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
327
+ const handleChange = () => {
328
+ setResolvedMode(getSystemPreference());
329
+ };
330
+ mediaQuery.addEventListener("change", handleChange);
331
+ return () => mediaQuery.removeEventListener("change", handleChange);
332
+ }, [mode]);
333
+ const value = (0, import_react.useMemo)(
334
+ () => ({ mode, resolvedMode, setMode, toggleMode }),
335
+ [mode, resolvedMode, setMode, toggleMode]
336
+ );
337
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value, children });
338
+ }
339
+
340
+ // src/theme/use-theme-mode.ts
341
+ var import_react2 = require("react");
342
+ function useThemeMode() {
343
+ const context = (0, import_react2.useContext)(ThemeContext);
344
+ if (!context) {
345
+ throw new Error("useThemeMode must be used within a ThemeProvider");
346
+ }
347
+ return context;
348
+ }
349
+
350
+ // src/lib/cn.ts
351
+ var import_clsx = require("clsx");
352
+ var import_tailwind_merge = require("tailwind-merge");
353
+ function cn(...inputs) {
354
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
355
+ }
356
+
357
+ // src/icons/provider-icons.ts
358
+ var import_lucide_react = require("lucide-react");
359
+ var providerIcons = {
360
+ frigate: import_lucide_react.Ship,
361
+ scrypted: import_lucide_react.Shield,
362
+ reolink: import_lucide_react.Radio,
363
+ homeAssistant: import_lucide_react.Home,
364
+ rtsp: import_lucide_react.Cast
365
+ };
366
+
367
+ // src/icons/status-icons.ts
368
+ var import_lucide_react2 = require("lucide-react");
369
+ var statusIcons = {
370
+ online: import_lucide_react2.CircleCheck,
371
+ offline: import_lucide_react2.CircleX,
372
+ degraded: import_lucide_react2.CircleAlert,
373
+ unknown: import_lucide_react2.CircleHelp
374
+ };
375
+
376
+ // src/primitives/button.tsx
377
+ var import_react3 = require("react");
378
+ var import_class_variance_authority = require("class-variance-authority");
379
+ var import_jsx_runtime2 = require("react/jsx-runtime");
380
+ var buttonVariants = (0, import_class_variance_authority.cva)(
381
+ "inline-flex items-center justify-center rounded-md font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none",
382
+ {
383
+ variants: {
384
+ variant: {
385
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90",
386
+ secondary: "bg-surface text-foreground hover:bg-surface-hover",
387
+ ghost: "hover:bg-surface-hover text-foreground-muted",
388
+ danger: "bg-danger text-white hover:bg-danger/90",
389
+ outline: "border border-border bg-transparent hover:bg-surface-hover"
390
+ },
391
+ size: {
392
+ sm: "h-7 px-2.5 text-xs gap-1.5",
393
+ md: "h-8 px-3 text-sm gap-2",
394
+ lg: "h-9 px-4 text-sm gap-2"
395
+ }
396
+ },
397
+ defaultVariants: {
398
+ variant: "primary",
399
+ size: "sm"
400
+ }
401
+ }
402
+ );
403
+ var Button = (0, import_react3.forwardRef)(
404
+ ({ className, variant, size, ...props }, ref) => {
405
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
406
+ "button",
407
+ {
408
+ ref,
409
+ className: cn(buttonVariants({ variant, size }), className),
410
+ ...props
411
+ }
412
+ );
413
+ }
414
+ );
415
+ Button.displayName = "Button";
416
+
417
+ // src/primitives/icon-button.tsx
418
+ var import_react4 = require("react");
419
+ var import_class_variance_authority2 = require("class-variance-authority");
420
+ var import_jsx_runtime3 = require("react/jsx-runtime");
421
+ var iconButtonVariants = (0, import_class_variance_authority2.cva)(
422
+ "inline-flex items-center justify-center rounded-md font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none",
423
+ {
424
+ variants: {
425
+ variant: {
426
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90",
427
+ secondary: "bg-surface text-foreground hover:bg-surface-hover",
428
+ ghost: "hover:bg-surface-hover text-foreground-muted",
429
+ danger: "bg-danger text-white hover:bg-danger/90",
430
+ outline: "border border-border bg-transparent hover:bg-surface-hover"
431
+ },
432
+ size: {
433
+ sm: "h-7 w-7",
434
+ md: "h-8 w-8",
435
+ lg: "h-9 w-9"
436
+ }
437
+ },
438
+ defaultVariants: {
439
+ variant: "primary",
440
+ size: "sm"
441
+ }
442
+ }
443
+ );
444
+ var IconButton = (0, import_react4.forwardRef)(
445
+ ({ className, variant, size, icon: Icon, ...props }, ref) => {
446
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
447
+ "button",
448
+ {
449
+ ref,
450
+ className: cn(iconButtonVariants({ variant, size }), className),
451
+ ...props,
452
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Icon, { className: "h-4 w-4" })
453
+ }
454
+ );
455
+ }
456
+ );
457
+ IconButton.displayName = "IconButton";
458
+
459
+ // src/primitives/badge.tsx
460
+ var import_react5 = require("react");
461
+ var import_class_variance_authority3 = require("class-variance-authority");
462
+ var import_jsx_runtime4 = require("react/jsx-runtime");
463
+ var badgeVariants = (0, import_class_variance_authority3.cva)(
464
+ "inline-flex items-center rounded-full text-xs font-medium px-2 py-0.5",
465
+ {
466
+ variants: {
467
+ variant: {
468
+ default: "bg-surface-hover text-foreground",
469
+ success: "bg-success/15 text-success",
470
+ warning: "bg-warning/15 text-warning",
471
+ danger: "bg-danger/15 text-danger",
472
+ info: "bg-info/15 text-info"
473
+ },
474
+ styleVariant: {
475
+ solid: "",
476
+ outline: "border bg-transparent"
477
+ }
478
+ },
479
+ defaultVariants: {
480
+ variant: "default",
481
+ styleVariant: "solid"
482
+ }
483
+ }
484
+ );
485
+ var Badge = (0, import_react5.forwardRef)(
486
+ ({ className, variant, style, ...props }, ref) => {
487
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
488
+ "span",
489
+ {
490
+ ref,
491
+ className: cn(badgeVariants({ variant, styleVariant: style }), className),
492
+ ...props
493
+ }
494
+ );
495
+ }
496
+ );
497
+ Badge.displayName = "Badge";
498
+
499
+ // src/primitives/card.tsx
500
+ var import_react6 = require("react");
501
+ var import_class_variance_authority4 = require("class-variance-authority");
502
+ var import_jsx_runtime5 = require("react/jsx-runtime");
503
+ var cardVariants = (0, import_class_variance_authority4.cva)("rounded-lg p-3", {
504
+ variants: {
505
+ variant: {
506
+ flat: "bg-surface",
507
+ bordered: "bg-surface border border-border"
508
+ }
509
+ },
510
+ defaultVariants: {
511
+ variant: "bordered"
512
+ }
513
+ });
514
+ var Card = (0, import_react6.forwardRef)(
515
+ ({ className, variant, ...props }, ref) => {
516
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
517
+ "div",
518
+ {
519
+ ref,
520
+ className: cn(cardVariants({ variant }), className),
521
+ ...props
522
+ }
523
+ );
524
+ }
525
+ );
526
+ Card.displayName = "Card";
527
+
528
+ // src/primitives/label.tsx
529
+ var import_react7 = require("react");
530
+ var import_jsx_runtime6 = require("react/jsx-runtime");
531
+ var Label = (0, import_react7.forwardRef)(
532
+ ({ className, ...props }, ref) => {
533
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
534
+ "label",
535
+ {
536
+ ref,
537
+ className: cn(
538
+ "text-[10px] uppercase tracking-wider text-foreground-muted font-medium",
539
+ className
540
+ ),
541
+ ...props
542
+ }
543
+ );
544
+ }
545
+ );
546
+ Label.displayName = "Label";
547
+
548
+ // src/primitives/separator.tsx
549
+ var import_react8 = require("react");
550
+ var import_class_variance_authority5 = require("class-variance-authority");
551
+ var import_jsx_runtime7 = require("react/jsx-runtime");
552
+ var separatorVariants = (0, import_class_variance_authority5.cva)("", {
553
+ variants: {
554
+ orientation: {
555
+ horizontal: "h-px w-full bg-border-subtle",
556
+ vertical: "w-px h-full bg-border-subtle"
557
+ }
558
+ },
559
+ defaultVariants: {
560
+ orientation: "horizontal"
561
+ }
562
+ });
563
+ var Separator = (0, import_react8.forwardRef)(
564
+ ({ className, orientation, ...props }, ref) => {
565
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
566
+ "div",
567
+ {
568
+ ref,
569
+ role: "separator",
570
+ className: cn(separatorVariants({ orientation }), className),
571
+ ...props
572
+ }
573
+ );
574
+ }
575
+ );
576
+ Separator.displayName = "Separator";
577
+
578
+ // src/primitives/skeleton.tsx
579
+ var import_react9 = require("react");
580
+ var import_jsx_runtime8 = require("react/jsx-runtime");
581
+ var Skeleton = (0, import_react9.forwardRef)(
582
+ ({ className, ...props }, ref) => {
583
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
584
+ "div",
585
+ {
586
+ ref,
587
+ className: cn("animate-pulse bg-surface-hover rounded-md h-4 w-full", className),
588
+ ...props
589
+ }
590
+ );
591
+ }
592
+ );
593
+ Skeleton.displayName = "Skeleton";
594
+
595
+ // src/primitives/input.tsx
596
+ var import_react10 = require("react");
597
+ var import_class_variance_authority6 = require("class-variance-authority");
598
+ var import_jsx_runtime9 = require("react/jsx-runtime");
599
+ var inputVariants = (0, import_class_variance_authority6.cva)(
600
+ "h-7 w-full px-2.5 text-xs bg-surface border rounded-md text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-primary transition-colors",
601
+ {
602
+ variants: {
603
+ state: {
604
+ default: "border-border",
605
+ error: "border-danger"
606
+ }
607
+ },
608
+ defaultVariants: {
609
+ state: "default"
610
+ }
611
+ }
612
+ );
613
+ var Input = (0, import_react10.forwardRef)(
614
+ ({ className, state, leftSlot, rightSlot, ...props }, ref) => {
615
+ if (leftSlot || rightSlot) {
616
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "relative flex items-center w-full", children: [
617
+ leftSlot && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute left-2.5 flex items-center pointer-events-none", children: leftSlot }),
618
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
619
+ "input",
620
+ {
621
+ ref,
622
+ className: cn(
623
+ inputVariants({ state }),
624
+ leftSlot ? "pl-7" : "",
625
+ rightSlot ? "pr-7" : "",
626
+ className
627
+ ),
628
+ ...props
629
+ }
630
+ ),
631
+ rightSlot && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute right-2.5 flex items-center pointer-events-none", children: rightSlot })
632
+ ] });
633
+ }
634
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
635
+ "input",
636
+ {
637
+ ref,
638
+ className: cn(inputVariants({ state }), className),
639
+ ...props
640
+ }
641
+ );
642
+ }
643
+ );
644
+ Input.displayName = "Input";
645
+
646
+ // src/primitives/select.tsx
647
+ var import_react11 = require("react");
648
+ var import_lucide_react3 = require("lucide-react");
649
+ var import_jsx_runtime10 = require("react/jsx-runtime");
650
+ var Select = (0, import_react11.forwardRef)(
651
+ ({ className, options, ...props }, ref) => {
652
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative w-full", children: [
653
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
654
+ "select",
655
+ {
656
+ ref,
657
+ className: cn(
658
+ "h-7 w-full px-2.5 text-xs bg-surface border border-border rounded-md text-foreground appearance-none pr-7 focus:outline-none focus:ring-1 focus:ring-primary",
659
+ className
660
+ ),
661
+ ...props,
662
+ children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: option.value, children: option.label }, option.value))
663
+ }
664
+ ),
665
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none text-foreground-muted", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.ChevronDown, { className: "h-3.5 w-3.5" }) })
666
+ ] });
667
+ }
668
+ );
669
+ Select.displayName = "Select";
670
+
671
+ // src/primitives/checkbox.tsx
672
+ var import_react12 = require("react");
673
+ var import_jsx_runtime11 = require("react/jsx-runtime");
674
+ var Checkbox = (0, import_react12.forwardRef)(
675
+ ({ className, ...props }, ref) => {
676
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
677
+ "input",
678
+ {
679
+ ref,
680
+ type: "checkbox",
681
+ className: cn(
682
+ "w-3.5 h-3.5 rounded-sm border border-border accent-primary",
683
+ className
684
+ ),
685
+ ...props
686
+ }
687
+ );
688
+ }
689
+ );
690
+ Checkbox.displayName = "Checkbox";
691
+
692
+ // src/primitives/switch.tsx
693
+ var import_react13 = require("react");
694
+ var import_jsx_runtime12 = require("react/jsx-runtime");
695
+ var Switch = (0, import_react13.forwardRef)(
696
+ ({ className, checked, onCheckedChange, label, ...props }, ref) => {
697
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
698
+ "button",
699
+ {
700
+ ref,
701
+ role: "switch",
702
+ "aria-checked": checked,
703
+ type: "button",
704
+ onClick: () => onCheckedChange(!checked),
705
+ className: cn("inline-flex items-center gap-2", className),
706
+ ...props,
707
+ children: [
708
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
709
+ "span",
710
+ {
711
+ className: cn(
712
+ "w-8 h-4 rounded-full transition-colors",
713
+ checked ? "bg-primary" : "bg-surface-hover"
714
+ ),
715
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
716
+ "span",
717
+ {
718
+ className: cn(
719
+ "block w-3.5 h-3.5 rounded-full bg-white transition-transform",
720
+ checked ? "translate-x-4" : "translate-x-0.5"
721
+ )
722
+ }
723
+ )
724
+ }
725
+ ),
726
+ label && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-xs text-foreground", children: label })
727
+ ]
728
+ }
729
+ );
730
+ }
731
+ );
732
+ Switch.displayName = "Switch";
733
+
734
+ // src/primitives/dialog.tsx
735
+ var import_react14 = require("react");
736
+ var import_class_variance_authority7 = require("class-variance-authority");
737
+ var import_jsx_runtime13 = require("react/jsx-runtime");
738
+ var DialogContext = (0, import_react14.createContext)(null);
739
+ function useDialogContext() {
740
+ const ctx = (0, import_react14.useContext)(DialogContext);
741
+ if (!ctx) throw new Error("Dialog compound components must be used within <Dialog>");
742
+ return ctx;
743
+ }
744
+ function Dialog({ children, open: controlledOpen, onOpenChange }) {
745
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react14.useState)(false);
746
+ const open = controlledOpen ?? uncontrolledOpen;
747
+ const contentId = (0, import_react14.useId)();
748
+ const setOpen = (0, import_react14.useCallback)(
749
+ (next) => {
750
+ onOpenChange?.(next);
751
+ if (controlledOpen === void 0) setUncontrolledOpen(next);
752
+ },
753
+ [controlledOpen, onOpenChange]
754
+ );
755
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogContext.Provider, { value: { open, setOpen, contentId }, children });
756
+ }
757
+ function DialogTrigger({ children, ...props }) {
758
+ const { setOpen } = useDialogContext();
759
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => setOpen(true), ...props, children });
760
+ }
761
+ var contentVariants = (0, import_class_variance_authority7.cva)(
762
+ "bg-background-elevated border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm",
763
+ {
764
+ variants: {
765
+ width: {
766
+ sm: "max-w-sm",
767
+ md: "max-w-md",
768
+ lg: "max-w-lg"
769
+ }
770
+ },
771
+ defaultVariants: { width: "md" }
772
+ }
773
+ );
774
+ var DialogContent = (0, import_react14.forwardRef)(
775
+ ({ className, width, children, ...props }, ref) => {
776
+ const { open, setOpen, contentId } = useDialogContext();
777
+ const innerRef = (0, import_react14.useRef)(null);
778
+ const dialogRef = ref ?? innerRef;
779
+ (0, import_react14.useEffect)(() => {
780
+ const el = dialogRef.current;
781
+ if (!el) return;
782
+ if (open && !el.open) el.showModal();
783
+ if (!open && el.open) el.close();
784
+ }, [open, dialogRef]);
785
+ const handleClick = (e) => {
786
+ if (e.target === e.currentTarget) setOpen(false);
787
+ };
788
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
789
+ "dialog",
790
+ {
791
+ ref: dialogRef,
792
+ id: contentId,
793
+ className: cn(contentVariants({ width }), "w-full", className),
794
+ onClick: handleClick,
795
+ onClose: () => setOpen(false),
796
+ ...props,
797
+ children
798
+ }
799
+ );
800
+ }
801
+ );
802
+ DialogContent.displayName = "DialogContent";
803
+ function DialogHeader({ className, ...props }) {
804
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("flex flex-col gap-1 mb-3", className), ...props });
805
+ }
806
+ function DialogFooter({ className, ...props }) {
807
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("flex justify-end gap-2 mt-4", className), ...props });
808
+ }
809
+ function DialogTitle({ className, ...props }) {
810
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: cn("text-sm font-semibold text-foreground", className), ...props });
811
+ }
812
+ function DialogDescription({ className, ...props }) {
813
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: cn("text-xs text-foreground-muted", className), ...props });
814
+ }
815
+
816
+ // src/primitives/dropdown.tsx
817
+ var import_react15 = require("react");
818
+ var import_jsx_runtime14 = require("react/jsx-runtime");
819
+ var DropdownContext = (0, import_react15.createContext)(null);
820
+ function useDropdownContext() {
821
+ const ctx = (0, import_react15.useContext)(DropdownContext);
822
+ if (!ctx) throw new Error("Dropdown compound components must be used within <Dropdown>");
823
+ return ctx;
824
+ }
825
+ function Dropdown({ children }) {
826
+ const [open, setOpen] = (0, import_react15.useState)(false);
827
+ const triggerId = (0, import_react15.useId)();
828
+ const contentId = (0, import_react15.useId)();
829
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DropdownContext.Provider, { value: { open, setOpen, triggerId, contentId }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "relative inline-block", children }) });
830
+ }
831
+ function DropdownTrigger({ children, ...props }) {
832
+ const { open, setOpen, triggerId, contentId } = useDropdownContext();
833
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
834
+ "button",
835
+ {
836
+ type: "button",
837
+ id: triggerId,
838
+ "aria-haspopup": "menu",
839
+ "aria-expanded": open,
840
+ "aria-controls": open ? contentId : void 0,
841
+ onClick: () => setOpen(!open),
842
+ ...props,
843
+ children
844
+ }
845
+ );
846
+ }
847
+ function DropdownContent({ className, children, ...props }) {
848
+ const { open, setOpen, contentId, triggerId } = useDropdownContext();
849
+ const ref = (0, import_react15.useRef)(null);
850
+ (0, import_react15.useEffect)(() => {
851
+ if (!open) return;
852
+ const handler = (e) => {
853
+ const el = ref.current;
854
+ const trigger = document.getElementById(triggerId);
855
+ if (el && !el.contains(e.target) && !trigger?.contains(e.target)) {
856
+ setOpen(false);
857
+ }
858
+ };
859
+ const escHandler = (e) => {
860
+ if (e.key === "Escape") setOpen(false);
861
+ };
862
+ document.addEventListener("mousedown", handler);
863
+ document.addEventListener("keydown", escHandler);
864
+ return () => {
865
+ document.removeEventListener("mousedown", handler);
866
+ document.removeEventListener("keydown", escHandler);
867
+ };
868
+ }, [open, setOpen, triggerId]);
869
+ if (!open) return null;
870
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
871
+ "div",
872
+ {
873
+ ref,
874
+ id: contentId,
875
+ role: "menu",
876
+ "aria-labelledby": triggerId,
877
+ className: cn(
878
+ "absolute left-0 top-full z-50 mt-1 bg-background-elevated border border-border rounded-md shadow-lg py-1 min-w-[160px]",
879
+ className
880
+ ),
881
+ ...props,
882
+ children
883
+ }
884
+ );
885
+ }
886
+ function DropdownItem({
887
+ className,
888
+ icon: Icon,
889
+ variant = "default",
890
+ children,
891
+ onClick,
892
+ ...props
893
+ }) {
894
+ const { setOpen } = useDropdownContext();
895
+ const handleClick = (0, import_react15.useCallback)(
896
+ (e) => {
897
+ onClick?.(e);
898
+ setOpen(false);
899
+ },
900
+ [onClick, setOpen]
901
+ );
902
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
903
+ "button",
904
+ {
905
+ type: "button",
906
+ role: "menuitem",
907
+ className: cn(
908
+ "h-7 text-xs px-2 w-full text-left flex items-center gap-2",
909
+ variant === "danger" ? "text-danger hover:bg-danger/10" : "text-foreground hover:bg-surface-hover",
910
+ className
911
+ ),
912
+ onClick: handleClick,
913
+ ...props,
914
+ children: [
915
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { size: 14 }),
916
+ children
917
+ ]
918
+ }
919
+ );
920
+ }
921
+
922
+ // src/primitives/tooltip.tsx
923
+ var import_react16 = require("react");
924
+ var import_jsx_runtime15 = require("react/jsx-runtime");
925
+ var TooltipContext = (0, import_react16.createContext)(null);
926
+ function useTooltipContext() {
927
+ const ctx = (0, import_react16.useContext)(TooltipContext);
928
+ if (!ctx) throw new Error("Tooltip compound components must be used within <Tooltip>");
929
+ return ctx;
930
+ }
931
+ function Tooltip({ children }) {
932
+ const [open, setOpen] = (0, import_react16.useState)(false);
933
+ const timerRef = (0, import_react16.useRef)(null);
934
+ const tooltipId = (0, import_react16.useId)();
935
+ const show = () => {
936
+ timerRef.current = setTimeout(() => setOpen(true), 300);
937
+ };
938
+ const hide = () => {
939
+ if (timerRef.current) clearTimeout(timerRef.current);
940
+ setOpen(false);
941
+ };
942
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipContext.Provider, { value: { open, show, hide, tooltipId }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "relative inline-block", children }) });
943
+ }
944
+ function TooltipTrigger({ children, ...props }) {
945
+ const { show, hide, tooltipId, open } = useTooltipContext();
946
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
947
+ "div",
948
+ {
949
+ onMouseEnter: show,
950
+ onMouseLeave: hide,
951
+ onFocus: show,
952
+ onBlur: hide,
953
+ "aria-describedby": open ? tooltipId : void 0,
954
+ ...props,
955
+ children
956
+ }
957
+ );
958
+ }
959
+ function TooltipContent({ className, children, ...props }) {
960
+ const { open, tooltipId } = useTooltipContext();
961
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
962
+ "div",
963
+ {
964
+ id: tooltipId,
965
+ role: "tooltip",
966
+ className: cn(
967
+ "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 bg-foreground text-background text-xs px-2 py-1 rounded-md shadow-md whitespace-nowrap pointer-events-none transition-opacity duration-150",
968
+ open ? "opacity-100" : "opacity-0",
969
+ className
970
+ ),
971
+ ...props,
972
+ children
973
+ }
974
+ );
975
+ }
976
+
977
+ // src/primitives/popover.tsx
978
+ var import_react17 = require("react");
979
+ var import_jsx_runtime16 = require("react/jsx-runtime");
980
+ var PopoverContext = (0, import_react17.createContext)(null);
981
+ function usePopoverContext() {
982
+ const ctx = (0, import_react17.useContext)(PopoverContext);
983
+ if (!ctx) throw new Error("Popover compound components must be used within <Popover>");
984
+ return ctx;
985
+ }
986
+ function Popover({ children, open: controlledOpen, onOpenChange }) {
987
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react17.useState)(false);
988
+ const open = controlledOpen ?? uncontrolledOpen;
989
+ const triggerId = (0, import_react17.useId)();
990
+ const contentId = (0, import_react17.useId)();
991
+ const setOpen = (0, import_react17.useCallback)(
992
+ (next) => {
993
+ onOpenChange?.(next);
994
+ if (controlledOpen === void 0) setUncontrolledOpen(next);
995
+ },
996
+ [controlledOpen, onOpenChange]
997
+ );
998
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PopoverContext.Provider, { value: { open, setOpen, triggerId, contentId }, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "relative inline-block", children }) });
999
+ }
1000
+ function PopoverTrigger({ children, ...props }) {
1001
+ const { open, setOpen, triggerId, contentId } = usePopoverContext();
1002
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1003
+ "button",
1004
+ {
1005
+ type: "button",
1006
+ id: triggerId,
1007
+ "aria-haspopup": "dialog",
1008
+ "aria-expanded": open,
1009
+ "aria-controls": open ? contentId : void 0,
1010
+ onClick: () => setOpen(!open),
1011
+ ...props,
1012
+ children
1013
+ }
1014
+ );
1015
+ }
1016
+ function PopoverContent({ className, children, ...props }) {
1017
+ const { open, setOpen, contentId, triggerId } = usePopoverContext();
1018
+ const ref = (0, import_react17.useRef)(null);
1019
+ (0, import_react17.useEffect)(() => {
1020
+ if (!open) return;
1021
+ const handler = (e) => {
1022
+ const el = ref.current;
1023
+ const trigger = document.getElementById(triggerId);
1024
+ if (el && !el.contains(e.target) && !trigger?.contains(e.target)) {
1025
+ setOpen(false);
1026
+ }
1027
+ };
1028
+ const escHandler = (e) => {
1029
+ if (e.key === "Escape") setOpen(false);
1030
+ };
1031
+ document.addEventListener("mousedown", handler);
1032
+ document.addEventListener("keydown", escHandler);
1033
+ return () => {
1034
+ document.removeEventListener("mousedown", handler);
1035
+ document.removeEventListener("keydown", escHandler);
1036
+ };
1037
+ }, [open, setOpen, triggerId]);
1038
+ if (!open) return null;
1039
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1040
+ "div",
1041
+ {
1042
+ ref,
1043
+ id: contentId,
1044
+ role: "dialog",
1045
+ "aria-labelledby": triggerId,
1046
+ className: cn(
1047
+ "absolute left-0 top-full z-50 mt-1 bg-background-elevated border border-border rounded-lg shadow-lg p-3",
1048
+ className
1049
+ ),
1050
+ ...props,
1051
+ children
1052
+ }
1053
+ );
1054
+ }
1055
+
1056
+ // src/primitives/tabs.tsx
1057
+ var import_react18 = require("react");
1058
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1059
+ var TabsContext = (0, import_react18.createContext)(null);
1060
+ function useTabsContext() {
1061
+ const ctx = (0, import_react18.useContext)(TabsContext);
1062
+ if (!ctx) throw new Error("Tabs compound components must be used within <Tabs>");
1063
+ return ctx;
1064
+ }
1065
+ function Tabs({
1066
+ value: controlledValue,
1067
+ onValueChange,
1068
+ defaultValue = "",
1069
+ className,
1070
+ ...props
1071
+ }) {
1072
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react18.useState)(defaultValue);
1073
+ const value = controlledValue ?? uncontrolledValue;
1074
+ const setValue = (0, import_react18.useCallback)(
1075
+ (next) => {
1076
+ onValueChange?.(next);
1077
+ if (controlledValue === void 0) setUncontrolledValue(next);
1078
+ },
1079
+ [controlledValue, onValueChange]
1080
+ );
1081
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TabsContext.Provider, { value: { value, setValue }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className, ...props }) });
1082
+ }
1083
+ function TabsList({ className, ...props }) {
1084
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1085
+ "div",
1086
+ {
1087
+ role: "tablist",
1088
+ className: cn("flex flex-row border-b border-border-subtle", className),
1089
+ ...props
1090
+ }
1091
+ );
1092
+ }
1093
+ function TabsTrigger({ value, className, ...props }) {
1094
+ const { value: activeValue, setValue } = useTabsContext();
1095
+ const isActive = value === activeValue;
1096
+ const panelId = `tabpanel-${value}`;
1097
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1098
+ "button",
1099
+ {
1100
+ type: "button",
1101
+ role: "tab",
1102
+ "aria-selected": isActive,
1103
+ "aria-controls": panelId,
1104
+ tabIndex: isActive ? 0 : -1,
1105
+ className: cn(
1106
+ "h-7 text-xs px-3 transition-colors",
1107
+ isActive ? "border-b-2 border-primary text-foreground font-medium" : "text-foreground-muted hover:text-foreground",
1108
+ className
1109
+ ),
1110
+ onClick: () => setValue(value),
1111
+ ...props
1112
+ }
1113
+ );
1114
+ }
1115
+ function TabsContent({ value, className, ...props }) {
1116
+ const { value: activeValue } = useTabsContext();
1117
+ if (value !== activeValue) return null;
1118
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1119
+ "div",
1120
+ {
1121
+ role: "tabpanel",
1122
+ id: `tabpanel-${value}`,
1123
+ className: cn("pt-3", className),
1124
+ ...props
1125
+ }
1126
+ );
1127
+ }
1128
+
1129
+ // src/primitives/scroll-area.tsx
1130
+ var import_react19 = require("react");
1131
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1132
+ var ScrollArea = (0, import_react19.forwardRef)(
1133
+ ({ className, ...props }, ref) => {
1134
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1135
+ "div",
1136
+ {
1137
+ ref,
1138
+ className: cn(
1139
+ "overflow-auto [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-surface-hover [&::-webkit-scrollbar-thumb]:rounded-full",
1140
+ className
1141
+ ),
1142
+ ...props
1143
+ }
1144
+ );
1145
+ }
1146
+ );
1147
+ ScrollArea.displayName = "ScrollArea";
1148
+
1149
+ // src/primitives/floating-panel.tsx
1150
+ var import_react20 = require("react");
1151
+ var import_lucide_react4 = require("lucide-react");
1152
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1153
+ function FloatingPanel({
1154
+ title,
1155
+ onClose,
1156
+ children,
1157
+ defaultWidth = 360,
1158
+ defaultHeight = 280,
1159
+ minWidth = 280,
1160
+ minHeight = 160,
1161
+ offsetIndex = 0,
1162
+ className
1163
+ }) {
1164
+ const [pos, setPos] = (0, import_react20.useState)({ x: 80 + offsetIndex * 30, y: 80 + offsetIndex * 30 });
1165
+ const [size, setSize] = (0, import_react20.useState)({ w: defaultWidth, h: defaultHeight });
1166
+ const [minimized, setMinimized] = (0, import_react20.useState)(false);
1167
+ const dragging = (0, import_react20.useRef)(false);
1168
+ const resizing = (0, import_react20.useRef)(false);
1169
+ const offset = (0, import_react20.useRef)({ x: 0, y: 0 });
1170
+ const onDragStart = (0, import_react20.useCallback)((e) => {
1171
+ e.preventDefault();
1172
+ dragging.current = true;
1173
+ offset.current = { x: e.clientX - pos.x, y: e.clientY - pos.y };
1174
+ }, [pos]);
1175
+ const onResizeStart = (0, import_react20.useCallback)((e) => {
1176
+ e.preventDefault();
1177
+ e.stopPropagation();
1178
+ resizing.current = true;
1179
+ offset.current = { x: e.clientX, y: e.clientY };
1180
+ }, []);
1181
+ (0, import_react20.useEffect)(() => {
1182
+ const onMouseMove = (e) => {
1183
+ if (dragging.current) setPos({ x: e.clientX - offset.current.x, y: e.clientY - offset.current.y });
1184
+ if (resizing.current) {
1185
+ const dx = e.clientX - offset.current.x;
1186
+ const dy = e.clientY - offset.current.y;
1187
+ offset.current = { x: e.clientX, y: e.clientY };
1188
+ setSize((prev) => ({ w: Math.max(minWidth, prev.w + dx), h: Math.max(minHeight, prev.h + dy) }));
1189
+ }
1190
+ };
1191
+ const onMouseUp = () => {
1192
+ dragging.current = false;
1193
+ resizing.current = false;
1194
+ };
1195
+ window.addEventListener("mousemove", onMouseMove);
1196
+ window.addEventListener("mouseup", onMouseUp);
1197
+ return () => {
1198
+ window.removeEventListener("mousemove", onMouseMove);
1199
+ window.removeEventListener("mouseup", onMouseUp);
1200
+ };
1201
+ }, [minWidth, minHeight]);
1202
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1203
+ "div",
1204
+ {
1205
+ className: cn(
1206
+ "fixed z-50 rounded-lg border border-border bg-background-elevated shadow-2xl flex flex-col overflow-hidden",
1207
+ className
1208
+ ),
1209
+ style: { left: pos.x, top: pos.y, width: minimized ? 280 : size.w, height: minimized ? "auto" : size.h },
1210
+ children: [
1211
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1212
+ "div",
1213
+ {
1214
+ onMouseDown: onDragStart,
1215
+ className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border cursor-move select-none shrink-0 bg-surface",
1216
+ children: [
1217
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
1218
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.GripHorizontal, { size: 12, className: "text-foreground-subtle shrink-0" }),
1219
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[11px] font-medium truncate", children: title })
1220
+ ] }),
1221
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-1 shrink-0", children: [
1222
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1223
+ "button",
1224
+ {
1225
+ onClick: () => setMinimized(!minimized),
1226
+ className: "p-0.5 rounded hover:bg-surface-hover text-foreground-muted transition-colors",
1227
+ title: minimized ? "Restore" : "Minimize",
1228
+ children: minimized ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.Maximize2, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.Minimize2, { size: 12 })
1229
+ }
1230
+ ),
1231
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1232
+ "button",
1233
+ {
1234
+ onClick: onClose,
1235
+ className: "p-0.5 rounded hover:bg-danger/20 text-foreground-muted hover:text-danger transition-colors",
1236
+ title: "Close",
1237
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.X, { size: 12 })
1238
+ }
1239
+ )
1240
+ ] })
1241
+ ]
1242
+ }
1243
+ ),
1244
+ !minimized && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex-1 min-h-0 overflow-y-auto relative", children: [
1245
+ children,
1246
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1247
+ "div",
1248
+ {
1249
+ onMouseDown: onResizeStart,
1250
+ className: "absolute bottom-0 right-0 w-4 h-4 cursor-nwse-resize",
1251
+ style: { background: "linear-gradient(135deg, transparent 50%, var(--color-foreground-subtle) 50%)", opacity: 0.4 }
1252
+ }
1253
+ )
1254
+ ] })
1255
+ ]
1256
+ }
1257
+ );
1258
+ }
1259
+
1260
+ // src/composites/status-badge.tsx
1261
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1262
+ var statusConfig = {
1263
+ online: { colorClass: "bg-success", label: "Online" },
1264
+ offline: { colorClass: "bg-danger", label: "Offline" },
1265
+ degraded: { colorClass: "bg-warning", label: "Degraded" },
1266
+ unknown: { colorClass: "bg-foreground-subtle", label: "Unknown" }
1267
+ };
1268
+ function StatusBadge({
1269
+ status,
1270
+ showDot = true,
1271
+ showLabel = true,
1272
+ size = "sm",
1273
+ className
1274
+ }) {
1275
+ const config = statusConfig[status];
1276
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1277
+ "span",
1278
+ {
1279
+ className: cn(
1280
+ "inline-flex items-center gap-1.5",
1281
+ size === "sm" ? "text-xs" : "text-sm",
1282
+ className
1283
+ ),
1284
+ children: [
1285
+ showDot && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1286
+ "span",
1287
+ {
1288
+ className: cn("h-1.5 w-1.5 shrink-0 rounded-full", config.colorClass),
1289
+ "aria-hidden": "true"
1290
+ }
1291
+ ),
1292
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-foreground", children: config.label })
1293
+ ]
1294
+ }
1295
+ );
1296
+ }
1297
+
1298
+ // src/composites/provider-badge.tsx
1299
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1300
+ var providerConfig = {
1301
+ frigate: { colorClass: "bg-provider-frigate", label: "Frigate" },
1302
+ scrypted: { colorClass: "bg-provider-scrypted", label: "Scrypted" },
1303
+ reolink: { colorClass: "bg-provider-reolink", label: "Reolink" },
1304
+ homeAssistant: { colorClass: "bg-provider-homeAssistant", label: "Home Assistant" },
1305
+ rtsp: { colorClass: "bg-provider-rtsp", label: "RTSP" }
1306
+ };
1307
+ function ProviderBadge({
1308
+ provider,
1309
+ showLabel = true,
1310
+ className
1311
+ }) {
1312
+ const config = providerConfig[provider];
1313
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: cn("inline-flex items-center gap-1.5 text-xs", className), children: [
1314
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1315
+ "span",
1316
+ {
1317
+ className: cn("h-1.5 w-1.5 shrink-0 rounded-sm", config.colorClass),
1318
+ "aria-hidden": "true"
1319
+ }
1320
+ ),
1321
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-foreground", children: config.label })
1322
+ ] });
1323
+ }
1324
+
1325
+ // src/composites/form-field.tsx
1326
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1327
+ function FormField({
1328
+ label,
1329
+ description,
1330
+ error,
1331
+ required,
1332
+ children,
1333
+ orientation = "vertical",
1334
+ className
1335
+ }) {
1336
+ const isHorizontal = orientation === "horizontal";
1337
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1338
+ "div",
1339
+ {
1340
+ className: cn(
1341
+ "flex gap-2",
1342
+ isHorizontal ? "flex-row items-center justify-between" : "flex-col",
1343
+ className
1344
+ ),
1345
+ children: [
1346
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: cn(isHorizontal ? "flex-1" : ""), children: [
1347
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Label, { children: [
1348
+ label,
1349
+ required && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-danger ml-0.5", children: "*" })
1350
+ ] }),
1351
+ description && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-foreground-subtle text-xs mt-0.5", children: description })
1352
+ ] }),
1353
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: cn(isHorizontal ? "shrink-0" : ""), children }),
1354
+ error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-danger text-xs", children: error })
1355
+ ]
1356
+ }
1357
+ );
1358
+ }
1359
+
1360
+ // src/composites/page-header.tsx
1361
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1362
+ function PageHeader({ title, subtitle, actions, className }) {
1363
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn("flex items-center justify-between mb-3", className), children: [
1364
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
1365
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "text-sm font-semibold text-foreground", children: title }),
1366
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-foreground-subtle text-xs", children: subtitle })
1367
+ ] }),
1368
+ actions && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex items-center gap-2", children: actions })
1369
+ ] });
1370
+ }
1371
+
1372
+ // src/composites/empty-state.tsx
1373
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1374
+ function EmptyState({
1375
+ icon: Icon,
1376
+ title,
1377
+ description,
1378
+ action,
1379
+ className
1380
+ }) {
1381
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: cn("flex flex-col items-center justify-center gap-3 py-12", className), children: [
1382
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Icon, { className: "h-12 w-12 text-foreground-subtle", "aria-hidden": "true" }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col items-center gap-1 text-center", children: [
1384
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-foreground-muted text-sm font-medium", children: title }),
1385
+ description && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-foreground-subtle text-xs max-w-xs", children: description })
1386
+ ] }),
1387
+ action && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "mt-1", children: action })
1388
+ ] });
1389
+ }
1390
+
1391
+ // src/composites/confirm-dialog.tsx
1392
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1393
+ function ConfirmDialog({
1394
+ title,
1395
+ message,
1396
+ confirmLabel = "Confirm",
1397
+ cancelLabel = "Cancel",
1398
+ onConfirm,
1399
+ onCancel,
1400
+ variant = "default",
1401
+ open,
1402
+ onOpenChange
1403
+ }) {
1404
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Dialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DialogContent, { children: [
1405
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DialogHeader, { children: [
1406
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DialogTitle, { children: title }),
1407
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(DialogDescription, { children: message })
1408
+ ] }),
1409
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DialogFooter, { children: [
1410
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { variant: "ghost", onClick: onCancel, children: cancelLabel }),
1411
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1412
+ Button,
1413
+ {
1414
+ variant: variant === "danger" ? "danger" : "primary",
1415
+ onClick: onConfirm,
1416
+ children: confirmLabel
1417
+ }
1418
+ )
1419
+ ] })
1420
+ ] }) });
1421
+ }
1422
+
1423
+ // src/composites/stat-card.tsx
1424
+ var import_lucide_react5 = require("lucide-react");
1425
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1426
+ function StatCard({ value, label, trend, className }) {
1427
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Card, { className: cn("flex flex-col gap-1", className), children: [
1428
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-baseline gap-2", children: [
1429
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: value }),
1430
+ trend && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1431
+ "span",
1432
+ {
1433
+ className: cn(
1434
+ "inline-flex items-center gap-0.5 text-xs font-medium",
1435
+ trend.direction === "up" ? "text-success" : "text-danger"
1436
+ ),
1437
+ children: [
1438
+ trend.direction === "up" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react5.TrendingUp, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react5.TrendingDown, { className: "h-3 w-3" }),
1439
+ trend.value,
1440
+ "%"
1441
+ ]
1442
+ }
1443
+ )
1444
+ ] }),
1445
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-xs text-foreground-muted", children: label })
1446
+ ] });
1447
+ }
1448
+
1449
+ // src/composites/key-value-list.tsx
1450
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1451
+ function KeyValueList({ items, className }) {
1452
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("dl", { className: cn("flex flex-col", className), children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1453
+ "div",
1454
+ {
1455
+ className: "flex items-center h-7",
1456
+ children: [
1457
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("dt", { className: "text-foreground-subtle text-xs w-1/3 shrink-0", children: item.key }),
1458
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("dd", { className: "text-foreground text-xs", children: item.value })
1459
+ ]
1460
+ },
1461
+ item.key
1462
+ )) });
1463
+ }
1464
+
1465
+ // src/composites/code-block.tsx
1466
+ var import_react21 = require("react");
1467
+ var import_lucide_react6 = require("lucide-react");
1468
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1469
+ function CodeBlock({ children, maxHeight = 300, className }) {
1470
+ const [copied, setCopied] = (0, import_react21.useState)(false);
1471
+ const handleCopy = (0, import_react21.useCallback)(() => {
1472
+ navigator.clipboard.writeText(children).then(() => {
1473
+ setCopied(true);
1474
+ setTimeout(() => setCopied(false), 2e3);
1475
+ });
1476
+ }, [children]);
1477
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cn("relative group", className), children: [
1478
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ScrollArea, { style: { maxHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("pre", { className: "font-mono text-xs bg-surface p-3 rounded-md border border-border-subtle", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("code", { children }) }) }),
1479
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1480
+ IconButton,
1481
+ {
1482
+ icon: copied ? import_lucide_react6.Check : import_lucide_react6.Copy,
1483
+ "aria-label": "Copy code",
1484
+ variant: "ghost",
1485
+ size: "sm",
1486
+ onClick: handleCopy
1487
+ }
1488
+ ) })
1489
+ ] });
1490
+ }
1491
+
1492
+ // src/composites/filter-bar.tsx
1493
+ var import_lucide_react7 = require("lucide-react");
1494
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1495
+ function FilterBar({ filters, values, onChange, className }) {
1496
+ const handleChange = (key, value) => {
1497
+ onChange({ ...values, [key]: value });
1498
+ };
1499
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
1500
+ switch (filter.type) {
1501
+ case "search":
1502
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1503
+ Input,
1504
+ {
1505
+ placeholder: filter.placeholder ?? "Search...",
1506
+ value: values[filter.key] ?? "",
1507
+ onChange: (e) => handleChange(filter.key, e.target.value),
1508
+ leftSlot: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react7.Search, { className: "h-3 w-3 text-foreground-subtle" }),
1509
+ className: "w-48"
1510
+ },
1511
+ filter.key
1512
+ );
1513
+ case "select":
1514
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1515
+ Select,
1516
+ {
1517
+ options: filter.options,
1518
+ value: values[filter.key] ?? "",
1519
+ onChange: (e) => handleChange(filter.key, e.target.value),
1520
+ className: "w-36"
1521
+ },
1522
+ filter.key
1523
+ );
1524
+ case "badge-toggle":
1525
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "flex items-center gap-1", children: filter.options.map((option) => {
1526
+ const currentValue = values[filter.key];
1527
+ const isActive = currentValue === option.value;
1528
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1529
+ "button",
1530
+ {
1531
+ type: "button",
1532
+ onClick: () => handleChange(
1533
+ filter.key,
1534
+ isActive ? void 0 : option.value
1535
+ ),
1536
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1537
+ Badge,
1538
+ {
1539
+ variant: isActive ? "info" : "default",
1540
+ className: "cursor-pointer",
1541
+ children: option.label
1542
+ }
1543
+ )
1544
+ },
1545
+ option.value
1546
+ );
1547
+ }) }, filter.key);
1548
+ default:
1549
+ return null;
1550
+ }
1551
+ }) });
1552
+ }
1553
+
1554
+ // src/composites/app-shell/sidebar-item.tsx
1555
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1556
+ function SidebarItem({
1557
+ label,
1558
+ icon: Icon,
1559
+ href,
1560
+ badge,
1561
+ active = false,
1562
+ className
1563
+ }) {
1564
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1565
+ "a",
1566
+ {
1567
+ href,
1568
+ className: cn(
1569
+ "flex items-center gap-2 h-7 px-2 text-[11px] transition-colors",
1570
+ active ? "border-l-2 border-primary bg-primary/[0.08] text-foreground rounded-r-md" : "text-foreground-subtle hover:bg-surface-hover rounded-md",
1571
+ className
1572
+ ),
1573
+ children: [
1574
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
1575
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "truncate flex-1", children: label }),
1576
+ badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Badge, { className: "ml-auto text-[10px] px-1.5 py-0", children: badge })
1577
+ ]
1578
+ }
1579
+ );
1580
+ }
1581
+
1582
+ // src/composites/app-shell/sidebar.tsx
1583
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1584
+ function Sidebar({ logo, sections, footer, className }) {
1585
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1586
+ "nav",
1587
+ {
1588
+ className: cn(
1589
+ "w-44 bg-surface border-r border-border h-full flex flex-col",
1590
+ className
1591
+ ),
1592
+ children: [
1593
+ logo && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "px-3 py-2 shrink-0", children: logo }),
1594
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex-1 overflow-auto px-1 py-1", children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: cn(sectionIndex > 0 ? "mt-3" : ""), children: [
1595
+ section.label && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "text-[10px] text-foreground-disabled uppercase tracking-wider px-2 mb-1 block", children: section.label }),
1596
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex flex-col gap-0.5", children: section.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(SidebarItem, { ...item }, item.href)) })
1597
+ ] }, sectionIndex)) }),
1598
+ footer && footer.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "shrink-0 px-1 pb-1", children: [
1599
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Separator, { className: "mb-1" }),
1600
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex flex-col gap-0.5", children: footer.map((item) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(SidebarItem, { ...item }, item.href)) })
1601
+ ] })
1602
+ ]
1603
+ }
1604
+ );
1605
+ }
1606
+
1607
+ // src/composites/app-shell/app-shell.tsx
1608
+ var import_lucide_react8 = require("lucide-react");
1609
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1610
+ function AppShell({ sidebar, header, children, className }) {
1611
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cn("flex h-screen", className), children: [
1612
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Sidebar, { ...sidebar }),
1613
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-1 flex-col min-w-0", children: [
1614
+ header && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
1615
+ header.breadcrumbs && header.breadcrumbs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("nav", { className: "flex items-center gap-1 text-xs flex-1 min-w-0", children: header.breadcrumbs.map((crumb, index) => {
1616
+ const isLast = index === header.breadcrumbs.length - 1;
1617
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "flex items-center gap-1", children: [
1618
+ index > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react8.ChevronRight, { className: "h-3 w-3 text-foreground-subtle shrink-0" }),
1619
+ crumb.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1620
+ "a",
1621
+ {
1622
+ href: crumb.href,
1623
+ className: "text-foreground-subtle hover:text-foreground transition-colors truncate",
1624
+ children: crumb.label
1625
+ }
1626
+ ) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-foreground truncate", children: crumb.label })
1627
+ ] }, index);
1628
+ }) }),
1629
+ header.actions && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex items-center gap-2 ml-auto shrink-0", children: header.actions })
1630
+ ] }),
1631
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("main", { className: "flex-1 overflow-auto p-4", children })
1632
+ ] })
1633
+ ] });
1634
+ }
1635
+
1636
+ // src/composites/data-table/data-table.tsx
1637
+ var import_react22 = require("react");
1638
+ var import_react_table = require("@tanstack/react-table");
1639
+
1640
+ // src/composites/data-table/data-table-header.tsx
1641
+ var import_lucide_react9 = require("lucide-react");
1642
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1643
+ function DataTableHeader({
1644
+ headerGroups,
1645
+ onSortingChange,
1646
+ stickyHeader,
1647
+ flexRender: render
1648
+ }) {
1649
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1650
+ "thead",
1651
+ {
1652
+ className: cn(
1653
+ stickyHeader && "sticky top-0 z-10 bg-background"
1654
+ ),
1655
+ children: headerGroups.map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("tr", { className: "h-6", children: headerGroup.headers.map((header) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1656
+ HeaderCell,
1657
+ {
1658
+ header,
1659
+ sortable: header.column.getCanSort() && !!onSortingChange,
1660
+ flexRender: render
1661
+ },
1662
+ header.id
1663
+ )) }, headerGroup.id))
1664
+ }
1665
+ );
1666
+ }
1667
+ function HeaderCell({ header, sortable, flexRender: render }) {
1668
+ const sorted = header.column.getIsSorted();
1669
+ const SortIcon = sorted === "asc" ? import_lucide_react9.ArrowUp : sorted === "desc" ? import_lucide_react9.ArrowDown : import_lucide_react9.ArrowUpDown;
1670
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1671
+ "th",
1672
+ {
1673
+ className: cn(
1674
+ "px-2 py-1 text-left text-[10px] text-foreground-subtle uppercase tracking-wider font-medium",
1675
+ sortable && "cursor-pointer select-none"
1676
+ ),
1677
+ onClick: sortable ? header.column.getToggleSortingHandler() : void 0,
1678
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
1679
+ header.isPlaceholder ? null : render(header.column.columnDef.header, header.getContext()),
1680
+ sortable && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(SortIcon, { className: "h-3 w-3" })
1681
+ ] })
1682
+ }
1683
+ );
1684
+ }
1685
+
1686
+ // src/composites/data-table/data-table-row.tsx
1687
+ var import_lucide_react10 = require("lucide-react");
1688
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1689
+ function DataTableRow({
1690
+ row,
1691
+ onRowClick,
1692
+ rowActions,
1693
+ flexRender: render
1694
+ }) {
1695
+ const actions = rowActions ? rowActions(row.original) : [];
1696
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
1697
+ "tr",
1698
+ {
1699
+ className: cn(
1700
+ "h-7 border-b border-border/50",
1701
+ onRowClick && "cursor-pointer",
1702
+ "hover:bg-surface-hover"
1703
+ ),
1704
+ onClick: onRowClick ? () => onRowClick(row.original) : void 0,
1705
+ children: [
1706
+ row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DataTableCell, { cell, flexRender: render }, cell.id)),
1707
+ actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "px-2 py-1.5 w-8", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(Dropdown, { children: [
1708
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1709
+ DropdownTrigger,
1710
+ {
1711
+ className: "p-0.5 rounded hover:bg-surface-hover",
1712
+ onClick: (e) => e.stopPropagation(),
1713
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react10.MoreHorizontal, { className: "h-3.5 w-3.5 text-foreground-muted" })
1714
+ }
1715
+ ),
1716
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DropdownContent, { className: "right-0 left-auto", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1717
+ DropdownItem,
1718
+ {
1719
+ icon: action.icon,
1720
+ variant: action.variant,
1721
+ onClick: (e) => {
1722
+ e.stopPropagation();
1723
+ action.onClick();
1724
+ },
1725
+ children: action.label
1726
+ },
1727
+ action.label
1728
+ )) })
1729
+ ] }) })
1730
+ ]
1731
+ }
1732
+ );
1733
+ }
1734
+ function DataTableCell({ cell, flexRender: render }) {
1735
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("td", { className: "px-2 py-1.5 text-xs text-foreground", children: render(cell.column.columnDef.cell, cell.getContext()) });
1736
+ }
1737
+
1738
+ // src/composites/data-table/data-table-pagination.tsx
1739
+ var import_lucide_react11 = require("lucide-react");
1740
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1741
+ var PAGE_SIZE_OPTIONS = [
1742
+ { value: "10", label: "10" },
1743
+ { value: "25", label: "25" },
1744
+ { value: "50", label: "50" },
1745
+ { value: "100", label: "100" }
1746
+ ];
1747
+ function DataTablePagination({
1748
+ page,
1749
+ pageSize,
1750
+ total,
1751
+ onPaginationChange
1752
+ }) {
1753
+ const totalPages = Math.max(1, Math.ceil(total / pageSize));
1754
+ const currentPage = page + 1;
1755
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
1756
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex items-center gap-2", children: [
1757
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { children: "Rows per page" }),
1758
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "w-16", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1759
+ Select,
1760
+ {
1761
+ options: PAGE_SIZE_OPTIONS,
1762
+ value: String(pageSize),
1763
+ onChange: (e) => onPaginationChange?.({
1764
+ pageIndex: 0,
1765
+ pageSize: Number(e.target.value)
1766
+ })
1767
+ }
1768
+ ) })
1769
+ ] }),
1770
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex items-center gap-2", children: [
1771
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { children: [
1772
+ "Page ",
1773
+ currentPage,
1774
+ " of ",
1775
+ totalPages
1776
+ ] }),
1777
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1778
+ IconButton,
1779
+ {
1780
+ icon: import_lucide_react11.ChevronLeft,
1781
+ "aria-label": "Previous page",
1782
+ variant: "ghost",
1783
+ size: "sm",
1784
+ disabled: page <= 0,
1785
+ onClick: () => onPaginationChange?.({ pageIndex: page - 1, pageSize })
1786
+ }
1787
+ ),
1788
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1789
+ IconButton,
1790
+ {
1791
+ icon: import_lucide_react11.ChevronRight,
1792
+ "aria-label": "Next page",
1793
+ variant: "ghost",
1794
+ size: "sm",
1795
+ disabled: currentPage >= totalPages,
1796
+ onClick: () => onPaginationChange?.({ pageIndex: page + 1, pageSize })
1797
+ }
1798
+ )
1799
+ ] })
1800
+ ] });
1801
+ }
1802
+
1803
+ // src/composites/data-table/data-table.tsx
1804
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1805
+ function DataTable({
1806
+ data,
1807
+ columns: userColumns,
1808
+ sorting,
1809
+ onSortingChange,
1810
+ filtering,
1811
+ onFilteringChange,
1812
+ pagination,
1813
+ onPaginationChange,
1814
+ loading = false,
1815
+ emptyState,
1816
+ rowActions,
1817
+ onRowClick,
1818
+ selectable = false,
1819
+ compact = true,
1820
+ stickyHeader = false,
1821
+ className
1822
+ }) {
1823
+ const columns = (0, import_react22.useMemo)(() => {
1824
+ if (!selectable) return userColumns;
1825
+ const selectColumn = {
1826
+ id: "__select",
1827
+ header: ({ table: table2 }) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1828
+ Checkbox,
1829
+ {
1830
+ checked: table2.getIsAllPageRowsSelected(),
1831
+ onChange: table2.getToggleAllPageRowsSelectedHandler(),
1832
+ "aria-label": "Select all"
1833
+ }
1834
+ ),
1835
+ cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1836
+ Checkbox,
1837
+ {
1838
+ checked: row.getIsSelected(),
1839
+ onChange: row.getToggleSelectedHandler(),
1840
+ "aria-label": "Select row"
1841
+ }
1842
+ ),
1843
+ enableSorting: false
1844
+ };
1845
+ return [selectColumn, ...userColumns];
1846
+ }, [userColumns, selectable]);
1847
+ const table = (0, import_react_table.useReactTable)({
1848
+ data,
1849
+ columns,
1850
+ state: {
1851
+ ...sorting !== void 0 && { sorting },
1852
+ ...filtering !== void 0 && { columnFilters: filtering },
1853
+ ...pagination !== void 0 && {
1854
+ pagination: { pageIndex: pagination.page, pageSize: pagination.pageSize }
1855
+ }
1856
+ },
1857
+ onSortingChange: onSortingChange ? (updater) => {
1858
+ const next = typeof updater === "function" ? updater(sorting ?? []) : updater;
1859
+ onSortingChange(next);
1860
+ } : void 0,
1861
+ onColumnFiltersChange: onFilteringChange ? (updater) => {
1862
+ const next = typeof updater === "function" ? updater(filtering ?? []) : updater;
1863
+ onFilteringChange(next);
1864
+ } : void 0,
1865
+ getCoreRowModel: (0, import_react_table.getCoreRowModel)(),
1866
+ getSortedRowModel: (0, import_react_table.getSortedRowModel)(),
1867
+ getFilteredRowModel: (0, import_react_table.getFilteredRowModel)(),
1868
+ getPaginationRowModel: pagination ? (0, import_react_table.getPaginationRowModel)() : void 0,
1869
+ manualPagination: pagination !== void 0,
1870
+ pageCount: pagination ? Math.ceil(pagination.total / pagination.pageSize) : void 0
1871
+ });
1872
+ const hasActions = !!rowActions;
1873
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: cn("overflow-auto", className), children: [
1874
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("table", { className: "w-full border-collapse", children: [
1875
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1876
+ DataTableHeader,
1877
+ {
1878
+ headerGroups: table.getHeaderGroups(),
1879
+ onSortingChange,
1880
+ stickyHeader,
1881
+ flexRender: import_react_table.flexRender
1882
+ }
1883
+ ),
1884
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tbody", { children: loading ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(LoadingRows, { colSpan: columns.length + (hasActions ? 1 : 0), compact }) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1885
+ "td",
1886
+ {
1887
+ colSpan: columns.length + (hasActions ? 1 : 0),
1888
+ className: "text-center py-8 text-xs text-foreground-muted",
1889
+ children: emptyState ?? "No data"
1890
+ }
1891
+ ) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1892
+ DataTableRow,
1893
+ {
1894
+ row,
1895
+ onRowClick,
1896
+ rowActions,
1897
+ flexRender: import_react_table.flexRender
1898
+ },
1899
+ row.id
1900
+ )) })
1901
+ ] }),
1902
+ pagination && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1903
+ DataTablePagination,
1904
+ {
1905
+ page: pagination.page,
1906
+ pageSize: pagination.pageSize,
1907
+ total: pagination.total,
1908
+ onPaginationChange
1909
+ }
1910
+ )
1911
+ ] });
1912
+ }
1913
+ function LoadingRows({ colSpan, compact }) {
1914
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_jsx_runtime36.Fragment, { children: Array.from({ length: 5 }).map((_, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tr", { className: compact ? "h-7" : "h-9", children: Array.from({ length: colSpan }).map((_2, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Skeleton, { className: "h-3 w-full" }) }, colIdx)) }, rowIdx)) });
1915
+ }
1916
+
1917
+ // src/composites/device-card.tsx
1918
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1919
+ var STATUS_COLORS = {
1920
+ online: "bg-success",
1921
+ offline: "bg-danger",
1922
+ warning: "bg-warning",
1923
+ unknown: "bg-foreground-subtle"
1924
+ };
1925
+ function DeviceCard({
1926
+ title,
1927
+ subtitle,
1928
+ status,
1929
+ selected,
1930
+ onClick,
1931
+ badges,
1932
+ actions,
1933
+ offlineAction,
1934
+ className
1935
+ }) {
1936
+ const isOffline = status === "offline";
1937
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
1938
+ "div",
1939
+ {
1940
+ onClick,
1941
+ className: cn(
1942
+ "w-full rounded-lg border p-3 text-left transition-colors",
1943
+ onClick && "cursor-pointer",
1944
+ selected ? "border-primary bg-primary/10" : "border-border bg-surface hover:bg-surface-hover",
1945
+ isOffline && !selected && "opacity-50",
1946
+ className
1947
+ ),
1948
+ children: [
1949
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
1950
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-sm font-medium truncate", children: title }),
1951
+ status && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: cn("h-2 w-2 rounded-full shrink-0", STATUS_COLORS[status]) })
1952
+ ] }),
1953
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "text-[11px] text-foreground-muted", children: subtitle }),
1954
+ badges && badges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex flex-wrap gap-1 mt-2", children: badges.map((badge, i) => {
1955
+ const cls = cn(
1956
+ "rounded px-1.5 py-0.5 text-[10px] flex items-center gap-0.5",
1957
+ selected ? "bg-primary/20" : "bg-surface-hover",
1958
+ badge.onClick && "hover:opacity-80 transition-opacity cursor-pointer"
1959
+ );
1960
+ return badge.onClick ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
1961
+ "button",
1962
+ {
1963
+ onClick: (e) => {
1964
+ e.stopPropagation();
1965
+ badge.onClick();
1966
+ },
1967
+ className: cls,
1968
+ children: [
1969
+ badge.icon,
1970
+ badge.label
1971
+ ]
1972
+ },
1973
+ i
1974
+ ) : /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: cls, children: [
1975
+ badge.icon,
1976
+ badge.label
1977
+ ] }, i);
1978
+ }) }),
1979
+ !isOffline && actions && actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex items-center gap-0.5 mt-2 -mb-1", children: actions.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1980
+ "button",
1981
+ {
1982
+ onClick: (e) => {
1983
+ e.stopPropagation();
1984
+ action.onClick();
1985
+ },
1986
+ className: "p-1 rounded hover:bg-surface-hover text-foreground-subtle hover:text-foreground transition-colors",
1987
+ title: action.label,
1988
+ "aria-label": action.label,
1989
+ children: action.icon
1990
+ },
1991
+ i
1992
+ )) }),
1993
+ isOffline && offlineAction && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "mt-2", onClick: (e) => e.stopPropagation(), children: offlineAction })
1994
+ ]
1995
+ }
1996
+ );
1997
+ }
1998
+
1999
+ // src/composites/device-grid.tsx
2000
+ var import_jsx_runtime38 = require("react/jsx-runtime");
2001
+ function DeviceGrid({
2002
+ children,
2003
+ minCardWidth = 220,
2004
+ gap = 3,
2005
+ className
2006
+ }) {
2007
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2008
+ "div",
2009
+ {
2010
+ className: cn(
2011
+ "p-4 overflow-y-auto flex-1 content-start",
2012
+ className
2013
+ ),
2014
+ style: {
2015
+ display: "grid",
2016
+ gridTemplateColumns: `repeat(auto-fill, minmax(${minCardWidth}px, 1fr))`,
2017
+ gap: `${gap * 4}px`
2018
+ },
2019
+ children
2020
+ }
2021
+ );
2022
+ }
2023
+ // Annotate the CommonJS export names for ESM import in node:
2024
+ 0 && (module.exports = {
2025
+ AppShell,
2026
+ Badge,
2027
+ Button,
2028
+ Card,
2029
+ Checkbox,
2030
+ CodeBlock,
2031
+ ConfirmDialog,
2032
+ DataTable,
2033
+ DeviceCard,
2034
+ DeviceGrid,
2035
+ Dialog,
2036
+ DialogContent,
2037
+ DialogDescription,
2038
+ DialogFooter,
2039
+ DialogHeader,
2040
+ DialogTitle,
2041
+ DialogTrigger,
2042
+ Dropdown,
2043
+ DropdownContent,
2044
+ DropdownItem,
2045
+ DropdownTrigger,
2046
+ EmptyState,
2047
+ FilterBar,
2048
+ FloatingPanel,
2049
+ FormField,
2050
+ IconButton,
2051
+ Input,
2052
+ KeyValueList,
2053
+ Label,
2054
+ PageHeader,
2055
+ Popover,
2056
+ PopoverContent,
2057
+ PopoverTrigger,
2058
+ ProviderBadge,
2059
+ ScrollArea,
2060
+ Select,
2061
+ Separator,
2062
+ Sidebar,
2063
+ SidebarItem,
2064
+ Skeleton,
2065
+ StatCard,
2066
+ StatusBadge,
2067
+ Switch,
2068
+ Tabs,
2069
+ TabsContent,
2070
+ TabsList,
2071
+ TabsTrigger,
2072
+ ThemeProvider,
2073
+ Tooltip,
2074
+ TooltipContent,
2075
+ TooltipTrigger,
2076
+ cn,
2077
+ createTheme,
2078
+ darkColors,
2079
+ defaultTheme,
2080
+ lightColors,
2081
+ providerIcons,
2082
+ statusIcons,
2083
+ themeToCss,
2084
+ useThemeMode
2085
+ });
2086
+ //# sourceMappingURL=index.cjs.map