@camstack/ui-library 0.1.34 → 0.1.36

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.js CHANGED
@@ -683,7 +683,7 @@ function DialogTrigger({ children, ...props }) {
683
683
  return /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => setOpen(true), ...props, children });
684
684
  }
685
685
  var contentVariants = cva7(
686
- "bg-background-elevated border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm",
686
+ "bg-background-elevated border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm max-w-[calc(100vw-2rem)] max-h-[calc(100dvh-2rem)] overflow-y-auto",
687
687
  {
688
688
  variants: {
689
689
  width: {
@@ -917,12 +917,92 @@ import {
917
917
  createContext as createContext5,
918
918
  useCallback as useCallback4,
919
919
  useContext as useContext5,
920
- useEffect as useEffect4,
920
+ useEffect as useEffect5,
921
921
  useId as useId4,
922
922
  useRef as useRef4,
923
923
  useState as useState5
924
924
  } from "react";
925
- import { jsx as jsx16 } from "react/jsx-runtime";
925
+
926
+ // src/hooks/use-is-mobile.ts
927
+ import { useSyncExternalStore } from "react";
928
+ var MOBILE_QUERY = "(max-width: 767px)";
929
+ function subscribe(callback) {
930
+ const mql = window.matchMedia(MOBILE_QUERY);
931
+ mql.addEventListener("change", callback);
932
+ return () => mql.removeEventListener("change", callback);
933
+ }
934
+ function getSnapshot() {
935
+ return window.matchMedia(MOBILE_QUERY).matches;
936
+ }
937
+ function getServerSnapshot() {
938
+ return false;
939
+ }
940
+ function useIsMobile() {
941
+ return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
942
+ }
943
+
944
+ // src/primitives/bottom-sheet.tsx
945
+ import { useEffect as useEffect4 } from "react";
946
+ import { X } from "lucide-react";
947
+ import { Fragment, jsx as jsx16, jsxs as jsxs5 } from "react/jsx-runtime";
948
+ function BottomSheet({ open, onClose, title, children, className }) {
949
+ useEffect4(() => {
950
+ if (!open) return;
951
+ const handleKeyDown = (e) => {
952
+ if (e.key === "Escape") onClose();
953
+ };
954
+ document.addEventListener("keydown", handleKeyDown);
955
+ document.body.style.overflow = "hidden";
956
+ return () => {
957
+ document.removeEventListener("keydown", handleKeyDown);
958
+ document.body.style.overflow = "";
959
+ };
960
+ }, [open, onClose]);
961
+ return /* @__PURE__ */ jsxs5(Fragment, { children: [
962
+ /* @__PURE__ */ jsx16(
963
+ "div",
964
+ {
965
+ className: cn(
966
+ "fixed inset-0 z-40 bg-black/50 transition-opacity duration-200",
967
+ open ? "opacity-100" : "pointer-events-none opacity-0"
968
+ ),
969
+ onClick: onClose,
970
+ "aria-hidden": "true"
971
+ }
972
+ ),
973
+ /* @__PURE__ */ jsxs5(
974
+ "div",
975
+ {
976
+ role: "dialog",
977
+ "aria-modal": "true",
978
+ className: cn(
979
+ "fixed inset-x-0 bottom-0 z-50 flex flex-col bg-background-elevated border-t border-border rounded-t-xl shadow-2xl transition-transform duration-200 ease-out",
980
+ "max-h-[80dvh]",
981
+ open ? "translate-y-0" : "translate-y-full",
982
+ className
983
+ ),
984
+ children: [
985
+ /* @__PURE__ */ jsx16("div", { className: "flex justify-center pt-2 pb-1", children: /* @__PURE__ */ jsx16("div", { className: "h-1 w-8 rounded-full bg-foreground-subtle/30" }) }),
986
+ title && /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between px-4 pb-2", children: [
987
+ /* @__PURE__ */ jsx16("span", { className: "text-sm font-medium text-foreground", children: title }),
988
+ /* @__PURE__ */ jsx16(
989
+ "button",
990
+ {
991
+ onClick: onClose,
992
+ className: "p-1 rounded-md hover:bg-surface-hover text-foreground-muted transition-colors",
993
+ children: /* @__PURE__ */ jsx16(X, { className: "h-4 w-4" })
994
+ }
995
+ )
996
+ ] }),
997
+ /* @__PURE__ */ jsx16("div", { className: "flex-1 overflow-y-auto px-4 pb-4", children })
998
+ ]
999
+ }
1000
+ )
1001
+ ] });
1002
+ }
1003
+
1004
+ // src/primitives/popover.tsx
1005
+ import { jsx as jsx17 } from "react/jsx-runtime";
926
1006
  var PopoverContext = createContext5(null);
927
1007
  function usePopoverContext() {
928
1008
  const ctx = useContext5(PopoverContext);
@@ -941,11 +1021,11 @@ function Popover({ children, open: controlledOpen, onOpenChange }) {
941
1021
  },
942
1022
  [controlledOpen, onOpenChange]
943
1023
  );
944
- return /* @__PURE__ */ jsx16(PopoverContext.Provider, { value: { open, setOpen, triggerId, contentId }, children: /* @__PURE__ */ jsx16("div", { className: "relative inline-block", children }) });
1024
+ return /* @__PURE__ */ jsx17(PopoverContext.Provider, { value: { open, setOpen, triggerId, contentId }, children: /* @__PURE__ */ jsx17("div", { className: "relative inline-block", children }) });
945
1025
  }
