@almadar/ui 2.2.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,14 @@
1
- import { useTheme, useUISlots } from './chunk-DKQN5FVU.js';
1
+ import { useTheme, useUISlots } from './chunk-YLKXEXBP.js';
2
2
  import { useTranslate, useQuerySingleton } from './chunk-GOZKH7QW.js';
3
3
  import { useEventBus } from './chunk-YXZM3WCF.js';
4
4
  import { cn, debugGroup, debug, debugGroupEnd, getNestedValue, isDebugEnabled } from './chunk-KKCVDUK7.js';
5
+ import { isPortalSlot } from './chunk-K2D5D3WK.js';
5
6
  import { __publicField } from './chunk-PKBMQBKP.js';
6
- import * as React41 from 'react';
7
- import React41__default, { useCallback, useRef, useState, useLayoutEffect, useEffect, createContext, useMemo, useContext, Suspense } from 'react';
8
7
  import * as LucideIcons from 'lucide-react';
9
8
  import { Loader2, ChevronDown, X, Check, Copy, AlertCircle, User, Sun, Moon, FileQuestion, Inbox, Search, Info, XCircle, CheckCircle, AlertTriangle, ChevronRight, Filter, Plus, ChevronLeft, HelpCircle, ChevronUp, MoreHorizontal, TrendingUp, TrendingDown, Minus, ArrowLeft, Calendar, Tag, Clock, CheckCircle2, DollarSign, FileText, Package } from 'lucide-react';
10
9
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
+ import * as React50 from 'react';
11
+ import React50__default, { useCallback, useRef, useState, useLayoutEffect, useEffect, lazy, createContext, useMemo, useId, useContext, Suspense } from 'react';
11
12
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
12
13
  import { createPortal } from 'react-dom';
13
14
  import ReactMarkdown from 'react-markdown';
@@ -16,7 +17,88 @@ import remarkMath from 'remark-math';
16
17
  import rehypeKatex from 'rehype-katex';
17
18
  import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism';
18
19
  import dark from 'react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus';
20
+ import { MapContainer, TileLayer, Marker, Popup, useMap } from 'react-leaflet';
21
+ import L from 'leaflet';
22
+ import 'leaflet/dist/leaflet.css';
19
23
 