946
1026
  function PopoverTrigger({ children, ...props }) {
947
1027
  const { open, setOpen, triggerId, contentId } = usePopoverContext();
948
- return /* @__PURE__ */ jsx16(
1028
+ return /* @__PURE__ */ jsx17(
949
1029
  "button",
950
1030
  {
951
1031
  type: "button",
@@ -961,9 +1041,10 @@ function PopoverTrigger({ children, ...props }) {
961
1041
  }
962
1042
  function PopoverContent({ className, children, ...props }) {
963
1043
  const { open, setOpen, contentId, triggerId } = usePopoverContext();
1044
+ const isMobile = useIsMobile();
964
1045
  const ref = useRef4(null);
965
- useEffect4(() => {
966
- if (!open) return;
1046
+ useEffect5(() => {
1047
+ if (!open || isMobile) return;
967
1048
  const handler = (e) => {
968
1049
  const el = ref.current;
969
1050
  const trigger = document.getElementById(triggerId);
@@ -980,9 +1061,12 @@ function PopoverContent({ className, children, ...props }) {
980
1061
  document.removeEventListener("mousedown", handler);
981
1062
  document.removeEventListener("keydown", escHandler);
982
1063
  };
983
- }, [open, setOpen, triggerId]);
1064
+ }, [open, setOpen, triggerId, isMobile]);
984
1065
  if (!open) return null;
985
- return /* @__PURE__ */ jsx16(
1066
+ if (isMobile) {
1067
+ return /* @__PURE__ */ jsx17(BottomSheet, { open, onClose: () => setOpen(false), children });
1068
+ }
1069
+ return /* @__PURE__ */ jsx17(
986
1070
  "div",
987
1071
  {
988
1072
  ref,
@@ -1006,7 +1090,7 @@ import {
1006
1090
  useContext as useContext6,
1007
1091
  useState as useState6
1008
1092
  } from "react";
1009
- import { jsx as jsx17 } from "react/jsx-runtime";
1093
+ import { jsx as jsx18 } from "react/jsx-runtime";
1010
1094
  var TabsContext = createContext6(null);
1011
1095
  function useTabsContext() {
1012
1096
  const ctx = useContext6(TabsContext);
@@ -1029,10 +1113,10 @@ function Tabs({
1029
1113
  },
1030
1114
  [controlledValue, onValueChange]
1031
1115
  );
1032
- return /* @__PURE__ */ jsx17(TabsContext.Provider, { value: { value, setValue }, children: /* @__PURE__ */ jsx17("div", { className, ...props }) });
1116
+ return /* @__PURE__ */ jsx18(TabsContext.Provider, { value: { value, setValue }, children: /* @__PURE__ */ jsx18("div", { className, ...props }) });
1033
1117
  }
1034
1118
  function TabsList({ className, ...props }) {
1035
- return /* @__PURE__ */ jsx17(
1119
+ return /* @__PURE__ */ jsx18(
1036
1120
  "div",
1037
1121
  {
1038
1122
  role: "tablist",
@@ -1045,7 +1129,7 @@ function TabsTrigger({ value, className, ...props }) {
1045
1129
  const { value: activeValue, setValue } = useTabsContext();
1046
1130
  const isActive = value === activeValue;
1047
1131
  const panelId = `tabpanel-${value}`;
1048
- return /* @__PURE__ */ jsx17(
1132
+ return /* @__PURE__ */ jsx18(
1049
1133
  "button",
1050
1134
  {
1051
1135
  type: "button",
@@ -1066,7 +1150,7 @@ function TabsTrigger({ value, className, ...props }) {
1066
1150
  function TabsContent({ value, className, ...props }) {
1067
1151
  const { value: activeValue } = useTabsContext();
1068
1152
  if (value !== activeValue) return null;
1069
- return /* @__PURE__ */ jsx17(
1153
+ return /* @__PURE__ */ jsx18(
1070
1154
  "div",
1071
1155
  {
1072
1156
  role: "tabpanel",
@@ -1079,10 +1163,10 @@ function TabsContent({ value, className, ...props }) {
1079
1163
 
1080
1164
  // src/primitives/scroll-area.tsx
1081
1165
  import { forwardRef as forwardRef13 } from "react";
1082
- import { jsx as jsx18 } from "react/jsx-runtime";
1166
+ import { jsx as jsx19 } from "react/jsx-runtime";
1083
1167
  var ScrollArea = forwardRef13(
1084
1168
  ({ className, ...props }, ref) => {
1085
- return /* @__PURE__ */ jsx18(
1169
+ return /* @__PURE__ */ jsx19(
1086
1170
  "div",
1087
1171
  {
1088
1172
  ref,
@@ -1098,9 +1182,9 @@ var ScrollArea = forwardRef13(
1098
1182
  ScrollArea.displayName = "ScrollArea";
1099
1183
 
1100
1184
  // src/primitives/floating-panel.tsx
1101
- import { useRef as useRef5, useState as useState7, useCallback as useCallback6, useEffect as useEffect5 } from "react";
1102
- import { X, Minimize2, Maximize2, GripHorizontal } from "lucide-react";
1103
- import { jsx as jsx19, jsxs as jsxs5 } from "react/jsx-runtime";
1185
+ import { useRef as useRef5, useState as useState7, useCallback as useCallback6, useEffect as useEffect6 } from "react";
1186
+ import { X as X2, Minimize2, Maximize2, GripHorizontal } from "lucide-react";
1187
+ import { jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
1104
1188
  function FloatingPanel({
1105
1189
  title,
1106
1190
  onClose,
@@ -1118,6 +1202,7 @@ function FloatingPanel({
1118
1202
  const dragging = useRef5(false);
1119
1203
  const resizing = useRef5(false);
1120
1204
  const offset = useRef5({ x: 0, y: 0 });
1205
+ const isMobile = useIsMobile();
1121
1206
  const onDragStart = useCallback6((e) => {
1122
1207
  e.preventDefault();
1123
1208
  dragging.current = true;
@@ -1129,7 +1214,7 @@ function FloatingPanel({
1129
1214
  resizing.current = true;
1130
1215
  offset.current = { x: e.clientX, y: e.clientY };
1131
1216
  }, []);
1132
- useEffect5(() => {
1217
+ useEffect6(() => {
1133
1218
  const onMouseMove = (e) => {
1134
1219
  if (dragging.current) setPos({ x: e.clientX - offset.current.x, y: e.clientY - offset.current.y });
1135
1220
  if (resizing.current) {
@@ -1150,7 +1235,43 @@ function FloatingPanel({
1150
1235
  window.removeEventListener("mouseup", onMouseUp);
1151
1236
  };
1152
1237
  }, [minWidth, minHeight]);
1153
- return /* @__PURE__ */ jsxs5(
1238
+ if (isMobile) {
1239
+ return /* @__PURE__ */ jsxs6(
1240
+ "div",
1241
+ {
1242
+ className: cn(
1243
+ "fixed inset-x-0 bottom-0 z-50 rounded-t-xl border-t border-border bg-background-elevated shadow-2xl flex flex-col overflow-hidden",
1244
+ className
1245
+ ),
1246
+ style: { maxHeight: "60dvh" },
1247
+ children: [
1248
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border shrink-0 bg-surface", children: [
1249
+ /* @__PURE__ */ jsx20("span", { className: "text-[11px] font-medium truncate", children: title }),
1250
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1 shrink-0", children: [
1251
+ /* @__PURE__ */ jsx20(
1252
+ "button",
1253
+ {
1254
+ onClick: () => setMinimized(!minimized),
1255
+ className: "p-0.5 rounded hover:bg-surface-hover text-foreground-muted transition-colors",
1256
+ children: minimized ? /* @__PURE__ */ jsx20(Maximize2, { size: 12 }) : /* @__PURE__ */ jsx20(Minimize2, { size: 12 })
1257
+ }
1258
+ ),
1259
+ /* @__PURE__ */ jsx20(
1260
+ "button",
1261
+ {
1262
+ onClick: onClose,
1263
+ className: "p-0.5 rounded hover:bg-danger/20 text-foreground-muted hover:text-danger transition-colors",
1264
+ children: /* @__PURE__ */ jsx20(X2, { size: 12 })
1265
+ }
1266
+ )
1267
+ ] })
1268
+ ] }),
1269
+ !minimized && /* @__PURE__ */ jsx20("div", { className: "flex-1 min-h-0 overflow-y-auto", children })
1270
+ ]
1271
+ }
1272
+ );
1273
+ }
1274
+ return /* @__PURE__ */ jsxs6(
1154
1275
  "div",
1155
1276
  {
1156
1277
  className: cn(
@@ -1159,42 +1280,42 @@ function FloatingPanel({
1159
1280
  ),
1160
1281
  style: { left: pos.x, top: pos.y, width: minimized ? 280 : size.w, height: minimized ? "auto" : size.h },
1161
1282
  children: [
1162
- /* @__PURE__ */ jsxs5(
1283
+ /* @__PURE__ */ jsxs6(
1163
1284
  "div",
1164
1285
  {
1165
1286
  onMouseDown: onDragStart,
1166
1287
  className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border cursor-move select-none shrink-0 bg-surface",
1167
1288
  children: [
1168
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 min-w-0", children: [
1169
- /* @__PURE__ */ jsx19(GripHorizontal, { size: 12, className: "text-foreground-subtle shrink-0" }),
1170
- /* @__PURE__ */ jsx19("span", { className: "text-[11px] font-medium truncate", children: title })
1289
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 min-w-0", children: [
1290
+ /* @__PURE__ */ jsx20(GripHorizontal, { size: 12, className: "text-foreground-subtle shrink-0" }),
1291
+ /* @__PURE__ */ jsx20("span", { className: "text-[11px] font-medium truncate", children: title })
1171
1292
  ] }),
1172
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 shrink-0", children: [
1173
- /* @__PURE__ */ jsx19(
1293
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1 shrink-0", children: [
1294
+ /* @__PURE__ */ jsx20(
1174
1295
  "button",
1175
1296
  {
1176
1297
  onClick: () => setMinimized(!minimized),
1177
1298
  className: "p-0.5 rounded hover:bg-surface-hover text-foreground-muted transition-colors",
1178
1299
  title: minimized ? "Restore" : "Minimize",
1179
- children: minimized ? /* @__PURE__ */ jsx19(Maximize2, { size: 12 }) : /* @__PURE__ */ jsx19(Minimize2, { size: 12 })
1300
+ children: minimized ? /* @__PURE__ */ jsx20(Maximize2, { size: 12 }) : /* @__PURE__ */ jsx20(Minimize2, { size: 12 })
1180
1301
  }
1181
1302
  ),
1182
- /* @__PURE__ */ jsx19(
1303
+ /* @__PURE__ */ jsx20(
1183
1304
  "button",
1184
1305
  {
1185
1306
  onClick: onClose,
1186
1307
  className: "p-0.5 rounded hover:bg-danger/20 text-foreground-muted hover:text-danger transition-colors",
1187
1308
  title: "Close",
1188
- children: /* @__PURE__ */ jsx19(X, { size: 12 })
1309
+ children: /* @__PURE__ */ jsx20(X2, { size: 12 })
1189
1310
  }
1190
1311
  )
1191
1312
  ] })
1192
1313
  ]
1193
1314
  }
1194
1315
  ),
1195
- !minimized && /* @__PURE__ */ jsxs5("div", { className: "flex-1 min-h-0 overflow-y-auto relative", children: [
1316
+ !minimized && /* @__PURE__ */ jsxs6("div", { className: "flex-1 min-h-0 overflow-y-auto relative", children: [
1196
1317
  children,
1197
- /* @__PURE__ */ jsx19(
1318
+ /* @__PURE__ */ jsx20(
1198
1319
  "div",
1199
1320
  {
1200
1321
  onMouseDown: onResizeStart,
@@ -1208,8 +1329,55 @@ function FloatingPanel({
1208
1329
  );
1209
1330
  }
1210
1331
 
1332
+ // src/primitives/mobile-drawer.tsx
1333
+ import { useEffect as useEffect7, useRef as useRef6 } from "react";
1334
+ import { Fragment as Fragment2, jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
1335
+ function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
1336
+ const drawerRef = useRef6(null);
1337
+ useEffect7(() => {
1338
+ if (!open) return;
1339
+ const handleKeyDown = (e) => {
1340
+ if (e.key === "Escape") onClose();
1341
+ };
1342
+ document.addEventListener("keydown", handleKeyDown);
1343
+ document.body.style.overflow = "hidden";
1344
+ return () => {
1345
+ document.removeEventListener("keydown", handleKeyDown);
1346
+ document.body.style.overflow = "";
1347
+ };
1348
+ }, [open, onClose]);
1349
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
1350
+ /* @__PURE__ */ jsx21(
1351
+ "div",
1352
+ {
1353
+ className: cn(
1354
+ "fixed inset-0 z-40 bg-black/50 backdrop-blur-sm transition-opacity duration-200",
1355
+ open ? "opacity-100" : "pointer-events-none opacity-0"
1356
+ ),
1357
+ onClick: onClose,
1358
+ "aria-hidden": "true"
1359
+ }
1360
+ ),
1361
+ /* @__PURE__ */ jsx21(
1362
+ "div",
1363
+ {
1364
+ ref: drawerRef,
1365
+ role: "dialog",
1366
+ "aria-modal": "true",
1367
+ className: cn(
1368
+ "fixed inset-y-0 left-0 z-50 flex flex-col bg-surface border-r border-border shadow-2xl transition-transform duration-200 ease-out",
1369
+ width,
1370
+ open ? "translate-x-0" : "-translate-x-full",
1371
+ className
1372
+ ),
1373
+ children
1374
+ }
1375
+ )
1376
+ ] });
1377
+ }
1378
+
1211
1379
  // src/composites/status-badge.tsx
1212
- import { jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
1380
+ import { jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
1213
1381
  var statusConfig = {
1214
1382
  online: { colorClass: "bg-success", label: "Online" },
1215
1383
  offline: { colorClass: "bg-danger", label: "Offline" },
@@ -1224,7 +1392,7 @@ function StatusBadge({
1224
1392
  className
1225
1393
  }) {
1226
1394
  const config = statusConfig[status];
1227
- return /* @__PURE__ */ jsxs6(
1395
+ return /* @__PURE__ */ jsxs8(
1228
1396
  "span",
1229
1397
  {
1230
1398
  className: cn(
@@ -1233,21 +1401,21 @@ function StatusBadge({
1233
1401
  className
1234
1402
  ),
1235
1403
  children: [
1236
- showDot && /* @__PURE__ */ jsx20(
1404
+ showDot && /* @__PURE__ */ jsx22(
1237
1405
  "span",
1238
1406
  {
1239
1407
  className: cn("h-1.5 w-1.5 shrink-0 rounded-full", config.colorClass),
1240
1408
  "aria-hidden": "true"
1241
1409
  }
1242
1410
  ),
1243
- showLabel && /* @__PURE__ */ jsx20("span", { className: "text-foreground", children: config.label })
1411
+ showLabel && /* @__PURE__ */ jsx22("span", { className: "text-foreground", children: config.label })
1244
1412
  ]
1245
1413
  }
1246
1414
  );
1247
1415
  }
1248
1416
 
1249
1417
  // src/composites/provider-badge.tsx
1250
- import { jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
1418
+ import { jsx as jsx23, jsxs as jsxs9 } from "react/jsx-runtime";
1251
1419
  var providerConfig = {
1252
1420
  frigate: { colorClass: "bg-provider-frigate", label: "Frigate" },
1253
1421
  scrypted: { colorClass: "bg-provider-scrypted", label: "Scrypted" },
@@ -1261,20 +1429,20 @@ function ProviderBadge({
1261
1429
  className
1262
1430
  }) {
1263
1431
  const config = providerConfig[provider];
1264
- return /* @__PURE__ */ jsxs7("span", { className: cn("inline-flex items-center gap-1.5 text-xs", className), children: [
1265
- /* @__PURE__ */ jsx21(
1432
+ return /* @__PURE__ */ jsxs9("span", { className: cn("inline-flex items-center gap-1.5 text-xs", className), children: [
1433
+ /* @__PURE__ */ jsx23(
1266
1434
  "span",
1267
1435
  {
1268
1436
  className: cn("h-1.5 w-1.5 shrink-0 rounded-sm", config.colorClass),
1269
1437
  "aria-hidden": "true"
1270
1438
  }
1271
1439
  ),
1272
- showLabel && /* @__PURE__ */ jsx21("span", { className: "text-foreground", children: config.label })
1440
+ showLabel && /* @__PURE__ */ jsx23("span", { className: "text-foreground", children: config.label })
1273
1441
  ] });
1274
1442
  }
1275
1443
 
1276
1444
  // src/composites/version-badge.tsx
1277
- import { jsx as jsx22 } from "react/jsx-runtime";
1445
+ import { jsx as jsx24 } from "react/jsx-runtime";
1278
1446
  var VARIANT_STYLES = {
1279
1447
  success: "bg-emerald-400 text-emerald-950",
1280
1448
  warning: "bg-amber-400 text-amber-950",
@@ -1283,7 +1451,7 @@ var VARIANT_STYLES = {
1283
1451
  neutral: "bg-foreground-subtle/20 text-foreground"
1284
1452
  };
1285
1453
  function SemanticBadge({ children, variant = "neutral", mono, className }) {
1286
- return /* @__PURE__ */ jsx22("span", { className: cn(
1454
+ return /* @__PURE__ */ jsx24("span", { className: cn(
1287
1455
  "inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-bold leading-tight",
1288
1456
  mono && "font-mono",
1289
1457
  VARIANT_STYLES[variant],
@@ -1292,11 +1460,11 @@ function SemanticBadge({ children, variant = "neutral", mono, className }) {
1292
1460
  }
1293
1461
  function VersionBadge({ version, preRelease, className }) {
1294
1462
  const isPreRelease = preRelease ?? /-(alpha|beta|rc|dev|canary|next)/i.test(version);
1295
- return /* @__PURE__ */ jsx22(SemanticBadge, { variant: isPreRelease ? "warning" : "success", mono: true, className, children: version });
1463
+ return /* @__PURE__ */ jsx24(SemanticBadge, { variant: isPreRelease ? "warning" : "success", mono: true, className, children: version });
1296
1464
  }
1297
1465
 
1298
1466
  // src/composites/form-field.tsx
1299
- import { jsx as jsx23, jsxs as jsxs8 } from "react/jsx-runtime";
1467
+ import { jsx as jsx25, jsxs as jsxs10 } from "react/jsx-runtime";
1300
1468
  function FormField({
1301
1469
  label,
1302
1470
  description,
@@ -1307,7 +1475,7 @@ function FormField({
1307
1475
  className
1308
1476
  }) {
1309
1477
  const isHorizontal = orientation === "horizontal";
1310
- return /* @__PURE__ */ jsxs8(
1478
+ return /* @__PURE__ */ jsxs10(
1311
1479
  "div",
1312
1480
  {
1313
1481
  className: cn(
@@ -1316,34 +1484,34 @@ function FormField({
1316
1484
  className
1317
1485
  ),
1318
1486
  children: [
1319
- /* @__PURE__ */ jsxs8("div", { className: cn(isHorizontal ? "flex-1" : ""), children: [
1320
- /* @__PURE__ */ jsxs8(Label, { children: [
1487
+ /* @__PURE__ */ jsxs10("div", { className: cn(isHorizontal ? "flex-1" : ""), children: [
1488
+ /* @__PURE__ */ jsxs10(Label, { children: [
1321
1489
  label,
1322
- required && /* @__PURE__ */ jsx23("span", { className: "text-danger ml-0.5", children: "*" })
1490
+ required && /* @__PURE__ */ jsx25("span", { className: "text-danger ml-0.5", children: "*" })
1323
1491
  ] }),
1324
- description && /* @__PURE__ */ jsx23("p", { className: "text-foreground-subtle text-xs mt-0.5", children: description })
1492
+ description && /* @__PURE__ */ jsx25("p", { className: "text-foreground-subtle text-xs mt-0.5", children: description })
1325
1493
  ] }),
1326
- /* @__PURE__ */ jsx23("div", { className: cn(isHorizontal ? "shrink-0" : ""), children }),
1327
- error && /* @__PURE__ */ jsx23("p", { className: "text-danger text-xs", children: error })
1494
+ /* @__PURE__ */ jsx25("div", { className: cn(isHorizontal ? "shrink-0" : ""), children }),
1495
+ error && /* @__PURE__ */ jsx25("p", { className: "text-danger text-xs", children: error })
1328
1496
  ]
1329
1497
  }
1330
1498
  );
1331
1499
  }
1332
1500
 
1333
1501
  // src/composites/page-header.tsx
1334
- import { jsx as jsx24, jsxs as jsxs9 } from "react/jsx-runtime";
1502
+ import { jsx as jsx26, jsxs as jsxs11 } from "react/jsx-runtime";
1335
1503
  function PageHeader({ title, subtitle, actions, className }) {
1336
- return /* @__PURE__ */ jsxs9("div", { className: cn("flex items-center justify-between mb-3", className), children: [
1337
- /* @__PURE__ */ jsxs9("div", { children: [
1338
- /* @__PURE__ */ jsx24("h1", { className: "text-sm font-semibold text-foreground", children: title }),
1339
- subtitle && /* @__PURE__ */ jsx24("p", { className: "text-foreground-subtle text-xs", children: subtitle })
1504
+ return /* @__PURE__ */ jsxs11("div", { className: cn("flex flex-col gap-2 mb-3 sm:flex-row sm:items-center sm:justify-between", className), children: [
1505
+ /* @__PURE__ */ jsxs11("div", { children: [
1506
+ /* @__PURE__ */ jsx26("h1", { className: "text-sm font-semibold text-foreground", children: title }),
1507
+ subtitle && /* @__PURE__ */ jsx26("p", { className: "text-foreground-subtle text-xs", children: subtitle })
1340
1508
  ] }),
1341
- actions && /* @__PURE__ */ jsx24("div", { className: "flex items-center gap-2", children: actions })
1509
+ actions && /* @__PURE__ */ jsx26("div", { className: "flex items-center gap-2 flex-wrap", children: actions })
1342
1510
  ] });
1343
1511
  }
1344
1512
 
1345
1513
  // src/composites/empty-state.tsx
1346
- import { jsx as jsx25, jsxs as jsxs10 } from "react/jsx-runtime";
1514
+ import { jsx as jsx27, jsxs as jsxs12 } from "react/jsx-runtime";
1347
1515
  function EmptyState({
1348
1516
  icon: Icon,
1349
1517
  title,
@@ -1351,18 +1519,18 @@ function EmptyState({
1351
1519
  action,
1352
1520
  className
1353
1521
  }) {
1354
- return /* @__PURE__ */ jsxs10("div", { className: cn("flex flex-col items-center justify-center gap-3 py-12", className), children: [
1355
- Icon && /* @__PURE__ */ jsx25(Icon, { className: "h-12 w-12 text-foreground-subtle", "aria-hidden": "true" }),
1356
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-col items-center gap-1 text-center", children: [
1357
- /* @__PURE__ */ jsx25("p", { className: "text-foreground-muted text-sm font-medium", children: title }),
1358
- description && /* @__PURE__ */ jsx25("p", { className: "text-foreground-subtle text-xs max-w-xs", children: description })
1522
+ return /* @__PURE__ */ jsxs12("div", { className: cn("flex flex-col items-center justify-center gap-3 py-12", className), children: [
1523
+ Icon && /* @__PURE__ */ jsx27(Icon, { className: "h-12 w-12 text-foreground-subtle", "aria-hidden": "true" }),
1524
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-center gap-1 text-center", children: [
1525
+ /* @__PURE__ */ jsx27("p", { className: "text-foreground-muted text-sm font-medium", children: title }),
1526
+ description && /* @__PURE__ */ jsx27("p", { className: "text-foreground-subtle text-xs max-w-xs", children: description })
1359
1527
  ] }),
1360
- action && /* @__PURE__ */ jsx25("div", { className: "mt-1", children: action })
1528
+ action && /* @__PURE__ */ jsx27("div", { className: "mt-1", children: action })
1361
1529
  ] });
1362
1530
  }
1363
1531
 
1364
1532
  // src/composites/confirm-dialog.tsx
1365
- import { jsx as jsx26, jsxs as jsxs11 } from "react/jsx-runtime";
1533
+ import { jsx as jsx28, jsxs as jsxs13 } from "react/jsx-runtime";
1366
1534
  function ConfirmDialog({
1367
1535
  title,
1368
1536
  message,
@@ -1374,14 +1542,14 @@ function ConfirmDialog({
1374
1542
  open,
1375
1543
  onOpenChange
1376
1544
  }) {
1377
- return /* @__PURE__ */ jsx26(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs11(DialogContent, { children: [
1378
- /* @__PURE__ */ jsxs11(DialogHeader, { children: [
1379
- /* @__PURE__ */ jsx26(DialogTitle, { children: title }),
1380
- /* @__PURE__ */ jsx26(DialogDescription, { children: message })
1545
+ return /* @__PURE__ */ jsx28(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs13(DialogContent, { children: [
1546
+ /* @__PURE__ */ jsxs13(DialogHeader, { children: [
1547
+ /* @__PURE__ */ jsx28(DialogTitle, { children: title }),
1548
+ /* @__PURE__ */ jsx28(DialogDescription, { children: message })
1381
1549
  ] }),
1382
- /* @__PURE__ */ jsxs11(DialogFooter, { children: [
1383
- /* @__PURE__ */ jsx26(Button, { variant: "ghost", onClick: onCancel, children: cancelLabel }),
1384
- /* @__PURE__ */ jsx26(
1550
+ /* @__PURE__ */ jsxs13(DialogFooter, { children: [
1551
+ /* @__PURE__ */ jsx28(Button, { variant: "ghost", onClick: onCancel, children: cancelLabel }),
1552
+ /* @__PURE__ */ jsx28(
1385
1553
  Button,
1386
1554
  {
1387
1555
  variant: variant === "danger" ? "danger" : "primary",
@@ -1395,12 +1563,12 @@ function ConfirmDialog({
1395
1563
 
1396
1564
  // src/composites/stat-card.tsx
1397
1565
  import { TrendingUp, TrendingDown } from "lucide-react";
1398
- import { jsx as jsx27, jsxs as jsxs12 } from "react/jsx-runtime";
1566
+ import { jsx as jsx29, jsxs as jsxs14 } from "react/jsx-runtime";
1399
1567
  function StatCard({ value, label, trend, className }) {
1400
- return /* @__PURE__ */ jsxs12(Card, { className: cn("flex flex-col gap-1", className), children: [
1401
- /* @__PURE__ */ jsxs12("div", { className: "flex items-baseline gap-2", children: [
1402
- /* @__PURE__ */ jsx27("span", { className: "text-2xl font-semibold text-foreground", children: value }),
1403
- trend && /* @__PURE__ */ jsxs12(
1568
+ return /* @__PURE__ */ jsxs14(Card, { className: cn("flex flex-col gap-1", className), children: [
1569
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-baseline gap-2", children: [
1570
+ /* @__PURE__ */ jsx29("span", { className: "text-2xl font-semibold text-foreground", children: value }),
1571
+ trend && /* @__PURE__ */ jsxs14(
1404
1572
  "span",
1405
1573
  {
1406
1574
  className: cn(
@@ -1408,27 +1576,27 @@ function StatCard({ value, label, trend, className }) {
1408
1576
  trend.direction === "up" ? "text-success" : "text-danger"
1409
1577
  ),
1410
1578
  children: [
1411
- trend.direction === "up" ? /* @__PURE__ */ jsx27(TrendingUp, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx27(TrendingDown, { className: "h-3 w-3" }),
1579
+ trend.direction === "up" ? /* @__PURE__ */ jsx29(TrendingUp, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx29(TrendingDown, { className: "h-3 w-3" }),
1412
1580
  trend.value,
1413
1581
  "%"
1414
1582
  ]
1415
1583
  }
1416
1584
  )
1417
1585
  ] }),
1418
- /* @__PURE__ */ jsx27("span", { className: "text-xs text-foreground-muted", children: label })
1586
+ /* @__PURE__ */ jsx29("span", { className: "text-xs text-foreground-muted", children: label })
1419
1587
  ] });
1420
1588
  }
1421
1589
 
1422
1590
  // src/composites/key-value-list.tsx
1423
- import { jsx as jsx28, jsxs as jsxs13 } from "react/jsx-runtime";
1591
+ import { jsx as jsx30, jsxs as jsxs15 } from "react/jsx-runtime";
1424
1592
  function KeyValueList({ items, className }) {
1425
- return /* @__PURE__ */ jsx28("dl", { className: cn("flex flex-col", className), children: items.map((item) => /* @__PURE__ */ jsxs13(
1593
+ return /* @__PURE__ */ jsx30("dl", { className: cn("flex flex-col", className), children: items.map((item) => /* @__PURE__ */ jsxs15(
1426
1594
  "div",
1427
1595
  {
1428
1596
  className: "flex items-center h-7",
1429
1597
  children: [
1430
- /* @__PURE__ */ jsx28("dt", { className: "text-foreground-subtle text-xs w-1/3 shrink-0", children: item.key }),
1431
- /* @__PURE__ */ jsx28("dd", { className: "text-foreground text-xs", children: item.value })
1598
+ /* @__PURE__ */ jsx30("dt", { className: "text-foreground-subtle text-xs w-1/3 shrink-0", children: item.key }),
1599
+ /* @__PURE__ */ jsx30("dd", { className: "text-foreground text-xs", children: item.value })
1432
1600
  ]
1433
1601
  },
1434
1602
  item.key
@@ -1438,7 +1606,7 @@ function KeyValueList({ items, className }) {
1438
1606
  // src/composites/code-block.tsx
1439
1607
  import { useCallback as useCallback7, useState as useState8 } from "react";
1440
1608
  import { Copy, Check } from "lucide-react";
1441
- import { jsx as jsx29, jsxs as jsxs14 } from "react/jsx-runtime";
1609
+ import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
1442
1610
  function CodeBlock({ children, maxHeight = 300, className }) {
1443
1611
  const [copied, setCopied] = useState8(false);
1444
1612
  const handleCopy = useCallback7(() => {
@@ -1447,9 +1615,9 @@ function CodeBlock({ children, maxHeight = 300, className }) {
1447
1615
  setTimeout(() => setCopied(false), 2e3);
1448
1616
  });
1449
1617
  }, [children]);
1450
- return /* @__PURE__ */ jsxs14("div", { className: cn("relative group", className), children: [
1451
- /* @__PURE__ */ jsx29(ScrollArea, { style: { maxHeight }, children: /* @__PURE__ */ jsx29("pre", { className: "font-mono text-xs bg-surface p-3 rounded-md border border-border-subtle", children: /* @__PURE__ */ jsx29("code", { children }) }) }),
1452
- /* @__PURE__ */ jsx29("div", { className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsx29(
1618
+ return /* @__PURE__ */ jsxs16("div", { className: cn("relative group", className), children: [
1619
+ /* @__PURE__ */ jsx31(ScrollArea, { style: { maxHeight }, children: /* @__PURE__ */ jsx31("pre", { className: "font-mono text-xs bg-surface p-3 rounded-md border border-border-subtle", children: /* @__PURE__ */ jsx31("code", { children }) }) }),
1620
+ /* @__PURE__ */ jsx31("div", { className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsx31(
1453
1621
  IconButton,
1454
1622
  {
1455
1623
  icon: copied ? Check : Copy,
@@ -1463,28 +1631,95 @@ function CodeBlock({ children, maxHeight = 300, className }) {
1463
1631
  }
1464
1632
 
1465
1633
  // src/composites/filter-bar.tsx
1466
- import { Search } from "lucide-react";
1467
- import { jsx as jsx30 } from "react/jsx-runtime";
1634
+ import { useState as useState9 } from "react";
1635
+ import { Search, SlidersHorizontal } from "lucide-react";
1636
+ import { Fragment as Fragment3, jsx as jsx32, jsxs as jsxs17 } from "react/jsx-runtime";
1468
1637
  function FilterBar({ filters, values, onChange, className }) {
1638
+ const isMobile = useIsMobile();
1639
+ const [sheetOpen, setSheetOpen] = useState9(false);
1469
1640
  const handleChange = (key, value) => {
1470
1641
  onChange({ ...values, [key]: value });
1471
1642
  };
1472
- return /* @__PURE__ */ jsx30("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
1643
+ const activeCount = Object.values(values).filter((v) => v !== void 0 && v !== "").length;
1644
+ if (isMobile) {
1645
+ const searchFilter = filters.find((f) => f.type === "search");
1646
+ const hasNonSearchFilters = filters.some((f) => f.type !== "search");
1647
+ return /* @__PURE__ */ jsxs17("div", { className: cn("flex items-center gap-2", className), children: [
1648
+ searchFilter && /* @__PURE__ */ jsx32(
1649
+ Input,
1650
+ {
1651
+ placeholder: searchFilter.placeholder ?? "Search...",
1652
+ value: values[searchFilter.key] ?? "",
1653
+ onChange: (e) => handleChange(searchFilter.key, e.target.value),
1654
+ leftSlot: /* @__PURE__ */ jsx32(Search, { className: "h-3 w-3 text-foreground-subtle" }),
1655
+ className: "flex-1"
1656
+ }
1657
+ ),
1658
+ hasNonSearchFilters && /* @__PURE__ */ jsxs17(Fragment3, { children: [
1659
+ /* @__PURE__ */ jsxs17(
1660
+ "button",
1661
+ {
1662
+ onClick: () => setSheetOpen(true),
1663
+ className: "flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-xs text-foreground-muted hover:bg-surface-hover transition-colors shrink-0",
1664
+ children: [
1665
+ /* @__PURE__ */ jsx32(SlidersHorizontal, { className: "h-3.5 w-3.5" }),
1666
+ "Filters",
1667
+ activeCount > 0 && /* @__PURE__ */ jsx32(Badge, { variant: "info", className: "ml-1 text-[10px] px-1 py-0", children: activeCount })
1668
+ ]
1669
+ }
1670
+ ),
1671
+ /* @__PURE__ */ jsx32(BottomSheet, { open: sheetOpen, onClose: () => setSheetOpen(false), title: "Filters", children: /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-3", children: filters.filter((f) => f.type !== "search").map((filter) => {
1672
+ switch (filter.type) {
1673
+ case "select":
1674
+ return /* @__PURE__ */ jsxs17("div", { children: [
1675
+ /* @__PURE__ */ jsx32("label", { className: "text-xs text-foreground-muted mb-1 block", children: filter.label }),
1676
+ /* @__PURE__ */ jsx32(
1677
+ Select,
1678
+ {
1679
+ options: filter.options,
1680
+ value: values[filter.key] ?? "",
1681
+ onChange: (e) => handleChange(filter.key, e.target.value),
1682
+ className: "w-full"
1683
+ }
1684
+ )
1685
+ ] }, filter.key);
1686
+ case "badge-toggle":
1687
+ return /* @__PURE__ */ jsx32("div", { className: "flex items-center gap-1 flex-wrap", children: filter.options.map((option) => {
1688
+ const currentValue = values[filter.key];
1689
+ const isActive = currentValue === option.value;
1690
+ return /* @__PURE__ */ jsx32(
1691
+ "button",
1692
+ {
1693
+ type: "button",
1694
+ onClick: () => handleChange(filter.key, isActive ? void 0 : option.value),
1695
+ children: /* @__PURE__ */ jsx32(Badge, { variant: isActive ? "info" : "default", className: "cursor-pointer", children: option.label })
1696
+ },
1697
+ option.value
1698
+ );
1699
+ }) }, filter.key);
1700
+ default:
1701
+ return null;
1702
+ }
1703
+ }) }) })
1704
+ ] })
1705
+ ] });
1706
+ }
1707
+ return /* @__PURE__ */ jsx32("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
1473
1708
  switch (filter.type) {
1474
1709
  case "search":
1475
- return /* @__PURE__ */ jsx30(
1710
+ return /* @__PURE__ */ jsx32(
1476
1711
  Input,
1477
1712
  {
1478
1713
  placeholder: filter.placeholder ?? "Search...",
1479
1714
  value: values[filter.key] ?? "",
1480
1715
  onChange: (e) => handleChange(filter.key, e.target.value),
1481
- leftSlot: /* @__PURE__ */ jsx30(Search, { className: "h-3 w-3 text-foreground-subtle" }),
1716
+ leftSlot: /* @__PURE__ */ jsx32(Search, { className: "h-3 w-3 text-foreground-subtle" }),
1482
1717
  className: "w-48"
1483
1718
  },
1484
1719
  filter.key
1485
1720
  );
1486
1721
  case "select":
1487
- return /* @__PURE__ */ jsx30(
1722
+ return /* @__PURE__ */ jsx32(
1488
1723
  Select,
1489
1724
  {
1490
1725
  options: filter.options,
@@ -1495,25 +1730,15 @@ function FilterBar({ filters, values, onChange, className }) {
1495
1730
  filter.key
1496
1731
  );
1497
1732
  case "badge-toggle":
1498
- return /* @__PURE__ */ jsx30("div", { className: "flex items-center gap-1", children: filter.options.map((option) => {
1733
+ return /* @__PURE__ */ jsx32("div", { className: "flex items-center gap-1", children: filter.options.map((option) => {
1499
1734
  const currentValue = values[filter.key];
1500
1735
  const isActive = currentValue === option.value;
1501
- return /* @__PURE__ */ jsx30(
1736
+ return /* @__PURE__ */ jsx32(
1502
1737
  "button",
1503
1738
  {
1504
1739
  type: "button",
1505
- onClick: () => handleChange(
1506
- filter.key,
1507
- isActive ? void 0 : option.value
1508
- ),
1509
- children: /* @__PURE__ */ jsx30(
1510
- Badge,
1511
- {
1512
- variant: isActive ? "info" : "default",
1513
- className: "cursor-pointer",
1514
- children: option.label
1515
- }
1516
- )
1740
+ onClick: () => handleChange(filter.key, isActive ? void 0 : option.value),
1741
+ children: /* @__PURE__ */ jsx32(Badge, { variant: isActive ? "info" : "default", className: "cursor-pointer", children: option.label })
1517
1742
  },
1518
1743
  option.value
1519
1744
  );
@@ -1525,7 +1750,7 @@ function FilterBar({ filters, values, onChange, className }) {
1525
1750
  }
1526
1751
 
1527
1752
  // src/composites/app-shell/sidebar-item.tsx
1528
- import { jsx as jsx31, jsxs as jsxs15 } from "react/jsx-runtime";
1753
+ import { jsx as jsx33, jsxs as jsxs18 } from "react/jsx-runtime";
1529
1754
  function SidebarItem({
1530
1755
  label,
1531
1756
  icon: Icon,
@@ -1534,7 +1759,7 @@ function SidebarItem({
1534
1759
  active = false,
1535
1760
  className
1536
1761
  }) {
1537
- return /* @__PURE__ */ jsxs15(
1762
+ return /* @__PURE__ */ jsxs18(
1538
1763
  "a",
1539
1764
  {
1540
1765
  href,
@@ -1544,33 +1769,33 @@ function SidebarItem({
1544
1769
  className
1545
1770
  ),
1546
1771
  children: [
1547
- /* @__PURE__ */ jsx31(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
1548
- /* @__PURE__ */ jsx31("span", { className: "truncate flex-1", children: label }),
1549
- badge !== void 0 && /* @__PURE__ */ jsx31(Badge, { className: "ml-auto text-[10px] px-1.5 py-0", children: badge })
1772
+ /* @__PURE__ */ jsx33(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
1773
+ /* @__PURE__ */ jsx33("span", { className: "truncate flex-1", children: label }),
1774
+ badge !== void 0 && /* @__PURE__ */ jsx33(Badge, { className: "ml-auto text-[10px] px-1.5 py-0", children: badge })
1550
1775
  ]
1551
1776
  }
1552
1777
  );
1553
1778
  }
1554
1779
 
1555
1780
  // src/composites/app-shell/sidebar.tsx
1556
- import { jsx as jsx32, jsxs as jsxs16 } from "react/jsx-runtime";
1557
- function Sidebar({ logo, sections, footer, className }) {
1558
- return /* @__PURE__ */ jsxs16(
1781
+ import { jsx as jsx34, jsxs as jsxs19 } from "react/jsx-runtime";
1782
+ function Sidebar({ logo, sections, footer, onNavigate, className }) {
1783
+ return /* @__PURE__ */ jsxs19(
1559
1784
  "nav",
1560
1785
  {
1561
1786
  className: cn(
1562
- "w-44 bg-surface border-r border-border h-full flex flex-col",
1787
+ "bg-surface border-r border-border h-full flex flex-col",
1563
1788
  className
1564
1789
  ),
1565
1790
  children: [
1566
- logo && /* @__PURE__ */ jsx32("div", { className: "px-3 py-2 shrink-0", children: logo }),
1567
- /* @__PURE__ */ jsx32("div", { className: "flex-1 overflow-auto px-1 py-1", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs16("div", { className: cn(sectionIndex > 0 ? "mt-3" : ""), children: [
1568
- section.label && /* @__PURE__ */ jsx32("span", { className: "text-[10px] text-foreground-disabled uppercase tracking-wider px-2 mb-1 block", children: section.label }),
1569
- /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-0.5", children: section.items.map((item) => /* @__PURE__ */ jsx32(SidebarItem, { ...item }, item.href)) })
1791
+ logo && /* @__PURE__ */ jsx34("div", { className: "px-3 py-2 shrink-0", children: logo }),
1792
+ /* @__PURE__ */ jsx34("div", { className: "flex-1 overflow-auto px-1 py-1", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs19("div", { className: cn(sectionIndex > 0 ? "mt-3" : ""), children: [
1793
+ section.label && /* @__PURE__ */ jsx34("span", { className: "text-[10px] text-foreground-disabled uppercase tracking-wider px-2 mb-1 block", children: section.label }),
1794
+ /* @__PURE__ */ jsx34("div", { className: "flex flex-col gap-0.5", onClick: onNavigate, children: section.items.map((item) => /* @__PURE__ */ jsx34(SidebarItem, { ...item }, item.href)) })
1570
1795
  ] }, sectionIndex)) }),
1571
- footer && footer.length > 0 && /* @__PURE__ */ jsxs16("div", { className: "shrink-0 px-1 pb-1", children: [
1572
- /* @__PURE__ */ jsx32(Separator, { className: "mb-1" }),
1573
- /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-0.5", children: footer.map((item) => /* @__PURE__ */ jsx32(SidebarItem, { ...item }, item.href)) })
1796
+ footer && footer.length > 0 && /* @__PURE__ */ jsxs19("div", { className: "shrink-0 px-1 pb-1", children: [
1797
+ /* @__PURE__ */ jsx34(Separator, { className: "mb-1" }),
1798
+ /* @__PURE__ */ jsx34("div", { className: "flex flex-col gap-0.5", onClick: onNavigate, children: footer.map((item) => /* @__PURE__ */ jsx34(SidebarItem, { ...item }, item.href)) })
1574
1799
  ] })
1575
1800
  ]
1576
1801
  }
@@ -1578,30 +1803,54 @@ function Sidebar({ logo, sections, footer, className }) {
1578
1803
  }
1579
1804
 
1580
1805
  // src/composites/app-shell/app-shell.tsx
1581
- import { ChevronRight } from "lucide-react";
1582
- import { jsx as jsx33, jsxs as jsxs17 } from "react/jsx-runtime";
1583
- function AppShell({ sidebar, header, children, className }) {
1584
- return /* @__PURE__ */ jsxs17("div", { className: cn("flex h-screen", className), children: [
1585
- /* @__PURE__ */ jsx33(Sidebar, { ...sidebar }),
1586
- /* @__PURE__ */ jsxs17("div", { className: "flex flex-1 flex-col min-w-0", children: [
1587
- header && /* @__PURE__ */ jsxs17("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
1588
- header.breadcrumbs && header.breadcrumbs.length > 0 && /* @__PURE__ */ jsx33("nav", { className: "flex items-center gap-1 text-xs flex-1 min-w-0", children: header.breadcrumbs.map((crumb, index) => {
1806
+ import { useState as useState10 } from "react";
1807
+ import { ChevronRight, Menu } from "lucide-react";
1808
+ import { jsx as jsx35, jsxs as jsxs20 } from "react/jsx-runtime";
1809
+ function AppShell({ sidebar, header, mobileLogo, mobileActions, children, className }) {
1810
+ const isMobile = useIsMobile();
1811
+ const [drawerOpen, setDrawerOpen] = useState10(false);
1812
+ return /* @__PURE__ */ jsxs20("div", { className: cn("flex h-screen", className), children: [
1813
+ !isMobile && /* @__PURE__ */ jsx35(Sidebar, { ...sidebar, className: cn("w-44", sidebar.className) }),
1814
+ isMobile && /* @__PURE__ */ jsx35(MobileDrawer, { open: drawerOpen, onClose: () => setDrawerOpen(false), width: "w-64", children: /* @__PURE__ */ jsx35(
1815
+ Sidebar,
1816
+ {
1817
+ ...sidebar,
1818
+ onNavigate: () => setDrawerOpen(false),
1819
+ className: "w-full border-r-0"
1820
+ }
1821
+ ) }),
1822
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-1 flex-col min-w-0", children: [
1823
+ isMobile && /* @__PURE__ */ jsxs20("header", { className: "flex items-center h-12 border-b border-border px-3 shrink-0 bg-surface/80 backdrop-blur-sm", children: [
1824
+ /* @__PURE__ */ jsx35(
1825
+ "button",
1826
+ {
1827
+ onClick: () => setDrawerOpen(true),
1828
+ className: "p-1.5 -ml-1.5 rounded-md hover:bg-surface-hover text-foreground-muted transition-colors",
1829
+ "aria-label": "Open menu",
1830
+ children: /* @__PURE__ */ jsx35(Menu, { className: "h-5 w-5" })
1831
+ }
1832
+ ),
1833
+ mobileLogo && /* @__PURE__ */ jsx35("div", { className: "flex-1 flex justify-center", children: mobileLogo }),
1834
+ mobileActions && /* @__PURE__ */ jsx35("div", { className: "shrink-0", children: mobileActions })
1835
+ ] }),
1836
+ !isMobile && header && /* @__PURE__ */ jsxs20("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
1837
+ header.breadcrumbs && header.breadcrumbs.length > 0 && /* @__PURE__ */ jsx35("nav", { className: "flex items-center gap-1 text-xs flex-1 min-w-0", children: header.breadcrumbs.map((crumb, index) => {
1589
1838
  const isLast = index === header.breadcrumbs.length - 1;
1590
- return /* @__PURE__ */ jsxs17("span", { className: "flex items-center gap-1", children: [
1591
- index > 0 && /* @__PURE__ */ jsx33(ChevronRight, { className: "h-3 w-3 text-foreground-subtle shrink-0" }),
1592
- crumb.href && !isLast ? /* @__PURE__ */ jsx33(
1839
+ return /* @__PURE__ */ jsxs20("span", { className: "flex items-center gap-1", children: [
1840
+ index > 0 && /* @__PURE__ */ jsx35(ChevronRight, { className: "h-3 w-3 text-foreground-subtle shrink-0" }),
1841
+ crumb.href && !isLast ? /* @__PURE__ */ jsx35(
1593
1842
  "a",
1594
1843
  {
1595
1844
  href: crumb.href,
1596
1845
  className: "text-foreground-subtle hover:text-foreground transition-colors truncate",
1597
1846
  children: crumb.label
1598
1847
  }
1599
- ) : /* @__PURE__ */ jsx33("span", { className: "text-foreground truncate", children: crumb.label })
1848
+ ) : /* @__PURE__ */ jsx35("span", { className: "text-foreground truncate", children: crumb.label })
1600
1849
  ] }, index);
1601
1850
  }) }),
1602
- header.actions && /* @__PURE__ */ jsx33("div", { className: "flex items-center gap-2 ml-auto shrink-0", children: header.actions })
1851
+ header.actions && /* @__PURE__ */ jsx35("div", { className: "flex items-center gap-2 ml-auto shrink-0", children: header.actions })
1603
1852
  ] }),
1604
- /* @__PURE__ */ jsx33("main", { className: "flex-1 overflow-auto p-4", children })
1853
+ /* @__PURE__ */ jsx35("main", { className: "flex-1 overflow-auto p-4", children })
1605
1854
  ] })
1606
1855
  ] });
1607
1856
  }
@@ -1619,20 +1868,20 @@ import {
1619
1868
 
1620
1869
  // src/composites/data-table/data-table-header.tsx
1621
1870
  import { ArrowUpDown, ArrowUp, ArrowDown } from "lucide-react";
1622
- import { jsx as jsx34, jsxs as jsxs18 } from "react/jsx-runtime";
1871
+ import { jsx as jsx36, jsxs as jsxs21 } from "react/jsx-runtime";
1623
1872
  function DataTableHeader({
1624
1873
  headerGroups,
1625
1874
  onSortingChange,
1626
1875
  stickyHeader,
1627
1876
  flexRender: render
1628
1877
  }) {
1629
- return /* @__PURE__ */ jsx34(
1878
+ return /* @__PURE__ */ jsx36(
1630
1879
  "thead",
1631
1880
  {
1632
1881
  className: cn(
1633
1882
  stickyHeader && "sticky top-0 z-10 bg-background"
1634
1883
  ),
1635
- children: headerGroups.map((headerGroup) => /* @__PURE__ */ jsx34("tr", { className: "h-6", children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx34(
1884
+ children: headerGroups.map((headerGroup) => /* @__PURE__ */ jsx36("tr", { className: "h-6", children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx36(
1636
1885
  HeaderCell,
1637
1886
  {
1638
1887
  header,
@@ -1647,7 +1896,7 @@ function DataTableHeader({
1647
1896
  function HeaderCell({ header, sortable, flexRender: render }) {
1648
1897
  const sorted = header.column.getIsSorted();
1649
1898
  const SortIcon = sorted === "asc" ? ArrowUp : sorted === "desc" ? ArrowDown : ArrowUpDown;
1650
- return /* @__PURE__ */ jsx34(
1899
+ return /* @__PURE__ */ jsx36(
1651
1900
  "th",
1652
1901
  {
1653
1902
  className: cn(
@@ -1655,9 +1904,9 @@ function HeaderCell({ header, sortable, flexRender: render }) {
1655
1904
  sortable && "cursor-pointer select-none"
1656
1905
  ),
1657
1906
  onClick: sortable ? header.column.getToggleSortingHandler() : void 0,
1658
- children: /* @__PURE__ */ jsxs18("span", { className: "inline-flex items-center gap-1", children: [
1907
+ children: /* @__PURE__ */ jsxs21("span", { className: "inline-flex items-center gap-1", children: [
1659
1908
  header.isPlaceholder ? null : render(header.column.columnDef.header, header.getContext()),
1660
- sortable && /* @__PURE__ */ jsx34(SortIcon, { className: "h-3 w-3" })
1909
+ sortable && /* @__PURE__ */ jsx36(SortIcon, { className: "h-3 w-3" })
1661
1910
  ] })
1662
1911
  }
1663
1912
  );
@@ -1665,7 +1914,7 @@ function HeaderCell({ header, sortable, flexRender: render }) {
1665
1914
 
1666
1915
  // src/composites/data-table/data-table-row.tsx
1667
1916
  import { MoreHorizontal } from "lucide-react";
1668
- import { jsx as jsx35, jsxs as jsxs19 } from "react/jsx-runtime";
1917
+ import { jsx as jsx37, jsxs as jsxs22 } from "react/jsx-runtime";
1669
1918
  function DataTableRow({
1670
1919
  row,
1671
1920
  onRowClick,
@@ -1673,7 +1922,7 @@ function DataTableRow({
1673
1922
  flexRender: render
1674
1923
  }) {
1675
1924
  const actions = rowActions ? rowActions(row.original) : [];
1676
- return /* @__PURE__ */ jsxs19(
1925
+ return /* @__PURE__ */ jsxs22(
1677
1926
  "tr",
1678
1927
  {
1679
1928
  className: cn(
@@ -1683,17 +1932,17 @@ function DataTableRow({
1683
1932
  ),
1684
1933
  onClick: onRowClick ? () => onRowClick(row.original) : void 0,
1685
1934
  children: [
1686
- row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx35(DataTableCell, { cell, flexRender: render }, cell.id)),
1687
- actions.length > 0 && /* @__PURE__ */ jsx35("td", { className: "px-2 py-1.5 w-8", children: /* @__PURE__ */ jsxs19(Dropdown, { children: [
1688
- /* @__PURE__ */ jsx35(
1935
+ row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx37(DataTableCell, { cell, flexRender: render }, cell.id)),
1936
+ actions.length > 0 && /* @__PURE__ */ jsx37("td", { className: "px-2 py-1.5 w-8", children: /* @__PURE__ */ jsxs22(Dropdown, { children: [
1937
+ /* @__PURE__ */ jsx37(
1689
1938
  DropdownTrigger,
1690
1939
  {
1691
1940
  className: "p-0.5 rounded hover:bg-surface-hover",
1692
1941
  onClick: (e) => e.stopPropagation(),
1693
- children: /* @__PURE__ */ jsx35(MoreHorizontal, { className: "h-3.5 w-3.5 text-foreground-muted" })
1942
+ children: /* @__PURE__ */ jsx37(MoreHorizontal, { className: "h-3.5 w-3.5 text-foreground-muted" })
1694
1943
  }
1695
1944
  ),
1696
- /* @__PURE__ */ jsx35(DropdownContent, { className: "right-0 left-auto", children: actions.map((action) => /* @__PURE__ */ jsx35(
1945
+ /* @__PURE__ */ jsx37(DropdownContent, { className: "right-0 left-auto", children: actions.map((action) => /* @__PURE__ */ jsx37(
1697
1946
  DropdownItem,
1698
1947
  {
1699
1948
  icon: action.icon,
@@ -1712,12 +1961,12 @@ function DataTableRow({
1712
1961
  );
1713
1962
  }
1714
1963
  function DataTableCell({ cell, flexRender: render }) {
1715
- return /* @__PURE__ */ jsx35("td", { className: "px-2 py-1.5 text-xs text-foreground", children: render(cell.column.columnDef.cell, cell.getContext()) });
1964
+ return /* @__PURE__ */ jsx37("td", { className: "px-2 py-1.5 text-xs text-foreground", children: render(cell.column.columnDef.cell, cell.getContext()) });
1716
1965
  }
1717
1966
 
1718
1967
  // src/composites/data-table/data-table-pagination.tsx
1719
1968
  import { ChevronLeft, ChevronRight as ChevronRight2 } from "lucide-react";
1720
- import { jsx as jsx36, jsxs as jsxs20 } from "react/jsx-runtime";
1969
+ import { jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
1721
1970
  var PAGE_SIZE_OPTIONS = [
1722
1971
  { value: "10", label: "10" },
1723
1972
  { value: "25", label: "25" },
@@ -1732,10 +1981,10 @@ function DataTablePagination({
1732
1981
  }) {
1733
1982
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
1734
1983
  const currentPage = page + 1;
1735
- return /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
1736
- /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-2", children: [
1737
- /* @__PURE__ */ jsx36("span", { children: "Rows per page" }),
1738
- /* @__PURE__ */ jsx36("div", { className: "w-16", children: /* @__PURE__ */ jsx36(
1984
+ return /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
1985
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2", children: [
1986
+ /* @__PURE__ */ jsx38("span", { children: "Rows per page" }),
1987
+ /* @__PURE__ */ jsx38("div", { className: "w-16", children: /* @__PURE__ */ jsx38(
1739
1988
  Select,
1740
1989
  {
1741
1990
  options: PAGE_SIZE_OPTIONS,
@@ -1747,14 +1996,14 @@ function DataTablePagination({
1747
1996
  }
1748
1997
  ) })
1749
1998
  ] }),
1750
- /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-2", children: [
1751
- /* @__PURE__ */ jsxs20("span", { children: [
1999
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2", children: [
2000
+ /* @__PURE__ */ jsxs23("span", { children: [
1752
2001
  "Page ",
1753
2002
  currentPage,
1754
2003
  " of ",
1755
2004
  totalPages
1756
2005
  ] }),
1757
- /* @__PURE__ */ jsx36(
2006
+ /* @__PURE__ */ jsx38(
1758
2007
  IconButton,
1759
2008
  {
1760
2009
  icon: ChevronLeft,
@@ -1765,7 +2014,7 @@ function DataTablePagination({
1765
2014
  onClick: () => onPaginationChange?.({ pageIndex: page - 1, pageSize })
1766
2015
  }
1767
2016
  ),
1768
- /* @__PURE__ */ jsx36(
2017
+ /* @__PURE__ */ jsx38(
1769
2018
  IconButton,
1770
2019
  {
1771
2020
  icon: ChevronRight2,
@@ -1781,7 +2030,7 @@ function DataTablePagination({
1781
2030
  }
1782
2031
 
1783
2032
  // src/composites/data-table/data-table.tsx
1784
- import { Fragment, jsx as jsx37, jsxs as jsxs21 } from "react/jsx-runtime";
2033
+ import { Fragment as Fragment4, jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
1785
2034
  function DataTable({
1786
2035
  data,
1787
2036
  columns: userColumns,
@@ -1798,13 +2047,14 @@ function DataTable({
1798
2047
  selectable = false,
1799
2048
  compact = true,
1800
2049
  stickyHeader = false,
1801
- className
2050
+ className,
2051
+ mobileMode = "scroll"
1802
2052
  }) {
1803
2053
  const columns = useMemo2(() => {
1804
2054
  if (!selectable) return userColumns;
1805
2055
  const selectColumn = {
1806
2056
  id: "__select",
1807
- header: ({ table: table2 }) => /* @__PURE__ */ jsx37(
2057
+ header: ({ table: table2 }) => /* @__PURE__ */ jsx39(
1808
2058
  Checkbox,
1809
2059
  {
1810
2060
  checked: table2.getIsAllPageRowsSelected(),
@@ -1812,7 +2062,7 @@ function DataTable({
1812
2062
  "aria-label": "Select all"
1813
2063
  }
1814
2064
  ),
1815
- cell: ({ row }) => /* @__PURE__ */ jsx37(
2065
+ cell: ({ row }) => /* @__PURE__ */ jsx39(
1816
2066
  Checkbox,
1817
2067
  {
1818
2068
  checked: row.getIsSelected(),
@@ -1850,9 +2100,71 @@ function DataTable({
1850
2100
  pageCount: pagination ? Math.ceil(pagination.total / pagination.pageSize) : void 0
1851
2101
  });
1852
2102
  const hasActions = !!rowActions;
1853
- return /* @__PURE__ */ jsxs21("div", { className: cn("overflow-auto", className), children: [
1854
- /* @__PURE__ */ jsxs21("table", { className: "w-full border-collapse", children: [
1855
- /* @__PURE__ */ jsx37(
2103
+ const isMobile = useIsMobile();
2104
+ const showCards = isMobile && mobileMode === "cards";
2105
+ if (showCards) {
2106
+ const rows = table.getRowModel().rows;
2107
+ if (loading) {
2108
+ return /* @__PURE__ */ jsx39("div", { className: cn("space-y-2", className), children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs24("div", { className: "rounded-lg border border-border bg-surface p-3 space-y-2", children: [
2109
+ /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-3/4" }),
2110
+ /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-1/2" }),
2111
+ /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-2/3" })
2112
+ ] }, i)) });
2113
+ }
2114
+ if (rows.length === 0) {
2115
+ return /* @__PURE__ */ jsx39("div", { className: cn("text-center py-8 text-xs text-foreground-muted", className), children: emptyState ?? "No data" });
2116
+ }
2117
+ return /* @__PURE__ */ jsxs24("div", { className: cn("space-y-2", className), children: [
2118
+ rows.map((row) => /* @__PURE__ */ jsxs24(
2119
+ "div",
2120
+ {
2121
+ className: cn(
2122
+ "rounded-lg border border-border bg-surface p-3 space-y-1.5",
2123
+ onRowClick && "cursor-pointer hover:bg-surface-hover transition-colors"
2124
+ ),
2125
+ onClick: onRowClick ? () => onRowClick(row.original) : void 0,
2126
+ children: [
2127
+ row.getVisibleCells().filter((cell) => cell.column.id !== "__select").map((cell) => {
2128
+ const header = cell.column.columnDef.header;
2129
+ const label = typeof header === "string" ? header : cell.column.id;
2130
+ return /* @__PURE__ */ jsxs24("div", { className: "flex items-baseline justify-between gap-2 text-xs", children: [
2131
+ /* @__PURE__ */ jsx39("span", { className: "text-foreground-muted shrink-0", children: label }),
2132
+ /* @__PURE__ */ jsx39("span", { className: "text-foreground text-right truncate", children: flexRender(cell.column.columnDef.cell, cell.getContext()) })
2133
+ ] }, cell.id);
2134
+ }),
2135
+ rowActions && /* @__PURE__ */ jsx39("div", { className: "flex items-center gap-1 pt-1 border-t border-border mt-1.5", children: rowActions(row.original).map((action, i) => /* @__PURE__ */ jsx39(
2136
+ "button",
2137
+ {
2138
+ onClick: (e) => {
2139
+ e.stopPropagation();
2140
+ action.onClick();
2141
+ },
2142
+ className: cn(
2143
+ "text-[11px] px-2 py-1 rounded-md transition-colors",
2144
+ action.variant === "danger" ? "text-danger hover:bg-danger/10" : "text-foreground-muted hover:bg-surface-hover"
2145
+ ),
2146
+ children: action.label
2147
+ },
2148
+ i
2149
+ )) })
2150
+ ]
2151
+ },
2152
+ row.id
2153
+ )),
2154
+ pagination && /* @__PURE__ */ jsx39(
2155
+ DataTablePagination,
2156
+ {
2157
+ page: pagination.page,
2158
+ pageSize: pagination.pageSize,
2159
+ total: pagination.total,
2160
+ onPaginationChange
2161
+ }
2162
+ )
2163
+ ] });
2164
+ }
2165
+ return /* @__PURE__ */ jsxs24("div", { className: cn("overflow-x-auto", className), children: [
2166
+ /* @__PURE__ */ jsxs24("table", { className: "w-full border-collapse", children: [
2167
+ /* @__PURE__ */ jsx39(
1856
2168
  DataTableHeader,
1857
2169
  {
1858
2170
  headerGroups: table.getHeaderGroups(),
@@ -1861,14 +2173,14 @@ function DataTable({
1861
2173
  flexRender
1862
2174
  }
1863
2175
  ),
1864
- /* @__PURE__ */ jsx37("tbody", { children: loading ? /* @__PURE__ */ jsx37(LoadingRows, { colSpan: columns.length + (hasActions ? 1 : 0), compact }) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ jsx37("tr", { children: /* @__PURE__ */ jsx37(
2176
+ /* @__PURE__ */ jsx39("tbody", { children: loading ? /* @__PURE__ */ jsx39(LoadingRows, { colSpan: columns.length + (hasActions ? 1 : 0), compact }) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ jsx39("tr", { children: /* @__PURE__ */ jsx39(
1865
2177
  "td",
1866
2178
  {
1867
2179
  colSpan: columns.length + (hasActions ? 1 : 0),
1868
2180
  className: "text-center py-8 text-xs text-foreground-muted",
1869
2181
  children: emptyState ?? "No data"
1870
2182
  }
1871
- ) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx37(
2183
+ ) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx39(
1872
2184
  DataTableRow,
1873
2185
  {
1874
2186
  row,
@@ -1879,7 +2191,7 @@ function DataTable({
1879
2191
  row.id
1880
2192
  )) })
1881
2193
  ] }),
1882
- pagination && /* @__PURE__ */ jsx37(
2194
+ pagination && /* @__PURE__ */ jsx39(
1883
2195
  DataTablePagination,
1884
2196
  {
1885
2197
  page: pagination.page,
@@ -1891,11 +2203,11 @@ function DataTable({
1891
2203
  ] });
1892
2204
  }
1893
2205
  function LoadingRows({ colSpan, compact }) {
1894
- return /* @__PURE__ */ jsx37(Fragment, { children: Array.from({ length: 5 }).map((_, rowIdx) => /* @__PURE__ */ jsx37("tr", { className: compact ? "h-7" : "h-9", children: Array.from({ length: colSpan }).map((_2, colIdx) => /* @__PURE__ */ jsx37("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx37(Skeleton, { className: "h-3 w-full" }) }, colIdx)) }, rowIdx)) });
2206
+ return /* @__PURE__ */ jsx39(Fragment4, { children: Array.from({ length: 5 }).map((_, rowIdx) => /* @__PURE__ */ jsx39("tr", { className: compact ? "h-7" : "h-9", children: Array.from({ length: colSpan }).map((_2, colIdx) => /* @__PURE__ */ jsx39("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-full" }) }, colIdx)) }, rowIdx)) });
1895
2207
  }
1896
2208
 
1897
2209
  // src/composites/device-card.tsx
1898
- import { jsx as jsx38, jsxs as jsxs22 } from "react/jsx-runtime";
2210
+ import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
1899
2211
  var STATUS_COLORS = {
1900
2212
  online: "bg-success",
1901
2213
  offline: "bg-danger",
@@ -1914,7 +2226,7 @@ function DeviceCard({
1914
2226
  className
1915
2227
  }) {
1916
2228
  const isOffline = status === "offline";
1917
- return /* @__PURE__ */ jsxs22(
2229
+ return /* @__PURE__ */ jsxs25(
1918
2230
  "div",
1919
2231
  {
1920
2232
  onClick,
@@ -1926,18 +2238,18 @@ function DeviceCard({
1926
2238
  className
1927
2239
  ),
1928
2240
  children: [
1929
- /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between mb-2", children: [
1930
- /* @__PURE__ */ jsx38("span", { className: "text-sm font-medium truncate", children: title }),
1931
- status && /* @__PURE__ */ jsx38("span", { className: cn("h-2 w-2 rounded-full shrink-0", STATUS_COLORS[status]) })
2241
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between mb-2", children: [
2242
+ /* @__PURE__ */ jsx40("span", { className: "text-sm font-medium truncate", children: title }),
2243
+ status && /* @__PURE__ */ jsx40("span", { className: cn("h-2 w-2 rounded-full shrink-0", STATUS_COLORS[status]) })
1932
2244
  ] }),
1933
- subtitle && /* @__PURE__ */ jsx38("div", { className: "text-[11px] text-foreground-muted", children: subtitle }),
1934
- badges && badges.length > 0 && /* @__PURE__ */ jsx38("div", { className: "flex flex-wrap gap-1 mt-2", children: badges.map((badge, i) => {
2245
+ subtitle && /* @__PURE__ */ jsx40("div", { className: "text-[11px] text-foreground-muted", children: subtitle }),
2246
+ badges && badges.length > 0 && /* @__PURE__ */ jsx40("div", { className: "flex flex-wrap gap-1 mt-2", children: badges.map((badge, i) => {
1935
2247
  const cls = cn(
1936
2248
  "rounded px-1.5 py-0.5 text-[10px] flex items-center gap-0.5",
1937
2249
  selected ? "bg-primary/20" : "bg-surface-hover",
1938
2250
  badge.onClick && "hover:opacity-80 transition-opacity cursor-pointer"
1939
2251
  );
1940
- return badge.onClick ? /* @__PURE__ */ jsxs22(
2252
+ return badge.onClick ? /* @__PURE__ */ jsxs25(
1941
2253
  "button",
1942
2254
  {
1943
2255
  onClick: (e) => {
@@ -1951,12 +2263,12 @@ function DeviceCard({
1951
2263
  ]
1952
2264
  },
1953
2265
  i
1954
- ) : /* @__PURE__ */ jsxs22("span", { className: cls, children: [
2266
+ ) : /* @__PURE__ */ jsxs25("span", { className: cls, children: [
1955
2267
  badge.icon,
1956
2268
  badge.label
1957
2269
  ] }, i);
1958
2270
  }) }),
1959
- !isOffline && actions && actions.length > 0 && /* @__PURE__ */ jsx38("div", { className: "flex items-center gap-0.5 mt-2 -mb-1", children: actions.map((action, i) => /* @__PURE__ */ jsx38(
2271
+ !isOffline && actions && actions.length > 0 && /* @__PURE__ */ jsx40("div", { className: "flex items-center gap-0.5 mt-2 -mb-1", children: actions.map((action, i) => /* @__PURE__ */ jsx40(
1960
2272
  "button",
1961
2273
  {
1962
2274
  onClick: (e) => {
@@ -1970,21 +2282,21 @@ function DeviceCard({
1970
2282
  },
1971
2283
  i
1972
2284
  )) }),
1973
- isOffline && offlineAction && /* @__PURE__ */ jsx38("div", { className: "mt-2", onClick: (e) => e.stopPropagation(), children: offlineAction })
2285
+ isOffline && offlineAction && /* @__PURE__ */ jsx40("div", { className: "mt-2", onClick: (e) => e.stopPropagation(), children: offlineAction })
1974
2286
  ]
1975
2287
  }
1976
2288
  );
1977
2289
  }
1978
2290
 
1979
2291
  // src/composites/device-grid.tsx
1980
- import { jsx as jsx39 } from "react/jsx-runtime";
2292
+ import { jsx as jsx41 } from "react/jsx-runtime";
1981
2293
  function DeviceGrid({
1982
2294
  children,
1983
2295
  minCardWidth = 220,
1984
2296
  gap = 3,
1985
2297
  className
1986
2298
  }) {
1987
- return /* @__PURE__ */ jsx39(
2299
+ return /* @__PURE__ */ jsx41(
1988
2300
  "div",
1989
2301
  {
1990
2302
  className: cn(
@@ -2002,9 +2314,9 @@ function DeviceGrid({
2002
2314
  }
2003
2315
 
2004
2316
  // src/composites/pipeline-step.tsx
2005
- import { useState as useState9 } from "react";
2317
+ import { useState as useState11 } from "react";
2006
2318
  import { ChevronRight as ChevronRight3, ChevronDown as ChevronDown2 } from "lucide-react";
2007
- import { jsx as jsx40, jsxs as jsxs23 } from "react/jsx-runtime";
2319
+ import { jsx as jsx42, jsxs as jsxs26 } from "react/jsx-runtime";
2008
2320
  var ADDON_COLORS = {
2009
2321
  "object-detection": "border-l-blue-500",
2010
2322
  "motion-detection": "border-l-amber-500",
@@ -2080,7 +2392,7 @@ function PipelineStep({
2080
2392
  onDelete,
2081
2393
  readOnly = false
2082
2394
  }) {
2083
- const [expanded, setExpanded] = useState9(false);
2395
+ const [expanded, setExpanded] = useState11(false);
2084
2396
  const color = borderColor(step.addonId, step.slot);
2085
2397
  const backends = backendsForRuntime(step.runtime, capabilities, schema);
2086
2398
  const rtOptions = runtimeOptions(capabilities);
@@ -2103,7 +2415,7 @@ function PipelineStep({
2103
2415
  if (e.target.closest(".step-config")) return;
2104
2416
  setExpanded((v) => !v);
2105
2417
  }
2106
- return /* @__PURE__ */ jsx40("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs23(
2418
+ return /* @__PURE__ */ jsx42("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs26(
2107
2419
  "div",
2108
2420
  {
2109
2421
  className: cn(
@@ -2112,18 +2424,18 @@ function PipelineStep({
2112
2424
  !step.enabled && "opacity-[0.45]"
2113
2425
  ),
2114
2426
  children: [
2115
- /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none", onClick: handleClick, children: [
2116
- /* @__PURE__ */ jsx40("span", { className: "text-foreground-subtle", children: expanded ? /* @__PURE__ */ jsx40(ChevronDown2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx40(ChevronRight3, { className: "h-4 w-4" }) }),
2117
- /* @__PURE__ */ jsxs23("div", { className: "flex-1 min-w-0", children: [
2118
- /* @__PURE__ */ jsx40("span", { className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none", children: step.slot }),
2119
- /* @__PURE__ */ jsx40("span", { className: "text-sm font-semibold text-foreground truncate block leading-tight", children: step.addonName }),
2120
- /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2121
- step.inputClasses.map((c) => /* @__PURE__ */ jsx40("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/12 text-blue-400", children: c }, c)),
2122
- step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ jsx40("span", { className: "text-foreground-subtle/40 text-[10px]", children: "\u2192" }),
2123
- step.outputClasses.map((c) => /* @__PURE__ */ jsx40("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/12 text-green-400", children: c }, c))
2427
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none", onClick: handleClick, children: [
2428
+ /* @__PURE__ */ jsx42("span", { className: "text-foreground-subtle", children: expanded ? /* @__PURE__ */ jsx42(ChevronDown2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx42(ChevronRight3, { className: "h-4 w-4" }) }),
2429
+ /* @__PURE__ */ jsxs26("div", { className: "flex-1 min-w-0", children: [
2430
+ /* @__PURE__ */ jsx42("span", { className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none", children: step.slot }),
2431
+ /* @__PURE__ */ jsx42("span", { className: "text-sm font-semibold text-foreground truncate block leading-tight", children: step.addonName }),
2432
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2433
+ step.inputClasses.map((c) => /* @__PURE__ */ jsx42("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/12 text-blue-400", children: c }, c)),
2434
+ step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ jsx42("span", { className: "text-foreground-subtle/40 text-[10px]", children: "\u2192" }),
2435
+ step.outputClasses.map((c) => /* @__PURE__ */ jsx42("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/12 text-green-400", children: c }, c))
2124
2436
  ] })
2125
2437
  ] }),
2126
- /* @__PURE__ */ jsx40(
2438
+ /* @__PURE__ */ jsx42(
2127
2439
  "button",
2128
2440
  {
2129
2441
  onClick: (e) => {
@@ -2134,16 +2446,16 @@ function PipelineStep({
2134
2446
  "relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors",
2135
2447
  step.enabled ? "bg-success" : "bg-foreground-subtle/30"
2136
2448
  ),
2137
- children: /* @__PURE__ */ jsx40("span", { className: cn(
2449
+ children: /* @__PURE__ */ jsx42("span", { className: cn(
2138
2450
  "inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",
2139
2451
  step.enabled ? "translate-x-6" : "translate-x-1"
2140
2452
  ) })
2141
2453
  }
2142
2454
  )
2143
2455
  ] }),
2144
- expanded && /* @__PURE__ */ jsxs23("div", { className: "step-config border-t border-border bg-background px-4 py-4 space-y-3", children: [
2145
- /* @__PURE__ */ jsxs23("div", { className: "grid grid-cols-2 gap-3", children: [
2146
- /* @__PURE__ */ jsx40(
2456
+ expanded && /* @__PURE__ */ jsxs26("div", { className: "step-config border-t border-border bg-background px-4 py-4 space-y-3", children: [
2457
+ /* @__PURE__ */ jsxs26("div", { className: "grid grid-cols-2 gap-3", children: [
2458
+ /* @__PURE__ */ jsx42(
2147
2459
  ConfigSelect,
2148
2460
  {
2149
2461
  label: "Agent",
@@ -2153,7 +2465,7 @@ function PipelineStep({
2153
2465
  onChange: (v) => onChange({ ...step, agentId: v })
2154
2466
  }
2155
2467
  ),
2156
- /* @__PURE__ */ jsx40(
2468
+ /* @__PURE__ */ jsx42(
2157
2469
  ConfigSelect,
2158
2470
  {
2159
2471
  label: "Runtime",
@@ -2163,7 +2475,7 @@ function PipelineStep({
2163
2475
  onChange: (v) => onChange({ ...step, runtime: v })
2164
2476
  }
2165
2477
  ),
2166
- /* @__PURE__ */ jsx40(
2478
+ /* @__PURE__ */ jsx42(
2167
2479
  ConfigSelect,
2168
2480
  {
2169
2481
  label: "Backend",
@@ -2173,7 +2485,7 @@ function PipelineStep({
2173
2485
  onChange: (v) => onChange({ ...step, backend: v })
2174
2486
  }
2175
2487
  ),
2176
- /* @__PURE__ */ jsx40(
2488
+ /* @__PURE__ */ jsx42(
2177
2489
  ConfigSelect,
2178
2490
  {
2179
2491
  label: "Model",
@@ -2184,15 +2496,15 @@ function PipelineStep({
2184
2496
  }
2185
2497
  )
2186
2498
  ] }),
2187
- /* @__PURE__ */ jsxs23("div", { children: [
2188
- /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between mb-1", children: [
2189
- /* @__PURE__ */ jsx40("span", { className: "text-[10px] font-medium text-foreground-subtle uppercase tracking-wide", children: "Confidence" }),
2190
- /* @__PURE__ */ jsxs23("span", { className: "text-xs font-medium text-foreground tabular-nums", children: [
2499
+ /* @__PURE__ */ jsxs26("div", { children: [
2500
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center justify-between mb-1", children: [
2501
+ /* @__PURE__ */ jsx42("span", { className: "text-[10px] font-medium text-foreground-subtle uppercase tracking-wide", children: "Confidence" }),
2502
+ /* @__PURE__ */ jsxs26("span", { className: "text-xs font-medium text-foreground tabular-nums", children: [
2191
2503
  (step.confidence * 100).toFixed(0),
2192
2504
  "%"
2193
2505
  ] })
2194
2506
  ] }),
2195
- /* @__PURE__ */ jsx40(
2507
+ /* @__PURE__ */ jsx42(
2196
2508
  "input",
2197
2509
  {
2198
2510
  type: "range",
@@ -2212,9 +2524,9 @@ function PipelineStep({
2212
2524
  ) });
2213
2525
  }
2214
2526
  function ConfigSelect({ label, value, options, disabled, onChange }) {
2215
- return /* @__PURE__ */ jsxs23("div", { children: [
2216
- /* @__PURE__ */ jsx40("label", { className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-1.5", children: label }),
2217
- /* @__PURE__ */ jsxs23(
2527
+ return /* @__PURE__ */ jsxs26("div", { children: [
2528
+ /* @__PURE__ */ jsx42("label", { className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-1.5", children: label }),
2529
+ /* @__PURE__ */ jsxs26(
2218
2530
  "select",
2219
2531
  {
2220
2532
  value,
@@ -2222,8 +2534,8 @@ function ConfigSelect({ label, value, options, disabled, onChange }) {
2222
2534
  disabled,
2223
2535
  className: "w-full rounded-lg border border-border bg-surface px-3 py-2 text-xs text-foreground focus:outline-none focus:border-primary/50",
2224
2536
  children: [
2225
- options.length === 0 && /* @__PURE__ */ jsx40("option", { value, children: value || "default" }),
2226
- options.map((o) => /* @__PURE__ */ jsx40("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
2537
+ options.length === 0 && /* @__PURE__ */ jsx42("option", { value, children: value || "default" }),
2538
+ options.map((o) => /* @__PURE__ */ jsx42("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
2227
2539
  ]
2228
2540
  }
2229
2541
  )
@@ -2232,29 +2544,29 @@ function ConfigSelect({ label, value, options, disabled, onChange }) {
2232
2544
 
2233
2545
  // src/composites/pipeline-runtime-selector.tsx
2234
2546
  import { Cpu, Star } from "lucide-react";
2235
- import { jsx as jsx41, jsxs as jsxs24 } from "react/jsx-runtime";
2547
+ import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
2236
2548
  function PipelineRuntimeSelector({ options, value, onChange }) {
2237
- return /* @__PURE__ */ jsx41("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
2549
+ return /* @__PURE__ */ jsx43("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
2238
2550
  const active = opt.id === value;
2239
- return /* @__PURE__ */ jsxs24(
2551
+ return /* @__PURE__ */ jsxs27(
2240
2552
  "button",
2241
2553
  {
2242
2554
  onClick: () => opt.available && onChange(opt.id),
2243
2555
  disabled: !opt.available,
2244
2556
  className: `flex items-center gap-2 rounded-lg border px-3 py-2 text-xs font-medium transition-all ${active ? "border-primary/40 bg-primary/10 text-primary" : opt.available ? "border-border bg-surface text-foreground-subtle hover:bg-surface-hover hover:text-foreground" : "border-border/40 bg-surface/40 text-foreground-subtle/40 cursor-not-allowed"}`,
2245
2557
  children: [
2246
- /* @__PURE__ */ jsx41(Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
2558
+ /* @__PURE__ */ jsx43(Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
2247
2559
  opt.label,
2248
- opt.isBest && /* @__PURE__ */ jsxs24("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-amber-500/15 px-1.5 py-0.5 text-[10px] font-semibold text-amber-400", children: [
2249
- /* @__PURE__ */ jsx41(Star, { className: "h-2.5 w-2.5" }),
2560
+ opt.isBest && /* @__PURE__ */ jsxs27("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-amber-500/15 px-1.5 py-0.5 text-[10px] font-semibold text-amber-400", children: [
2561
+ /* @__PURE__ */ jsx43(Star, { className: "h-2.5 w-2.5" }),
2250
2562
  "Best"
2251
2563
  ] }),
2252
- opt.platformScore != null && /* @__PURE__ */ jsxs24("span", { className: "text-[10px] text-foreground-subtle/60", children: [
2564
+ opt.platformScore != null && /* @__PURE__ */ jsxs27("span", { className: "text-[10px] text-foreground-subtle/60", children: [
2253
2565
  "(",
2254
2566
  opt.platformScore,
2255
2567
  ")"
2256
2568
  ] }),
2257
- /* @__PURE__ */ jsx41(
2569
+ /* @__PURE__ */ jsx43(
2258
2570
  "span",
2259
2571
  {
2260
2572
  className: `h-1.5 w-1.5 rounded-full ${opt.available ? "bg-success" : "bg-danger"}`
@@ -2268,8 +2580,8 @@ function PipelineRuntimeSelector({ options, value, onChange }) {
2268
2580
  }
2269
2581
 
2270
2582
  // src/composites/pipeline-builder.tsx
2271
- import { useMemo as useMemo3, useState as useState10 } from "react";
2272
- import { Save, CopyPlus, Trash2, PlusCircle, X as X2 } from "lucide-react";
2583
+ import { useMemo as useMemo3, useState as useState12 } from "react";
2584
+ import { Save, CopyPlus, Trash2, PlusCircle, X as X3 } from "lucide-react";
2273
2585
 
2274
2586
  // src/lib/validate-template.ts
2275
2587
  function validateTemplate(steps, schema) {
@@ -2301,7 +2613,7 @@ function validateTemplate(steps, schema) {
2301
2613
  }
2302
2614
 
2303
2615
  // src/composites/pipeline-builder.tsx
2304
- import { jsx as jsx42, jsxs as jsxs25 } from "react/jsx-runtime";
2616
+ import { jsx as jsx44, jsxs as jsxs28 } from "react/jsx-runtime";
2305
2617
  function buildSchemaMap(schema) {
2306
2618
  const map = /* @__PURE__ */ new Map();
2307
2619
  for (const slot of schema.slots) {
@@ -2330,20 +2642,20 @@ function createDefaultStep(addon, fallbackRuntime, fallbackBackend) {
2330
2642
  };
2331
2643
  }
2332
2644
  function PlaceholderStep({ addon, onClick }) {
2333
- return /* @__PURE__ */ jsx42(
2645
+ return /* @__PURE__ */ jsx44(
2334
2646
  "button",
2335
2647
  {
2336
2648
  type: "button",
2337
2649
  onClick,
2338
2650
  className: "w-full rounded-xl border-2 border-dashed border-border/60 px-4 py-3 text-left transition-all hover:border-primary/30 hover:bg-surface/60 group",
2339
- children: /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-3", children: [
2340
- /* @__PURE__ */ jsx42(PlusCircle, { className: "h-[18px] w-[18px] text-foreground-subtle/30 group-hover:text-primary/60 shrink-0" }),
2341
- /* @__PURE__ */ jsxs25("div", { className: "flex-1 min-w-0", children: [
2342
- /* @__PURE__ */ jsx42("span", { className: "text-[13px] font-medium text-foreground-subtle/50 group-hover:text-foreground-subtle block truncate", children: addon.name }),
2343
- /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2344
- addon.inputClasses.map((c) => /* @__PURE__ */ jsx42("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/8 text-blue-400/50", children: c }, c)),
2345
- addon.inputClasses.length > 0 && addon.outputClasses.length > 0 && /* @__PURE__ */ jsx42("span", { className: "text-foreground-subtle/25 text-[10px]", children: "\u2192" }),
2346
- addon.outputClasses.map((c) => /* @__PURE__ */ jsx42("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/8 text-green-400/50", children: c }, c))
2651
+ children: /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-3", children: [
2652
+ /* @__PURE__ */ jsx44(PlusCircle, { className: "h-[18px] w-[18px] text-foreground-subtle/30 group-hover:text-primary/60 shrink-0" }),
2653
+ /* @__PURE__ */ jsxs28("div", { className: "flex-1 min-w-0", children: [
2654
+ /* @__PURE__ */ jsx44("span", { className: "text-[13px] font-medium text-foreground-subtle/50 group-hover:text-foreground-subtle block truncate", children: addon.name }),
2655
+ /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2656
+ addon.inputClasses.map((c) => /* @__PURE__ */ jsx44("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/8 text-blue-400/50", children: c }, c)),
2657
+ addon.inputClasses.length > 0 && addon.outputClasses.length > 0 && /* @__PURE__ */ jsx44("span", { className: "text-foreground-subtle/25 text-[10px]", children: "\u2192" }),
2658
+ addon.outputClasses.map((c) => /* @__PURE__ */ jsx44("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/8 text-green-400/50", children: c }, c))
2347
2659
  ] })
2348
2660
  ] })
2349
2661
  ] })
@@ -2366,7 +2678,7 @@ function PipelineBuilder({
2366
2678
  }) {
2367
2679
  const excluded = useMemo3(() => new Set(excludeAddons), [excludeAddons]);
2368
2680
  const schemaMap = useMemo3(() => buildSchemaMap(schema), [schema]);
2369
- const [warnings, setWarnings] = useState10([]);
2681
+ const [warnings, setWarnings] = useState12([]);
2370
2682
  const bestPlatformScore = capabilities.platformScores?.find((s) => s.available);
2371
2683
  const hasPython = capabilities.runtimes.python.available && capabilities.runtimes.python.backends.some((b) => b.available);
2372
2684
  const defaultRuntime = bestPlatformScore?.runtime ?? (hasPython ? "python" : "node");
@@ -2455,8 +2767,8 @@ function PipelineBuilder({
2455
2767
  }
2456
2768
  function renderStep(step) {
2457
2769
  const childPlaceholders = getChildPlaceholders(step);
2458
- return /* @__PURE__ */ jsxs25("div", { className: "space-y-1.5", children: [
2459
- /* @__PURE__ */ jsx42(
2770
+ return /* @__PURE__ */ jsxs28("div", { className: "space-y-1.5", children: [
2771
+ /* @__PURE__ */ jsx44(
2460
2772
  PipelineStep,
2461
2773
  {
2462
2774
  step,
@@ -2468,12 +2780,12 @@ function PipelineBuilder({
2468
2780
  readOnly
2469
2781
  }
2470
2782
  ),
2471
- (step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ jsxs25("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/40 space-y-1.5", children: [
2472
- /* @__PURE__ */ jsx42("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/40", children: "Slot: Cropper / Classifier" }),
2783
+ (step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ jsxs28("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/40 space-y-1.5", children: [
2784
+ /* @__PURE__ */ jsx44("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/40", children: "Slot: Cropper / Classifier" }),
2473
2785
  step.children.map((child) => {
2474
2786
  const childChildPlaceholders = getChildPlaceholders(child);
2475
- return /* @__PURE__ */ jsxs25("div", { className: "space-y-1.5", children: [
2476
- /* @__PURE__ */ jsx42(
2787
+ return /* @__PURE__ */ jsxs28("div", { className: "space-y-1.5", children: [
2788
+ /* @__PURE__ */ jsx44(
2477
2789
  PipelineStep,
2478
2790
  {
2479
2791
  step: child,
@@ -2496,9 +2808,9 @@ function PipelineBuilder({
2496
2808
  readOnly
2497
2809
  }
2498
2810
  ),
2499
- (child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ jsxs25("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/30 space-y-1.5", children: [
2500
- /* @__PURE__ */ jsx42("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/30", children: "Slot: Recognizer" }),
2501
- child.children.map((grandchild) => /* @__PURE__ */ jsx42(
2811
+ (child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ jsxs28("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/30 space-y-1.5", children: [
2812
+ /* @__PURE__ */ jsx44("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/30", children: "Slot: Recognizer" }),
2813
+ child.children.map((grandchild) => /* @__PURE__ */ jsx44(
2502
2814
  PipelineStep,
2503
2815
  {
2504
2816
  step: grandchild,
@@ -2526,7 +2838,7 @@ function PipelineBuilder({
2526
2838
  },
2527
2839
  grandchild.addonId
2528
2840
  )),
2529
- !readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ jsx42(
2841
+ !readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ jsx44(
2530
2842
  PlaceholderStep,
2531
2843
  {
2532
2844
  addon,
@@ -2545,7 +2857,7 @@ function PipelineBuilder({
2545
2857
  ] })
2546
2858
  ] }, child.addonId);
2547
2859
  }),
2548
- !readOnly && childPlaceholders.map((addon) => /* @__PURE__ */ jsx42(
2860
+ !readOnly && childPlaceholders.map((addon) => /* @__PURE__ */ jsx44(
2549
2861
  PlaceholderStep,
2550
2862
  {
2551
2863
  addon,
@@ -2557,22 +2869,22 @@ function PipelineBuilder({
2557
2869
  ] }, step.addonId);
2558
2870
  }
2559
2871
  const rootSlots = schema.slots.filter((s) => s.parentSlot === null).sort((a, b) => a.priority - b.priority);
2560
- return /* @__PURE__ */ jsxs25("div", { className: "space-y-4", children: [
2561
- /* @__PURE__ */ jsx42("div", { className: "rounded-xl border border-border bg-surface p-3", children: /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2", children: [
2562
- /* @__PURE__ */ jsx42("div", { className: "relative flex-1 min-w-0", children: /* @__PURE__ */ jsxs25(
2872
+ return /* @__PURE__ */ jsxs28("div", { className: "space-y-4", children: [
2873
+ /* @__PURE__ */ jsx44("div", { className: "rounded-xl border border-border bg-surface p-3", children: /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-2", children: [
2874
+ /* @__PURE__ */ jsx44("div", { className: "relative flex-1 min-w-0", children: /* @__PURE__ */ jsxs28(
2563
2875
  "select",
2564
2876
  {
2565
2877
  value: selectedTemplateId ?? "",
2566
2878
  onChange: handleSelectTemplate,
2567
2879
  className: "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground focus:outline-none focus:border-primary/50",
2568
2880
  children: [
2569
- /* @__PURE__ */ jsx42("option", { value: "", children: "No template" }),
2570
- templates.map((t) => /* @__PURE__ */ jsx42("option", { value: t.id, children: t.name }, t.id))
2881
+ /* @__PURE__ */ jsx44("option", { value: "", children: "No template" }),
2882
+ templates.map((t) => /* @__PURE__ */ jsx44("option", { value: t.id, children: t.name }, t.id))
2571
2883
  ]
2572
2884
  }
2573
2885
  ) }),
2574
- dirty && /* @__PURE__ */ jsx42("span", { className: "h-1.5 w-1.5 rounded-full bg-amber-500 shrink-0" }),
2575
- /* @__PURE__ */ jsx42(
2886
+ dirty && /* @__PURE__ */ jsx44("span", { className: "h-1.5 w-1.5 rounded-full bg-amber-500 shrink-0" }),
2887
+ /* @__PURE__ */ jsx44(
2576
2888
  "button",
2577
2889
  {
2578
2890
  onClick: handleSave,
@@ -2582,10 +2894,10 @@ function PipelineBuilder({
2582
2894
  "p-2 rounded-lg border border-border transition-colors",
2583
2895
  selectedTemplateId && !readOnly ? "text-foreground-subtle hover:bg-surface-hover" : "text-foreground-subtle/30 cursor-not-allowed"
2584
2896
  ),
2585
- children: /* @__PURE__ */ jsx42(Save, { className: "h-4 w-4" })
2897
+ children: /* @__PURE__ */ jsx44(Save, { className: "h-4 w-4" })
2586
2898
  }
2587
2899
  ),
2588
- /* @__PURE__ */ jsx42(
2900
+ /* @__PURE__ */ jsx44(
2589
2901
  "button",
2590
2902
  {
2591
2903
  onClick: handleSaveAs,
@@ -2595,10 +2907,10 @@ function PipelineBuilder({
2595
2907
  "p-2 rounded-lg border border-border transition-colors",
2596
2908
  !readOnly ? "text-foreground-subtle hover:bg-surface-hover" : "text-foreground-subtle/30 cursor-not-allowed"
2597
2909
  ),
2598
- children: /* @__PURE__ */ jsx42(CopyPlus, { className: "h-4 w-4" })
2910
+ children: /* @__PURE__ */ jsx44(CopyPlus, { className: "h-4 w-4" })
2599
2911
  }
2600
2912
  ),
2601
- /* @__PURE__ */ jsx42(
2913
+ /* @__PURE__ */ jsx44(
2602
2914
  "button",
2603
2915
  {
2604
2916
  onClick: handleDelete,
@@ -2608,16 +2920,16 @@ function PipelineBuilder({
2608
2920
  "p-2 rounded-lg border border-border transition-colors",
2609
2921
  selectedTemplateId && !readOnly ? "text-foreground-subtle hover:text-danger" : "text-foreground-subtle/30 cursor-not-allowed"
2610
2922
  ),
2611
- children: /* @__PURE__ */ jsx42(Trash2, { className: "h-4 w-4" })
2923
+ children: /* @__PURE__ */ jsx44(Trash2, { className: "h-4 w-4" })
2612
2924
  }
2613
2925
  )
2614
2926
  ] }) }),
2615
- warnings.length > 0 && /* @__PURE__ */ jsxs25("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-xs text-amber-400 space-y-1", children: [
2616
- /* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between", children: [
2617
- /* @__PURE__ */ jsx42("span", { className: "font-medium", children: "Template loaded with warnings:" }),
2618
- /* @__PURE__ */ jsx42("button", { onClick: () => setWarnings([]), className: "text-amber-400/60 hover:text-amber-400", children: /* @__PURE__ */ jsx42(X2, { className: "h-3.5 w-3.5" }) })
2927
+ warnings.length > 0 && /* @__PURE__ */ jsxs28("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-xs text-amber-400 space-y-1", children: [
2928
+ /* @__PURE__ */ jsxs28("div", { className: "flex items-center justify-between", children: [
2929
+ /* @__PURE__ */ jsx44("span", { className: "font-medium", children: "Template loaded with warnings:" }),
2930
+ /* @__PURE__ */ jsx44("button", { onClick: () => setWarnings([]), className: "text-amber-400/60 hover:text-amber-400", children: /* @__PURE__ */ jsx44(X3, { className: "h-3.5 w-3.5" }) })
2619
2931
  ] }),
2620
- warnings.map((w, i) => /* @__PURE__ */ jsxs25("div", { children: [
2932
+ warnings.map((w, i) => /* @__PURE__ */ jsxs28("div", { children: [
2621
2933
  "\u2022 ",
2622
2934
  w
2623
2935
  ] }, i))
@@ -2625,13 +2937,13 @@ function PipelineBuilder({
2625
2937
  rootSlots.map((slot) => {
2626
2938
  const slotSteps = steps.filter((s) => s.slot === slot.id && !excluded.has(s.addonId));
2627
2939
  const missingRootAddons = slot.addons.filter((a) => !existingIds.has(a.id) && !excluded.has(a.id));
2628
- return /* @__PURE__ */ jsxs25("div", { className: "space-y-2", children: [
2629
- /* @__PURE__ */ jsxs25("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50", children: [
2940
+ return /* @__PURE__ */ jsxs28("div", { className: "space-y-2", children: [
2941
+ /* @__PURE__ */ jsxs28("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50", children: [
2630
2942
  "Slot: ",
2631
2943
  slot.label
2632
2944
  ] }),
2633
2945
  slotSteps.map((step) => renderStep(step)),
2634
- !readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ jsx42(PlaceholderStep, { addon, onClick: () => {
2946
+ !readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ jsx44(PlaceholderStep, { addon, onClick: () => {
2635
2947
  onChange([...steps, createDefaultStep(addon, defaultRuntime, defaultBackend)]);
2636
2948
  } }, addon.id))
2637
2949
  ] }, slot.id);
@@ -2711,8 +3023,8 @@ function getClassColor(className, customColors) {
2711
3023
  }
2712
3024
 
2713
3025
  // src/composites/detection-canvas.tsx
2714
- import { useRef as useRef6, useEffect as useEffect6 } from "react";
2715
- import { Fragment as Fragment2, jsx as jsx43, jsxs as jsxs26 } from "react/jsx-runtime";
3026
+ import { useRef as useRef7, useEffect as useEffect8 } from "react";
3027
+ import { Fragment as Fragment5, jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
2716
3028
  var DEFAULT_CLASS_COLORS = CLASS_COLORS;
2717
3029
  function DetectionCanvas({
2718
3030
  src,
@@ -2732,7 +3044,7 @@ function DetectionCanvas({
2732
3044
  }
2733
3045
  const ratio = aspectRatio ?? (imageWidth && imageHeight ? `${imageWidth}/${imageHeight}` : "16/9");
2734
3046
  const filteredDetections = detections.filter((d) => d.confidence >= minConfidence);
2735
- return /* @__PURE__ */ jsx43(
3047
+ return /* @__PURE__ */ jsx45(
2736
3048
  "div",
2737
3049
  {
2738
3050
  className: cn(
@@ -2740,10 +3052,10 @@ function DetectionCanvas({
2740
3052
  className
2741
3053
  ),
2742
3054
  style: { aspectRatio: ratio },
2743
- children: src ? /* @__PURE__ */ jsxs26(Fragment2, { children: [
2744
- /* @__PURE__ */ jsx43("img", { src, className: "absolute inset-0 w-full h-full object-fill", alt: "" }),
3055
+ children: src ? /* @__PURE__ */ jsxs29(Fragment5, { children: [
3056
+ /* @__PURE__ */ jsx45("img", { src, className: "absolute inset-0 w-full h-full object-fill", alt: "" }),
2745
3057
  filteredDetections.map(
2746
- (d, i) => d.mask && d.maskWidth && d.maskHeight ? /* @__PURE__ */ jsx43(
3058
+ (d, i) => d.mask && d.maskWidth && d.maskHeight ? /* @__PURE__ */ jsx45(
2747
3059
  MaskOverlay,
2748
3060
  {
2749
3061
  mask: d.mask,
@@ -2757,7 +3069,7 @@ function DetectionCanvas({
2757
3069
  `mask-${i}`
2758
3070
  ) : null
2759
3071
  ),
2760
- filteredDetections.map((d, i) => /* @__PURE__ */ jsx43(
3072
+ filteredDetections.map((d, i) => /* @__PURE__ */ jsx45(
2761
3073
  BoundingBox,
2762
3074
  {
2763
3075
  detection: d,
@@ -2777,7 +3089,7 @@ function DetectionCanvas({
2777
3089
  const ph = py2 - py1;
2778
3090
  if (pw > 0 && ph > 0 && cw * ch / (pw * ph) > 0.8) return false;
2779
3091
  return true;
2780
- }).map((child, j) => /* @__PURE__ */ jsx43(
3092
+ }).map((child, j) => /* @__PURE__ */ jsx45(
2781
3093
  ChildBoundingBox,
2782
3094
  {
2783
3095
  child,
@@ -2790,7 +3102,7 @@ function DetectionCanvas({
2790
3102
  },
2791
3103
  `det-${i}`
2792
3104
  ))
2793
- ] }) : /* @__PURE__ */ jsx43("div", { className: "w-full h-full flex items-center justify-center text-foreground-subtle text-sm", children: placeholder ?? "No image loaded" })
3105
+ ] }) : /* @__PURE__ */ jsx45("div", { className: "w-full h-full flex items-center justify-center text-foreground-subtle text-sm", children: placeholder ?? "No image loaded" })
2794
3106
  }
2795
3107
  );
2796
3108
  }
@@ -2807,15 +3119,15 @@ function BoundingBox({
2807
3119
  const labelCount = 1 + (detection.labelsData?.length ?? 0);
2808
3120
  const labelHeightPx = labelCount * 16 + 4;
2809
3121
  const topPct = y1 / imageHeight * 100;
2810
- const containerRef = useRef6(null);
3122
+ const containerRef = useRef7(null);
2811
3123
  const showBelow = topPct < labelHeightPx / imageHeight * 100 * 1.5;
2812
- const labelsElement = /* @__PURE__ */ jsxs26(
3124
+ const labelsElement = /* @__PURE__ */ jsxs29(
2813
3125
  "div",
2814
3126
  {
2815
3127
  className: `absolute left-0 flex flex-col items-start gap-px ${showBelow ? "" : ""}`,
2816
3128
  style: showBelow ? { top: "100%", marginTop: "2px" } : { bottom: "100%", marginBottom: "2px" },
2817
3129
  children: [
2818
- /* @__PURE__ */ jsxs26(
3130
+ /* @__PURE__ */ jsxs29(
2819
3131
  "span",
2820
3132
  {
2821
3133
  className: "text-[10px] px-1 rounded-sm whitespace-nowrap text-white",
@@ -2826,7 +3138,7 @@ function BoundingBox({
2826
3138
  ]
2827
3139
  }
2828
3140
  ),
2829
- detection.labelsData?.map((l, k) => /* @__PURE__ */ jsxs26(
3141
+ detection.labelsData?.map((l, k) => /* @__PURE__ */ jsxs29(
2830
3142
  "span",
2831
3143
  {
2832
3144
  className: "text-[9px] font-semibold px-1 rounded-sm whitespace-nowrap text-white",
@@ -2843,7 +3155,7 @@ function BoundingBox({
2843
3155
  ]
2844
3156
  }
2845
3157
  );
2846
- return /* @__PURE__ */ jsxs26(
3158
+ return /* @__PURE__ */ jsxs29(
2847
3159
  "div",
2848
3160
  {
2849
3161
  ref: containerRef,
@@ -2873,8 +3185,8 @@ function MaskOverlay({
2873
3185
  imageHeight,
2874
3186
  color
2875
3187
  }) {
2876
- const canvasRef = useRef6(null);
2877
- useEffect6(() => {
3188
+ const canvasRef = useRef7(null);
3189
+ useEffect8(() => {
2878
3190
  const canvas = canvasRef.current;
2879
3191
  if (!canvas) return;
2880
3192
  const ctx = canvas.getContext("2d");
@@ -2902,7 +3214,7 @@ function MaskOverlay({
2902
3214
  ctx.putImageData(imageData, 0, 0);
2903
3215
  }, [mask, maskWidth, maskHeight, color]);
2904
3216
  const [x1, y1, x2, y2] = bbox;
2905
- return /* @__PURE__ */ jsx43(
3217
+ return /* @__PURE__ */ jsx45(
2906
3218
  "canvas",
2907
3219
  {
2908
3220
  ref: canvasRef,
@@ -2928,7 +3240,7 @@ function ChildBoundingBox({
2928
3240
  const pw = px2 - px1;
2929
3241
  const ph = py2 - py1;
2930
3242
  if (pw <= 0 || ph <= 0) return null;
2931
- return /* @__PURE__ */ jsx43(
3243
+ return /* @__PURE__ */ jsx45(
2932
3244
  "div",
2933
3245
  {
2934
3246
  className: "absolute rounded-sm",
@@ -2945,13 +3257,13 @@ function ChildBoundingBox({
2945
3257
  const labelCount = 1 + (child.labelsData?.length ?? 0);
2946
3258
  const relTop = (cy1 - py1) / ph * 100;
2947
3259
  const showBelow = relTop < labelCount * 6;
2948
- return /* @__PURE__ */ jsxs26(
3260
+ return /* @__PURE__ */ jsxs29(
2949
3261
  "div",
2950
3262
  {
2951
3263
  className: "absolute left-0 flex flex-col items-start gap-px",
2952
3264
  style: showBelow ? { top: "100%", marginTop: "1px" } : { bottom: "100%", marginBottom: "1px" },
2953
3265
  children: [
2954
- /* @__PURE__ */ jsxs26(
3266
+ /* @__PURE__ */ jsxs29(
2955
3267
  "span",
2956
3268
  {
2957
3269
  className: "text-[9px] px-0.5 rounded-sm whitespace-nowrap text-white",
@@ -2962,7 +3274,7 @@ function ChildBoundingBox({
2962
3274
  ]
2963
3275
  }
2964
3276
  ),
2965
- child.labelsData?.map((l, k) => /* @__PURE__ */ jsxs26(
3277
+ child.labelsData?.map((l, k) => /* @__PURE__ */ jsxs29(
2966
3278
  "span",
2967
3279
  {
2968
3280
  className: "text-[8px] font-semibold px-0.5 rounded-sm whitespace-nowrap text-white",
@@ -2985,7 +3297,7 @@ function ChildBoundingBox({
2985
3297
  }
2986
3298
 
2987
3299
  // src/composites/detection-result-tree.tsx
2988
- import { jsx as jsx44, jsxs as jsxs27 } from "react/jsx-runtime";
3300
+ import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
2989
3301
  function DetectionResultTree({
2990
3302
  detections,
2991
3303
  classColors,
@@ -2995,15 +3307,15 @@ function DetectionResultTree({
2995
3307
  }) {
2996
3308
  const colors = classColors;
2997
3309
  if (detections.length === 0) {
2998
- return /* @__PURE__ */ jsx44("div", { className: "text-sm text-foreground-subtle italic text-center py-4", children: "No detections" });
3310
+ return /* @__PURE__ */ jsx46("div", { className: "text-sm text-foreground-subtle italic text-center py-4", children: "No detections" });
2999
3311
  }
3000
- return /* @__PURE__ */ jsxs27("div", { className, children: [
3001
- /* @__PURE__ */ jsxs27("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide mb-2", children: [
3312
+ return /* @__PURE__ */ jsxs30("div", { className, children: [
3313
+ /* @__PURE__ */ jsxs30("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide mb-2", children: [
3002
3314
  "Detections (",
3003
3315
  detections.length,
3004
3316
  ")"
3005
3317
  ] }),
3006
- /* @__PURE__ */ jsx44("div", { className: "space-y-2", children: detections.map((d, i) => /* @__PURE__ */ jsx44(
3318
+ /* @__PURE__ */ jsx46("div", { className: "space-y-2", children: detections.map((d, i) => /* @__PURE__ */ jsx46(
3007
3319
  DetectionNode,
3008
3320
  {
3009
3321
  detection: d,
@@ -3025,10 +3337,10 @@ function DetectionNode({
3025
3337
  }) {
3026
3338
  const color = getClassColor(detection.className, colors);
3027
3339
  const isVisible = !hiddenKeys?.has(path);
3028
- return /* @__PURE__ */ jsxs27("div", { className: `rounded-md border border-border bg-surface p-3 space-y-1 ${isVisible ? "" : "opacity-40"}`, children: [
3029
- /* @__PURE__ */ jsxs27("div", { className: "flex justify-between items-center", children: [
3030
- /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
3031
- onToggleVisibility && /* @__PURE__ */ jsx44(
3340
+ return /* @__PURE__ */ jsxs30("div", { className: `rounded-md border border-border bg-surface p-3 space-y-1 ${isVisible ? "" : "opacity-40"}`, children: [
3341
+ /* @__PURE__ */ jsxs30("div", { className: "flex justify-between items-center", children: [
3342
+ /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
3343
+ onToggleVisibility && /* @__PURE__ */ jsx46(
3032
3344
  "input",
3033
3345
  {
3034
3346
  type: "checkbox",
@@ -3037,45 +3349,45 @@ function DetectionNode({
3037
3349
  className: "h-3.5 w-3.5 rounded border-border accent-primary cursor-pointer shrink-0"
3038
3350
  }
3039
3351
  ),
3040
- /* @__PURE__ */ jsx44(
3352
+ /* @__PURE__ */ jsx46(
3041
3353
  "span",
3042
3354
  {
3043
3355
  className: "h-2.5 w-2.5 rounded-full shrink-0",
3044
3356
  style: { backgroundColor: color }
3045
3357
  }
3046
3358
  ),
3047
- /* @__PURE__ */ jsx44("span", { className: "text-sm font-medium text-foreground", children: detection.className }),
3048
- detection.mask && detection.maskWidth && detection.maskHeight && /* @__PURE__ */ jsxs27("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3359
+ /* @__PURE__ */ jsx46("span", { className: "text-sm font-medium text-foreground", children: detection.className }),
3360
+ detection.mask && detection.maskWidth && detection.maskHeight && /* @__PURE__ */ jsxs30("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3049
3361
  "mask ",
3050
3362
  detection.maskWidth,
3051
3363
  "x",
3052
3364
  detection.maskHeight
3053
3365
  ] })
3054
3366
  ] }),
3055
- /* @__PURE__ */ jsx44(ConfidenceBadge, { confidence: detection.confidence })
3367
+ /* @__PURE__ */ jsx46(ConfidenceBadge, { confidence: detection.confidence })
3056
3368
  ] }),
3057
- /* @__PURE__ */ jsxs27("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
3369
+ /* @__PURE__ */ jsxs30("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
3058
3370
  "bbox: [",
3059
3371
  detection.bbox.map((v) => Math.round(v)).join(", "),
3060
3372
  "]"
3061
3373
  ] }),
3062
- detection.labelsData && detection.labelsData.length > 0 && /* @__PURE__ */ jsx44("div", { className: "flex flex-wrap gap-1 mt-1", children: detection.labelsData.map((l, k) => /* @__PURE__ */ jsxs27(
3374
+ detection.labelsData && detection.labelsData.length > 0 && /* @__PURE__ */ jsx46("div", { className: "flex flex-wrap gap-1 mt-1", children: detection.labelsData.map((l, k) => /* @__PURE__ */ jsxs30(
3063
3375
  "span",
3064
3376
  {
3065
3377
  className: "inline-flex items-center gap-1 text-[10px] font-medium px-1.5 py-0.5 rounded-full",
3066
3378
  style: { backgroundColor: getClassColor(l.addonId ?? l.label, colors) + "20", color: getClassColor(l.addonId ?? l.label, colors) },
3067
3379
  children: [
3068
3380
  l.label,
3069
- /* @__PURE__ */ jsxs27("span", { className: "opacity-60", children: [
3381
+ /* @__PURE__ */ jsxs30("span", { className: "opacity-60", children: [
3070
3382
  (l.score * 100).toFixed(0),
3071
3383
  "%"
3072
3384
  ] }),
3073
- l.addonId && /* @__PURE__ */ jsx44("span", { className: "opacity-40 text-[8px]", children: l.addonId })
3385
+ l.addonId && /* @__PURE__ */ jsx46("span", { className: "opacity-40 text-[8px]", children: l.addonId })
3074
3386
  ]
3075
3387
  },
3076
3388
  k
3077
3389
  )) }),
3078
- detection.children && detection.children.length > 0 && /* @__PURE__ */ jsx44(
3390
+ detection.children && detection.children.length > 0 && /* @__PURE__ */ jsx46(
3079
3391
  ChildrenTree,
3080
3392
  {
3081
3393
  children: detection.children,
@@ -3094,13 +3406,13 @@ function ChildrenTree({
3094
3406
  hiddenKeys,
3095
3407
  onToggleVisibility
3096
3408
  }) {
3097
- return /* @__PURE__ */ jsx44("div", { className: "ml-4 mt-1.5 space-y-1.5 border-l-2 border-border pl-3", children: children.map((child, j) => {
3409
+ return /* @__PURE__ */ jsx46("div", { className: "ml-4 mt-1.5 space-y-1.5 border-l-2 border-border pl-3", children: children.map((child, j) => {
3098
3410
  const childPath = `${parentPath}.${j}`;
3099
3411
  const childColor = getClassColor(child.className, colors);
3100
3412
  const isVisible = !hiddenKeys?.has(childPath);
3101
- return /* @__PURE__ */ jsxs27("div", { className: `text-xs space-y-0.5 ${isVisible ? "" : "opacity-40"}`, children: [
3102
- /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-1.5", children: [
3103
- onToggleVisibility && /* @__PURE__ */ jsx44(
3413
+ return /* @__PURE__ */ jsxs30("div", { className: `text-xs space-y-0.5 ${isVisible ? "" : "opacity-40"}`, children: [
3414
+ /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-1.5", children: [
3415
+ onToggleVisibility && /* @__PURE__ */ jsx46(
3104
3416
  "input",
3105
3417
  {
3106
3418
  type: "checkbox",
@@ -3109,26 +3421,26 @@ function ChildrenTree({
3109
3421
  className: "h-3 w-3 rounded border-border accent-primary cursor-pointer shrink-0"
3110
3422
  }
3111
3423
  ),
3112
- /* @__PURE__ */ jsx44(
3424
+ /* @__PURE__ */ jsx46(
3113
3425
  "span",
3114
3426
  {
3115
3427
  className: "h-1.5 w-1.5 rounded-full shrink-0",
3116
3428
  style: { backgroundColor: childColor }
3117
3429
  }
3118
3430
  ),
3119
- /* @__PURE__ */ jsx44("span", { className: "font-medium", style: { color: childColor }, children: child.className }),
3120
- /* @__PURE__ */ jsxs27("span", { className: "text-foreground-subtle", children: [
3431
+ /* @__PURE__ */ jsx46("span", { className: "font-medium", style: { color: childColor }, children: child.className }),
3432
+ /* @__PURE__ */ jsxs30("span", { className: "text-foreground-subtle", children: [
3121
3433
  (child.confidence * 100).toFixed(0),
3122
3434
  "%"
3123
3435
  ] }),
3124
- child.mask && child.maskWidth && child.maskHeight && /* @__PURE__ */ jsxs27("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3436
+ child.mask && child.maskWidth && child.maskHeight && /* @__PURE__ */ jsxs30("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3125
3437
  "mask ",
3126
3438
  child.maskWidth,
3127
3439
  "x",
3128
3440
  child.maskHeight
3129
3441
  ] })
3130
3442
  ] }),
3131
- child.labelsData && child.labelsData.length > 0 && /* @__PURE__ */ jsx44("div", { className: "flex flex-wrap gap-1 ml-5 mt-0.5", children: child.labelsData.map((l, k) => /* @__PURE__ */ jsxs27(
3443
+ child.labelsData && child.labelsData.length > 0 && /* @__PURE__ */ jsx46("div", { className: "flex flex-wrap gap-1 ml-5 mt-0.5", children: child.labelsData.map((l, k) => /* @__PURE__ */ jsxs30(
3132
3444
  "span",
3133
3445
  {
3134
3446
  className: "inline-flex items-center gap-0.5 text-[9px] font-medium px-1 py-0.5 rounded-full",
@@ -3136,7 +3448,7 @@ function ChildrenTree({
3136
3448
  children: [
3137
3449
  l.label,
3138
3450
  " ",
3139
- /* @__PURE__ */ jsxs27("span", { className: "opacity-60", children: [
3451
+ /* @__PURE__ */ jsxs30("span", { className: "opacity-60", children: [
3140
3452
  (l.score * 100).toFixed(0),
3141
3453
  "%"
3142
3454
  ] })
@@ -3144,7 +3456,7 @@ function ChildrenTree({
3144
3456
  },
3145
3457
  k
3146
3458
  )) }),
3147
- child.children && child.children.length > 0 && /* @__PURE__ */ jsx44(
3459
+ child.children && child.children.length > 0 && /* @__PURE__ */ jsx46(
3148
3460
  ChildrenTree,
3149
3461
  {
3150
3462
  children: child.children,
@@ -3159,30 +3471,30 @@ function ChildrenTree({
3159
3471
  }
3160
3472
  function ConfidenceBadge({ confidence }) {
3161
3473
  const level = confidence >= 0.8 ? "bg-success/10 text-success" : confidence >= 0.5 ? "bg-warning/10 text-warning" : "bg-danger/10 text-danger";
3162
- return /* @__PURE__ */ jsxs27("span", { className: `text-xs font-medium px-2 py-0.5 rounded-full ${level}`, children: [
3474
+ return /* @__PURE__ */ jsxs30("span", { className: `text-xs font-medium px-2 py-0.5 rounded-full ${level}`, children: [
3163
3475
  (confidence * 100).toFixed(1),
3164
3476
  "%"
3165
3477
  ] });
3166
3478
  }
3167
3479
 
3168
3480
  // src/composites/step-timings.tsx
3169
- import { jsx as jsx45, jsxs as jsxs28 } from "react/jsx-runtime";
3481
+ import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
3170
3482
  function StepTimings({ timings, totalMs, className }) {
3171
3483
  const entries = Object.entries(timings);
3172
3484
  if (entries.length === 0 && totalMs === void 0) return null;
3173
- return /* @__PURE__ */ jsxs28("div", { className: `rounded-lg border border-border bg-surface p-3 space-y-2 ${className ?? ""}`, children: [
3174
- /* @__PURE__ */ jsx45("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide", children: "Timings" }),
3175
- /* @__PURE__ */ jsxs28("div", { className: "space-y-1 text-xs", children: [
3176
- entries.map(([step, ms]) => /* @__PURE__ */ jsxs28("div", { className: "flex justify-between", children: [
3177
- /* @__PURE__ */ jsx45("span", { className: "text-foreground-subtle", children: step }),
3178
- /* @__PURE__ */ jsxs28("span", { className: "font-mono text-foreground", children: [
3485
+ return /* @__PURE__ */ jsxs31("div", { className: `rounded-lg border border-border bg-surface p-3 space-y-2 ${className ?? ""}`, children: [
3486
+ /* @__PURE__ */ jsx47("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide", children: "Timings" }),
3487
+ /* @__PURE__ */ jsxs31("div", { className: "space-y-1 text-xs", children: [
3488
+ entries.map(([step, ms]) => /* @__PURE__ */ jsxs31("div", { className: "flex justify-between", children: [
3489
+ /* @__PURE__ */ jsx47("span", { className: "text-foreground-subtle", children: step }),
3490
+ /* @__PURE__ */ jsxs31("span", { className: "font-mono text-foreground", children: [
3179
3491
  ms.toFixed(1),
3180
3492
  "ms"
3181
3493
  ] })
3182
3494
  ] }, step)),
3183
- totalMs !== void 0 && /* @__PURE__ */ jsxs28("div", { className: "flex justify-between pt-1 border-t border-border font-medium text-foreground", children: [
3184
- /* @__PURE__ */ jsx45("span", { children: "Total" }),
3185
- /* @__PURE__ */ jsxs28("span", { className: "font-mono", children: [
3495
+ totalMs !== void 0 && /* @__PURE__ */ jsxs31("div", { className: "flex justify-between pt-1 border-t border-border font-medium text-foreground", children: [
3496
+ /* @__PURE__ */ jsx47("span", { children: "Total" }),
3497
+ /* @__PURE__ */ jsxs31("span", { className: "font-mono", children: [
3186
3498
  totalMs.toFixed(1),
3187
3499
  "ms"
3188
3500
  ] })
@@ -3192,7 +3504,7 @@ function StepTimings({ timings, totalMs, className }) {
3192
3504
  }
3193
3505
 
3194
3506
  // src/composites/image-selector.tsx
3195
- import { jsx as jsx46, jsxs as jsxs29 } from "react/jsx-runtime";
3507
+ import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
3196
3508
  function ImageSelector({
3197
3509
  images,
3198
3510
  selectedFilename,
@@ -3218,8 +3530,8 @@ function ImageSelector({
3218
3530
  };
3219
3531
  input.click();
3220
3532
  };
3221
- return /* @__PURE__ */ jsxs29("div", { className: `flex flex-wrap items-center gap-2 ${className ?? ""}`, children: [
3222
- images.map((img) => /* @__PURE__ */ jsx46(
3533
+ return /* @__PURE__ */ jsxs32("div", { className: `flex flex-wrap items-center gap-2 ${className ?? ""}`, children: [
3534
+ images.map((img) => /* @__PURE__ */ jsx48(
3223
3535
  "button",
3224
3536
  {
3225
3537
  onClick: () => onSelect(img.filename),
@@ -3228,7 +3540,7 @@ function ImageSelector({
3228
3540
  },
3229
3541
  img.filename
3230
3542
  )),
3231
- /* @__PURE__ */ jsx46(
3543
+ /* @__PURE__ */ jsx48(
3232
3544
  "button",
3233
3545
  {
3234
3546
  onClick: handleUploadClick,
@@ -3236,12 +3548,12 @@ function ImageSelector({
3236
3548
  children: "Upload..."
3237
3549
  }
3238
3550
  ),
3239
- uploadedName && /* @__PURE__ */ jsx46("span", { className: "text-xs text-foreground-subtle", children: uploadedName })
3551
+ uploadedName && /* @__PURE__ */ jsx48("span", { className: "text-xs text-foreground-subtle", children: uploadedName })
3240
3552
  ] });
3241
3553
  }
3242
3554
 
3243
3555
  // src/composites/inference-config-selector.tsx
3244
- import { jsx as jsx47, jsxs as jsxs30 } from "react/jsx-runtime";
3556
+ import { jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
3245
3557
  var SELECT_CLASS = "w-full px-3 py-2 text-sm rounded-md border border-border bg-surface text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50";
3246
3558
  function InferenceConfigSelector({
3247
3559
  runtime,
@@ -3261,16 +3573,16 @@ function InferenceConfigSelector({
3261
3573
  showAgent = false
3262
3574
  }) {
3263
3575
  const containerClass = layout === "grid" ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4" : layout === "horizontal" ? "flex flex-wrap items-end gap-4" : "space-y-3";
3264
- return /* @__PURE__ */ jsxs30("div", { className: `${containerClass} ${className ?? ""}`, children: [
3265
- showAgent && agents.length > 0 && /* @__PURE__ */ jsxs30("label", { className: "space-y-1", children: [
3266
- /* @__PURE__ */ jsx47("span", { className: "text-xs font-medium text-foreground-subtle", children: "Agent" }),
3267
- /* @__PURE__ */ jsx47(
3576
+ return /* @__PURE__ */ jsxs33("div", { className: `${containerClass} ${className ?? ""}`, children: [
3577
+ showAgent && agents.length > 0 && /* @__PURE__ */ jsxs33("label", { className: "space-y-1", children: [
3578
+ /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-foreground-subtle", children: "Agent" }),
3579
+ /* @__PURE__ */ jsx49(
3268
3580
  "select",
3269
3581
  {
3270
3582
  value: agentId,
3271
3583
  onChange: (e) => onAgentChange?.(e.target.value),
3272
3584
  className: SELECT_CLASS,
3273
- children: agents.map((a) => /* @__PURE__ */ jsxs30("option", { value: a.id, children: [
3585
+ children: agents.map((a) => /* @__PURE__ */ jsxs33("option", { value: a.id, children: [
3274
3586
  a.name,
3275
3587
  " (",
3276
3588
  a.status,
@@ -3279,45 +3591,45 @@ function InferenceConfigSelector({
3279
3591
  }
3280
3592
  )
3281
3593
  ] }),
3282
- /* @__PURE__ */ jsxs30("label", { className: "space-y-1", children: [
3283
- /* @__PURE__ */ jsx47("span", { className: "text-xs font-medium text-foreground-subtle", children: "Runtime" }),
3284
- /* @__PURE__ */ jsx47(
3594
+ /* @__PURE__ */ jsxs33("label", { className: "space-y-1", children: [
3595
+ /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-foreground-subtle", children: "Runtime" }),
3596
+ /* @__PURE__ */ jsx49(
3285
3597
  "select",
3286
3598
  {
3287
3599
  value: runtime,
3288
3600
  onChange: (e) => onRuntimeChange(e.target.value),
3289
3601
  className: SELECT_CLASS,
3290
- children: runtimes.map((r) => /* @__PURE__ */ jsxs30("option", { value: r.value, disabled: !r.available, children: [
3602
+ children: runtimes.map((r) => /* @__PURE__ */ jsxs33("option", { value: r.value, disabled: !r.available, children: [
3291
3603
  r.label,
3292
3604
  !r.available ? " (unavailable)" : ""
3293
3605
  ] }, r.value))
3294
3606
  }
3295
3607
  )
3296
3608
  ] }),
3297
- /* @__PURE__ */ jsxs30("label", { className: "space-y-1", children: [
3298
- /* @__PURE__ */ jsx47("span", { className: "text-xs font-medium text-foreground-subtle", children: "Backend" }),
3299
- /* @__PURE__ */ jsx47(
3609
+ /* @__PURE__ */ jsxs33("label", { className: "space-y-1", children: [
3610
+ /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-foreground-subtle", children: "Backend" }),
3611
+ /* @__PURE__ */ jsx49(
3300
3612
  "select",
3301
3613
  {
3302
3614
  value: backend,
3303
3615
  onChange: (e) => onBackendChange(e.target.value),
3304
3616
  className: SELECT_CLASS,
3305
- children: backends.map((b) => /* @__PURE__ */ jsxs30("option", { value: b.id, disabled: !b.available, children: [
3617
+ children: backends.map((b) => /* @__PURE__ */ jsxs33("option", { value: b.id, disabled: !b.available, children: [
3306
3618
  b.label,
3307
3619
  !b.available ? " (unavailable)" : ""
3308
3620
  ] }, b.id))
3309
3621
  }
3310
3622
  )
3311
3623
  ] }),
3312
- /* @__PURE__ */ jsxs30("label", { className: "space-y-1", children: [
3313
- /* @__PURE__ */ jsx47("span", { className: "text-xs font-medium text-foreground-subtle", children: "Model" }),
3314
- /* @__PURE__ */ jsx47(
3624
+ /* @__PURE__ */ jsxs33("label", { className: "space-y-1", children: [
3625
+ /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-foreground-subtle", children: "Model" }),
3626
+ /* @__PURE__ */ jsx49(
3315
3627
  "select",
3316
3628
  {
3317
3629
  value: modelId,
3318
3630
  onChange: (e) => onModelChange(e.target.value),
3319
3631
  className: SELECT_CLASS,
3320
- children: models.length === 0 ? /* @__PURE__ */ jsx47("option", { value: "", children: "No compatible models" }) : models.map((m) => /* @__PURE__ */ jsxs30("option", { value: m.id, children: [
3632
+ children: models.length === 0 ? /* @__PURE__ */ jsx49("option", { value: "", children: "No compatible models" }) : models.map((m) => /* @__PURE__ */ jsxs33("option", { value: m.id, children: [
3321
3633
  m.name,
3322
3634
  m.downloaded ? " \u2713" : ""
3323
3635
  ] }, m.id))
@@ -3332,15 +3644,15 @@ import { createElement } from "react";
3332
3644
  import { createRoot } from "react-dom/client";
3333
3645
 
3334
3646
  // src/composites/dev-shell.tsx
3335
- import { createContext as createContext7, useCallback as useCallback8, useContext as useContext7, useMemo as useMemo4, useState as useState12 } from "react";
3647
+ import { createContext as createContext7, useCallback as useCallback8, useContext as useContext7, useMemo as useMemo4, useState as useState14 } from "react";
3336
3648
  import { createTRPCClient, createWSClient, wsLink, httpLink, splitLink } from "@trpc/client";
3337
3649
  import superjson from "superjson";
3338
3650
 
3339
3651
  // src/composites/login-form.tsx
3340
- import { useState as useState11 } from "react";
3341
- import { jsx as jsx48, jsxs as jsxs31 } from "react/jsx-runtime";
3652
+ import { useState as useState13 } from "react";
3653
+ import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
3342
3654
  function EyeIcon({ className }) {
3343
- return /* @__PURE__ */ jsxs31(
3655
+ return /* @__PURE__ */ jsxs34(
3344
3656
  "svg",
3345
3657
  {
3346
3658
  xmlns: "http://www.w3.org/2000/svg",
@@ -3352,14 +3664,14 @@ function EyeIcon({ className }) {
3352
3664
  strokeLinejoin: "round",
3353
3665
  className,
3354
3666
  children: [
3355
- /* @__PURE__ */ jsx48("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }),
3356
- /* @__PURE__ */ jsx48("circle", { cx: "12", cy: "12", r: "3" })
3667
+ /* @__PURE__ */ jsx50("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }),
3668
+ /* @__PURE__ */ jsx50("circle", { cx: "12", cy: "12", r: "3" })
3357
3669
  ]
3358
3670
  }
3359
3671
  );
3360
3672
  }
3361
3673
  function EyeOffIcon({ className }) {
3362
- return /* @__PURE__ */ jsxs31(
3674
+ return /* @__PURE__ */ jsxs34(
3363
3675
  "svg",
3364
3676
  {
3365
3677
  xmlns: "http://www.w3.org/2000/svg",
@@ -3371,16 +3683,16 @@ function EyeOffIcon({ className }) {
3371
3683
  strokeLinejoin: "round",
3372
3684
  className,
3373
3685
  children: [
3374
- /* @__PURE__ */ jsx48("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }),
3375
- /* @__PURE__ */ jsx48("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }),
3376
- /* @__PURE__ */ jsx48("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }),
3377
- /* @__PURE__ */ jsx48("path", { d: "m2 2 20 20" })
3686
+ /* @__PURE__ */ jsx50("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }),
3687
+ /* @__PURE__ */ jsx50("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }),
3688
+ /* @__PURE__ */ jsx50("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }),
3689
+ /* @__PURE__ */ jsx50("path", { d: "m2 2 20 20" })
3378
3690
  ]
3379
3691
  }
3380
3692
  );
3381
3693
  }
3382
3694
  function SpinnerIcon({ className }) {
3383
- return /* @__PURE__ */ jsx48(
3695
+ return /* @__PURE__ */ jsx50(
3384
3696
  "svg",
3385
3697
  {
3386
3698
  xmlns: "http://www.w3.org/2000/svg",
@@ -3391,7 +3703,7 @@ function SpinnerIcon({ className }) {
3391
3703
  strokeLinecap: "round",
3392
3704
  strokeLinejoin: "round",
3393
3705
  className,
3394
- children: /* @__PURE__ */ jsx48("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
3706
+ children: /* @__PURE__ */ jsx50("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
3395
3707
  }
3396
3708
  );
3397
3709
  }
@@ -3402,11 +3714,11 @@ function LoginForm({
3402
3714
  error: externalError,
3403
3715
  className
3404
3716
  }) {
3405
- const [username, setUsername] = useState11("");
3406
- const [password, setPassword] = useState11("");
3407
- const [showPassword, setShowPassword] = useState11(false);
3408
- const [submitting, setSubmitting] = useState11(false);
3409
- const [internalError, setInternalError] = useState11(null);
3717
+ const [username, setUsername] = useState13("");
3718
+ const [password, setPassword] = useState13("");
3719
+ const [showPassword, setShowPassword] = useState13(false);
3720
+ const [submitting, setSubmitting] = useState13(false);
3721
+ const [internalError, setInternalError] = useState13(null);
3410
3722
  const error = externalError ?? internalError;
3411
3723
  const handleSubmit = async (e) => {
3412
3724
  e.preventDefault();
@@ -3422,26 +3734,26 @@ function LoginForm({
3422
3734
  setSubmitting(false);
3423
3735
  }
3424
3736
  };
3425
- return /* @__PURE__ */ jsx48(
3737
+ return /* @__PURE__ */ jsx50(
3426
3738
  "div",
3427
3739
  {
3428
3740
  className: cn(
3429
3741
  "flex min-h-screen items-center justify-center bg-background p-4",
3430
3742
  className
3431
3743
  ),
3432
- children: /* @__PURE__ */ jsxs31("div", { className: "w-full max-w-sm", children: [
3433
- logoSrc && /* @__PURE__ */ jsx48("div", { className: "flex justify-center mb-8", children: /* @__PURE__ */ jsx48("img", { src: logoSrc, alt: "Logo", className: "h-12" }) }),
3434
- serverUrl && /* @__PURE__ */ jsx48("p", { className: "mb-4 text-center text-xs text-foreground-subtle truncate", children: serverUrl }),
3435
- /* @__PURE__ */ jsxs31(
3744
+ children: /* @__PURE__ */ jsxs34("div", { className: "w-full max-w-sm", children: [
3745
+ logoSrc && /* @__PURE__ */ jsx50("div", { className: "flex justify-center mb-8", children: /* @__PURE__ */ jsx50("img", { src: logoSrc, alt: "Logo", className: "h-12" }) }),
3746
+ serverUrl && /* @__PURE__ */ jsx50("p", { className: "mb-4 text-center text-xs text-foreground-subtle truncate", children: serverUrl }),
3747
+ /* @__PURE__ */ jsxs34(
3436
3748
  "form",
3437
3749
  {
3438
3750
  onSubmit: handleSubmit,
3439
3751
  className: "space-y-4 rounded-xl border border-border bg-surface p-6 shadow-xl shadow-black/10",
3440
3752
  children: [
3441
- error && /* @__PURE__ */ jsx48("div", { className: "rounded-md bg-danger/10 border border-danger/20 px-3 py-2 text-xs text-danger", children: error }),
3442
- /* @__PURE__ */ jsxs31("div", { className: "space-y-1.5", children: [
3443
- /* @__PURE__ */ jsx48("label", { className: "text-xs font-medium text-foreground-subtle", children: "Username" }),
3444
- /* @__PURE__ */ jsx48(
3753
+ error && /* @__PURE__ */ jsx50("div", { className: "rounded-md bg-danger/10 border border-danger/20 px-3 py-2 text-xs text-danger", children: error }),
3754
+ /* @__PURE__ */ jsxs34("div", { className: "space-y-1.5", children: [
3755
+ /* @__PURE__ */ jsx50("label", { className: "text-xs font-medium text-foreground-subtle", children: "Username" }),
3756
+ /* @__PURE__ */ jsx50(
3445
3757
  "input",
3446
3758
  {
3447
3759
  type: "text",
@@ -3453,10 +3765,10 @@ function LoginForm({
3453
3765
  }
3454
3766
  )
3455
3767
  ] }),
3456
- /* @__PURE__ */ jsxs31("div", { className: "space-y-1.5", children: [
3457
- /* @__PURE__ */ jsx48("label", { className: "text-xs font-medium text-foreground-subtle", children: "Password" }),
3458
- /* @__PURE__ */ jsxs31("div", { className: "relative", children: [
3459
- /* @__PURE__ */ jsx48(
3768
+ /* @__PURE__ */ jsxs34("div", { className: "space-y-1.5", children: [
3769
+ /* @__PURE__ */ jsx50("label", { className: "text-xs font-medium text-foreground-subtle", children: "Password" }),
3770
+ /* @__PURE__ */ jsxs34("div", { className: "relative", children: [
3771
+ /* @__PURE__ */ jsx50(
3460
3772
  "input",
3461
3773
  {
3462
3774
  type: showPassword ? "text" : "password",
@@ -3467,26 +3779,26 @@ function LoginForm({
3467
3779
  className: "w-full rounded-lg border border-border bg-background px-3 py-2.5 pr-10 text-sm text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary"
3468
3780
  }
3469
3781
  ),
3470
- /* @__PURE__ */ jsx48(
3782
+ /* @__PURE__ */ jsx50(
3471
3783
  "button",
3472
3784
  {
3473
3785
  type: "button",
3474
3786
  onClick: () => setShowPassword((prev) => !prev),
3475
3787
  className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-foreground-subtle hover:text-foreground",
3476
3788
  tabIndex: -1,
3477
- children: showPassword ? /* @__PURE__ */ jsx48(EyeOffIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx48(EyeIcon, { className: "h-4 w-4" })
3789
+ children: showPassword ? /* @__PURE__ */ jsx50(EyeOffIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx50(EyeIcon, { className: "h-4 w-4" })
3478
3790
  }
3479
3791
  )
3480
3792
  ] })
3481
3793
  ] }),
3482
- /* @__PURE__ */ jsxs31(
3794
+ /* @__PURE__ */ jsxs34(
3483
3795
  "button",
3484
3796
  {
3485
3797
  type: "submit",
3486
3798
  disabled: submitting,
3487
3799
  className: "w-full rounded-lg bg-primary px-4 py-2.5 text-sm font-semibold text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2",
3488
3800
  children: [
3489
- submitting && /* @__PURE__ */ jsx48(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
3801
+ submitting && /* @__PURE__ */ jsx50(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
3490
3802
  submitting ? "Logging in..." : "Log in"
3491
3803
  ]
3492
3804
  }
@@ -3500,7 +3812,7 @@ function LoginForm({
3500
3812
  }
3501
3813
 
3502
3814
  // src/composites/dev-shell.tsx
3503
- import { jsx as jsx49, jsxs as jsxs32 } from "react/jsx-runtime";
3815
+ import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
3504
3816
  var STORAGE_KEY = "camstack_dev_token";
3505
3817
  var DevShellContext = createContext7(null);
3506
3818
  function useDevShell() {
@@ -3515,7 +3827,7 @@ function getStoredToken() {
3515
3827
  return localStorage.getItem(STORAGE_KEY);
3516
3828
  }
3517
3829
  function SunIcon({ className }) {
3518
- return /* @__PURE__ */ jsxs32(
3830
+ return /* @__PURE__ */ jsxs35(
3519
3831
  "svg",
3520
3832
  {
3521
3833
  xmlns: "http://www.w3.org/2000/svg",
@@ -3527,21 +3839,21 @@ function SunIcon({ className }) {
3527
3839
  strokeLinejoin: "round",
3528
3840
  className,
3529
3841
  children: [
3530
- /* @__PURE__ */ jsx49("circle", { cx: "12", cy: "12", r: "4" }),
3531
- /* @__PURE__ */ jsx49("path", { d: "M12 2v2" }),
3532
- /* @__PURE__ */ jsx49("path", { d: "M12 20v2" }),
3533
- /* @__PURE__ */ jsx49("path", { d: "m4.93 4.93 1.41 1.41" }),
3534
- /* @__PURE__ */ jsx49("path", { d: "m17.66 17.66 1.41 1.41" }),
3535
- /* @__PURE__ */ jsx49("path", { d: "M2 12h2" }),
3536
- /* @__PURE__ */ jsx49("path", { d: "M20 12h2" }),
3537
- /* @__PURE__ */ jsx49("path", { d: "m6.34 17.66-1.41 1.41" }),
3538
- /* @__PURE__ */ jsx49("path", { d: "m19.07 4.93-1.41 1.41" })
3842
+ /* @__PURE__ */ jsx51("circle", { cx: "12", cy: "12", r: "4" }),
3843
+ /* @__PURE__ */ jsx51("path", { d: "M12 2v2" }),
3844
+ /* @__PURE__ */ jsx51("path", { d: "M12 20v2" }),
3845
+ /* @__PURE__ */ jsx51("path", { d: "m4.93 4.93 1.41 1.41" }),
3846
+ /* @__PURE__ */ jsx51("path", { d: "m17.66 17.66 1.41 1.41" }),
3847
+ /* @__PURE__ */ jsx51("path", { d: "M2 12h2" }),
3848
+ /* @__PURE__ */ jsx51("path", { d: "M20 12h2" }),
3849
+ /* @__PURE__ */ jsx51("path", { d: "m6.34 17.66-1.41 1.41" }),
3850
+ /* @__PURE__ */ jsx51("path", { d: "m19.07 4.93-1.41 1.41" })
3539
3851
  ]
3540
3852
  }
3541
3853
  );
3542
3854
  }
3543
3855
  function MoonIcon({ className }) {
3544
- return /* @__PURE__ */ jsx49(
3856
+ return /* @__PURE__ */ jsx51(
3545
3857
  "svg",
3546
3858
  {
3547
3859
  xmlns: "http://www.w3.org/2000/svg",
@@ -3552,7 +3864,7 @@ function MoonIcon({ className }) {
3552
3864
  strokeLinecap: "round",
3553
3865
  strokeLinejoin: "round",
3554
3866
  className,
3555
- children: /* @__PURE__ */ jsx49("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" })
3867
+ children: /* @__PURE__ */ jsx51("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" })
3556
3868
  }
3557
3869
  );
3558
3870
  }
@@ -3591,15 +3903,15 @@ function DevShellInner({
3591
3903
  () => ({ trpc, token, logout: onLogout }),
3592
3904
  [trpc, token, onLogout]
3593
3905
  );
3594
- return /* @__PURE__ */ jsx49(DevShellContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs32("div", { className: "min-h-screen bg-background text-foreground", children: [
3595
- /* @__PURE__ */ jsxs32("div", { className: "flex items-center justify-between border-b border-border bg-surface px-4 py-2", children: [
3596
- /* @__PURE__ */ jsxs32("div", { className: "flex items-center gap-2", children: [
3597
- /* @__PURE__ */ jsx49("span", { className: "rounded bg-warning/20 px-2 py-0.5 text-xs font-bold text-warning", children: "DEV MODE" }),
3598
- title && /* @__PURE__ */ jsx49("span", { className: "text-sm font-medium text-foreground", children: title }),
3599
- /* @__PURE__ */ jsx49("span", { className: "text-xs text-foreground-subtle", children: serverUrl })
3906
+ return /* @__PURE__ */ jsx51(DevShellContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs35("div", { className: "min-h-screen bg-background text-foreground", children: [
3907
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center justify-between border-b border-border bg-surface px-4 py-2", children: [
3908
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
3909
+ /* @__PURE__ */ jsx51("span", { className: "rounded bg-warning/20 px-2 py-0.5 text-xs font-bold text-warning", children: "DEV MODE" }),
3910
+ title && /* @__PURE__ */ jsx51("span", { className: "text-sm font-medium text-foreground", children: title }),
3911
+ /* @__PURE__ */ jsx51("span", { className: "text-xs text-foreground-subtle", children: serverUrl })
3600
3912
  ] }),
3601
- /* @__PURE__ */ jsxs32("div", { className: "flex items-center gap-2", children: [
3602
- /* @__PURE__ */ jsxs32(
3913
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
3914
+ /* @__PURE__ */ jsxs35(
3603
3915
  "button",
3604
3916
  {
3605
3917
  type: "button",
@@ -3607,12 +3919,12 @@ function DevShellInner({
3607
3919
  className: "flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors",
3608
3920
  title: `Theme: ${theme.mode}`,
3609
3921
  children: [
3610
- theme.resolvedMode === "dark" ? /* @__PURE__ */ jsx49(SunIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx49(MoonIcon, { className: "h-3.5 w-3.5" }),
3922
+ theme.resolvedMode === "dark" ? /* @__PURE__ */ jsx51(SunIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx51(MoonIcon, { className: "h-3.5 w-3.5" }),
3611
3923
  theme.mode === "dark" ? "Dark" : theme.mode === "light" ? "Light" : "System"
3612
3924
  ]
3613
3925
  }
3614
3926
  ),
3615
- /* @__PURE__ */ jsx49(
3927
+ /* @__PURE__ */ jsx51(
3616
3928
  "button",
3617
3929
  {
3618
3930
  type: "button",
@@ -3623,7 +3935,7 @@ function DevShellInner({
3623
3935
  )
3624
3936
  ] })
3625
3937
  ] }),
3626
- /* @__PURE__ */ jsx49("div", { className: "p-4", children: children({ trpc, theme }) })
3938
+ /* @__PURE__ */ jsx51("div", { className: "p-4", children: children({ trpc, theme }) })
3627
3939
  ] }) });
3628
3940
  }
3629
3941
  function DevShell({
@@ -3631,7 +3943,7 @@ function DevShell({
3631
3943
  serverUrl = "https://localhost:4443",
3632
3944
  title
3633
3945
  }) {
3634
- const [token, setToken] = useState12(getStoredToken);
3946
+ const [token, setToken] = useState14(getStoredToken);
3635
3947
  const handleLogin = useCallback8(
3636
3948
  async (username, password) => {
3637
3949
  const anonClient = createTRPCClient({
@@ -3654,9 +3966,9 @@ function DevShell({
3654
3966
  setToken(null);
3655
3967
  }, []);
3656
3968
  if (!token) {
3657
- return /* @__PURE__ */ jsx49(ThemeProvider, { children: /* @__PURE__ */ jsx49(LoginForm, { onLogin: handleLogin, serverUrl }) });
3969
+ return /* @__PURE__ */ jsx51(ThemeProvider, { children: /* @__PURE__ */ jsx51(LoginForm, { onLogin: handleLogin, serverUrl }) });
3658
3970
  }
3659
- return /* @__PURE__ */ jsx49(ThemeProvider, { children: /* @__PURE__ */ jsx49(
3971
+ return /* @__PURE__ */ jsx51(ThemeProvider, { children: /* @__PURE__ */ jsx51(
3660
3972
  DevShellInner,
3661
3973
  {
3662
3974
  serverUrl,
@@ -3697,6 +4009,7 @@ function mountAddonPage(PageComponent, options = {}) {
3697
4009
  export {
3698
4010
  AppShell,
3699
4011
  Badge,
4012
+ BottomSheet,
3700
4013
  Button,
3701
4014
  CLASS_COLORS,
3702
4015
  Card,
@@ -3733,6 +4046,7 @@ export {
3733
4046
  KeyValueList,
3734
4047
  Label,
3735
4048
  LoginForm,
4049
+ MobileDrawer,
3736
4050
  PageHeader,
3737
4051
  PipelineBuilder,
3738
4052
  PipelineRuntimeSelector,
@@ -3772,6 +4086,7 @@ export {
3772
4086
  statusIcons,
3773
4087
  themeToCss,
3774
4088
  useDevShell,
4089
+ useIsMobile,
3775
4090
  useThemeMode
3776
4091
  };
3777
4092
  //# sourceMappingURL=index.js.map