24
+ var iconAliases = {
25
+ "close": LucideIcons.X,
26
+ "trash": LucideIcons.Trash2,
27
+ "loader": LucideIcons.Loader2,
28
+ "stop": LucideIcons.Square,
29
+ "volume": LucideIcons.Volume2,
30
+ "volume-off": LucideIcons.VolumeX,
31
+ "refresh": LucideIcons.RefreshCw,
32
+ "share": LucideIcons.Share2,
33
+ "sort-asc": LucideIcons.ArrowUpNarrowWide,
34
+ "sort-desc": LucideIcons.ArrowDownNarrowWide
35
+ };
36
+ function kebabToPascal(name) {
37
+ return name.split("-").map((part) => {
38
+ if (/^\d+$/.test(part)) return part;
39
+ return part.charAt(0).toUpperCase() + part.slice(1);
40
+ }).join("");
41
+ }
42
+ var resolvedCache = /* @__PURE__ */ new Map();
43
+ function resolveIcon(name) {
44
+ const cached = resolvedCache.get(name);
45
+ if (cached) return cached;
46
+ const resolved = doResolve(name);
47
+ resolvedCache.set(name, resolved);
48
+ return resolved;
49
+ }
50
+ function doResolve(name) {
51
+ if (iconAliases[name]) return iconAliases[name];
52
+ const pascalName = kebabToPascal(name);
53
+ const directLookup = LucideIcons[pascalName];
54
+ if (directLookup && typeof directLookup === "object") return directLookup;
55
+ const asIs = LucideIcons[name];
56
+ if (asIs && typeof asIs === "object") return asIs;
57
+ return LucideIcons.HelpCircle;
58
+ }
59
+ var sizeClasses = {
60
+ xs: "w-3 h-3",
61
+ sm: "w-4 h-4",
62
+ md: "w-5 h-5",
63
+ lg: "w-6 h-6",
64
+ xl: "w-8 h-8"
65
+ };
66
+ var animationClasses = {
67
+ none: "",
68
+ spin: "animate-spin",
69
+ pulse: "animate-pulse"
70
+ };
71
+ var Icon = ({
72
+ icon,
73
+ name,
74
+ size = "md",
75
+ color,
76
+ animation = "none",
77
+ className,
78
+ strokeWidth,
79
+ style
80
+ }) => {
81
+ const IconComponent = icon ?? (name ? resolveIcon(name) : LucideIcons.HelpCircle);
82
+ const effectiveStrokeWidth = strokeWidth ?? void 0;
83
+ return /* @__PURE__ */ jsx(
84
+ IconComponent,
85
+ {
86
+ className: cn(
87
+ sizeClasses[size],
88
+ animationClasses[animation],
89
+ // Use theme's icon color or provided color
90
+ color ? color : "text-[var(--icon-color,currentColor)]",
91
+ className
92
+ ),
93
+ strokeWidth: effectiveStrokeWidth,
94
+ style: {
95
+ ...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
96
+ ...style
97
+ }
98
+ }
99
+ );
100
+ };
101
+ Icon.displayName = "Icon";
20
102
  var variantStyles = {
21
103
  primary: [
22
104
  "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
@@ -75,7 +157,7 @@ var iconSizeStyles = {
75
157
  md: "h-4 w-4",
76
158
  lg: "h-5 w-5"
77
159
  };
78
- var Button = React41__default.forwardRef(
160
+ var Button = React50__default.forwardRef(
79
161
  ({
80
162
  className,
81
163
  variant = "primary",
@@ -84,8 +166,8 @@ var Button = React41__default.forwardRef(
84
166
  disabled,
85
167
  leftIcon,
86
168
  rightIcon,
87
- icon: IconComponent,
88
- iconRight: IconRightComponent,
169
+ icon: iconProp,
170
+ iconRight: iconRightProp,
89
171
  action,
90
172
  actionPayload,
91
173
  label,
@@ -94,6 +176,8 @@ var Button = React41__default.forwardRef(
94
176
  ...props
95
177
  }, ref) => {
96
178
  const eventBus = useEventBus();
179
+ const IconComponent = typeof iconProp === "string" ? resolveIcon(iconProp) : iconProp;
180
+ const IconRightComponent = typeof iconRightProp === "string" ? resolveIcon(iconRightProp) : iconRightProp;
97
181
  const resolvedLeftIcon = leftIcon || IconComponent && /* @__PURE__ */ jsx(IconComponent, { className: iconSizeStyles[size] });
98
182
  const resolvedRightIcon = rightIcon || IconRightComponent && /* @__PURE__ */ jsx(IconRightComponent, { className: iconSizeStyles[size] });
99
183
  const handleClick = (e) => {
@@ -120,6 +204,7 @@ var Button = React41__default.forwardRef(
120
204
  ),
121
205
  onClick: handleClick,
122
206
  ...props,
207
+ "data-testid": props["data-testid"] ?? (action ? `action-${action}` : void 0),
123
208
  children: [
124
209
  isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : resolvedLeftIcon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: resolvedLeftIcon }),
125
210
  children || label,
@@ -130,7 +215,7 @@ var Button = React41__default.forwardRef(
130
215
  }
131
216
  );
132
217
  Button.displayName = "Button";
133
- var Input = React41__default.forwardRef(
218
+ var Input = React50__default.forwardRef(
134
219
  ({
135
220
  className,
136
221
  inputType,
@@ -242,7 +327,7 @@ var Input = React41__default.forwardRef(
242
327
  }
243
328
  );
244
329
  Input.displayName = "Input";
245
- var Label = React41__default.forwardRef(
330
+ var Label = React50__default.forwardRef(
246
331
  ({ className, required, children, ...props }, ref) => {
247
332
  return /* @__PURE__ */ jsxs(
248
333
  "label",
@@ -262,7 +347,7 @@ var Label = React41__default.forwardRef(
262
347
  }
263
348
  );
264
349
  Label.displayName = "Label";
265
- var Textarea = React41__default.forwardRef(
350
+ var Textarea = React50__default.forwardRef(
266
351
  ({ className, error, ...props }, ref) => {
267
352
  return /* @__PURE__ */ jsx(
268
353
  "textarea",
@@ -285,7 +370,7 @@ var Textarea = React41__default.forwardRef(
285
370
  }
286
371
  );
287
372
  Textarea.displayName = "Textarea";
288
- var Select = React41__default.forwardRef(
373
+ var Select = React50__default.forwardRef(
289
374
  ({ className, options, placeholder, error, ...props }, ref) => {
290
375
  return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
291
376
  /* @__PURE__ */ jsxs(
@@ -321,7 +406,7 @@ var Select = React41__default.forwardRef(
321
406
  }
322
407
  );
323
408
  Select.displayName = "Select";
324
- var Checkbox = React41__default.forwardRef(
409
+ var Checkbox = React50__default.forwardRef(
325
410
  ({ className, label, id, ...props }, ref) => {
326
411
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
327
412
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
@@ -387,7 +472,7 @@ var shadowStyles = {
387
472
  md: "shadow-[var(--shadow-main)]",
388
473
  lg: "shadow-[var(--shadow-lg)]"
389
474
  };
390
- var Card = React41__default.forwardRef(
475
+ var Card = React50__default.forwardRef(
391
476
  ({
392
477
  className,
393
478
  variant = "bordered",
@@ -423,9 +508,9 @@ var Card = React41__default.forwardRef(
423
508
  }
424
509
  );
425
510
  Card.displayName = "Card";
426
- var CardHeader = React41__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
511
+ var CardHeader = React50__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
427
512
  CardHeader.displayName = "CardHeader";
428
- var CardTitle = React41__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
513
+ var CardTitle = React50__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
429
514
  "h3",
430
515
  {
431
516
  ref,
@@ -438,11 +523,11 @@ var CardTitle = React41__default.forwardRef(({ className, ...props }, ref) => /*
438
523
  }
439
524
  ));
440
525
  CardTitle.displayName = "CardTitle";
441
- var CardContent = React41__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
526
+ var CardContent = React50__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
442
527
  CardContent.displayName = "CardContent";
443
528
  var CardBody = CardContent;
444
529
  CardBody.displayName = "CardBody";
445
- var CardFooter = React41__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
530
+ var CardFooter = React50__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
446
531
  "div",
447
532
  {
448
533
  ref,
@@ -488,19 +573,28 @@ var sizeStyles2 = {
488
573
  md: "px-2.5 py-1 text-sm",
489
574
  lg: "px-3 py-1.5 text-base"
490
575
  };
491
- var Badge = React41__default.forwardRef(
492
- ({ className, variant = "default", size = "sm", ...props }, ref) => {
493
- return /* @__PURE__ */ jsx(
576
+ var Badge = React50__default.forwardRef(
577
+ ({ className, variant = "default", size = "sm", label, icon, children, ...props }, ref) => {
578
+ const iconSizes2 = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
579
+ const resolvedIcon = typeof icon === "string" ? (() => {
580
+ const I = resolveIcon(icon);
581
+ return I ? /* @__PURE__ */ jsx(I, { className: iconSizes2[size] }) : null;
582
+ })() : icon;
583
+ return /* @__PURE__ */ jsxs(
494
584
  "span",
495
585
  {
496
586
  ref,
497
587
  className: cn(
498
- "inline-flex items-center font-bold rounded-[var(--radius-sm)]",
588
+ "inline-flex items-center gap-1 font-bold rounded-[var(--radius-sm)]",
499
589
  variantStyles3[variant],
500
590
  sizeStyles2[size],
501
591
  className
502
592
  ),
503
- ...props
593
+ ...props,
594
+ children: [
595
+ resolvedIcon,
596
+ children || label
597
+ ]
504
598
  }
505
599
  );
506
600
  }
@@ -512,7 +606,7 @@ var sizeStyles3 = {
512
606
  md: "h-6 w-6",
513
607
  lg: "h-8 w-8"
514
608
  };
515
- var Spinner = React41__default.forwardRef(
609
+ var Spinner = React50__default.forwardRef(
516
610
  ({ className, size = "md", ...props }, ref) => {
517
611
  return /* @__PURE__ */ jsx(
518
612
  "div",
@@ -526,7 +620,7 @@ var Spinner = React41__default.forwardRef(
526
620
  }
527
621
  );
528
622
  Spinner.displayName = "Spinner";
529
- var sizeClasses = {
623
+ var sizeClasses2 = {
530
624
  xs: "w-6 h-6 text-xs",
531
625
  sm: "w-8 h-8 text-sm",
532
626
  md: "w-10 h-10 text-base",
@@ -602,7 +696,7 @@ var Avatar = ({
602
696
  "relative inline-flex items-center justify-center",
603
697
  "bg-[var(--color-muted)] border-[length:var(--border-width)] border-[var(--color-border)]",
604
698
  "overflow-hidden",
605
- sizeClasses[size],
699
+ sizeClasses2[size],
606
700
  isClickable && "cursor-pointer hover:bg-[var(--color-surface-hover)] transition-colors",
607
701
  className
608
702
  ),
@@ -777,7 +871,7 @@ var positionStyles = {
777
871
  fixed: "fixed",
778
872
  sticky: "sticky"
779
873
  };
780
- var Box = React41__default.forwardRef(
874
+ var Box = React50__default.forwardRef(
781
875
  ({
782
876
  padding,
783
877
  paddingX,
@@ -969,157 +1063,6 @@ var Divider = ({
969
1063
  );
970
1064
  };
971
1065
  Divider.displayName = "Divider";
972
- var iconMap = {
973
- // Navigation & Actions
974
- "chevron-right": LucideIcons.ChevronRight,
975
- "chevron-left": LucideIcons.ChevronLeft,
976
- "chevron-down": LucideIcons.ChevronDown,
977
- "chevron-up": LucideIcons.ChevronUp,
978
- "arrow-right": LucideIcons.ArrowRight,
979
- "arrow-left": LucideIcons.ArrowLeft,
980
- "arrow-up": LucideIcons.ArrowUp,
981
- "arrow-down": LucideIcons.ArrowDown,
982
- "x": LucideIcons.X,
983
- "close": LucideIcons.X,
984
- "menu": LucideIcons.Menu,
985
- "more-vertical": LucideIcons.MoreVertical,
986
- "more-horizontal": LucideIcons.MoreHorizontal,
987
- // Status & Feedback
988
- "check": LucideIcons.Check,
989
- "check-circle": LucideIcons.CheckCircle,
990
- "alert-circle": LucideIcons.AlertCircle,
991
- "alert-triangle": LucideIcons.AlertTriangle,
992
- "info": LucideIcons.Info,
993
- "help-circle": LucideIcons.HelpCircle,
994
- "loader": LucideIcons.Loader2,
995
- // CRUD Operations
996
- "plus": LucideIcons.Plus,
997
- "minus": LucideIcons.Minus,
998
- "edit": LucideIcons.Edit,
999
- "pencil": LucideIcons.Pencil,
1000
- "trash": LucideIcons.Trash2,
1001
- "trash-2": LucideIcons.Trash2,
1002
- "save": LucideIcons.Save,
1003
- "copy": LucideIcons.Copy,
1004
- "clipboard": LucideIcons.Clipboard,
1005
- // Files & Documents
1006
- "file": LucideIcons.File,
1007
- "file-text": LucideIcons.FileText,
1008
- "folder": LucideIcons.Folder,
1009
- "folder-open": LucideIcons.FolderOpen,
1010
- "download": LucideIcons.Download,
1011
- "upload": LucideIcons.Upload,
1012
- "image": LucideIcons.Image,
1013
- // Communication
1014
- "mail": LucideIcons.Mail,
1015
- "message-circle": LucideIcons.MessageCircle,
1016
- "send": LucideIcons.Send,
1017
- "phone": LucideIcons.Phone,
1018
- // User & Profile
1019
- "user": LucideIcons.User,
1020
- "users": LucideIcons.Users,
1021
- "user-plus": LucideIcons.UserPlus,
1022
- "settings": LucideIcons.Settings,
1023
- "log-out": LucideIcons.LogOut,
1024
- "log-in": LucideIcons.LogIn,
1025
- // Search & Filter
1026
- "search": LucideIcons.Search,
1027
- "filter": LucideIcons.Filter,
1028
- "sort-asc": LucideIcons.ArrowUpNarrowWide,
1029
- "sort-desc": LucideIcons.ArrowDownNarrowWide,
1030
- // Layout & View
1031
- "grid": LucideIcons.Grid,
1032
- "list": LucideIcons.List,
1033
- "layout": LucideIcons.Layout,
1034
- "maximize": LucideIcons.Maximize,
1035
- "minimize": LucideIcons.Minimize,
1036
- "eye": LucideIcons.Eye,
1037
- "eye-off": LucideIcons.EyeOff,
1038
- // Media & Playback
1039
- "play": LucideIcons.Play,
1040
- "pause": LucideIcons.Pause,
1041
- "stop": LucideIcons.Square,
1042
- "volume": LucideIcons.Volume2,
1043
- "volume-off": LucideIcons.VolumeX,
1044
- // Time & Calendar
1045
- "calendar": LucideIcons.Calendar,
1046
- "clock": LucideIcons.Clock,
1047
- // Misc
1048
- "star": LucideIcons.Star,
1049
- "heart": LucideIcons.Heart,
1050
- "home": LucideIcons.Home,
1051
- "link": LucideIcons.Link,
1052
- "external-link": LucideIcons.ExternalLink,
1053
- "refresh": LucideIcons.RefreshCw,
1054
- "refresh-cw": LucideIcons.RefreshCw,
1055
- "zap": LucideIcons.Zap,
1056
- "bell": LucideIcons.Bell,
1057
- "bookmark": LucideIcons.Bookmark,
1058
- "share": LucideIcons.Share2,
1059
- "lock": LucideIcons.Lock,
1060
- "unlock": LucideIcons.Unlock,
1061
- "globe": LucideIcons.Globe,
1062
- "database": LucideIcons.Database,
1063
- "code": LucideIcons.Code,
1064
- "terminal": LucideIcons.Terminal
1065
- };
1066
- function resolveIcon(name) {
1067
- if (iconMap[name]) {
1068
- return iconMap[name];
1069
- }
1070
- const lowerName = name.toLowerCase();
1071
- if (iconMap[lowerName]) {
1072
- return iconMap[lowerName];
1073
- }
1074
- const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
1075
- if (iconMap[kebabName]) {
1076
- return iconMap[kebabName];
1077
- }
1078
- return LucideIcons.HelpCircle;
1079
- }
1080
- var sizeClasses2 = {
1081
- xs: "w-3 h-3",
1082
- sm: "w-4 h-4",
1083
- md: "w-5 h-5",
1084
- lg: "w-6 h-6",
1085
- xl: "w-8 h-8"
1086
- };
1087
- var animationClasses = {
1088
- none: "",
1089
- spin: "animate-spin",
1090
- pulse: "animate-pulse"
1091
- };
1092
- var Icon = ({
1093
- icon,
1094
- name,
1095
- size = "md",
1096
- color,
1097
- animation = "none",
1098
- className,
1099
- strokeWidth,
1100
- style
1101
- }) => {
1102
- const IconComponent = icon ?? (name ? resolveIcon(name) : LucideIcons.HelpCircle);
1103
- const effectiveStrokeWidth = strokeWidth ?? void 0;
1104
- return /* @__PURE__ */ jsx(
1105
- IconComponent,
1106
- {
1107
- className: cn(
1108
- sizeClasses2[size],
1109
- animationClasses[animation],
1110
- // Use theme's icon color or provided color
1111
- color ? color : "text-[var(--icon-color,currentColor)]",
1112
- className
1113
- ),
1114
- strokeWidth: effectiveStrokeWidth,
1115
- style: {
1116
- ...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
1117
- ...style
1118
- }
1119
- }
1120
- );
1121
- };
1122
- Icon.displayName = "Icon";
1123
1066
  var colorClasses = {
1124
1067
  default: "bg-[var(--color-primary)]",
1125
1068
  primary: "bg-[var(--color-primary)]",
@@ -1273,7 +1216,7 @@ var ProgressBar = ({
1273
1216
  return null;
1274
1217
  };
1275
1218
  ProgressBar.displayName = "ProgressBar";
1276
- var Radio = React41__default.forwardRef(
1219
+ var Radio = React50__default.forwardRef(
1277
1220
  ({
1278
1221
  label,
1279
1222
  helperText,
@@ -1377,7 +1320,7 @@ var Radio = React41__default.forwardRef(
1377
1320
  }
1378
1321
  );
1379
1322
  Radio.displayName = "Radio";
1380
- var Switch = React41.forwardRef(
1323
+ var Switch = React50.forwardRef(
1381
1324
  ({
1382
1325
  checked,
1383
1326
  defaultChecked = false,
@@ -1388,10 +1331,10 @@ var Switch = React41.forwardRef(
1388
1331
  name,
1389
1332
  className
1390
1333
  }, ref) => {
1391
- const [isChecked, setIsChecked] = React41.useState(
1334
+ const [isChecked, setIsChecked] = React50.useState(
1392
1335
  checked !== void 0 ? checked : defaultChecked
1393
1336
  );
1394
- React41.useEffect(() => {
1337
+ React50.useEffect(() => {
1395
1338
  if (checked !== void 0) {
1396
1339
  setIsChecked(checked);
1397
1340
  }
@@ -1626,6 +1569,8 @@ var variantStyles5 = {
1626
1569
  h4: "text-xl font-bold text-[var(--color-foreground)]",
1627
1570
  h5: "text-lg font-bold text-[var(--color-foreground)]",
1628
1571
  h6: "text-base font-bold text-[var(--color-foreground)]",
1572
+ heading: "text-2xl font-bold text-[var(--color-foreground)]",
1573
+ subheading: "text-lg font-semibold text-[var(--color-foreground)]",
1629
1574
  body1: "text-base font-normal text-[var(--color-foreground)]",
1630
1575
  body2: "text-sm font-normal text-[var(--color-foreground)]",
1631
1576
  body: "text-base font-normal text-[var(--color-foreground)]",
@@ -1658,6 +1603,8 @@ var defaultElements = {
1658
1603
  h4: "h4",
1659
1604
  h5: "h5",
1660
1605
  h6: "h6",
1606
+ heading: "h2",
1607
+ subheading: "h3",
1661
1608
  body1: "p",
1662
1609
  body2: "p",
1663
1610
  body: "p",
@@ -1951,7 +1898,7 @@ var Overlay = ({
1951
1898
  isVisible = true,
1952
1899
  onClick,
1953
1900
  className,
1954
- blur = true,
1901
+ blur = false,
1955
1902
  action
1956
1903
  }) => {
1957
1904
  const eventBus = useEventBus();
@@ -1966,7 +1913,7 @@ var Overlay = ({
1966
1913
  "div",
1967
1914
  {
1968
1915
  className: cn(
1969
- "fixed inset-0 z-40 bg-[var(--color-background)]/80",
1916
+ "fixed inset-0 z-40 bg-black/50",
1970
1917
  blur && "backdrop-blur-sm",
1971
1918
  className
1972
1919
  ),
@@ -1975,6 +1922,33 @@ var Overlay = ({
1975
1922
  }
1976
1923
  );
1977
1924
  };
1925
+ var FlipContainer = ({
1926
+ flipped,
1927
+ className,
1928
+ children,
1929
+ onClick
1930
+ }) => {
1931
+ return /* @__PURE__ */ jsx(
1932
+ Box,
1933
+ {
1934
+ className: cn("relative w-full cursor-pointer", className),
1935
+ style: { perspective: "1000px" },
1936
+ onClick,
1937
+ children: /* @__PURE__ */ jsx(
1938
+ Box,
1939
+ {
1940
+ className: "relative w-full h-full transition-transform duration-500",
1941
+ style: {
1942
+ transformStyle: "preserve-3d",
1943
+ transform: flipped ? "rotateY(180deg)" : "rotateY(0deg)"
1944
+ },
1945
+ children
1946
+ }
1947
+ )
1948
+ }
1949
+ );
1950
+ };
1951
+ FlipContainer.displayName = "FlipContainer";
1978
1952
  function toSharedContext(ctx) {
1979
1953
  return createMinimalContext(
1980
1954
  {
@@ -2031,8 +2005,8 @@ var LawReferenceTooltip = ({
2031
2005
  position = "top",
2032
2006
  className
2033
2007
  }) => {
2034
- const [isVisible, setIsVisible] = React41__default.useState(false);
2035
- const timeoutRef = React41__default.useRef(null);
2008
+ const [isVisible, setIsVisible] = React50__default.useState(false);
2009
+ const timeoutRef = React50__default.useRef(null);
2036
2010
  const handleMouseEnter = () => {
2037
2011
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2038
2012
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -2041,7 +2015,7 @@ var LawReferenceTooltip = ({
2041
2015
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2042
2016
  setIsVisible(false);
2043
2017
  };
2044
- React41__default.useEffect(() => {
2018
+ React50__default.useEffect(() => {
2045
2019
  return () => {
2046
2020
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2047
2021
  };
@@ -2135,6 +2109,79 @@ var LawReferenceTooltip = ({
2135
2109
  );
2136
2110
  };
2137
2111
  LawReferenceTooltip.displayName = "LawReferenceTooltip";
2112
+ var DAY_ABBREVIATIONS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2113
+ function DayCell({
2114
+ date,
2115
+ isToday = false,
2116
+ onClick,
2117
+ className
2118
+ }) {
2119
+ const handleClick = useCallback(() => {
2120
+ onClick?.(date);
2121
+ }, [onClick, date]);
2122
+ const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
2123
+ return /* @__PURE__ */ jsxs(
2124
+ Box,
2125
+ {
2126
+ className: cn(
2127
+ "p-2 text-center cursor-pointer hover:bg-[var(--color-muted)] transition-colors",
2128
+ isToday && "bg-blue-500/10",
2129
+ className
2130
+ ),
2131
+ onClick: handleClick,
2132
+ children: [
2133
+ /* @__PURE__ */ jsx(
2134
+ Typography,
2135
+ {
2136
+ variant: "small",
2137
+ className: cn(
2138
+ "font-medium",
2139
+ isToday ? "text-blue-600" : "text-[var(--color-muted-foreground)]"
2140
+ ),
2141
+ children: dayAbbr
2142
+ }
2143
+ ),
2144
+ /* @__PURE__ */ jsx(
2145
+ Box,
2146
+ {
2147
+ display: "flex",
2148
+ rounded: "full",
2149
+ className: cn(
2150
+ "h-8 w-8 mx-auto items-center justify-center",
2151
+ isToday && "bg-blue-600 text-white"
2152
+ ),
2153
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
2154
+ }
2155
+ )
2156
+ ]
2157
+ }
2158
+ );
2159
+ }
2160
+ DayCell.displayName = "DayCell";
2161
+ function TimeSlotCell({
2162
+ time,
2163
+ onClick,
2164
+ className,
2165
+ children,
2166
+ isOccupied = false
2167
+ }) {
2168
+ const handleClick = useCallback(() => {
2169
+ onClick?.(time);
2170
+ }, [onClick, time]);
2171
+ return /* @__PURE__ */ jsx(
2172
+ Box,
2173
+ {
2174
+ className: cn(
2175
+ "p-1 min-h-[60px] cursor-pointer hover:bg-[var(--color-muted)] transition-colors",
2176
+ isOccupied && "bg-[var(--color-muted)]/30",
2177
+ className
2178
+ ),
2179
+ onClick: handleClick,
2180
+ children
2181
+ }
2182
+ );
2183
+ }
2184
+ TimeSlotCell.displayName = "TimeSlotCell";
2138
2185
  var heartIcon = (filled, size) => /* @__PURE__ */ jsx(
2139
2186
  "svg",
2140
2187
  {
@@ -2217,9 +2264,9 @@ function ScoreDisplay({
2217
2264
  animated = true,
2218
2265
  locale = "en-US"
2219
2266
  }) {
2220
- const [displayValue, setDisplayValue] = React41.useState(value);
2221
- const [isAnimating, setIsAnimating] = React41.useState(false);
2222
- React41.useEffect(() => {
2267
+ const [displayValue, setDisplayValue] = React50.useState(value);
2268
+ const [isAnimating, setIsAnimating] = React50.useState(false);
2269
+ React50.useEffect(() => {
2223
2270
  if (!animated || displayValue === value) {
2224
2271
  setDisplayValue(value);
2225
2272
  return;
@@ -2292,9 +2339,9 @@ function ControlButton({
2292
2339
  className
2293
2340
  }) {
2294
2341
  const eventBus = useEventBus();
2295
- const [isPressed, setIsPressed] = React41.useState(false);
2342
+ const [isPressed, setIsPressed] = React50.useState(false);
2296
2343
  const actualPressed = pressed ?? isPressed;
2297
- const handlePointerDown = React41.useCallback(
2344
+ const handlePointerDown = React50.useCallback(
2298
2345
  (e) => {
2299
2346
  e.preventDefault();
2300
2347
  if (disabled) return;
@@ -2304,7 +2351,7 @@ function ControlButton({
2304
2351
  },
2305
2352
  [disabled, pressEvent, eventBus, onPress]
2306
2353
  );
2307
- const handlePointerUp = React41.useCallback(
2354
+ const handlePointerUp = React50.useCallback(
2308
2355
  (e) => {
2309
2356
  e.preventDefault();
2310
2357
  if (disabled) return;
@@ -2314,7 +2361,7 @@ function ControlButton({
2314
2361
  },
2315
2362
  [disabled, releaseEvent, eventBus, onRelease]
2316
2363
  );
2317
- const handlePointerLeave = React41.useCallback(
2364
+ const handlePointerLeave = React50.useCallback(
2318
2365
  (e) => {
2319
2366
  if (isPressed) {
2320
2367
  setIsPressed(false);
@@ -2542,7 +2589,7 @@ var ErrorState = ({
2542
2589
  );
2543
2590
  };
2544
2591
  ErrorState.displayName = "ErrorState";
2545
- var ErrorBoundary = class extends React41__default.Component {
2592
+ var ErrorBoundary = class extends React50__default.Component {
2546
2593
  constructor(props) {
2547
2594
  super(props);
2548
2595
  __publicField(this, "reset", () => {
@@ -2946,7 +2993,7 @@ var variantIconColors = {
2946
2993
  warning: "text-[var(--color-warning)]",
2947
2994
  error: "text-[var(--color-error)]"
2948
2995
  };
2949
- var iconMap2 = {
2996
+ var iconMap = {
2950
2997
  info: Info,
2951
2998
  success: CheckCircle,
2952
2999
  warning: AlertTriangle,
@@ -2985,7 +3032,7 @@ var Alert = ({
2985
3032
  /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx(
2986
3033
  Icon,
2987
3034
  {
2988
- icon: iconMap2[variant],
3035
+ icon: iconMap[variant],
2989
3036
  size: "md",
2990
3037
  className: variantIconColors[variant]
2991
3038
  }
@@ -3997,7 +4044,7 @@ function getColsClass(cols) {
3997
4044
  }
3998
4045
  return classes.join(" ");
3999
4046
  }
4000
- var Grid2 = ({
4047
+ var Grid = ({
4001
4048
  cols = 1,
4002
4049
  rows,
4003
4050
  gap = "md",
@@ -4034,7 +4081,7 @@ var Grid2 = ({
4034
4081
  }
4035
4082
  );
4036
4083
  };
4037
- Grid2.displayName = "Grid";
4084
+ Grid.displayName = "Grid";
4038
4085
  var InputGroup = ({
4039
4086
  leftAddon,
4040
4087
  rightAddon,
@@ -4089,7 +4136,7 @@ var InputGroup = ({
4089
4136
  ] });
4090
4137
  };
4091
4138
  InputGroup.displayName = "InputGroup";
4092
- var Menu2 = ({
4139
+ var Menu = ({
4093
4140
  trigger,
4094
4141
  items,
4095
4142
  position = "bottom-left",
@@ -4150,8 +4197,8 @@ var Menu2 = ({
4150
4197
  "bottom-start": "top-full left-0 mt-2",
4151
4198
  "bottom-end": "top-full right-0 mt-2"
4152
4199
  };
4153
- const triggerChild = React41__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx("span", { children: trigger });
4154
- const triggerElement = React41__default.cloneElement(
4200
+ const triggerChild = React50__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx("span", { children: trigger });
4201
+ const triggerElement = React50__default.cloneElement(
4155
4202
  triggerChild,
4156
4203
  {
4157
4204
  ref: triggerRef,
@@ -4247,7 +4294,7 @@ var Menu2 = ({
4247
4294
  )
4248
4295
  ] });
4249
4296
  };
4250
- Menu2.displayName = "Menu";
4297
+ Menu.displayName = "Menu";
4251
4298
  var sizeClasses4 = {
4252
4299
  sm: "max-w-md",
4253
4300
  md: "max-w-lg",
@@ -4355,6 +4402,7 @@ var Modal = ({
4355
4402
  {
4356
4403
  type: "button",
4357
4404
  onClick: handleClose,
4405
+ "data-event": "CLOSE",
4358
4406
  className: cn(
4359
4407
  "p-1 transition-colors rounded-[var(--radius-sm)]",
4360
4408
  "hover:bg-[var(--color-muted)]"
@@ -4612,8 +4660,8 @@ var Popover = ({
4612
4660
  onMouseEnter: handleOpen,
4613
4661
  onMouseLeave: handleClose
4614
4662
  };
4615
- const childElement = React41__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
4616
- const triggerElement = React41__default.cloneElement(
4663
+ const childElement = React50__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
4664
+ const triggerElement = React50__default.cloneElement(
4617
4665
  childElement,
4618
4666
  {
4619
4667
  ref: triggerRef,
@@ -5193,7 +5241,7 @@ var variantClasses = {
5193
5241
  info: "bg-[var(--color-card)] border-[length:var(--border-width)] border-[var(--color-info)]",
5194
5242
  warning: "bg-[var(--color-card)] border-[length:var(--border-width)] border-[var(--color-warning)]"
5195
5243
  };
5196
- var iconMap3 = {
5244
+ var iconMap2 = {
5197
5245
  success: CheckCircle,
5198
5246
  error: AlertCircle,
5199
5247
  info: Info,
@@ -5251,7 +5299,7 @@ var Toast = ({
5251
5299
  /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx(
5252
5300
  Icon,
5253
5301
  {
5254
- icon: iconMap3[variant],
5302
+ icon: iconMap2[variant],
5255
5303
  size: "md",
5256
5304
  className: iconColors[variant]
5257
5305
  }
@@ -5343,8 +5391,8 @@ var Tooltip = ({
5343
5391
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
5344
5392
  };
5345
5393
  }, []);
5346
- const triggerElement = React41__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
5347
- const trigger = React41__default.cloneElement(triggerElement, {
5394
+ const triggerElement = React50__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
5395
+ const trigger = React50__default.cloneElement(triggerElement, {
5348
5396
  ref: triggerRef,
5349
5397
  onMouseEnter: handleMouseEnter,
5350
5398
  onMouseLeave: handleMouseLeave,
@@ -5593,7 +5641,7 @@ var WizardProgress = ({
5593
5641
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: steps.map((step, index) => {
5594
5642
  const isActive = index === currentStep;
5595
5643
  const isCompleted = index < currentStep;
5596
- return /* @__PURE__ */ jsxs(React41__default.Fragment, { children: [
5644
+ return /* @__PURE__ */ jsxs(React50__default.Fragment, { children: [
5597
5645
  /* @__PURE__ */ jsx(
5598
5646
  "button",
5599
5647
  {
@@ -5723,7 +5771,7 @@ var WizardNavigation = ({
5723
5771
  );
5724
5772
  };
5725
5773
  WizardNavigation.displayName = "WizardNavigation";
5726
- var MarkdownContent = React41__default.memo(
5774
+ var MarkdownContent = React50__default.memo(
5727
5775
  ({ content, direction, className }) => {
5728
5776
  const { t: _t } = useTranslate();
5729
5777
  return /* @__PURE__ */ jsx(
@@ -5824,7 +5872,7 @@ var MarkdownContent = React41__default.memo(
5824
5872
  (prev, next) => prev.content === next.content && prev.className === next.className && prev.direction === next.direction
5825
5873
  );
5826
5874
  MarkdownContent.displayName = "MarkdownContent";
5827
- var CodeBlock = React41__default.memo(
5875
+ var CodeBlock = React50__default.memo(
5828
5876
  ({
5829
5877
  code,
5830
5878
  language = "text",
@@ -6049,6 +6097,156 @@ var ScaledDiagram = ({
6049
6097
  );
6050
6098
  };
6051
6099
  ScaledDiagram.displayName = "ScaledDiagram";
6100
+ function getStartOfWeek(date) {
6101
+ const d = new Date(date);
6102
+ const day = d.getDay();
6103
+ const diff = d.getDate() - day + (day === 0 ? -6 : 1);
6104
+ d.setDate(diff);
6105
+ d.setHours(0, 0, 0, 0);
6106
+ return d;
6107
+ }
6108
+ function getWeekDays(start) {
6109
+ const days = [];
6110
+ for (let i = 0; i < 7; i++) {
6111
+ const day = new Date(start);
6112
+ day.setDate(start.getDate() + i);
6113
+ days.push(day);
6114
+ }
6115
+ return days;
6116
+ }
6117
+ function generateDefaultTimeSlots() {
6118
+ const slots = [];
6119
+ for (let hour = 9; hour <= 17; hour++) {
6120
+ slots.push(`${hour.toString().padStart(2, "0")}:00`);
6121
+ }
6122
+ return slots;
6123
+ }
6124
+ function eventInSlot(event, day, slotTime) {
6125
+ const eventStart = new Date(event.startTime);
6126
+ const [slotHour, slotMinute] = slotTime.split(":").map(Number);
6127
+ return eventStart.toDateString() === day.toDateString() && eventStart.getHours() === slotHour && eventStart.getMinutes() === slotMinute;
6128
+ }
6129
+ function CalendarGrid({
6130
+ weekStart,
6131
+ timeSlots,
6132
+ events = [],
6133
+ onSlotClick,
6134
+ onDayClick,
6135
+ onEventClick,
6136
+ className
6137
+ }) {
6138
+ const resolvedWeekStart = useMemo(
6139
+ () => weekStart ? getStartOfWeek(weekStart) : getStartOfWeek(/* @__PURE__ */ new Date()),
6140
+ [weekStart]
6141
+ );
6142
+ const weekDays = useMemo(
6143
+ () => getWeekDays(resolvedWeekStart),
6144
+ [resolvedWeekStart]
6145
+ );
6146
+ const resolvedTimeSlots = useMemo(
6147
+ () => timeSlots ?? generateDefaultTimeSlots(),
6148
+ [timeSlots]
6149
+ );
6150
+ const handleSlotClick = useCallback(
6151
+ (day, time) => {
6152
+ onSlotClick?.(day, time);
6153
+ },
6154
+ [onSlotClick]
6155
+ );
6156
+ const handleEventClick = useCallback(
6157
+ (event, e) => {
6158
+ e.stopPropagation();
6159
+ onEventClick?.(event);
6160
+ },
6161
+ [onEventClick]
6162
+ );
6163
+ const eventsForDayCount = useCallback(
6164
+ (day) => events.filter(
6165
+ (ev) => new Date(ev.startTime).toDateString() === day.toDateString()
6166
+ ).length,
6167
+ [events]
6168
+ );
6169
+ const renderEvent = (event) => /* @__PURE__ */ jsx(
6170
+ Box,
6171
+ {
6172
+ rounded: "md",
6173
+ padding: "xs",
6174
+ border: true,
6175
+ className: cn(
6176
+ "cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
6177
+ event.color ? event.color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
6178
+ ),
6179
+ onClick: (e) => handleEventClick(event, e),
6180
+ children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
6181
+ },
6182
+ event.id
6183
+ );
6184
+ return /* @__PURE__ */ jsx(Box, { className: cn("overflow-x-auto", className), children: /* @__PURE__ */ jsxs(Box, { className: "min-w-[800px]", children: [
6185
+ /* @__PURE__ */ jsxs(Box, { className: "grid grid-cols-8 border-b border-[var(--color-border)]", children: [
6186
+ /* @__PURE__ */ jsx(Box, { className: "p-2" }),
6187
+ weekDays.map((day) => {
6188
+ const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
6189
+ const count = eventsForDayCount(day);
6190
+ return /* @__PURE__ */ jsxs(
6191
+ Box,
6192
+ {
6193
+ className: "border-l border-[var(--color-border)]",
6194
+ children: [
6195
+ /* @__PURE__ */ jsx(
6196
+ DayCell,
6197
+ {
6198
+ date: day,
6199
+ isToday,
6200
+ onClick: onDayClick
6201
+ }
6202
+ ),
6203
+ count > 0 && /* @__PURE__ */ jsx(Box, { className: "text-center pb-1", children: /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: count }) })
6204
+ ]
6205
+ },
6206
+ day.toISOString()
6207
+ );
6208
+ })
6209
+ ] }),
6210
+ /* @__PURE__ */ jsx(Box, { className: "max-h-[500px] overflow-y-auto", children: resolvedTimeSlots.map((time) => /* @__PURE__ */ jsxs(
6211
+ Box,
6212
+ {
6213
+ className: "grid grid-cols-8 border-b border-[var(--color-border)]",
6214
+ children: [
6215
+ /* @__PURE__ */ jsx(Box, { className: "p-2 text-right pr-3", children: /* @__PURE__ */ jsx(
6216
+ Typography,
6217
+ {
6218
+ variant: "small",
6219
+ className: "text-[var(--color-muted-foreground)]",
6220
+ children: time
6221
+ }
6222
+ ) }),
6223
+ weekDays.map((day) => {
6224
+ const slotEvents = events.filter(
6225
+ (ev) => eventInSlot(ev, day, time)
6226
+ );
6227
+ const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
6228
+ return /* @__PURE__ */ jsx(
6229
+ TimeSlotCell,
6230
+ {
6231
+ time,
6232
+ isOccupied: slotEvents.length > 0,
6233
+ onClick: () => handleSlotClick(day, time),
6234
+ className: cn(
6235
+ "border-l border-[var(--color-border)]",
6236
+ isToday && "bg-blue-50/30"
6237
+ ),
6238
+ children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: slotEvents.map(renderEvent) })
6239
+ },
6240
+ `${day.toISOString()}-${time}`
6241
+ );
6242
+ })
6243
+ ]
6244
+ },
6245
+ time
6246
+ )) })
6247
+ ] }) });
6248
+ }
6249
+ CalendarGrid.displayName = "CalendarGrid";
6052
6250
  var RepeatableFormSection = ({
6053
6251
  sectionType,
6054
6252
  title,
@@ -6423,26 +6621,1356 @@ var FormSectionHeader = ({
6423
6621
  );
6424
6622
  };
6425
6623
  FormSectionHeader.displayName = "FormSectionHeader";
6426
-
6427
- // components/organisms/types.ts
6428
- var EntityDisplayEvents = {
6429
- SORT: "SORT",
6430
- PAGINATE: "PAGINATE",
6431
- SEARCH: "SEARCH",
6432
- FILTER: "FILTER",
6433
- CLEAR_FILTERS: "CLEAR_FILTERS",
6434
- SELECT: "SELECT",
6624
+ var FlipCard = ({
6625
+ front,
6626
+ back,
6627
+ flipped = false,
6628
+ onFlip,
6629
+ className,
6630
+ height = "h-64"
6631
+ }) => {
6632
+ return /* @__PURE__ */ jsxs(
6633
+ FlipContainer,
6634
+ {
6635
+ flipped,
6636
+ className: cn(height, className),
6637
+ onClick: onFlip,
6638
+ children: [
6639
+ /* @__PURE__ */ jsx(
6640
+ Box,
6641
+ {
6642
+ className: "absolute inset-0 w-full h-full rounded-lg shadow-lg flex items-center justify-center p-6",
6643
+ style: { backfaceVisibility: "hidden", transform: "rotateY(0deg)" },
6644
+ children: front
6645
+ }
6646
+ ),
6647
+ /* @__PURE__ */ jsx(
6648
+ Box,
6649
+ {
6650
+ className: "absolute inset-0 w-full h-full rounded-lg shadow-lg flex items-center justify-center p-6",
6651
+ style: { backfaceVisibility: "hidden", transform: "rotateY(180deg)" },
6652
+ children: back
6653
+ }
6654
+ )
6655
+ ]
6656
+ }
6657
+ );
6658
+ };
6659
+ FlipCard.displayName = "FlipCard";
6660
+ var DEFAULT_OPTIONS = [
6661
+ { label: "1W", value: "week" },
6662
+ { label: "1M", value: "month" },
6663
+ { label: "3M", value: "3months" },
6664
+ { label: "1Y", value: "year" }
6665
+ ];
6666
+ var DateRangeSelector = ({
6667
+ options = DEFAULT_OPTIONS,
6668
+ selected = "month",
6669
+ onSelect,
6670
+ className
6671
+ }) => {
6672
+ return /* @__PURE__ */ jsx(HStack, { gap: "xs", className: cn(className), children: options.map((option) => /* @__PURE__ */ jsx(
6673
+ Button,
6674
+ {
6675
+ variant: selected === option.value ? "primary" : "ghost",
6676
+ size: "sm",
6677
+ onClick: () => onSelect?.(option.value),
6678
+ children: option.label
6679
+ },
6680
+ option.value
6681
+ )) });
6682
+ };
6683
+ DateRangeSelector.displayName = "DateRangeSelector";
6684
+ var ChartLegend = ({
6685
+ items,
6686
+ className,
6687
+ direction = "horizontal"
6688
+ }) => {
6689
+ const Wrapper = direction === "horizontal" ? HStack : VStack;
6690
+ return /* @__PURE__ */ jsx(Wrapper, { gap: "md", className: cn("flex-wrap", className), children: items.map((item) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
6691
+ /* @__PURE__ */ jsx(
6692
+ Box,
6693
+ {
6694
+ className: "rounded-full shrink-0",
6695
+ style: {
6696
+ width: 10,
6697
+ height: 10,
6698
+ backgroundColor: item.color
6699
+ }
6700
+ }
6701
+ ),
6702
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-[var(--color-muted-foreground)]", children: item.label })
6703
+ ] }, item.label)) });
6704
+ };
6705
+ ChartLegend.displayName = "ChartLegend";
6706
+ var LineChart = ({
6707
+ data,
6708
+ width = 400,
6709
+ height = 200,
6710
+ showGrid = true,
6711
+ showValues = false,
6712
+ showArea = true,
6713
+ lineColor = "var(--color-primary)",
6714
+ areaColor = "var(--color-primary)",
6715
+ className
6716
+ }) => {
6717
+ const gradientId = useId();
6718
+ const sortedData = useMemo(() => {
6719
+ return [...data].sort(
6720
+ (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
6721
+ );
6722
+ }, [data]);
6723
+ const points = useMemo(() => {
6724
+ if (sortedData.length === 0) return [];
6725
+ const values = sortedData.map((d) => d.value);
6726
+ const minVal = Math.min(...values);
6727
+ const maxVal = Math.max(...values);
6728
+ const range = maxVal - minVal || 1;
6729
+ const padding = 20;
6730
+ const chartWidth = width - padding * 2;
6731
+ const chartHeight = height - padding * 2;
6732
+ return sortedData.map((point, index) => ({
6733
+ x: padding + index / (sortedData.length - 1 || 1) * chartWidth,
6734
+ y: padding + chartHeight - (point.value - minVal) / range * chartHeight,
6735
+ value: point.value,
6736
+ label: point.label
6737
+ }));
6738
+ }, [sortedData, width, height]);
6739
+ const linePath = useMemo(() => {
6740
+ if (points.length === 0) return "";
6741
+ return points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
6742
+ }, [points]);
6743
+ const areaPath = useMemo(() => {
6744
+ if (points.length === 0 || !showArea) return "";
6745
+ const bottom = height - 20;
6746
+ const first = points[0];
6747
+ const last = points[points.length - 1];
6748
+ return `${linePath} L ${last.x} ${bottom} L ${first.x} ${bottom} Z`;
6749
+ }, [linePath, points, height, showArea]);
6750
+ if (data.length === 0) {
6751
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center text-[var(--color-muted-foreground)]", className), style: { width, height }, children: "No data" });
6752
+ }
6753
+ return /* @__PURE__ */ jsx(Box, { className: cn(className), children: /* @__PURE__ */ jsxs(
6754
+ "svg",
6755
+ {
6756
+ viewBox: `0 0 ${width} ${height}`,
6757
+ width: "100%",
6758
+ height: "100%",
6759
+ preserveAspectRatio: "xMidYMid meet",
6760
+ children: [
6761
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
6762
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.3" }),
6763
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
6764
+ ] }) }),
6765
+ showGrid && /* @__PURE__ */ jsxs(Fragment, { children: [
6766
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: height * 0.25, x2: width - 20, y2: height * 0.25, stroke: "var(--color-border, #e5e7eb)", strokeWidth: "1" }),
6767
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: height * 0.5, x2: width - 20, y2: height * 0.5, stroke: "var(--color-border, #e5e7eb)", strokeWidth: "1" }),
6768
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: height * 0.75, x2: width - 20, y2: height * 0.75, stroke: "var(--color-border, #e5e7eb)", strokeWidth: "1" })
6769
+ ] }),
6770
+ showArea && areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: `url(#${gradientId})` }),
6771
+ linePath && /* @__PURE__ */ jsx(
6772
+ "path",
6773
+ {
6774
+ d: linePath,
6775
+ fill: "none",
6776
+ stroke: lineColor,
6777
+ strokeWidth: "2",
6778
+ strokeLinejoin: "round",
6779
+ strokeLinecap: "round"
6780
+ }
6781
+ ),
6782
+ points.map((point, index) => /* @__PURE__ */ jsx(
6783
+ "circle",
6784
+ {
6785
+ cx: point.x,
6786
+ cy: point.y,
6787
+ r: "4",
6788
+ fill: lineColor,
6789
+ stroke: "var(--color-background, white)",
6790
+ strokeWidth: "2"
6791
+ },
6792
+ index
6793
+ )),
6794
+ showValues && points.map((point, index) => /* @__PURE__ */ jsx(
6795
+ "text",
6796
+ {
6797
+ x: point.x,
6798
+ y: point.y - 10,
6799
+ textAnchor: "middle",
6800
+ fontSize: "11",
6801
+ fill: "var(--color-foreground, currentColor)",
6802
+ children: point.label ?? point.value
6803
+ },
6804
+ `label-${index}`
6805
+ ))
6806
+ ]
6807
+ }
6808
+ ) });
6809
+ };
6810
+ LineChart.displayName = "LineChart";
6811
+ var sizeMap4 = {
6812
+ sm: { dot: 6, active: 8 },
6813
+ md: { dot: 8, active: 10 },
6814
+ lg: { dot: 10, active: 14 }
6815
+ };
6816
+ var stateColors = {
6817
+ active: "var(--color-primary)",
6818
+ complete: "var(--color-success, #22c55e)",
6819
+ pending: "var(--color-muted, #d4d4d8)"
6820
+ };
6821
+ var ProgressDots = ({
6822
+ count,
6823
+ currentIndex,
6824
+ getState,
6825
+ onDotClick,
6826
+ className,
6827
+ size = "md"
6828
+ }) => {
6829
+ const defaultGetState = useCallback(
6830
+ (index) => {
6831
+ if (index === currentIndex) return "active";
6832
+ return "pending";
6833
+ },
6834
+ [currentIndex]
6835
+ );
6836
+ const resolveState = getState ?? defaultGetState;
6837
+ const dims = sizeMap4[size];
6838
+ return /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", className: cn(className), children: Array.from({ length: count }, (_, index) => {
6839
+ const state = resolveState(index);
6840
+ const isActive = state === "active";
6841
+ const dotSize = isActive ? dims.active : dims.dot;
6842
+ return /* @__PURE__ */ jsx(
6843
+ Box,
6844
+ {
6845
+ className: cn(
6846
+ "rounded-full transition-all duration-200",
6847
+ onDotClick && "cursor-pointer"
6848
+ ),
6849
+ style: {
6850
+ width: dotSize,
6851
+ height: dotSize,
6852
+ backgroundColor: stateColors[state],
6853
+ transform: isActive ? "scale(1.2)" : "scale(1)"
6854
+ },
6855
+ onClick: onDotClick ? () => onDotClick(index) : void 0
6856
+ },
6857
+ index
6858
+ );
6859
+ }) });
6860
+ };
6861
+ ProgressDots.displayName = "ProgressDots";
6862
+ var sizeMap5 = {
6863
+ sm: { button: "sm", gap: "gap-0.5", container: "w-28" },
6864
+ md: { button: "md", gap: "gap-1", container: "w-40" },
6865
+ lg: { button: "lg", gap: "gap-1.5", container: "w-52" }
6866
+ };
6867
+ var arrowIcons = {
6868
+ up: "\u25B2",
6869
+ down: "\u25BC",
6870
+ left: "\u25C0",
6871
+ right: "\u25B6"
6872
+ };
6873
+ function DPad({
6874
+ onDirection,
6875
+ directionEvent,
6876
+ size = "md",
6877
+ includeDiagonals = false,
6878
+ className,
6879
+ disabled
6880
+ }) {
6881
+ const eventBus = useEventBus();
6882
+ const sizes = sizeMap5[size];
6883
+ const [activeDirections, setActiveDirections] = React50.useState(/* @__PURE__ */ new Set());
6884
+ const handlePress = React50.useCallback(
6885
+ (direction) => {
6886
+ setActiveDirections((prev) => new Set(prev).add(direction));
6887
+ if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
6888
+ onDirection?.(direction, true);
6889
+ },
6890
+ [directionEvent, eventBus, onDirection]
6891
+ );
6892
+ const handleRelease = React50.useCallback(
6893
+ (direction) => {
6894
+ setActiveDirections((prev) => {
6895
+ const next = new Set(prev);
6896
+ next.delete(direction);
6897
+ return next;
6898
+ });
6899
+ if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: false });
6900
+ onDirection?.(direction, false);
6901
+ },
6902
+ [directionEvent, eventBus, onDirection]
6903
+ );
6904
+ const createButton = (direction) => /* @__PURE__ */ jsx(
6905
+ ControlButton,
6906
+ {
6907
+ icon: arrowIcons[direction],
6908
+ size: sizes.button,
6909
+ variant: "secondary",
6910
+ pressed: activeDirections.has(direction),
6911
+ onPress: () => handlePress(direction),
6912
+ onRelease: () => handleRelease(direction),
6913
+ disabled
6914
+ },
6915
+ direction
6916
+ );
6917
+ return /* @__PURE__ */ jsxs("div", { className: cn("inline-grid grid-cols-3", sizes.gap, sizes.container, className), children: [
6918
+ /* @__PURE__ */ jsx("div", {}),
6919
+ createButton("up"),
6920
+ /* @__PURE__ */ jsx("div", {}),
6921
+ createButton("left"),
6922
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 rounded-full bg-gray-700 border-2 border-gray-600" }) }),
6923
+ createButton("right"),
6924
+ /* @__PURE__ */ jsx("div", {}),
6925
+ createButton("down"),
6926
+ /* @__PURE__ */ jsx("div", {})
6927
+ ] });
6928
+ }
6929
+ DPad.displayName = "DPad";
6930
+ var sizeMap6 = {
6931
+ sm: "sm",
6932
+ md: "md",
6933
+ lg: "lg"
6934
+ };
6935
+ var layoutMap = {
6936
+ horizontal: "flex flex-row gap-2",
6937
+ vertical: "flex flex-col gap-2",
6938
+ diamond: "grid grid-cols-3 gap-1"
6939
+ };
6940
+ function ActionButtons({
6941
+ buttons,
6942
+ onAction,
6943
+ actionEvent,
6944
+ layout = "horizontal",
6945
+ size = "md",
6946
+ className,
6947
+ disabled
6948
+ }) {
6949
+ const eventBus = useEventBus();
6950
+ const [activeButtons, setActiveButtons] = React50.useState(/* @__PURE__ */ new Set());
6951
+ const handlePress = React50.useCallback(
6952
+ (id) => {
6953
+ setActiveButtons((prev) => new Set(prev).add(id));
6954
+ if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
6955
+ onAction?.(id, true);
6956
+ },
6957
+ [actionEvent, eventBus, onAction]
6958
+ );
6959
+ const handleRelease = React50.useCallback(
6960
+ (id) => {
6961
+ setActiveButtons((prev) => {
6962
+ const next = new Set(prev);
6963
+ next.delete(id);
6964
+ return next;
6965
+ });
6966
+ if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: false });
6967
+ onAction?.(id, false);
6968
+ },
6969
+ [actionEvent, eventBus, onAction]
6970
+ );
6971
+ if (layout === "diamond" && buttons.length === 4) {
6972
+ const [top, right, bottom, left] = buttons;
6973
+ return /* @__PURE__ */ jsxs("div", { className: cn(layoutMap[layout], className), children: [
6974
+ /* @__PURE__ */ jsx("div", {}),
6975
+ /* @__PURE__ */ jsx(
6976
+ ControlButton,
6977
+ {
6978
+ icon: top.icon,
6979
+ label: top.label,
6980
+ size: sizeMap6[size],
6981
+ variant: top.variant,
6982
+ pressed: activeButtons.has(top.id),
6983
+ onPress: () => handlePress(top.id),
6984
+ onRelease: () => handleRelease(top.id),
6985
+ disabled
6986
+ }
6987
+ ),
6988
+ /* @__PURE__ */ jsx("div", {}),
6989
+ /* @__PURE__ */ jsx(
6990
+ ControlButton,
6991
+ {
6992
+ icon: left.icon,
6993
+ label: left.label,
6994
+ size: sizeMap6[size],
6995
+ variant: left.variant,
6996
+ pressed: activeButtons.has(left.id),
6997
+ onPress: () => handlePress(left.id),
6998
+ onRelease: () => handleRelease(left.id),
6999
+ disabled
7000
+ }
7001
+ ),
7002
+ /* @__PURE__ */ jsx("div", {}),
7003
+ /* @__PURE__ */ jsx(
7004
+ ControlButton,
7005
+ {
7006
+ icon: right.icon,
7007
+ label: right.label,
7008
+ size: sizeMap6[size],
7009
+ variant: right.variant,
7010
+ pressed: activeButtons.has(right.id),
7011
+ onPress: () => handlePress(right.id),
7012
+ onRelease: () => handleRelease(right.id),
7013
+ disabled
7014
+ }
7015
+ ),
7016
+ /* @__PURE__ */ jsx("div", {}),
7017
+ /* @__PURE__ */ jsx(
7018
+ ControlButton,
7019
+ {
7020
+ icon: bottom.icon,
7021
+ label: bottom.label,
7022
+ size: sizeMap6[size],
7023
+ variant: bottom.variant,
7024
+ pressed: activeButtons.has(bottom.id),
7025
+ onPress: () => handlePress(bottom.id),
7026
+ onRelease: () => handleRelease(bottom.id),
7027
+ disabled
7028
+ }
7029
+ ),
7030
+ /* @__PURE__ */ jsx("div", {})
7031
+ ] });
7032
+ }
7033
+ return /* @__PURE__ */ jsx("div", { className: cn(layoutMap[layout], className), children: buttons.map((button) => /* @__PURE__ */ jsx(
7034
+ ControlButton,
7035
+ {
7036
+ icon: button.icon,
7037
+ label: button.label,
7038
+ size: sizeMap6[size],
7039
+ variant: button.variant,
7040
+ pressed: activeButtons.has(button.id),
7041
+ onPress: () => handlePress(button.id),
7042
+ onRelease: () => handleRelease(button.id),
7043
+ disabled
7044
+ },
7045
+ button.id
7046
+ )) });
7047
+ }
7048
+ ActionButtons.displayName = "ActionButtons";
7049
+ var sizeMap7 = {
7050
+ sm: "text-xs px-2 py-1",
7051
+ md: "text-sm px-3 py-1.5",
7052
+ lg: "text-base px-4 py-2"
7053
+ };
7054
+ var variantMap2 = {
7055
+ default: "bg-gray-800/80 border-gray-700",
7056
+ primary: "bg-blue-900/80 border-blue-700",
7057
+ success: "bg-green-900/80 border-green-700",
7058
+ warning: "bg-yellow-900/80 border-yellow-700",
7059
+ danger: "bg-red-900/80 border-red-700"
7060
+ };
7061
+ function StatBadge({
7062
+ label,
7063
+ value = 0,
7064
+ max,
7065
+ format = "number",
7066
+ icon,
7067
+ size = "md",
7068
+ variant = "default",
7069
+ className,
7070
+ // Ignored config props (used for schema binding)
7071
+ source: _source,
7072
+ field: _field
7073
+ }) {
7074
+ const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
7075
+ return /* @__PURE__ */ jsxs(
7076
+ "div",
7077
+ {
7078
+ className: cn(
7079
+ "inline-flex items-center gap-2 rounded-lg border backdrop-blur-sm",
7080
+ sizeMap7[size] ?? sizeMap7.md,
7081
+ variantMap2[variant] ?? variantMap2.default,
7082
+ className
7083
+ ),
7084
+ children: [
7085
+ icon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? (() => {
7086
+ const I = resolveIcon(icon);
7087
+ return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : icon;
7088
+ })() : icon }),
7089
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400 font-medium", children: label }),
7090
+ format === "hearts" && max && /* @__PURE__ */ jsx(
7091
+ HealthBar,
7092
+ {
7093
+ current: numValue,
7094
+ max,
7095
+ format: "hearts",
7096
+ size: size === "lg" ? "md" : "sm"
7097
+ }
7098
+ ),
7099
+ format === "bar" && max && /* @__PURE__ */ jsx(
7100
+ HealthBar,
7101
+ {
7102
+ current: numValue,
7103
+ max,
7104
+ format: "bar",
7105
+ size: size === "lg" ? "md" : "sm"
7106
+ }
7107
+ ),
7108
+ format === "number" && /* @__PURE__ */ jsx(
7109
+ ScoreDisplay,
7110
+ {
7111
+ value: numValue,
7112
+ size: size === "lg" ? "md" : "sm",
7113
+ animated: true
7114
+ }
7115
+ ),
7116
+ format === "text" && /* @__PURE__ */ jsx("span", { className: "font-bold text-white", children: value })
7117
+ ]
7118
+ }
7119
+ );
7120
+ }
7121
+ StatBadge.displayName = "StatBadge";
7122
+ var GROUP_COLORS = [
7123
+ "#3b82f6",
7124
+ // blue-500
7125
+ "#10b981",
7126
+ // emerald-500
7127
+ "#f59e0b",
7128
+ // amber-500
7129
+ "#ef4444",
7130
+ // red-500
7131
+ "#8b5cf6",
7132
+ // violet-500
7133
+ "#ec4899",
7134
+ // pink-500
7135
+ "#06b6d4",
7136
+ // cyan-500
7137
+ "#84cc16"
7138
+ // lime-500
7139
+ ];
7140
+ var DEFAULT_NODE_COLOR = "#3b82f6";
7141
+ var DEFAULT_EDGE_COLOR = "#9ca3af";
7142
+ var DEFAULT_NODE_SIZE = 8;
7143
+ function resolveNodeColor(node, groups) {
7144
+ if (node.color) return node.color;
7145
+ if (node.group) {
7146
+ const idx = groups.indexOf(node.group);
7147
+ return GROUP_COLORS[idx % GROUP_COLORS.length];
7148
+ }
7149
+ return DEFAULT_NODE_COLOR;
7150
+ }
7151
+ var GraphView = ({
7152
+ nodes,
7153
+ edges,
7154
+ onNodeClick,
7155
+ onNodeHover,
7156
+ width: propWidth,
7157
+ height: propHeight,
7158
+ className,
7159
+ showLabels = true,
7160
+ zoomToFit = true
7161
+ }) => {
7162
+ const containerRef = useRef(null);
7163
+ const animRef = useRef(0);
7164
+ const [simNodes, setSimNodes] = useState([]);
7165
+ const [settled, setSettled] = useState(false);
7166
+ const [hoveredId, setHoveredId] = useState(null);
7167
+ const [dimensions, setDimensions] = useState({ width: propWidth ?? 600, height: propHeight ?? 400 });
7168
+ const w = propWidth ?? dimensions.width;
7169
+ const h = propHeight ?? dimensions.height;
7170
+ const groups = useMemo(
7171
+ () => [...new Set(nodes.map((n) => n.group).filter((g) => Boolean(g)))],
7172
+ [nodes]
7173
+ );
7174
+ const connectedIds = useMemo(() => {
7175
+ if (!hoveredId) return /* @__PURE__ */ new Set();
7176
+ const connected = /* @__PURE__ */ new Set([hoveredId]);
7177
+ for (const edge of edges) {
7178
+ if (edge.source === hoveredId) connected.add(edge.target);
7179
+ if (edge.target === hoveredId) connected.add(edge.source);
7180
+ }
7181
+ return connected;
7182
+ }, [hoveredId, edges]);
7183
+ useEffect(() => {
7184
+ if (propWidth && propHeight) return;
7185
+ const el = containerRef.current;
7186
+ if (!el) return;
7187
+ const update = () => {
7188
+ setDimensions({
7189
+ width: el.clientWidth || 600,
7190
+ height: el.clientHeight || 400
7191
+ });
7192
+ };
7193
+ update();
7194
+ window.addEventListener("resize", update);
7195
+ return () => window.removeEventListener("resize", update);
7196
+ }, [propWidth, propHeight]);
7197
+ useEffect(() => {
7198
+ if (nodes.length === 0) {
7199
+ setSimNodes([]);
7200
+ setSettled(true);
7201
+ return;
7202
+ }
7203
+ const initialNodes = nodes.map((n, idx) => {
7204
+ const angle = idx / nodes.length * 2 * Math.PI;
7205
+ const radius = Math.min(w, h) * 0.3;
7206
+ return {
7207
+ id: n.id,
7208
+ label: n.label,
7209
+ color: resolveNodeColor(n, groups),
7210
+ size: n.size ?? DEFAULT_NODE_SIZE,
7211
+ group: n.group,
7212
+ x: w / 2 + radius * Math.cos(angle) + (Math.random() - 0.5) * 20,
7213
+ y: h / 2 + radius * Math.sin(angle) + (Math.random() - 0.5) * 20,
7214
+ vx: 0,
7215
+ vy: 0,
7216
+ fx: 0,
7217
+ fy: 0
7218
+ };
7219
+ });
7220
+ let iterations = 0;
7221
+ const maxIterations = 120;
7222
+ let currentNodes = initialNodes;
7223
+ const tick = () => {
7224
+ const centerX = w / 2;
7225
+ const centerY = h / 2;
7226
+ for (const node of currentNodes) {
7227
+ node.fx = 0;
7228
+ node.fy = 0;
7229
+ }
7230
+ for (let i = 0; i < currentNodes.length; i++) {
7231
+ for (let j = i + 1; j < currentNodes.length; j++) {
7232
+ const a = currentNodes[i];
7233
+ const b = currentNodes[j];
7234
+ const dx = b.x - a.x;
7235
+ const dy = b.y - a.y;
7236
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
7237
+ const force = 800 / (dist * dist);
7238
+ const fx = dx / dist * force;
7239
+ const fy = dy / dist * force;
7240
+ a.fx -= fx;
7241
+ a.fy -= fy;
7242
+ b.fx += fx;
7243
+ b.fy += fy;
7244
+ }
7245
+ }
7246
+ for (const edge of edges) {
7247
+ const source = currentNodes.find((n) => n.id === edge.source);
7248
+ const target = currentNodes.find((n) => n.id === edge.target);
7249
+ if (!source || !target) continue;
7250
+ const dx = target.x - source.x;
7251
+ const dy = target.y - source.y;
7252
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
7253
+ const force = (dist - 100) * 0.05;
7254
+ const fx = dx / dist * force;
7255
+ const fy = dy / dist * force;
7256
+ source.fx += fx;
7257
+ source.fy += fy;
7258
+ target.fx -= fx;
7259
+ target.fy -= fy;
7260
+ }
7261
+ for (const node of currentNodes) {
7262
+ node.fx += (centerX - node.x) * 0.01;
7263
+ node.fy += (centerY - node.y) * 0.01;
7264
+ }
7265
+ const damping = 0.85;
7266
+ const margin = 40;
7267
+ for (const node of currentNodes) {
7268
+ node.vx = (node.vx + node.fx) * damping;
7269
+ node.vy = (node.vy + node.fy) * damping;
7270
+ node.x += node.vx;
7271
+ node.y += node.vy;
7272
+ node.x = Math.max(margin, Math.min(w - margin, node.x));
7273
+ node.y = Math.max(margin, Math.min(h - margin, node.y));
7274
+ }
7275
+ iterations++;
7276
+ setSimNodes([...currentNodes]);
7277
+ if (iterations < maxIterations) {
7278
+ animRef.current = requestAnimationFrame(tick);
7279
+ } else {
7280
+ setSettled(true);
7281
+ }
7282
+ };
7283
+ setSettled(false);
7284
+ animRef.current = requestAnimationFrame(tick);
7285
+ return () => {
7286
+ cancelAnimationFrame(animRef.current);
7287
+ };
7288
+ }, [nodes, edges, w, h, groups]);
7289
+ const viewBox = useMemo(() => {
7290
+ if (!zoomToFit || !settled || simNodes.length === 0) {
7291
+ return `0 0 ${w} ${h}`;
7292
+ }
7293
+ const pad = 60;
7294
+ let minX = Infinity;
7295
+ let minY = Infinity;
7296
+ let maxX = -Infinity;
7297
+ let maxY = -Infinity;
7298
+ for (const node of simNodes) {
7299
+ minX = Math.min(minX, node.x - node.size);
7300
+ minY = Math.min(minY, node.y - node.size);
7301
+ maxX = Math.max(maxX, node.x + node.size);
7302
+ maxY = Math.max(maxY, node.y + node.size);
7303
+ }
7304
+ const fitW = maxX - minX + pad * 2;
7305
+ const fitH = maxY - minY + pad * 2;
7306
+ return `${minX - pad} ${minY - pad} ${fitW} ${fitH}`;
7307
+ }, [zoomToFit, settled, simNodes, w, h]);
7308
+ const nodeMap = useMemo(() => {
7309
+ const map = /* @__PURE__ */ new Map();
7310
+ for (const n of simNodes) {
7311
+ map.set(n.id, n);
7312
+ }
7313
+ return map;
7314
+ }, [simNodes]);
7315
+ const handleNodeMouseEnter = useCallback(
7316
+ (node) => {
7317
+ setHoveredId(node.id);
7318
+ if (onNodeHover) {
7319
+ onNodeHover({ id: node.id, label: node.label, color: node.color, size: node.size, group: node.group });
7320
+ }
7321
+ },
7322
+ [onNodeHover]
7323
+ );
7324
+ const handleNodeMouseLeave = useCallback(() => {
7325
+ setHoveredId(null);
7326
+ if (onNodeHover) {
7327
+ onNodeHover(null);
7328
+ }
7329
+ }, [onNodeHover]);
7330
+ const handleNodeClickInternal = useCallback(
7331
+ (node) => {
7332
+ if (onNodeClick) {
7333
+ onNodeClick({ id: node.id, label: node.label, color: node.color, size: node.size, group: node.group });
7334
+ }
7335
+ },
7336
+ [onNodeClick]
7337
+ );
7338
+ if (nodes.length === 0) {
7339
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center", className), style: { width: w, height: h }, children: /* @__PURE__ */ jsx(Box, { className: "text-[var(--color-muted-foreground)] text-sm", children: "No graph data" }) });
7340
+ }
7341
+ return /* @__PURE__ */ jsx(
7342
+ Box,
7343
+ {
7344
+ ref: containerRef,
7345
+ className: cn("relative overflow-hidden rounded-lg border border-[var(--color-border)] bg-[var(--color-card)]", className),
7346
+ style: { width: propWidth ?? "100%", height: h },
7347
+ children: /* @__PURE__ */ jsxs(
7348
+ "svg",
7349
+ {
7350
+ width: "100%",
7351
+ height: "100%",
7352
+ viewBox,
7353
+ preserveAspectRatio: "xMidYMid meet",
7354
+ children: [
7355
+ edges.map((edge, idx) => {
7356
+ const source = nodeMap.get(edge.source);
7357
+ const target = nodeMap.get(edge.target);
7358
+ if (!source || !target) return null;
7359
+ const isHighlighted = hoveredId ? connectedIds.has(edge.source) && connectedIds.has(edge.target) : true;
7360
+ return /* @__PURE__ */ jsxs("g", { children: [
7361
+ /* @__PURE__ */ jsx(
7362
+ "line",
7363
+ {
7364
+ x1: source.x,
7365
+ y1: source.y,
7366
+ x2: target.x,
7367
+ y2: target.y,
7368
+ stroke: edge.color ?? DEFAULT_EDGE_COLOR,
7369
+ strokeWidth: 1.5,
7370
+ opacity: isHighlighted ? 0.8 : 0.15
7371
+ }
7372
+ ),
7373
+ showLabels && edge.label && /* @__PURE__ */ jsx(
7374
+ "text",
7375
+ {
7376
+ x: (source.x + target.x) / 2,
7377
+ y: (source.y + target.y) / 2 - 6,
7378
+ textAnchor: "middle",
7379
+ fill: "var(--color-muted-foreground)",
7380
+ fontSize: 9,
7381
+ opacity: isHighlighted ? 0.9 : 0.2,
7382
+ children: edge.label
7383
+ }
7384
+ )
7385
+ ] }, `edge-${idx}`);
7386
+ }),
7387
+ simNodes.map((node) => {
7388
+ const isHighlighted = hoveredId ? connectedIds.has(node.id) : true;
7389
+ const isHovered = hoveredId === node.id;
7390
+ return /* @__PURE__ */ jsxs(
7391
+ "g",
7392
+ {
7393
+ style: { cursor: onNodeClick ? "pointer" : "default" },
7394
+ onMouseEnter: () => handleNodeMouseEnter(node),
7395
+ onMouseLeave: handleNodeMouseLeave,
7396
+ onClick: () => handleNodeClickInternal(node),
7397
+ children: [
7398
+ /* @__PURE__ */ jsx(
7399
+ "circle",
7400
+ {
7401
+ cx: node.x,
7402
+ cy: node.y,
7403
+ r: isHovered ? node.size * 1.4 : node.size,
7404
+ fill: node.color,
7405
+ opacity: isHighlighted ? 1 : 0.3,
7406
+ stroke: isHovered ? "#ffffff" : "none",
7407
+ strokeWidth: isHovered ? 2 : 0
7408
+ }
7409
+ ),
7410
+ showLabels && /* @__PURE__ */ jsx(
7411
+ "text",
7412
+ {
7413
+ x: node.x,
7414
+ y: node.y + node.size + 12,
7415
+ textAnchor: "middle",
7416
+ fill: "var(--color-foreground)",
7417
+ fontSize: 11,
7418
+ fontWeight: isHovered ? "bold" : "normal",
7419
+ opacity: isHighlighted ? 0.9 : 0.2,
7420
+ children: node.label ?? node.id
7421
+ }
7422
+ )
7423
+ ]
7424
+ },
7425
+ node.id
7426
+ );
7427
+ })
7428
+ ]
7429
+ }
7430
+ )
7431
+ }
7432
+ );
7433
+ };
7434
+ GraphView.displayName = "GraphView";
7435
+ var defaultIcon = L.icon({
7436
+ iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
7437
+ iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png",
7438
+ shadowUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png",
7439
+ iconSize: [25, 41],
7440
+ iconAnchor: [12, 41],
7441
+ popupAnchor: [1, -34],
7442
+ shadowSize: [41, 41]
7443
+ });
7444
+ L.Marker.prototype.options.icon = defaultIcon;
7445
+ function MapUpdater({ centerLat, centerLng, zoom }) {
7446
+ const map = useMap();
7447
+ const prevRef = useRef({ centerLat, centerLng, zoom });
7448
+ useEffect(() => {
7449
+ const prev = prevRef.current;
7450
+ if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
7451
+ map.setView([centerLat, centerLng], zoom);
7452
+ prevRef.current = { centerLat, centerLng, zoom };
7453
+ }
7454
+ }, [map, centerLat, centerLng, zoom]);
7455
+ return null;
7456
+ }
7457
+ function MapClickHandler({ onMapClick }) {
7458
+ const map = useMap();
7459
+ useEffect(() => {
7460
+ if (!onMapClick) return;
7461
+ const handler = (e) => {
7462
+ onMapClick(e.latlng.lat, e.latlng.lng);
7463
+ };
7464
+ map.on("click", handler);
7465
+ return () => {
7466
+ map.off("click", handler);
7467
+ };
7468
+ }, [map, onMapClick]);
7469
+ return null;
7470
+ }
7471
+ function MapView({
7472
+ markers = [],
7473
+ centerLat = 51.505,
7474
+ centerLng = -0.09,
7475
+ zoom = 13,
7476
+ height = "400px",
7477
+ onMarkerClick,
7478
+ onMapClick,
7479
+ mapClickEvent,
7480
+ markerClickEvent,
7481
+ showClickedPin = false,
7482
+ className,
7483
+ showAttribution = true
7484
+ }) {
7485
+ const eventBus = useEventBus();
7486
+ const [clickedPosition, setClickedPosition] = useState(null);
7487
+ const handleMapClick = useCallback((lat, lng) => {
7488
+ if (showClickedPin) {
7489
+ setClickedPosition({ lat, lng });
7490
+ }
7491
+ onMapClick?.(lat, lng);
7492
+ if (mapClickEvent) {
7493
+ eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
7494
+ }
7495
+ }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
7496
+ const handleMarkerClick = useCallback((marker) => {
7497
+ onMarkerClick?.(marker);
7498
+ if (markerClickEvent) {
7499
+ eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
7500
+ }
7501
+ }, [onMarkerClick, markerClickEvent, eventBus]);
7502
+ return /* @__PURE__ */ jsx(
7503
+ Box,
7504
+ {
7505
+ className: cn("relative w-full overflow-hidden rounded-lg", className),
7506
+ style: { height },
7507
+ "data-testid": "map-view",
7508
+ children: /* @__PURE__ */ jsxs(
7509
+ MapContainer,
7510
+ {
7511
+ center: [centerLat, centerLng],
7512
+ zoom,
7513
+ style: { height: "100%", width: "100%" },
7514
+ attributionControl: showAttribution,
7515
+ children: [
7516
+ /* @__PURE__ */ jsx(
7517
+ TileLayer,
7518
+ {
7519
+ url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
7520
+ attribution: showAttribution ? '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>' : void 0
7521
+ }
7522
+ ),
7523
+ /* @__PURE__ */ jsx(MapUpdater, { centerLat, centerLng, zoom }),
7524
+ /* @__PURE__ */ jsx(MapClickHandler, { onMapClick: handleMapClick }),
7525
+ showClickedPin && clickedPosition && /* @__PURE__ */ jsx(Marker, { position: [clickedPosition.lat, clickedPosition.lng], children: /* @__PURE__ */ jsx(Popup, { children: /* @__PURE__ */ jsxs(Typography, { variant: "body2", children: [
7526
+ clickedPosition.lat.toFixed(5),
7527
+ ", ",
7528
+ clickedPosition.lng.toFixed(5)
7529
+ ] }) }) }),
7530
+ markers.map((marker) => /* @__PURE__ */ jsx(
7531
+ Marker,
7532
+ {
7533
+ position: [marker.lat, marker.lng],
7534
+ eventHandlers: onMarkerClick || markerClickEvent ? { click: () => handleMarkerClick(marker) } : void 0,
7535
+ children: marker.label ? /* @__PURE__ */ jsxs(Popup, { children: [
7536
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", children: marker.label }),
7537
+ marker.category ? /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: marker.category }) : null
7538
+ ] }) : null
7539
+ },
7540
+ marker.id
7541
+ ))
7542
+ ]
7543
+ }
7544
+ )
7545
+ }
7546
+ );
7547
+ }
7548
+ function fieldLabel(key) {
7549
+ return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
7550
+ }
7551
+ function statusVariant(value) {
7552
+ const v = value.toLowerCase();
7553
+ if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
7554
+ if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
7555
+ if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
7556
+ if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
7557
+ return "default";
7558
+ }
7559
+ function formatDate(value) {
7560
+ if (!value) return "";
7561
+ const d = new Date(String(value));
7562
+ if (isNaN(d.getTime())) return String(value);
7563
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
7564
+ }
7565
+ function formatValue(value, format) {
7566
+ if (value === void 0 || value === null) return "";
7567
+ switch (format) {
7568
+ case "date":
7569
+ return formatDate(value);
7570
+ case "currency":
7571
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
7572
+ case "number":
7573
+ return typeof value === "number" ? value.toLocaleString() : String(value);
7574
+ case "percent":
7575
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
7576
+ case "boolean":
7577
+ return value ? "Yes" : "No";
7578
+ default:
7579
+ return String(value);
7580
+ }
7581
+ }
7582
+ var gapStyles5 = {
7583
+ none: "gap-0",
7584
+ sm: "gap-2",
7585
+ md: "gap-4",
7586
+ lg: "gap-6",
7587
+ xl: "gap-8"
7588
+ };
7589
+ var DataGrid = ({
7590
+ entity,
7591
+ fields: fieldsProp,
7592
+ columns: columnsProp,
7593
+ itemActions,
7594
+ cols,
7595
+ gap = "md",
7596
+ minCardWidth = 280,
7597
+ className,
7598
+ isLoading = false,
7599
+ error = null,
7600
+ imageField
7601
+ }) => {
7602
+ const eventBus = useEventBus();
7603
+ const { t } = useTranslate();
7604
+ const fields = fieldsProp ?? columnsProp ?? [];
7605
+ const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
7606
+ const titleField = fields.find((f) => f.variant === "h3" || f.variant === "h4") ?? fields[0];
7607
+ const badgeFields = fields.filter((f) => f.variant === "badge" && f !== titleField);
7608
+ const bodyFields = fields.filter((f) => f !== titleField && !badgeFields.includes(f));
7609
+ const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
7610
+ const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
7611
+ const handleActionClick = (action, itemData) => (e) => {
7612
+ e.stopPropagation();
7613
+ eventBus.emit(`UI:${action.event}`, { row: itemData });
7614
+ };
7615
+ const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
7616
+ const colsClass = cols ? {
7617
+ 1: "grid-cols-1",
7618
+ 2: "sm:grid-cols-2",
7619
+ 3: "sm:grid-cols-2 lg:grid-cols-3",
7620
+ 4: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
7621
+ 5: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
7622
+ 6: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
7623
+ }[cols] : void 0;
7624
+ if (isLoading) {
7625
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
7626
+ }
7627
+ if (error) {
7628
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
7629
+ }
7630
+ if (data.length === 0) {
7631
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
7632
+ }
7633
+ return /* @__PURE__ */ jsx(
7634
+ Box,
7635
+ {
7636
+ className: cn("grid", gapStyles5[gap], colsClass, className),
7637
+ style: gridTemplateColumns ? { gridTemplateColumns } : void 0,
7638
+ children: data.map((item, index) => {
7639
+ const itemData = item;
7640
+ const id = itemData.id || String(index);
7641
+ const titleValue = getNestedValue(itemData, titleField?.name ?? "");
7642
+ return /* @__PURE__ */ jsxs(
7643
+ Box,
7644
+ {
7645
+ "data-entity-row": true,
7646
+ className: cn(
7647
+ "bg-[var(--color-card)] rounded-[var(--radius-lg)]",
7648
+ "border border-[var(--color-border)]",
7649
+ "shadow-[var(--shadow-sm)] hover:shadow-[var(--shadow-hover)]",
7650
+ "hover:border-[var(--color-primary)] transition-all",
7651
+ "flex flex-col"
7652
+ ),
7653
+ children: [
7654
+ imageField && (() => {
7655
+ const imgUrl = getNestedValue(itemData, imageField);
7656
+ if (!imgUrl || typeof imgUrl !== "string") return null;
7657
+ return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-[var(--radius-lg)]", children: /* @__PURE__ */ jsx(
7658
+ "img",
7659
+ {
7660
+ src: imgUrl,
7661
+ alt: titleValue !== void 0 ? String(titleValue) : "",
7662
+ className: "w-full h-full object-cover",
7663
+ loading: "lazy"
7664
+ }
7665
+ ) });
7666
+ })(),
7667
+ /* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
7668
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
7669
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7670
+ titleField?.icon && /* @__PURE__ */ jsx(Icon, { name: titleField.icon, size: "sm", className: "text-[var(--color-primary)] flex-shrink-0" }),
7671
+ /* @__PURE__ */ jsx(
7672
+ Typography,
7673
+ {
7674
+ variant: titleField?.variant === "h3" ? "h3" : "h4",
7675
+ className: "font-semibold truncate",
7676
+ children: String(titleValue)
7677
+ }
7678
+ )
7679
+ ] }),
7680
+ badgeFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
7681
+ const val = getNestedValue(itemData, field.name);
7682
+ if (val === void 0 || val === null) return null;
7683
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7684
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
7685
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant(String(val)), children: String(val) })
7686
+ ] }, field.name);
7687
+ }) })
7688
+ ] }),
7689
+ dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxs(
7690
+ Button,
7691
+ {
7692
+ variant: "ghost",
7693
+ size: "sm",
7694
+ onClick: handleActionClick(action, itemData),
7695
+ "data-testid": `action-${action.event}`,
7696
+ className: "text-[var(--color-error)] hover:bg-[var(--color-error)]/10 px-2",
7697
+ children: [
7698
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs" }),
7699
+ action.label
7700
+ ]
7701
+ },
7702
+ idx
7703
+ )) })
7704
+ ] }) }),
7705
+ bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
7706
+ const value = getNestedValue(itemData, field.name);
7707
+ if (value === void 0 || value === null || value === "") return null;
7708
+ if (field.format === "boolean") {
7709
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
7710
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7711
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
7712
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
7713
+ ] }),
7714
+ /* @__PURE__ */ jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
7715
+ ] }, field.name);
7716
+ }
7717
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
7718
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7719
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
7720
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
7721
+ ] }),
7722
+ /* @__PURE__ */ jsx(
7723
+ Typography,
7724
+ {
7725
+ variant: field.variant === "caption" ? "caption" : "small",
7726
+ className: "text-right truncate max-w-[60%]",
7727
+ children: formatValue(value, field.format)
7728
+ }
7729
+ )
7730
+ ] }, field.name);
7731
+ }) }) }),
7732
+ primaryActions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 mt-auto border-t border-[var(--color-border)]", children: /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "justify-end", children: primaryActions.map((action, idx) => /* @__PURE__ */ jsxs(
7733
+ Button,
7734
+ {
7735
+ variant: action.variant === "primary" ? "primary" : "ghost",
7736
+ size: "sm",
7737
+ onClick: handleActionClick(action, itemData),
7738
+ "data-testid": `action-${action.event}`,
7739
+ children: [
7740
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
7741
+ action.label
7742
+ ]
7743
+ },
7744
+ idx
7745
+ )) }) })
7746
+ ]
7747
+ },
7748
+ id
7749
+ );
7750
+ })
7751
+ }
7752
+ );
7753
+ };
7754
+ DataGrid.displayName = "DataGrid";
7755
+ function fieldLabel2(key) {
7756
+ return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
7757
+ }
7758
+ function statusVariant2(value) {
7759
+ const v = value.toLowerCase();
7760
+ if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
7761
+ if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
7762
+ if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
7763
+ if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
7764
+ return "default";
7765
+ }
7766
+ function formatDate2(value) {
7767
+ if (!value) return "";
7768
+ const d = new Date(String(value));
7769
+ if (isNaN(d.getTime())) return String(value);
7770
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
7771
+ }
7772
+ function formatValue2(value, format) {
7773
+ if (value === void 0 || value === null) return "";
7774
+ switch (format) {
7775
+ case "date":
7776
+ return formatDate2(value);
7777
+ case "currency":
7778
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
7779
+ case "number":
7780
+ return typeof value === "number" ? value.toLocaleString() : String(value);
7781
+ case "percent":
7782
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
7783
+ case "boolean":
7784
+ return value ? "Yes" : "No";
7785
+ default:
7786
+ return String(value);
7787
+ }
7788
+ }
7789
+ var DataList = ({
7790
+ entity,
7791
+ fields: fieldsProp,
7792
+ columns: columnsProp,
7793
+ itemActions,
7794
+ gap = "none",
7795
+ variant = "default",
7796
+ className,
7797
+ isLoading = false,
7798
+ error = null
7799
+ }) => {
7800
+ const eventBus = useEventBus();
7801
+ const { t } = useTranslate();
7802
+ const fields = fieldsProp ?? columnsProp ?? [];
7803
+ const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
7804
+ const titleField = fields.find((f) => f.variant === "h3" || f.variant === "h4") ?? fields[0];
7805
+ const badgeFields = fields.filter((f) => f.variant === "badge" && f !== titleField);
7806
+ const progressFields = fields.filter((f) => f.variant === "progress");
7807
+ const bodyFields = fields.filter(
7808
+ (f) => f !== titleField && !badgeFields.includes(f) && !progressFields.includes(f)
7809
+ );
7810
+ const handleActionClick = (action, itemData) => (e) => {
7811
+ e.stopPropagation();
7812
+ eventBus.emit(`UI:${action.event}`, { row: itemData });
7813
+ };
7814
+ if (isLoading) {
7815
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
7816
+ }
7817
+ if (error) {
7818
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
7819
+ }
7820
+ if (data.length === 0) {
7821
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
7822
+ }
7823
+ const gapClass = {
7824
+ none: "",
7825
+ sm: "gap-1",
7826
+ md: "gap-2",
7827
+ lg: "gap-4"
7828
+ }[gap];
7829
+ const isCard = variant === "card";
7830
+ const isCompact = variant === "compact";
7831
+ return /* @__PURE__ */ jsx(
7832
+ Box,
7833
+ {
7834
+ className: cn(
7835
+ isCard && "bg-[var(--color-card)] rounded-[var(--radius-xl)] border border-[var(--color-border)] shadow-[var(--shadow-lg)] overflow-hidden",
7836
+ !isCard && gapClass,
7837
+ className
7838
+ ),
7839
+ children: data.map((item, index) => {
7840
+ const itemData = item;
7841
+ const id = itemData.id || String(index);
7842
+ const titleValue = getNestedValue(itemData, titleField?.name ?? "");
7843
+ const isLast = index === data.length - 1;
7844
+ return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, children: [
7845
+ /* @__PURE__ */ jsxs(
7846
+ Box,
7847
+ {
7848
+ className: cn(
7849
+ "group flex items-center gap-4 transition-all duration-200",
7850
+ isCompact ? "px-4 py-2" : "px-6 py-4",
7851
+ "hover:bg-[var(--color-muted)]/80",
7852
+ !isCard && !isCompact && "rounded-[var(--radius-lg)] border border-transparent hover:border-[var(--color-border)]"
7853
+ ),
7854
+ children: [
7855
+ /* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
7856
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
7857
+ titleField?.icon && /* @__PURE__ */ jsx(
7858
+ Icon,
7859
+ {
7860
+ name: titleField.icon,
7861
+ size: isCompact ? "xs" : "sm",
7862
+ className: "text-[var(--color-primary)] flex-shrink-0"
7863
+ }
7864
+ ),
7865
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(
7866
+ Typography,
7867
+ {
7868
+ variant: titleField?.variant === "h3" ? "h3" : "h4",
7869
+ className: cn("font-semibold truncate flex-1", isCompact && "text-sm"),
7870
+ children: String(titleValue)
7871
+ }
7872
+ ),
7873
+ badgeFields.map((field) => {
7874
+ const val = getNestedValue(itemData, field.name);
7875
+ if (val === void 0 || val === null) return null;
7876
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
7877
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
7878
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant2(String(val)), children: String(val) })
7879
+ ] }, field.name);
7880
+ })
7881
+ ] }),
7882
+ bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
7883
+ const value = getNestedValue(itemData, field.name);
7884
+ if (value === void 0 || value === null || value === "") return null;
7885
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7886
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
7887
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
7888
+ field.label ?? fieldLabel2(field.name),
7889
+ ":"
7890
+ ] }),
7891
+ /* @__PURE__ */ jsx(Typography, { variant: "small", children: formatValue2(value, field.format) })
7892
+ ] }, field.name);
7893
+ }) }),
7894
+ progressFields.map((field) => {
7895
+ const value = getNestedValue(itemData, field.name);
7896
+ if (typeof value !== "number") return null;
7897
+ return /* @__PURE__ */ jsxs(Box, { className: "mt-2 max-w-xs", children: [
7898
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center mb-1", children: [
7899
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
7900
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
7901
+ ] }),
7902
+ /* @__PURE__ */ jsx(ProgressBar, { value, max: 100 })
7903
+ ] }, field.name);
7904
+ })
7905
+ ] }),
7906
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
7907
+ HStack,
7908
+ {
7909
+ gap: "xs",
7910
+ className: cn(
7911
+ "flex-shrink-0 transition-opacity duration-200",
7912
+ "opacity-0 group-hover:opacity-100"
7913
+ ),
7914
+ children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
7915
+ Button,
7916
+ {
7917
+ variant: action.variant ?? "ghost",
7918
+ size: "sm",
7919
+ onClick: handleActionClick(action, itemData),
7920
+ "data-testid": `action-${action.event}`,
7921
+ className: cn(
7922
+ action.variant === "danger" && "text-[var(--color-error)] hover:bg-[var(--color-error)]/10"
7923
+ ),
7924
+ children: [
7925
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
7926
+ action.label
7927
+ ]
7928
+ },
7929
+ idx
7930
+ ))
7931
+ }
7932
+ )
7933
+ ]
7934
+ }
7935
+ ),
7936
+ isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-[var(--color-border)]/40" })
7937
+ ] }, id);
7938
+ })
7939
+ }
7940
+ );
7941
+ };
7942
+ DataList.displayName = "DataList";
7943
+
7944
+ // components/organisms/types.ts
7945
+ var EntityDisplayEvents = {
7946
+ SORT: "SORT",
7947
+ PAGINATE: "PAGINATE",
7948
+ SEARCH: "SEARCH",
7949
+ FILTER: "FILTER",
7950
+ CLEAR_FILTERS: "CLEAR_FILTERS",
7951
+ SELECT: "SELECT",
6435
7952
  DESELECT: "DESELECT"
6436
7953
  };
7954
+ function humanizeFieldName(name) {
7955
+ return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\b([A-Z])([A-Z]+)\b/g, (_, first, rest) => first + rest.toLowerCase()).trim();
7956
+ }
6437
7957
  function normalizeColumns(columns) {
6438
7958
  return columns.map((col) => {
6439
7959
  if (typeof col === "string") {
6440
- const header = col.replace(/([A-Z])/g, " $1").replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase()).trim();
6441
- return { key: col, header };
7960
+ const header2 = humanizeFieldName(col);
7961
+ return { key: col, header: header2 };
6442
7962
  }
6443
- return col;
7963
+ const key = col.key ?? col.name ?? "";
7964
+ const header = col.header ?? col.label ?? humanizeFieldName(String(key));
7965
+ return { ...col, key, header };
6444
7966
  });
6445
7967
  }
7968
+ function asBooleanValue(value) {
7969
+ if (typeof value === "boolean") return value;
7970
+ if (value === "true") return true;
7971
+ if (value === "false") return false;
7972
+ return null;
7973
+ }
6446
7974
  function DataTable({
6447
7975
  fields,
6448
7976
  columns,
@@ -6739,7 +8267,13 @@ function DataTable({
6739
8267
  {
6740
8268
  "data-column": String(col.key),
6741
8269
  className: "px-4 py-3 text-sm text-[var(--color-foreground)] whitespace-nowrap sm:whitespace-normal",
6742
- children: col.render ? col.render(cellValue, row, rowIndex) : String(cellValue ?? "")
8270
+ children: col.render ? col.render(cellValue, row, rowIndex) : (() => {
8271
+ const boolVal = asBooleanValue(cellValue);
8272
+ if (boolVal !== null) {
8273
+ return boolVal ? /* @__PURE__ */ jsx(Badge, { variant: "success", children: t("common.yes") }) : /* @__PURE__ */ jsx(Badge, { variant: "neutral", children: t("common.no") });
8274
+ }
8275
+ return String(cellValue ?? "");
8276
+ })()
6743
8277
  },
6744
8278
  String(col.key)
6745
8279
  );
@@ -6825,7 +8359,7 @@ var StatCard = ({
6825
8359
  trend: manualTrend,
6826
8360
  trendDirection: manualDirection,
6827
8361
  invertTrend = false,
6828
- icon: Icon2,
8362
+ icon: iconProp,
6829
8363
  iconBg = "bg-[var(--color-muted)]",
6830
8364
  iconColor = "text-[var(--color-foreground)]",
6831
8365
  subtitle,
@@ -6837,10 +8371,11 @@ var StatCard = ({
6837
8371
  isLoading: externalLoading,
6838
8372
  error: externalError
6839
8373
  }) => {
8374
+ const Icon2 = typeof iconProp === "string" ? resolveIcon(iconProp) ?? void 0 : iconProp;
6840
8375
  const labelToUse = propLabel ?? propTitle;
6841
8376
  const eventBus = useEventBus();
6842
8377
  const { t } = useTranslate();
6843
- const handleActionClick = React41__default.useCallback(() => {
8378
+ const handleActionClick = React50__default.useCallback(() => {
6844
8379
  if (action?.event) {
6845
8380
  eventBus.emit(`UI:${action.event}`, {});
6846
8381
  }
@@ -6851,7 +8386,7 @@ var StatCard = ({
6851
8386
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
6852
8387
  const isLoading = externalLoading ?? false;
6853
8388
  const error = externalError;
6854
- const computeMetricValue = React41__default.useCallback(
8389
+ const computeMetricValue = React50__default.useCallback(
6855
8390
  (metric, items) => {
6856
8391
  if (metric.value !== void 0) {
6857
8392
  return metric.value;
@@ -6890,7 +8425,7 @@ var StatCard = ({
6890
8425
  },
6891
8426
  []
6892
8427
  );
6893
- const schemaStats = React41__default.useMemo(() => {
8428
+ const schemaStats = React50__default.useMemo(() => {
6894
8429
  if (!metrics || metrics.length === 0) return null;
6895
8430
  return metrics.map((metric) => ({
6896
8431
  label: metric.label,
@@ -6898,7 +8433,7 @@ var StatCard = ({
6898
8433
  format: metric.format
6899
8434
  }));
6900
8435
  }, [metrics, data, computeMetricValue]);
6901
- const calculatedTrend = React41__default.useMemo(() => {
8436
+ const calculatedTrend = React50__default.useMemo(() => {
6902
8437
  if (manualTrend !== void 0) return manualTrend;
6903
8438
  if (previousValue === void 0 || currentValue === void 0)
6904
8439
  return void 0;
@@ -7034,7 +8569,7 @@ var PageHeader = ({
7034
8569
  info: "bg-[var(--color-info)]/10 text-[var(--color-info)]"
7035
8570
  };
7036
8571
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
7037
- breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React41__default.Fragment, { children: [
8572
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React50__default.Fragment, { children: [
7038
8573
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
7039
8574
  crumb.href ? /* @__PURE__ */ jsx(
7040
8575
  "a",
@@ -7170,9 +8705,68 @@ function formatFieldValue(value, fieldName) {
7170
8705
  }
7171
8706
  return String(value);
7172
8707
  }
8708
+ var ReactMarkdown2 = lazy(() => import('react-markdown'));
8709
+ function renderRichFieldValue(value, fieldName, fieldType) {
8710
+ if (value === void 0 || value === null) return "\u2014";
8711
+ const str = String(value);
8712
+ switch (fieldType) {
8713
+ case "image":
8714
+ case "url": {
8715
+ if (str.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str.startsWith("data:image/")) {
8716
+ return /* @__PURE__ */ jsx(Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsx(
8717
+ "img",
8718
+ {
8719
+ src: str,
8720
+ alt: formatFieldLabel(fieldName),
8721
+ className: "max-w-full max-h-64 rounded-[var(--radius-md)] object-contain",
8722
+ loading: "lazy"
8723
+ }
8724
+ ) });
8725
+ }
8726
+ return str;
8727
+ }
8728
+ case "markdown":
8729
+ case "richtext":
8730
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children: str }), children: /* @__PURE__ */ jsx(Box, { className: "prose prose-sm max-w-none dark:prose-invert", children: /* @__PURE__ */ jsx(ReactMarkdown2, { children: str }) }) });
8731
+ case "code":
8732
+ return /* @__PURE__ */ jsx(Box, { className: "mt-1 rounded-[var(--radius-md)] bg-[var(--color-muted)] p-3 overflow-x-auto", children: /* @__PURE__ */ jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsx("code", { children: str }) }) });
8733
+ case "html":
8734
+ return /* @__PURE__ */ jsx(Box, { className: "mt-1 prose prose-sm max-w-none dark:prose-invert break-words", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: str }) });
8735
+ case "date":
8736
+ case "datetime": {
8737
+ const d = new Date(str);
8738
+ if (!isNaN(d.getTime())) {
8739
+ return d.toLocaleDateString(void 0, {
8740
+ year: "numeric",
8741
+ month: "long",
8742
+ day: "numeric",
8743
+ ...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
8744
+ });
8745
+ }
8746
+ return str;
8747
+ }
8748
+ default:
8749
+ return formatFieldValue(value, fieldName);
8750
+ }
8751
+ }
7173
8752
  function normalizeFieldDefs(fields) {
7174
8753
  if (!fields) return [];
7175
- return fields.map((f) => typeof f === "string" ? f : f.key);
8754
+ return fields.map((f) => {
8755
+ if (typeof f === "string") return f;
8756
+ if ("key" in f) return f.key;
8757
+ if ("name" in f) return f.name;
8758
+ return String(f);
8759
+ });
8760
+ }
8761
+ function buildFieldTypeMap(fields) {
8762
+ const map = {};
8763
+ if (!fields) return map;
8764
+ for (const f of fields) {
8765
+ if (typeof f === "object" && "name" in f && "type" in f) {
8766
+ map[f.name] = f.type;
8767
+ }
8768
+ }
8769
+ return map;
7176
8770
  }
7177
8771
  var DetailPanel = ({
7178
8772
  title: propTitle,
@@ -7196,9 +8790,10 @@ var DetailPanel = ({
7196
8790
  const isFieldDefArray = (arr) => {
7197
8791
  if (!arr || arr.length === 0) return false;
7198
8792
  const first = arr[0];
7199
- return typeof first === "string" || typeof first === "object" && first !== null && "key" in first;
8793
+ return typeof first === "string" || typeof first === "object" && first !== null && ("key" in first || "name" in first);
7200
8794
  };
7201
8795
  const effectiveFieldNames = isFieldDefArray(propFields) ? normalizeFieldDefs(propFields) : fieldNames;
8796
+ const fieldTypeMap = isFieldDefArray(propFields) ? buildFieldTypeMap(propFields) : {};
7202
8797
  useCallback(
7203
8798
  (action, data2) => {
7204
8799
  if (action.navigatesTo) {
@@ -7273,7 +8868,7 @@ var DetailPanel = ({
7273
8868
  if (value !== void 0 && value !== null) {
7274
8869
  overviewFields.push({
7275
8870
  label: formatFieldLabel(field),
7276
- value: formatFieldValue(value, field),
8871
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
7277
8872
  icon: getFieldIcon(field)
7278
8873
  });
7279
8874
  }
@@ -7289,7 +8884,7 @@ var DetailPanel = ({
7289
8884
  if (value !== void 0 && value !== null) {
7290
8885
  metricsFields.push({
7291
8886
  label: formatFieldLabel(field),
7292
- value: formatFieldValue(value, field),
8887
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
7293
8888
  icon: getFieldIcon(field)
7294
8889
  });
7295
8890
  }
@@ -7305,7 +8900,7 @@ var DetailPanel = ({
7305
8900
  if (value !== void 0 && value !== null) {
7306
8901
  timelineFields.push({
7307
8902
  label: formatFieldLabel(field),
7308
- value: formatFieldValue(value, field),
8903
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
7309
8904
  icon: getFieldIcon(field)
7310
8905
  });
7311
8906
  }
@@ -7321,7 +8916,7 @@ var DetailPanel = ({
7321
8916
  if (value !== void 0 && value !== null) {
7322
8917
  descFields.push({
7323
8918
  label: formatFieldLabel(field),
7324
- value: String(value),
8919
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
7325
8920
  icon: getFieldIcon(field)
7326
8921
  });
7327
8922
  }
@@ -7361,96 +8956,123 @@ var DetailPanel = ({
7361
8956
  }
7362
8957
  );
7363
8958
  }
7364
- const content = /* @__PURE__ */ jsxs(VStack, { gap: "lg", children: [
7365
- /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
7366
- /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "start", children: [
7367
- /* @__PURE__ */ jsxs(VStack, { gap: "sm", flex: true, className: "min-w-0", children: [
7368
- avatar,
7369
- /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
7370
- subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle }),
7371
- normalizedData && effectiveFieldNames && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: effectiveFieldNames.filter(
7372
- (f) => f.toLowerCase().includes("status") || f.toLowerCase().includes("priority")
7373
- ).map((field) => {
7374
- const value = getNestedValue(normalizedData, field);
7375
- if (!value) return null;
7376
- return /* @__PURE__ */ jsx(
7377
- Badge,
7378
- {
7379
- variant: getBadgeVariant(field, String(value)),
7380
- children: String(value)
7381
- },
7382
- field
7383
- );
7384
- }) }),
7385
- status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
7386
- ] }),
7387
- slideOver && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleClose, icon: X })
7388
- ] }),
8959
+ const allFields = [];
8960
+ if (sections) {
8961
+ for (const section of sections) {
8962
+ for (const field of section.fields) {
8963
+ if (typeof field === "string") {
8964
+ const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
8965
+ allFields.push({
8966
+ label: formatFieldLabel(field),
8967
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
8968
+ icon: getFieldIcon(field)
8969
+ });
8970
+ } else {
8971
+ allFields.push(field);
8972
+ }
8973
+ }
8974
+ }
8975
+ }
8976
+ const closeAction = actions?.find(
8977
+ (a) => a.event === "CLOSE" || a.event === "CANCEL" || a.label?.toLowerCase() === "close"
8978
+ );
8979
+ const otherActions = actions?.filter((a) => a !== closeAction) ?? [];
8980
+ const effectiveCloseAction = closeAction ?? { event: void 0};
8981
+ const content = /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
8982
+ /* @__PURE__ */ jsxs(HStack, { justify: "end", align: "center", gap: "xs", children: [
8983
+ otherActions.map((action, idx) => /* @__PURE__ */ jsx(
8984
+ Button,
8985
+ {
8986
+ variant: action.variant || "secondary",
8987
+ size: "sm",
8988
+ action: action.event,
8989
+ actionPayload: { row: normalizedData },
8990
+ icon: action.icon,
8991
+ "data-testid": action.event ? `action-${action.event}` : void 0,
8992
+ children: action.label
8993
+ },
8994
+ idx
8995
+ )),
8996
+ /* @__PURE__ */ jsx(
8997
+ Button,
8998
+ {
8999
+ variant: "ghost",
9000
+ size: "sm",
9001
+ action: effectiveCloseAction.event,
9002
+ actionPayload: { row: normalizedData },
9003
+ onClick: effectiveCloseAction.event ? void 0 : handleClose,
9004
+ icon: X,
9005
+ "data-testid": effectiveCloseAction.event ? `action-${effectiveCloseAction.event}` : "action-close"
9006
+ }
9007
+ )
9008
+ ] }),
9009
+ avatar,
9010
+ /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
9011
+ subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle }),
9012
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", wrap: true, children: [
7389
9013
  normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
7390
- (f) => f.toLowerCase().includes("progress") || f.toLowerCase().includes("percent")
9014
+ (f) => f.toLowerCase().includes("status") || f.toLowerCase().includes("priority")
7391
9015
  ).map((field) => {
7392
9016
  const value = getNestedValue(normalizedData, field);
7393
- if (value === void 0 || value === null || typeof value !== "number")
7394
- return null;
7395
- return /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "w-full", children: [
7396
- /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
7397
- /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: formatFieldLabel(field) }),
7398
- /* @__PURE__ */ jsxs(Typography, { variant: "small", weight: "medium", children: [
7399
- value,
7400
- "%"
7401
- ] })
7402
- ] }),
7403
- /* @__PURE__ */ jsx(ProgressBar, { value })
7404
- ] }, field);
7405
- }),
7406
- actions && actions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
7407
- /* @__PURE__ */ jsx(Divider, {}),
7408
- /* @__PURE__ */ jsx(HStack, { gap: "sm", children: actions.map((action, idx) => /* @__PURE__ */ jsx(
7409
- Button,
9017
+ if (!value) return null;
9018
+ return /* @__PURE__ */ jsx(
9019
+ Badge,
7410
9020
  {
7411
- variant: action.variant || "secondary",
7412
- action: action.event,
7413
- actionPayload: { row: normalizedData },
7414
- icon: action.icon,
7415
- "data-testid": action.event ? `action-${action.event}` : void 0,
7416
- children: action.label
9021
+ variant: getBadgeVariant(field, String(value)),
9022
+ children: String(value)
7417
9023
  },
7418
- idx
7419
- )) })
7420
- ] })
7421
- ] }) }),
7422
- sections && sections.map((section, sectionIdx) => /* @__PURE__ */ jsx(Card, { variant: "bordered", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
7423
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "semibold", children: section.title }),
9024
+ field
9025
+ );
9026
+ }),
9027
+ status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
9028
+ ] }),
9029
+ normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
9030
+ (f) => f.toLowerCase().includes("progress") || f.toLowerCase().includes("percent")
9031
+ ).map((field) => {
9032
+ const value = getNestedValue(normalizedData, field);
9033
+ if (value === void 0 || value === null || typeof value !== "number")
9034
+ return null;
9035
+ return /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "w-full", children: [
9036
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
9037
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: formatFieldLabel(field) }),
9038
+ /* @__PURE__ */ jsxs(Typography, { variant: "small", weight: "medium", children: [
9039
+ value,
9040
+ "%"
9041
+ ] })
9042
+ ] }),
9043
+ /* @__PURE__ */ jsx(ProgressBar, { value })
9044
+ ] }, field);
9045
+ }),
9046
+ allFields.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
7424
9047
  /* @__PURE__ */ jsx(Divider, {}),
7425
- /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "250px", maxCols: 2, gap: "lg", children: section.fields.map((field, fieldIdx) => {
7426
- const fieldKey = typeof field === "string" ? field : void 0;
7427
- const resolved = typeof field === "string" ? { label: formatFieldLabel(field), value: normalizedData ? formatFieldValue(getNestedValue(normalizedData, field), field) : "\u2014", icon: getFieldIcon(field) } : field;
7428
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "start", "data-field": fieldKey, children: [
7429
- resolved.icon && /* @__PURE__ */ jsx(
7430
- Icon,
9048
+ /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "250px", maxCols: 2, gap: "lg", children: allFields.map((field, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "start", children: [
9049
+ field.icon && /* @__PURE__ */ jsx(
9050
+ Icon,
9051
+ {
9052
+ icon: field.icon,
9053
+ size: "md",
9054
+ className: "text-[var(--color-muted-foreground)] mt-1"
9055
+ }
9056
+ ),
9057
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", flex: true, className: "min-w-0", children: [
9058
+ /* @__PURE__ */ jsx(
9059
+ Typography,
7431
9060
  {
7432
- icon: resolved.icon,
7433
- size: "md",
7434
- className: "text-[var(--color-muted-foreground)] mt-1"
9061
+ variant: "small",
9062
+ color: "secondary",
9063
+ weight: "medium",
9064
+ children: field.label
7435
9065
  }
7436
9066
  ),
7437
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", flex: true, className: "min-w-0", children: [
7438
- /* @__PURE__ */ jsx(
7439
- Typography,
7440
- {
7441
- variant: "small",
7442
- color: "secondary",
7443
- weight: "medium",
7444
- children: resolved.label
7445
- }
7446
- ),
7447
- /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children: resolved.value || "\u2014" })
7448
- ] })
7449
- ] }, fieldIdx);
7450
- }) })
7451
- ] }) }, sectionIdx)),
7452
- footer && /* @__PURE__ */ jsx(Card, { variant: "bordered", children: footer })
7453
- ] });
9067
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children: field.value || "\u2014" })
9068
+ ] })
9069
+ ] }, idx)) })
9070
+ ] }),
9071
+ footer && /* @__PURE__ */ jsxs(Fragment, { children: [
9072
+ /* @__PURE__ */ jsx(Divider, {}),
9073
+ footer
9074
+ ] })
9075
+ ] }) });
7454
9076
  return /* @__PURE__ */ jsx(
7455
9077
  Box,
7456
9078
  {
@@ -7484,7 +9106,7 @@ var layoutStyles = {
7484
9106
  horizontal: "flex flex-row flex-wrap items-end",
7485
9107
  inline: "flex flex-row flex-wrap items-center"
7486
9108
  };
7487
- var gapStyles5 = {
9109
+ var gapStyles6 = {
7488
9110
  sm: "gap-2",
7489
9111
  md: "gap-4",
7490
9112
  lg: "gap-6"
@@ -7580,7 +9202,7 @@ var Form = ({
7580
9202
  const normalizedInitialData = initialData ?? {};
7581
9203
  const resolvedEntity = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
7582
9204
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
7583
- const entityDerivedFields = React41__default.useMemo(() => {
9205
+ const entityDerivedFields = React50__default.useMemo(() => {
7584
9206
  if (fields && fields.length > 0) return void 0;
7585
9207
  if (!resolvedEntity) return void 0;
7586
9208
  return resolvedEntity.fields.map(
@@ -7599,14 +9221,14 @@ var Form = ({
7599
9221
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
7600
9222
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
7601
9223
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
7602
- const [formData, setFormData] = React41__default.useState(
9224
+ const [formData, setFormData] = React50__default.useState(
7603
9225
  normalizedInitialData
7604
9226
  );
7605
- const [collapsedSections, setCollapsedSections] = React41__default.useState(
9227
+ const [collapsedSections, setCollapsedSections] = React50__default.useState(
7606
9228
  /* @__PURE__ */ new Set()
7607
9229
  );
7608
9230
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
7609
- const evalContext = React41__default.useMemo(
9231
+ const evalContext = React50__default.useMemo(
7610
9232
  () => ({
7611
9233
  formValues: formData,
7612
9234
  globalVariables: externalContext?.globalVariables ?? {},
@@ -7615,13 +9237,13 @@ var Form = ({
7615
9237
  }),
7616
9238
  [formData, externalContext]
7617
9239
  );
7618
- React41__default.useEffect(() => {
9240
+ React50__default.useEffect(() => {
7619
9241
  const data = initialData;
7620
9242
  if (data && Object.keys(data).length > 0) {
7621
9243
  setFormData(data);
7622
9244
  }
7623
9245
  }, [initialData]);
7624
- const processCalculations = React41__default.useCallback(
9246
+ const processCalculations = React50__default.useCallback(
7625
9247
  (changedFieldId, newFormData) => {
7626
9248
  if (!hiddenCalculations.length) return;
7627
9249
  const context = {
@@ -7646,7 +9268,7 @@ var Form = ({
7646
9268
  },
7647
9269
  [hiddenCalculations, externalContext, eventBus]
7648
9270
  );
7649
- const checkViolations = React41__default.useCallback(
9271
+ const checkViolations = React50__default.useCallback(
7650
9272
  (changedFieldId, newFormData) => {
7651
9273
  if (!violationTriggers.length) return;
7652
9274
  const context = {
@@ -7683,7 +9305,7 @@ var Form = ({
7683
9305
  processCalculations(name, newFormData);
7684
9306
  checkViolations(name, newFormData);
7685
9307
  };
7686
- const isFieldVisible = React41__default.useCallback(
9308
+ const isFieldVisible = React50__default.useCallback(
7687
9309
  (fieldName) => {
7688
9310
  const condition = conditionalFields[fieldName];
7689
9311
  if (!condition) return true;
@@ -7691,7 +9313,7 @@ var Form = ({
7691
9313
  },
7692
9314
  [conditionalFields, evalContext]
7693
9315
  );
7694
- const isSectionVisible = React41__default.useCallback(
9316
+ const isSectionVisible = React50__default.useCallback(
7695
9317
  (section) => {
7696
9318
  if (!section.condition) return true;
7697
9319
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -7723,7 +9345,7 @@ var Form = ({
7723
9345
  eventBus.emit(`UI:${onCancel}`);
7724
9346
  }
7725
9347
  };
7726
- const renderField = React41__default.useCallback(
9348
+ const renderField = React50__default.useCallback(
7727
9349
  (field) => {
7728
9350
  const fieldName = field.name || field.field;
7729
9351
  if (!fieldName) return null;
@@ -7744,7 +9366,7 @@ var Form = ({
7744
9366
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
7745
9367
  );
7746
9368
  const effectiveFields = entityDerivedFields ?? fields;
7747
- const normalizedFields = React41__default.useMemo(() => {
9369
+ const normalizedFields = React50__default.useMemo(() => {
7748
9370
  if (!effectiveFields || effectiveFields.length === 0) return [];
7749
9371
  return effectiveFields.map((field) => {
7750
9372
  if (typeof field === "string") {
@@ -7753,7 +9375,7 @@ var Form = ({
7753
9375
  return field;
7754
9376
  });
7755
9377
  }, [effectiveFields]);
7756
- const schemaFields = React41__default.useMemo(() => {
9378
+ const schemaFields = React50__default.useMemo(() => {
7757
9379
  if (normalizedFields.length === 0) return null;
7758
9380
  if (isDebugEnabled()) {
7759
9381
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -7763,7 +9385,7 @@ var Form = ({
7763
9385
  }
7764
9386
  return normalizedFields.map(renderField).filter(Boolean);
7765
9387
  }, [normalizedFields, renderField, entityName, conditionalFields]);
7766
- const sectionElements = React41__default.useMemo(() => {
9388
+ const sectionElements = React50__default.useMemo(() => {
7767
9389
  if (!sections || sections.length === 0) return null;
7768
9390
  return sections.map((section) => {
7769
9391
  if (!isSectionVisible(section)) {
@@ -7943,7 +9565,7 @@ var Form = ({
7943
9565
  return /* @__PURE__ */ jsxs(
7944
9566
  "form",
7945
9567
  {
7946
- className: cn(layoutStyles[layout], gapStyles5[gap], className),
9568
+ className: cn(layoutStyles[layout], gapStyles6[gap], className),
7947
9569
  onSubmit: handleSubmit,
7948
9570
  ...props,
7949
9571
  children: [
@@ -8011,9 +9633,37 @@ function formatDateTimeValue(value) {
8011
9633
  Form.displayName = "Form";
8012
9634
  function normalizeFields(fields) {
8013
9635
  if (!fields) return [];
8014
- return fields.map((f) => typeof f === "string" ? f : f.key);
9636
+ return fields.map((f) => typeof f === "string" ? f : f.key ?? f.name ?? "");
8015
9637
  }
8016
- var gapStyles6 = {
9638
+ function fieldLabel3(key) {
9639
+ return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
9640
+ }
9641
+ function asBooleanValue2(value) {
9642
+ if (typeof value === "boolean") return value;
9643
+ if (value === "true") return true;
9644
+ if (value === "false") return false;
9645
+ return null;
9646
+ }
9647
+ var STATUS_FIELDS = /* @__PURE__ */ new Set(["status", "state", "priority", "type", "category", "role", "level", "tier"]);
9648
+ function isDateField(key) {
9649
+ const lower = key.toLowerCase();
9650
+ return lower.includes("date") || lower.includes("time") || lower.endsWith("at") || lower.endsWith("_at");
9651
+ }
9652
+ function formatDate3(value) {
9653
+ if (!value) return "";
9654
+ const d = new Date(String(value));
9655
+ if (isNaN(d.getTime())) return String(value);
9656
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
9657
+ }
9658
+ function statusVariant3(value) {
9659
+ const v = value.toLowerCase();
9660
+ if (["active", "completed", "done", "approved", "published", "resolved", "open"].includes(v)) return "success";
9661
+ if (["pending", "in_progress", "in-progress", "review", "draft", "processing"].includes(v)) return "warning";
9662
+ if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed"].includes(v)) return "error";
9663
+ if (["new", "created", "scheduled", "queued"].includes(v)) return "info";
9664
+ return "default";
9665
+ }
9666
+ var gapStyles7 = {
8017
9667
  none: "gap-0",
8018
9668
  sm: "gap-2",
8019
9669
  md: "gap-4",
@@ -8045,7 +9695,8 @@ var CardGrid = ({
8045
9695
  fieldNames,
8046
9696
  columns,
8047
9697
  itemActions,
8048
- showTotal = true
9698
+ showTotal = true,
9699
+ imageField
8049
9700
  }) => {
8050
9701
  const eventBus = useEventBus();
8051
9702
  const { t } = useTranslate();
@@ -8057,6 +9708,28 @@ var CardGrid = ({
8057
9708
  const handlePageChange = (newPage) => {
8058
9709
  eventBus.emit("UI:PAGINATE", { page: newPage, pageSize });
8059
9710
  };
9711
+ const titleField = effectiveFieldNames?.[0];
9712
+ const statusField = effectiveFieldNames?.find((f) => STATUS_FIELDS.has(f.toLowerCase()));
9713
+ const bodyFields = effectiveFieldNames?.filter((f) => f !== titleField && f !== statusField) ?? [];
9714
+ const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
9715
+ const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
9716
+ const handleActionClick = (action, itemData) => (e) => {
9717
+ e.stopPropagation();
9718
+ if (action.navigatesTo) {
9719
+ const url = action.navigatesTo.replace(/\{\{row\.(\w+(?:\.\w+)*)\}\}/g, (_, field) => {
9720
+ const value = getNestedValue(itemData, field);
9721
+ return value !== void 0 && value !== null ? String(value) : "";
9722
+ });
9723
+ eventBus.emit("UI:NAVIGATE", { url, row: itemData });
9724
+ return;
9725
+ }
9726
+ if (action.event) {
9727
+ eventBus.emit(`UI:${action.event}`, { row: itemData });
9728
+ }
9729
+ if (action.onClick) {
9730
+ action.onClick(itemData);
9731
+ }
9732
+ };
8060
9733
  const renderContent = () => {
8061
9734
  if (children) {
8062
9735
  return children;
@@ -8071,62 +9744,85 @@ var CardGrid = ({
8071
9744
  ] }) });
8072
9745
  }
8073
9746
  if (normalizedData.length === 0) {
8074
- return /* @__PURE__ */ jsx(Box, { className: "col-span-full text-center py-8 text-[var(--color-muted-foreground)]", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: "No items found" }) });
9747
+ return /* @__PURE__ */ jsx(Box, { className: "col-span-full text-center py-12 text-[var(--color-muted-foreground)]", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
8075
9748
  }
8076
9749
  return normalizedData.map((item, index) => {
8077
9750
  const itemData = item;
8078
9751
  const id = itemData.id || String(index);
8079
- const cardFields = effectiveFieldNames || Object.keys(itemData).slice(0, 3);
8080
- const handleActionClick = (action) => (e) => {
8081
- e.stopPropagation();
8082
- if (action.navigatesTo) {
8083
- const url = action.navigatesTo.replace(/\{\{row\.(\w+(?:\.\w+)*)\}\}/g, (_, field) => {
8084
- const value = getNestedValue(itemData, field);
8085
- return value !== void 0 && value !== null ? String(value) : "";
8086
- });
8087
- eventBus.emit("UI:NAVIGATE", { url, row: itemData });
8088
- return;
8089
- }
8090
- if (action.event) {
8091
- eventBus.emit(`UI:${action.event}`, { row: itemData });
8092
- }
8093
- if (action.onClick) {
8094
- action.onClick(itemData);
8095
- }
8096
- };
9752
+ const titleValue = titleField ? getNestedValue(itemData, titleField) : void 0;
9753
+ const statusValue = statusField ? getNestedValue(itemData, statusField) : void 0;
8097
9754
  return /* @__PURE__ */ jsxs(
8098
9755
  Box,
8099
9756
  {
8100
9757
  "data-entity-row": true,
8101
9758
  className: cn(
8102
- "bg-[var(--color-card)] rounded-[var(--radius-lg)] border border-[var(--color-border)] p-4 shadow-[var(--shadow-sm)]",
8103
- "cursor-pointer hover:border-[var(--color-primary)] transition-colors"
9759
+ "bg-[var(--color-card)] rounded-[var(--radius-lg)] border border-[var(--color-border)]",
9760
+ "shadow-[var(--shadow-sm)] hover:shadow-[var(--shadow-hover)]",
9761
+ "cursor-pointer hover:border-[var(--color-primary)] transition-all",
9762
+ "flex flex-col"
8104
9763
  ),
8105
9764
  action: "VIEW",
8106
9765
  actionPayload: { row: itemData },
8107
9766
  children: [
8108
- cardFields.map((field) => {
8109
- const value = getNestedValue(itemData, field);
8110
- if (value === void 0 || value === null) return null;
8111
- return /* @__PURE__ */ jsxs(Box, { className: "mb-2 last:mb-0", children: [
8112
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "uppercase", children: field }),
8113
- /* @__PURE__ */ jsx(Typography, { variant: "small", children: String(value) })
8114
- ] }, field);
8115
- }),
8116
- itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "mt-3 pt-3 border-t border-[var(--color-border)]", children: itemActions.map((action, actionIdx) => {
8117
- const buttonVariant = action.variant || "secondary";
8118
- return /* @__PURE__ */ jsx(
9767
+ imageField && (() => {
9768
+ const imgUrl = getNestedValue(itemData, imageField);
9769
+ if (!imgUrl || typeof imgUrl !== "string") return null;
9770
+ return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-[var(--radius-lg)]", children: /* @__PURE__ */ jsx(
9771
+ "img",
9772
+ {
9773
+ src: imgUrl,
9774
+ alt: titleValue !== void 0 ? String(titleValue) : "",
9775
+ className: "w-full h-full object-cover",
9776
+ loading: "lazy"
9777
+ }
9778
+ ) });
9779
+ })(),
9780
+ /* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
9781
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
9782
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "font-semibold truncate", children: String(titleValue) }),
9783
+ statusValue !== void 0 && statusValue !== null && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(statusValue)), children: String(statusValue) }) })
9784
+ ] }),
9785
+ dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, actionIdx) => /* @__PURE__ */ jsx(
8119
9786
  Button,
8120
9787
  {
8121
- variant: buttonVariant,
9788
+ variant: "ghost",
8122
9789
  size: "sm",
8123
- onClick: handleActionClick(action),
9790
+ onClick: handleActionClick(action, itemData),
8124
9791
  "data-testid": action.event ? `action-${action.event}` : void 0,
9792
+ className: "text-[var(--color-error)] hover:bg-[var(--color-error)]/10 px-2",
8125
9793
  children: action.label
8126
9794
  },
8127
9795
  actionIdx
8128
- );
8129
- }) })
9796
+ )) })
9797
+ ] }) }),
9798
+ bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
9799
+ const value = getNestedValue(itemData, field);
9800
+ if (value === void 0 || value === null || value === "") return null;
9801
+ const boolVal = asBooleanValue2(value);
9802
+ if (boolVal !== null) {
9803
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between", children: [
9804
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fieldLabel3(field) }),
9805
+ boolVal ? /* @__PURE__ */ jsx(Badge, { variant: "success", children: t("common.yes") || "Yes" }) : /* @__PURE__ */ jsx(Badge, { variant: "neutral", children: t("common.no") || "No" })
9806
+ ] }, field);
9807
+ }
9808
+ const displayValue = isDateField(field) ? formatDate3(value) : STATUS_FIELDS.has(field.toLowerCase()) ? void 0 : String(value);
9809
+ if (!displayValue) return null;
9810
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between", children: [
9811
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fieldLabel3(field) }),
9812
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-right truncate max-w-[60%]", children: displayValue })
9813
+ ] }, field);
9814
+ }) }) }),
9815
+ primaryActions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 mt-auto border-t border-[var(--color-border)]", children: /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "justify-end", children: primaryActions.map((action, actionIdx) => /* @__PURE__ */ jsx(
9816
+ Button,
9817
+ {
9818
+ variant: action.variant === "primary" ? "primary" : "ghost",
9819
+ size: "sm",
9820
+ onClick: handleActionClick(action, itemData),
9821
+ "data-testid": action.event ? `action-${action.event}` : void 0,
9822
+ children: action.label
9823
+ },
9824
+ actionIdx
9825
+ )) }) })
8130
9826
  ]
8131
9827
  },
8132
9828
  id
@@ -8139,7 +9835,7 @@ var CardGrid = ({
8139
9835
  {
8140
9836
  className: cn(
8141
9837
  "grid",
8142
- gapStyles6[gap],
9838
+ gapStyles7[gap],
8143
9839
  alignStyles4[alignItems],
8144
9840
  maxCols === 1 && "grid-cols-1",
8145
9841
  maxCols === 2 && "sm:grid-cols-2",
@@ -8168,7 +9864,7 @@ var CardGrid = ({
8168
9864
  CardGrid.displayName = "CardGrid";
8169
9865
  function MasterDetail({
8170
9866
  entity,
8171
- masterFields = [],
9867
+ masterFields,
8172
9868
  detailFields: _detailFields,
8173
9869
  // Captured but not used here - detail handled separately
8174
9870
  loading: externalLoading,
@@ -8183,6 +9879,7 @@ function MasterDetail({
8183
9879
  return /* @__PURE__ */ jsx(
8184
9880
  DataTable,
8185
9881
  {
9882
+ fields: masterFields,
8186
9883
  columns: masterFields,
8187
9884
  entity,
8188
9885
  isLoading: loading || isLoading,
@@ -8254,7 +9951,7 @@ function GridPattern({
8254
9951
  style,
8255
9952
  children
8256
9953
  }) {
8257
- return /* @__PURE__ */ jsx(Grid2, { cols, gap, rowGap, colGap, className, style, children });
9954
+ return /* @__PURE__ */ jsx(Grid, { cols, gap, rowGap, colGap, className, style, children });
8258
9955
  }
8259
9956
  GridPattern.displayName = "GridPattern";
8260
9957
  function CenterPattern({
@@ -8271,14 +9968,14 @@ function SpacerPattern({ size = "flex" }) {
8271
9968
  if (size === "flex") {
8272
9969
  return /* @__PURE__ */ jsx(Spacer, {});
8273
9970
  }
8274
- const sizeMap4 = {
9971
+ const sizeMap8 = {
8275
9972
  xs: "0.25rem",
8276
9973
  sm: "0.5rem",
8277
9974
  md: "1rem",
8278
9975
  lg: "1.5rem",
8279
9976
  xl: "2rem"
8280
9977
  };
8281
- return /* @__PURE__ */ jsx(Box, { style: { width: sizeMap4[size], height: sizeMap4[size], flexShrink: 0 } });
9978
+ return /* @__PURE__ */ jsx(Box, { style: { width: sizeMap8[size], height: sizeMap8[size], flexShrink: 0 } });
8282
9979
  }
8283
9980
  SpacerPattern.displayName = "SpacerPattern";
8284
9981
  function DividerPattern({
@@ -8539,7 +10236,7 @@ function InputPattern({
8539
10236
  className
8540
10237
  }) {
8541
10238
  const { emit } = useEventBus();
8542
- const [localValue, setLocalValue] = React41__default.useState(value);
10239
+ const [localValue, setLocalValue] = React50__default.useState(value);
8543
10240
  const handleChange = (e) => {
8544
10241
  setLocalValue(e.target.value);
8545
10242
  if (onChange) {
@@ -8576,7 +10273,7 @@ function TextareaPattern({
8576
10273
  className
8577
10274
  }) {
8578
10275
  const { emit } = useEventBus();
8579
- const [localValue, setLocalValue] = React41__default.useState(value);
10276
+ const [localValue, setLocalValue] = React50__default.useState(value);
8580
10277
  const handleChange = (e) => {
8581
10278
  setLocalValue(e.target.value);
8582
10279
  if (onChange) {
@@ -8607,7 +10304,7 @@ function SelectPattern({
8607
10304
  className
8608
10305
  }) {
8609
10306
  const { emit } = useEventBus();
8610
- const [localValue, setLocalValue] = React41__default.useState(value);
10307
+ const [localValue, setLocalValue] = React50__default.useState(value);
8611
10308
  const handleChange = (e) => {
8612
10309
  setLocalValue(e.target.value);
8613
10310
  if (onChange) {
@@ -8636,7 +10333,7 @@ function CheckboxPattern({
8636
10333
  className
8637
10334
  }) {
8638
10335
  const { emit } = useEventBus();
8639
- const [localChecked, setLocalChecked] = React41__default.useState(checked);
10336
+ const [localChecked, setLocalChecked] = React50__default.useState(checked);
8640
10337
  const handleChange = (e) => {
8641
10338
  setLocalChecked(e.target.checked);
8642
10339
  if (onChange) {
@@ -8750,7 +10447,7 @@ function MenuPattern({
8750
10447
  ...item,
8751
10448
  onClick: () => emit(`UI:${item.event}`, {})
8752
10449
  }));
8753
- return /* @__PURE__ */ jsx(Menu2, { items: menuItems, trigger, position, className });
10450
+ return /* @__PURE__ */ jsx(Menu, { items: menuItems, trigger, position, className });
8754
10451
  }
8755
10452
  MenuPattern.displayName = "MenuPattern";
8756
10453
  function AccordionPattern({
@@ -8813,6 +10510,35 @@ function FloatButtonPattern({
8813
10510
  );
8814
10511
  }
8815
10512
  FloatButtonPattern.displayName = "FloatButtonPattern";
10513
+ function MapViewPattern({
10514
+ markers,
10515
+ centerLat,
10516
+ centerLng,
10517
+ zoom,
10518
+ height,
10519
+ mapClickEvent,
10520
+ markerClickEvent,
10521
+ showClickedPin,
10522
+ className,
10523
+ showAttribution
10524
+ }) {
10525
+ return /* @__PURE__ */ jsx(
10526
+ MapView,
10527
+ {
10528
+ markers,
10529
+ centerLat,
10530
+ centerLng,
10531
+ zoom,
10532
+ height,
10533
+ mapClickEvent,
10534
+ markerClickEvent,
10535
+ showClickedPin,
10536
+ className,
10537
+ showAttribution
10538
+ }
10539
+ );
10540
+ }
10541
+ MapViewPattern.displayName = "MapViewPattern";
8816
10542
  var ALLOWED_CUSTOM_COMPONENTS = [
8817
10543
  "div",
8818
10544
  "span",
@@ -9037,7 +10763,7 @@ function SuspenseConfigProvider({
9037
10763
  config,
9038
10764
  children
9039
10765
  }) {
9040
- return React41__default.createElement(
10766
+ return React50__default.createElement(
9041
10767
  SuspenseConfigContext.Provider,
9042
10768
  { value: config },
9043
10769
  children
@@ -9113,6 +10839,8 @@ var COMPONENT_REGISTRY = {
9113
10839
  ContainerPattern,
9114
10840
  SimpleGridPattern,
9115
10841
  FloatButtonPattern,
10842
+ // Map patterns
10843
+ MapViewPattern,
9116
10844
  // Custom pattern
9117
10845
  CustomPattern
9118
10846
  };
@@ -9175,7 +10903,9 @@ var PATTERN_TO_COMPONENT = {
9175
10903
  "simple-grid": "SimpleGridPattern",
9176
10904
  "float-button": "FloatButtonPattern",
9177
10905
  // Custom pattern
9178
- custom: "CustomPattern"
10906
+ custom: "CustomPattern",
10907
+ // Map patterns
10908
+ "map-view": "MapViewPattern"
9179
10909
  };
9180
10910
  function getComponentForPattern(patternType) {
9181
10911
  const componentName = PATTERN_TO_COMPONENT[patternType];
@@ -9214,6 +10944,9 @@ function UISlotComponent({
9214
10944
  if (pattern === "clear") {
9215
10945
  return null;
9216
10946
  }
10947
+ if (isPortalSlot(slot)) {
10948
+ return /* @__PURE__ */ jsx(CompiledPortal, { slot, className, pattern, sourceTrait, children });
10949
+ }
9217
10950
  return /* @__PURE__ */ jsx(
9218
10951
  Box,
9219
10952
  {
@@ -9264,6 +10997,70 @@ function UISlotComponent({
9264
10997
  }
9265
10998
  );
9266
10999
  }
11000
+ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
11001
+ const [portalRoot, setPortalRoot] = useState(null);
11002
+ const eventBus = useUISlots();
11003
+ useEffect(() => {
11004
+ let root = document.getElementById("ui-slot-portal-root");
11005
+ if (!root) {
11006
+ root = document.createElement("div");
11007
+ root.id = "ui-slot-portal-root";
11008
+ document.body.appendChild(root);
11009
+ }
11010
+ setPortalRoot(root);
11011
+ }, []);
11012
+ const handleDismiss = () => {
11013
+ eventBus.clear(slot);
11014
+ };
11015
+ if (!portalRoot) return null;
11016
+ let wrapper;
11017
+ switch (slot) {
11018
+ case "modal":
11019
+ wrapper = /* @__PURE__ */ jsx(Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, children: /* @__PURE__ */ jsx(
11020
+ Box,
11021
+ {
11022
+ className: cn("ui-slot", `ui-slot-${slot}`, className),
11023
+ "data-pattern": pattern,
11024
+ "data-source-trait": sourceTrait,
11025
+ children
11026
+ }
11027
+ ) });
11028
+ break;
11029
+ case "drawer":
11030
+ wrapper = /* @__PURE__ */ jsx(Drawer, { isOpen: true, onClose: handleDismiss, position: "right", children: /* @__PURE__ */ jsx(
11031
+ Box,
11032
+ {
11033
+ className: cn("ui-slot", `ui-slot-${slot}`, className),
11034
+ "data-pattern": pattern,
11035
+ "data-source-trait": sourceTrait,
11036
+ children
11037
+ }
11038
+ ) });
11039
+ break;
11040
+ case "toast":
11041
+ wrapper = /* @__PURE__ */ jsx(Box, { className: "fixed top-4 right-4 z-50", children: /* @__PURE__ */ jsx(
11042
+ Box,
11043
+ {
11044
+ className: cn("ui-slot", `ui-slot-${slot}`, className),
11045
+ "data-pattern": pattern,
11046
+ "data-source-trait": sourceTrait,
11047
+ children
11048
+ }
11049
+ ) });
11050
+ break;
11051
+ default:
11052
+ wrapper = /* @__PURE__ */ jsx(
11053
+ Box,
11054
+ {
11055
+ className: cn("ui-slot", `ui-slot-${slot}`, className),
11056
+ "data-pattern": pattern,
11057
+ "data-source-trait": sourceTrait,
11058
+ children
11059
+ }
11060
+ );
11061
+ }
11062
+ return createPortal(wrapper, portalRoot);
11063
+ }
9267
11064
  function SlotPortal({
9268
11065
  slot,
9269
11066
  content,
@@ -9451,4 +11248,4 @@ function UISlotRenderer({
9451
11248
  }
9452
11249
  UISlotRenderer.displayName = "UISlotRenderer";
9453
11250
 
9454
- export { Accordion, Alert, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, Card, Card2, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Center, Checkbox, CodeBlock, ConditionalWrapper, Container, ControlButton, DataTable, DetailPanel, Divider, Drawer, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FilterGroup, Flex, FloatingActionButton, Form, FormField, FormSectionHeader, Grid2 as Grid, HStack, Heading, HealthBar, Icon, Input, InputGroup, Label, LawReferenceTooltip, LoadingState, MarkdownContent, MasterDetail, Menu2 as Menu, Modal, Overlay, PageHeader, Pagination, Popover, ProgressBar, QuizBlock, Radio, RelationSelect, RepeatableFormSection, ScaledDiagram, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, Spacer, Spinner, Sprite, Stack, StatCard, StateIndicator, SuspenseConfigProvider, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, Toast, Tooltip, Typography, UISlotComponent, UISlotRenderer, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite };
11251
+ export { Accordion, ActionButtons, Alert, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, Card, Card2, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Center, ChartLegend, Checkbox, CodeBlock, ConditionalWrapper, Container, ControlButton, DPad, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DetailPanel, Divider, Drawer, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormField, FormSectionHeader, GraphView, Grid, HStack, Heading, HealthBar, Icon, Input, InputGroup, Label, LawReferenceTooltip, LineChart, LoadingState, MapView, MarkdownContent, MasterDetail, Menu, Modal, Overlay, PageHeader, Pagination, Popover, ProgressBar, ProgressDots, QuizBlock, Radio, RelationSelect, RepeatableFormSection, ScaledDiagram, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, Spacer, Spinner, Sprite, Stack, StatBadge, StatCard, StateIndicator, SuspenseConfigProvider, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Toast, Tooltip, Typography, UISlotComponent, UISlotRenderer, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite };