@almadar/ui 2.1.11 → 2.4.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-BTXQJGFB.js';
2
- import { useTranslate, useQuerySingleton } from './chunk-JLEMVREZ.js';
1
+ import { useTheme, useUISlots } from './chunk-DKQN5FVU.js';
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 React47 from 'react';
11
+ import React47__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';
@@ -17,6 +18,84 @@ 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';
19
20
 
21
+ var iconAliases = {
22
+ "close": LucideIcons.X,
23
+ "trash": LucideIcons.Trash2,
24
+ "loader": LucideIcons.Loader2,
25
+ "stop": LucideIcons.Square,
26
+ "volume": LucideIcons.Volume2,
27
+ "volume-off": LucideIcons.VolumeX,
28
+ "refresh": LucideIcons.RefreshCw,
29
+ "share": LucideIcons.Share2,
30
+ "sort-asc": LucideIcons.ArrowUpNarrowWide,
31
+ "sort-desc": LucideIcons.ArrowDownNarrowWide
32
+ };
33
+ function kebabToPascal(name) {
34
+ return name.split("-").map((part) => {
35
+ if (/^\d+$/.test(part)) return part;
36
+ return part.charAt(0).toUpperCase() + part.slice(1);
37
+ }).join("");
38
+ }
39
+ var resolvedCache = /* @__PURE__ */ new Map();
40
+ function resolveIcon(name) {
41
+ const cached = resolvedCache.get(name);
42
+ if (cached) return cached;
43
+ const resolved = doResolve(name);
44
+ resolvedCache.set(name, resolved);
45
+ return resolved;
46
+ }
47
+ function doResolve(name) {
48
+ if (iconAliases[name]) return iconAliases[name];
49
+ const pascalName = kebabToPascal(name);
50
+ const directLookup = LucideIcons[pascalName];
51
+ if (directLookup && typeof directLookup === "object") return directLookup;
52
+ const asIs = LucideIcons[name];
53
+ if (asIs && typeof asIs === "object") return asIs;
54
+ return LucideIcons.HelpCircle;
55
+ }
56
+ var sizeClasses = {
57
+ xs: "w-3 h-3",
58
+ sm: "w-4 h-4",
59
+ md: "w-5 h-5",
60
+ lg: "w-6 h-6",
61
+ xl: "w-8 h-8"
62
+ };
63
+ var animationClasses = {
64
+ none: "",
65
+ spin: "animate-spin",
66
+ pulse: "animate-pulse"
67
+ };
68
+ var Icon = ({
69
+ icon,
70
+ name,
71
+ size = "md",
72
+ color,
73
+ animation = "none",
74
+ className,
75
+ strokeWidth,
76
+ style
77
+ }) => {
78
+ const IconComponent = icon ?? (name ? resolveIcon(name) : LucideIcons.HelpCircle);
79
+ const effectiveStrokeWidth = strokeWidth ?? void 0;
80
+ return /* @__PURE__ */ jsx(
81
+ IconComponent,
82
+ {
83
+ className: cn(
84
+ sizeClasses[size],
85
+ animationClasses[animation],
86
+ // Use theme's icon color or provided color
87
+ color ? color : "text-[var(--icon-color,currentColor)]",
88
+ className
89
+ ),
90
+ strokeWidth: effectiveStrokeWidth,
91
+ style: {
92
+ ...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
93
+ ...style
94
+ }
95
+ }
96
+ );
97
+ };
98
+ Icon.displayName = "Icon";
20
99
  var variantStyles = {
21
100
  primary: [
22
101
  "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
@@ -75,7 +154,7 @@ var iconSizeStyles = {
75
154
  md: "h-4 w-4",
76
155
  lg: "h-5 w-5"
77
156
  };
78
- var Button = React41__default.forwardRef(
157
+ var Button = React47__default.forwardRef(
79
158
  ({
80
159
  className,
81
160
  variant = "primary",
@@ -84,8 +163,8 @@ var Button = React41__default.forwardRef(
84
163
  disabled,
85
164
  leftIcon,
86
165
  rightIcon,
87
- icon: IconComponent,
88
- iconRight: IconRightComponent,
166
+ icon: iconProp,
167
+ iconRight: iconRightProp,
89
168
  action,
90
169
  actionPayload,
91
170
  label,
@@ -94,6 +173,8 @@ var Button = React41__default.forwardRef(
94
173
  ...props
95
174
  }, ref) => {
96
175
  const eventBus = useEventBus();
176
+ const IconComponent = typeof iconProp === "string" ? resolveIcon(iconProp) : iconProp;
177
+ const IconRightComponent = typeof iconRightProp === "string" ? resolveIcon(iconRightProp) : iconRightProp;
97
178
  const resolvedLeftIcon = leftIcon || IconComponent && /* @__PURE__ */ jsx(IconComponent, { className: iconSizeStyles[size] });
98
179
  const resolvedRightIcon = rightIcon || IconRightComponent && /* @__PURE__ */ jsx(IconRightComponent, { className: iconSizeStyles[size] });
99
180
  const handleClick = (e) => {
@@ -120,6 +201,7 @@ var Button = React41__default.forwardRef(
120
201
  ),
121
202
  onClick: handleClick,
122
203
  ...props,
204
+ "data-testid": props["data-testid"] ?? (action ? `action-${action}` : void 0),
123
205
  children: [
124
206
  isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : resolvedLeftIcon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: resolvedLeftIcon }),
125
207
  children || label,
@@ -130,7 +212,7 @@ var Button = React41__default.forwardRef(
130
212
  }
131
213
  );
132
214
  Button.displayName = "Button";
133
- var Input = React41__default.forwardRef(
215
+ var Input = React47__default.forwardRef(
134
216
  ({
135
217
  className,
136
218
  inputType,
@@ -242,7 +324,7 @@ var Input = React41__default.forwardRef(
242
324
  }
243
325
  );
244
326
  Input.displayName = "Input";
245
- var Label = React41__default.forwardRef(
327
+ var Label = React47__default.forwardRef(
246
328
  ({ className, required, children, ...props }, ref) => {
247
329
  return /* @__PURE__ */ jsxs(
248
330
  "label",
@@ -262,7 +344,7 @@ var Label = React41__default.forwardRef(
262
344
  }
263
345
  );
264
346
  Label.displayName = "Label";
265
- var Textarea = React41__default.forwardRef(
347
+ var Textarea = React47__default.forwardRef(
266
348
  ({ className, error, ...props }, ref) => {
267
349
  return /* @__PURE__ */ jsx(
268
350
  "textarea",
@@ -285,7 +367,7 @@ var Textarea = React41__default.forwardRef(
285
367
  }
286
368
  );
287
369
  Textarea.displayName = "Textarea";
288
- var Select = React41__default.forwardRef(
370
+ var Select = React47__default.forwardRef(
289
371
  ({ className, options, placeholder, error, ...props }, ref) => {
290
372
  return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
291
373
  /* @__PURE__ */ jsxs(
@@ -321,7 +403,7 @@ var Select = React41__default.forwardRef(
321
403
  }
322
404
  );
323
405
  Select.displayName = "Select";
324
- var Checkbox = React41__default.forwardRef(
406
+ var Checkbox = React47__default.forwardRef(
325
407
  ({ className, label, id, ...props }, ref) => {
326
408
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
327
409
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
@@ -387,7 +469,7 @@ var shadowStyles = {
387
469
  md: "shadow-[var(--shadow-main)]",
388
470
  lg: "shadow-[var(--shadow-lg)]"
389
471
  };
390
- var Card = React41__default.forwardRef(
472
+ var Card = React47__default.forwardRef(
391
473
  ({
392
474
  className,
393
475
  variant = "bordered",
@@ -423,9 +505,9 @@ var Card = React41__default.forwardRef(
423
505
  }
424
506
  );
425
507
  Card.displayName = "Card";
426
- var CardHeader = React41__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
508
+ var CardHeader = React47__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
427
509
  CardHeader.displayName = "CardHeader";
428
- var CardTitle = React41__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
510
+ var CardTitle = React47__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
429
511
  "h3",
430
512
  {
431
513
  ref,
@@ -438,11 +520,11 @@ var CardTitle = React41__default.forwardRef(({ className, ...props }, ref) => /*
438
520
  }
439
521
  ));
440
522
  CardTitle.displayName = "CardTitle";
441
- var CardContent = React41__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
523
+ var CardContent = React47__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
442
524
  CardContent.displayName = "CardContent";
443
525
  var CardBody = CardContent;
444
526
  CardBody.displayName = "CardBody";
445
- var CardFooter = React41__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
527
+ var CardFooter = React47__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
446
528
  "div",
447
529
  {
448
530
  ref,
@@ -488,8 +570,8 @@ var sizeStyles2 = {
488
570
  md: "px-2.5 py-1 text-sm",
489
571
  lg: "px-3 py-1.5 text-base"
490
572
  };
491
- var Badge = React41__default.forwardRef(
492
- ({ className, variant = "default", size = "sm", ...props }, ref) => {
573
+ var Badge = React47__default.forwardRef(
574
+ ({ className, variant = "default", size = "sm", label, children, ...props }, ref) => {
493
575
  return /* @__PURE__ */ jsx(
494
576
  "span",
495
577
  {
@@ -500,7 +582,8 @@ var Badge = React41__default.forwardRef(
500
582
  sizeStyles2[size],
501
583
  className
502
584
  ),
503
- ...props
585
+ ...props,
586
+ children: children || label
504
587
  }
505
588
  );
506
589
  }
@@ -512,7 +595,7 @@ var sizeStyles3 = {
512
595
  md: "h-6 w-6",
513
596
  lg: "h-8 w-8"
514
597
  };
515
- var Spinner = React41__default.forwardRef(
598
+ var Spinner = React47__default.forwardRef(
516
599
  ({ className, size = "md", ...props }, ref) => {
517
600
  return /* @__PURE__ */ jsx(
518
601
  "div",
@@ -526,7 +609,7 @@ var Spinner = React41__default.forwardRef(
526
609
  }
527
610
  );
528
611
  Spinner.displayName = "Spinner";
529
- var sizeClasses = {
612
+ var sizeClasses2 = {
530
613
  xs: "w-6 h-6 text-xs",
531
614
  sm: "w-8 h-8 text-sm",
532
615
  md: "w-10 h-10 text-base",
@@ -602,7 +685,7 @@ var Avatar = ({
602
685
  "relative inline-flex items-center justify-center",
603
686
  "bg-[var(--color-muted)] border-[length:var(--border-width)] border-[var(--color-border)]",
604
687
  "overflow-hidden",
605
- sizeClasses[size],
688
+ sizeClasses2[size],
606
689
  isClickable && "cursor-pointer hover:bg-[var(--color-surface-hover)] transition-colors",
607
690
  className
608
691
  ),
@@ -777,7 +860,7 @@ var positionStyles = {
777
860
  fixed: "fixed",
778
861
  sticky: "sticky"
779
862
  };
780
- var Box = React41__default.forwardRef(
863
+ var Box = React47__default.forwardRef(
781
864
  ({
782
865
  padding,
783
866
  paddingX,
@@ -969,157 +1052,6 @@ var Divider = ({
969
1052
  );
970
1053
  };
971
1054
  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
1055
  var colorClasses = {
1124
1056
  default: "bg-[var(--color-primary)]",
1125
1057
  primary: "bg-[var(--color-primary)]",
@@ -1273,7 +1205,7 @@ var ProgressBar = ({
1273
1205
  return null;
1274
1206
  };
1275
1207
  ProgressBar.displayName = "ProgressBar";
1276
- var Radio = React41__default.forwardRef(
1208
+ var Radio = React47__default.forwardRef(
1277
1209
  ({
1278
1210
  label,
1279
1211
  helperText,
@@ -1377,7 +1309,7 @@ var Radio = React41__default.forwardRef(
1377
1309
  }
1378
1310
  );
1379
1311
  Radio.displayName = "Radio";
1380
- var Switch = React41.forwardRef(
1312
+ var Switch = React47.forwardRef(
1381
1313
  ({
1382
1314
  checked,
1383
1315
  defaultChecked = false,
@@ -1388,10 +1320,10 @@ var Switch = React41.forwardRef(
1388
1320
  name,
1389
1321
  className
1390
1322
  }, ref) => {
1391
- const [isChecked, setIsChecked] = React41.useState(
1323
+ const [isChecked, setIsChecked] = React47.useState(
1392
1324
  checked !== void 0 ? checked : defaultChecked
1393
1325
  );
1394
- React41.useEffect(() => {
1326
+ React47.useEffect(() => {
1395
1327
  if (checked !== void 0) {
1396
1328
  setIsChecked(checked);
1397
1329
  }
@@ -1626,6 +1558,8 @@ var variantStyles5 = {
1626
1558
  h4: "text-xl font-bold text-[var(--color-foreground)]",
1627
1559
  h5: "text-lg font-bold text-[var(--color-foreground)]",
1628
1560
  h6: "text-base font-bold text-[var(--color-foreground)]",
1561
+ heading: "text-2xl font-bold text-[var(--color-foreground)]",
1562
+ subheading: "text-lg font-semibold text-[var(--color-foreground)]",
1629
1563
  body1: "text-base font-normal text-[var(--color-foreground)]",
1630
1564
  body2: "text-sm font-normal text-[var(--color-foreground)]",
1631
1565
  body: "text-base font-normal text-[var(--color-foreground)]",
@@ -1658,6 +1592,8 @@ var defaultElements = {
1658
1592
  h4: "h4",
1659
1593
  h5: "h5",
1660
1594
  h6: "h6",
1595
+ heading: "h2",
1596
+ subheading: "h3",
1661
1597
  body1: "p",
1662
1598
  body2: "p",
1663
1599
  body: "p",
@@ -1951,7 +1887,7 @@ var Overlay = ({
1951
1887
  isVisible = true,
1952
1888
  onClick,
1953
1889
  className,
1954
- blur = true,
1890
+ blur = false,
1955
1891
  action
1956
1892
  }) => {
1957
1893
  const eventBus = useEventBus();
@@ -1966,7 +1902,7 @@ var Overlay = ({
1966
1902
  "div",
1967
1903
  {
1968
1904
  className: cn(
1969
- "fixed inset-0 z-40 bg-[var(--color-background)]/80",
1905
+ "fixed inset-0 z-40 bg-black/50",
1970
1906
  blur && "backdrop-blur-sm",
1971
1907
  className
1972
1908
  ),
@@ -1975,6 +1911,33 @@ var Overlay = ({
1975
1911
  }
1976
1912
  );
1977
1913
  };
1914
+ var FlipContainer = ({
1915
+ flipped,
1916
+ className,
1917
+ children,
1918
+ onClick
1919
+ }) => {
1920
+ return /* @__PURE__ */ jsx(
1921
+ Box,
1922
+ {
1923
+ className: cn("relative w-full cursor-pointer", className),
1924
+ style: { perspective: "1000px" },
1925
+ onClick,
1926
+ children: /* @__PURE__ */ jsx(
1927
+ Box,
1928
+ {
1929
+ className: "relative w-full h-full transition-transform duration-500",
1930
+ style: {
1931
+ transformStyle: "preserve-3d",
1932
+ transform: flipped ? "rotateY(180deg)" : "rotateY(0deg)"
1933
+ },
1934
+ children
1935
+ }
1936
+ )
1937
+ }
1938
+ );
1939
+ };
1940
+ FlipContainer.displayName = "FlipContainer";
1978
1941
  function toSharedContext(ctx) {
1979
1942
  return createMinimalContext(
1980
1943
  {
@@ -2031,8 +1994,8 @@ var LawReferenceTooltip = ({
2031
1994
  position = "top",
2032
1995
  className
2033
1996
  }) => {
2034
- const [isVisible, setIsVisible] = React41__default.useState(false);
2035
- const timeoutRef = React41__default.useRef(null);
1997
+ const [isVisible, setIsVisible] = React47__default.useState(false);
1998
+ const timeoutRef = React47__default.useRef(null);
2036
1999
  const handleMouseEnter = () => {
2037
2000
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2038
2001
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -2041,7 +2004,7 @@ var LawReferenceTooltip = ({
2041
2004
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2042
2005
  setIsVisible(false);
2043
2006
  };
2044
- React41__default.useEffect(() => {
2007
+ React47__default.useEffect(() => {
2045
2008
  return () => {
2046
2009
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2047
2010
  };
@@ -2135,6 +2098,79 @@ var LawReferenceTooltip = ({
2135
2098
  );
2136
2099
  };
2137
2100
  LawReferenceTooltip.displayName = "LawReferenceTooltip";
2101
+ var DAY_ABBREVIATIONS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2102
+ function DayCell({
2103
+ date,
2104
+ isToday = false,
2105
+ onClick,
2106
+ className
2107
+ }) {
2108
+ const handleClick = useCallback(() => {
2109
+ onClick?.(date);
2110
+ }, [onClick, date]);
2111
+ const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
2112
+ return /* @__PURE__ */ jsxs(
2113
+ Box,
2114
+ {
2115
+ className: cn(
2116
+ "p-2 text-center cursor-pointer hover:bg-[var(--color-muted)] transition-colors",
2117
+ isToday && "bg-blue-500/10",
2118
+ className
2119
+ ),
2120
+ onClick: handleClick,
2121
+ children: [
2122
+ /* @__PURE__ */ jsx(
2123
+ Typography,
2124
+ {
2125
+ variant: "small",
2126
+ className: cn(
2127
+ "font-medium",
2128
+ isToday ? "text-blue-600" : "text-[var(--color-muted-foreground)]"
2129
+ ),
2130
+ children: dayAbbr
2131
+ }
2132
+ ),
2133
+ /* @__PURE__ */ jsx(
2134
+ Box,
2135
+ {
2136
+ display: "flex",
2137
+ rounded: "full",
2138
+ className: cn(
2139
+ "h-8 w-8 mx-auto items-center justify-center",
2140
+ isToday && "bg-blue-600 text-white"
2141
+ ),
2142
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
2143
+ }
2144
+ )
2145
+ ]
2146
+ }
2147
+ );
2148
+ }
2149
+ DayCell.displayName = "DayCell";
2150
+ function TimeSlotCell({
2151
+ time,
2152
+ onClick,
2153
+ className,
2154
+ children,
2155
+ isOccupied = false
2156
+ }) {
2157
+ const handleClick = useCallback(() => {
2158
+ onClick?.(time);
2159
+ }, [onClick, time]);
2160
+ return /* @__PURE__ */ jsx(
2161
+ Box,
2162
+ {
2163
+ className: cn(
2164
+ "p-1 min-h-[60px] cursor-pointer hover:bg-[var(--color-muted)] transition-colors",
2165
+ isOccupied && "bg-[var(--color-muted)]/30",
2166
+ className
2167
+ ),
2168
+ onClick: handleClick,
2169
+ children
2170
+ }
2171
+ );
2172
+ }
2173
+ TimeSlotCell.displayName = "TimeSlotCell";
2138
2174
  var heartIcon = (filled, size) => /* @__PURE__ */ jsx(
2139
2175
  "svg",
2140
2176
  {
@@ -2217,9 +2253,9 @@ function ScoreDisplay({
2217
2253
  animated = true,
2218
2254
  locale = "en-US"
2219
2255
  }) {
2220
- const [displayValue, setDisplayValue] = React41.useState(value);
2221
- const [isAnimating, setIsAnimating] = React41.useState(false);
2222
- React41.useEffect(() => {
2256
+ const [displayValue, setDisplayValue] = React47.useState(value);
2257
+ const [isAnimating, setIsAnimating] = React47.useState(false);
2258
+ React47.useEffect(() => {
2223
2259
  if (!animated || displayValue === value) {
2224
2260
  setDisplayValue(value);
2225
2261
  return;
@@ -2292,9 +2328,9 @@ function ControlButton({
2292
2328
  className
2293
2329
  }) {
2294
2330
  const eventBus = useEventBus();
2295
- const [isPressed, setIsPressed] = React41.useState(false);
2331
+ const [isPressed, setIsPressed] = React47.useState(false);
2296
2332
  const actualPressed = pressed ?? isPressed;
2297
- const handlePointerDown = React41.useCallback(
2333
+ const handlePointerDown = React47.useCallback(
2298
2334
  (e) => {
2299
2335
  e.preventDefault();
2300
2336
  if (disabled) return;
@@ -2304,7 +2340,7 @@ function ControlButton({
2304
2340
  },
2305
2341
  [disabled, pressEvent, eventBus, onPress]
2306
2342
  );
2307
- const handlePointerUp = React41.useCallback(
2343
+ const handlePointerUp = React47.useCallback(
2308
2344
  (e) => {
2309
2345
  e.preventDefault();
2310
2346
  if (disabled) return;
@@ -2314,7 +2350,7 @@ function ControlButton({
2314
2350
  },
2315
2351
  [disabled, releaseEvent, eventBus, onRelease]
2316
2352
  );
2317
- const handlePointerLeave = React41.useCallback(
2353
+ const handlePointerLeave = React47.useCallback(
2318
2354
  (e) => {
2319
2355
  if (isPressed) {
2320
2356
  setIsPressed(false);
@@ -2542,7 +2578,7 @@ var ErrorState = ({
2542
2578
  );
2543
2579
  };
2544
2580
  ErrorState.displayName = "ErrorState";
2545
- var ErrorBoundary = class extends React41__default.Component {
2581
+ var ErrorBoundary = class extends React47__default.Component {
2546
2582
  constructor(props) {
2547
2583
  super(props);
2548
2584
  __publicField(this, "reset", () => {
@@ -2946,7 +2982,7 @@ var variantIconColors = {
2946
2982
  warning: "text-[var(--color-warning)]",
2947
2983
  error: "text-[var(--color-error)]"
2948
2984
  };
2949
- var iconMap2 = {
2985
+ var iconMap = {
2950
2986
  info: Info,
2951
2987
  success: CheckCircle,
2952
2988
  warning: AlertTriangle,
@@ -2985,7 +3021,7 @@ var Alert = ({
2985
3021
  /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx(
2986
3022
  Icon,
2987
3023
  {
2988
- icon: iconMap2[variant],
3024
+ icon: iconMap[variant],
2989
3025
  size: "md",
2990
3026
  className: variantIconColors[variant]
2991
3027
  }
@@ -3997,7 +4033,7 @@ function getColsClass(cols) {
3997
4033
  }
3998
4034
  return classes.join(" ");
3999
4035
  }
4000
- var Grid2 = ({
4036
+ var Grid = ({
4001
4037
  cols = 1,
4002
4038
  rows,
4003
4039
  gap = "md",
@@ -4034,7 +4070,7 @@ var Grid2 = ({
4034
4070
  }
4035
4071
  );
4036
4072
  };
4037
- Grid2.displayName = "Grid";
4073
+ Grid.displayName = "Grid";
4038
4074
  var InputGroup = ({
4039
4075
  leftAddon,
4040
4076
  rightAddon,
@@ -4089,7 +4125,7 @@ var InputGroup = ({
4089
4125
  ] });
4090
4126
  };
4091
4127
  InputGroup.displayName = "InputGroup";
4092
- var Menu2 = ({
4128
+ var Menu = ({
4093
4129
  trigger,
4094
4130
  items,
4095
4131
  position = "bottom-left",
@@ -4150,8 +4186,8 @@ var Menu2 = ({
4150
4186
  "bottom-start": "top-full left-0 mt-2",
4151
4187
  "bottom-end": "top-full right-0 mt-2"
4152
4188
  };
4153
- const triggerChild = React41__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx("span", { children: trigger });
4154
- const triggerElement = React41__default.cloneElement(
4189
+ const triggerChild = React47__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx("span", { children: trigger });
4190
+ const triggerElement = React47__default.cloneElement(
4155
4191
  triggerChild,
4156
4192
  {
4157
4193
  ref: triggerRef,
@@ -4247,7 +4283,7 @@ var Menu2 = ({
4247
4283
  )
4248
4284
  ] });
4249
4285
  };
4250
- Menu2.displayName = "Menu";
4286
+ Menu.displayName = "Menu";
4251
4287
  var sizeClasses4 = {
4252
4288
  sm: "max-w-md",
4253
4289
  md: "max-w-lg",
@@ -4355,6 +4391,7 @@ var Modal = ({
4355
4391
  {
4356
4392
  type: "button",
4357
4393
  onClick: handleClose,
4394
+ "data-event": "CLOSE",
4358
4395
  className: cn(
4359
4396
  "p-1 transition-colors rounded-[var(--radius-sm)]",
4360
4397
  "hover:bg-[var(--color-muted)]"
@@ -4612,8 +4649,8 @@ var Popover = ({
4612
4649
  onMouseEnter: handleOpen,
4613
4650
  onMouseLeave: handleClose
4614
4651
  };
4615
- const childElement = React41__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
4616
- const triggerElement = React41__default.cloneElement(
4652
+ const childElement = React47__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
4653
+ const triggerElement = React47__default.cloneElement(
4617
4654
  childElement,
4618
4655
  {
4619
4656
  ref: triggerRef,
@@ -5193,7 +5230,7 @@ var variantClasses = {
5193
5230
  info: "bg-[var(--color-card)] border-[length:var(--border-width)] border-[var(--color-info)]",
5194
5231
  warning: "bg-[var(--color-card)] border-[length:var(--border-width)] border-[var(--color-warning)]"
5195
5232
  };
5196
- var iconMap3 = {
5233
+ var iconMap2 = {
5197
5234
  success: CheckCircle,
5198
5235
  error: AlertCircle,
5199
5236
  info: Info,
@@ -5251,7 +5288,7 @@ var Toast = ({
5251
5288
  /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx(
5252
5289
  Icon,
5253
5290
  {
5254
- icon: iconMap3[variant],
5291
+ icon: iconMap2[variant],
5255
5292
  size: "md",
5256
5293
  className: iconColors[variant]
5257
5294
  }
@@ -5343,8 +5380,8 @@ var Tooltip = ({
5343
5380
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
5344
5381
  };
5345
5382
  }, []);
5346
- const triggerElement = React41__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
5347
- const trigger = React41__default.cloneElement(triggerElement, {
5383
+ const triggerElement = React47__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
5384
+ const trigger = React47__default.cloneElement(triggerElement, {
5348
5385
  ref: triggerRef,
5349
5386
  onMouseEnter: handleMouseEnter,
5350
5387
  onMouseLeave: handleMouseLeave,
@@ -5593,7 +5630,7 @@ var WizardProgress = ({
5593
5630
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: steps.map((step, index) => {
5594
5631
  const isActive = index === currentStep;
5595
5632
  const isCompleted = index < currentStep;
5596
- return /* @__PURE__ */ jsxs(React41__default.Fragment, { children: [
5633
+ return /* @__PURE__ */ jsxs(React47__default.Fragment, { children: [
5597
5634
  /* @__PURE__ */ jsx(
5598
5635
  "button",
5599
5636
  {
@@ -5723,7 +5760,7 @@ var WizardNavigation = ({
5723
5760
  );
5724
5761
  };
5725
5762
  WizardNavigation.displayName = "WizardNavigation";
5726
- var MarkdownContent = React41__default.memo(
5763
+ var MarkdownContent = React47__default.memo(
5727
5764
  ({ content, direction, className }) => {
5728
5765
  const { t: _t } = useTranslate();
5729
5766
  return /* @__PURE__ */ jsx(
@@ -5824,7 +5861,7 @@ var MarkdownContent = React41__default.memo(
5824
5861
  (prev, next) => prev.content === next.content && prev.className === next.className && prev.direction === next.direction
5825
5862
  );
5826
5863
  MarkdownContent.displayName = "MarkdownContent";
5827
- var CodeBlock = React41__default.memo(
5864
+ var CodeBlock = React47__default.memo(
5828
5865
  ({
5829
5866
  code,
5830
5867
  language = "text",
@@ -6049,6 +6086,156 @@ var ScaledDiagram = ({
6049
6086
  );
6050
6087
  };
6051
6088
  ScaledDiagram.displayName = "ScaledDiagram";
6089
+ function getStartOfWeek(date) {
6090
+ const d = new Date(date);
6091
+ const day = d.getDay();
6092
+ const diff = d.getDate() - day + (day === 0 ? -6 : 1);
6093
+ d.setDate(diff);
6094
+ d.setHours(0, 0, 0, 0);
6095
+ return d;
6096
+ }
6097
+ function getWeekDays(start) {
6098
+ const days = [];
6099
+ for (let i = 0; i < 7; i++) {
6100
+ const day = new Date(start);
6101
+ day.setDate(start.getDate() + i);
6102
+ days.push(day);
6103
+ }
6104
+ return days;
6105
+ }
6106
+ function generateDefaultTimeSlots() {
6107
+ const slots = [];
6108
+ for (let hour = 9; hour <= 17; hour++) {
6109
+ slots.push(`${hour.toString().padStart(2, "0")}:00`);
6110
+ }
6111
+ return slots;
6112
+ }
6113
+ function eventInSlot(event, day, slotTime) {
6114
+ const eventStart = new Date(event.startTime);
6115
+ const [slotHour, slotMinute] = slotTime.split(":").map(Number);
6116
+ return eventStart.toDateString() === day.toDateString() && eventStart.getHours() === slotHour && eventStart.getMinutes() === slotMinute;
6117
+ }
6118
+ function CalendarGrid({
6119
+ weekStart,
6120
+ timeSlots,
6121
+ events = [],
6122
+ onSlotClick,
6123
+ onDayClick,
6124
+ onEventClick,
6125
+ className
6126
+ }) {
6127
+ const resolvedWeekStart = useMemo(
6128
+ () => weekStart ? getStartOfWeek(weekStart) : getStartOfWeek(/* @__PURE__ */ new Date()),
6129
+ [weekStart]
6130
+ );
6131
+ const weekDays = useMemo(
6132
+ () => getWeekDays(resolvedWeekStart),
6133
+ [resolvedWeekStart]
6134
+ );
6135
+ const resolvedTimeSlots = useMemo(
6136
+ () => timeSlots ?? generateDefaultTimeSlots(),
6137
+ [timeSlots]
6138
+ );
6139
+ const handleSlotClick = useCallback(
6140
+ (day, time) => {
6141
+ onSlotClick?.(day, time);
6142
+ },
6143
+ [onSlotClick]
6144
+ );
6145
+ const handleEventClick = useCallback(
6146
+ (event, e) => {
6147
+ e.stopPropagation();
6148
+ onEventClick?.(event);
6149
+ },
6150
+ [onEventClick]
6151
+ );
6152
+ const eventsForDayCount = useCallback(
6153
+ (day) => events.filter(
6154
+ (ev) => new Date(ev.startTime).toDateString() === day.toDateString()
6155
+ ).length,
6156
+ [events]
6157
+ );
6158
+ const renderEvent = (event) => /* @__PURE__ */ jsx(
6159
+ Box,
6160
+ {
6161
+ rounded: "md",
6162
+ padding: "xs",
6163
+ border: true,
6164
+ className: cn(
6165
+ "cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
6166
+ event.color ? event.color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
6167
+ ),
6168
+ onClick: (e) => handleEventClick(event, e),
6169
+ children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
6170
+ },
6171
+ event.id
6172
+ );
6173
+ return /* @__PURE__ */ jsx(Box, { className: cn("overflow-x-auto", className), children: /* @__PURE__ */ jsxs(Box, { className: "min-w-[800px]", children: [
6174
+ /* @__PURE__ */ jsxs(Box, { className: "grid grid-cols-8 border-b border-[var(--color-border)]", children: [
6175
+ /* @__PURE__ */ jsx(Box, { className: "p-2" }),
6176
+ weekDays.map((day) => {
6177
+ const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
6178
+ const count = eventsForDayCount(day);
6179
+ return /* @__PURE__ */ jsxs(
6180
+ Box,
6181
+ {
6182
+ className: "border-l border-[var(--color-border)]",
6183
+ children: [
6184
+ /* @__PURE__ */ jsx(
6185
+ DayCell,
6186
+ {
6187
+ date: day,
6188
+ isToday,
6189
+ onClick: onDayClick
6190
+ }
6191
+ ),
6192
+ count > 0 && /* @__PURE__ */ jsx(Box, { className: "text-center pb-1", children: /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: count }) })
6193
+ ]
6194
+ },
6195
+ day.toISOString()
6196
+ );
6197
+ })
6198
+ ] }),
6199
+ /* @__PURE__ */ jsx(Box, { className: "max-h-[500px] overflow-y-auto", children: resolvedTimeSlots.map((time) => /* @__PURE__ */ jsxs(
6200
+ Box,
6201
+ {
6202
+ className: "grid grid-cols-8 border-b border-[var(--color-border)]",
6203
+ children: [
6204
+ /* @__PURE__ */ jsx(Box, { className: "p-2 text-right pr-3", children: /* @__PURE__ */ jsx(
6205
+ Typography,
6206
+ {
6207
+ variant: "small",
6208
+ className: "text-[var(--color-muted-foreground)]",
6209
+ children: time
6210
+ }
6211
+ ) }),
6212
+ weekDays.map((day) => {
6213
+ const slotEvents = events.filter(
6214
+ (ev) => eventInSlot(ev, day, time)
6215
+ );
6216
+ const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
6217
+ return /* @__PURE__ */ jsx(
6218
+ TimeSlotCell,
6219
+ {
6220
+ time,
6221
+ isOccupied: slotEvents.length > 0,
6222
+ onClick: () => handleSlotClick(day, time),
6223
+ className: cn(
6224
+ "border-l border-[var(--color-border)]",
6225
+ isToday && "bg-blue-50/30"
6226
+ ),
6227
+ children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: slotEvents.map(renderEvent) })
6228
+ },
6229
+ `${day.toISOString()}-${time}`
6230
+ );
6231
+ })
6232
+ ]
6233
+ },
6234
+ time
6235
+ )) })
6236
+ ] }) });
6237
+ }
6238
+ CalendarGrid.displayName = "CalendarGrid";
6052
6239
  var RepeatableFormSection = ({
6053
6240
  sectionType,
6054
6241
  title,
@@ -6423,26 +6610,983 @@ var FormSectionHeader = ({
6423
6610
  );
6424
6611
  };
6425
6612
  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",
6435
- DESELECT: "DESELECT"
6436
- };
6437
- function normalizeColumns(columns) {
6438
- return columns.map((col) => {
6613
+ var FlipCard = ({
6614
+ front,
6615
+ back,
6616
+ flipped = false,
6617
+ onFlip,
6618
+ className,
6619
+ height = "h-64"
6620
+ }) => {
6621
+ return /* @__PURE__ */ jsxs(
6622
+ FlipContainer,
6623
+ {
6624
+ flipped,
6625
+ className: cn(height, className),
6626
+ onClick: onFlip,
6627
+ children: [
6628
+ /* @__PURE__ */ jsx(
6629
+ Box,
6630
+ {
6631
+ className: "absolute inset-0 w-full h-full rounded-lg shadow-lg flex items-center justify-center p-6",
6632
+ style: { backfaceVisibility: "hidden", transform: "rotateY(0deg)" },
6633
+ children: front
6634
+ }
6635
+ ),
6636
+ /* @__PURE__ */ jsx(
6637
+ Box,
6638
+ {
6639
+ className: "absolute inset-0 w-full h-full rounded-lg shadow-lg flex items-center justify-center p-6",
6640
+ style: { backfaceVisibility: "hidden", transform: "rotateY(180deg)" },
6641
+ children: back
6642
+ }
6643
+ )
6644
+ ]
6645
+ }
6646
+ );
6647
+ };
6648
+ FlipCard.displayName = "FlipCard";
6649
+ var DEFAULT_OPTIONS = [
6650
+ { label: "1W", value: "week" },
6651
+ { label: "1M", value: "month" },
6652
+ { label: "3M", value: "3months" },
6653
+ { label: "1Y", value: "year" }
6654
+ ];
6655
+ var DateRangeSelector = ({
6656
+ options = DEFAULT_OPTIONS,
6657
+ selected = "month",
6658
+ onSelect,
6659
+ className
6660
+ }) => {
6661
+ return /* @__PURE__ */ jsx(HStack, { gap: "xs", className: cn(className), children: options.map((option) => /* @__PURE__ */ jsx(
6662
+ Button,
6663
+ {
6664
+ variant: selected === option.value ? "primary" : "ghost",
6665
+ size: "sm",
6666
+ onClick: () => onSelect?.(option.value),
6667
+ children: option.label
6668
+ },
6669
+ option.value
6670
+ )) });
6671
+ };
6672
+ DateRangeSelector.displayName = "DateRangeSelector";
6673
+ var ChartLegend = ({
6674
+ items,
6675
+ className,
6676
+ direction = "horizontal"
6677
+ }) => {
6678
+ const Wrapper = direction === "horizontal" ? HStack : VStack;
6679
+ return /* @__PURE__ */ jsx(Wrapper, { gap: "md", className: cn("flex-wrap", className), children: items.map((item) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
6680
+ /* @__PURE__ */ jsx(
6681
+ Box,
6682
+ {
6683
+ className: "rounded-full shrink-0",
6684
+ style: {
6685
+ width: 10,
6686
+ height: 10,
6687
+ backgroundColor: item.color
6688
+ }
6689
+ }
6690
+ ),
6691
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-[var(--color-muted-foreground)]", children: item.label })
6692
+ ] }, item.label)) });
6693
+ };
6694
+ ChartLegend.displayName = "ChartLegend";
6695
+ var LineChart = ({
6696
+ data,
6697
+ width = 400,
6698
+ height = 200,
6699
+ showGrid = true,
6700
+ showValues = false,
6701
+ showArea = true,
6702
+ lineColor = "var(--color-primary)",
6703
+ areaColor = "var(--color-primary)",
6704
+ className
6705
+ }) => {
6706
+ const gradientId = useId();
6707
+ const sortedData = useMemo(() => {
6708
+ return [...data].sort(
6709
+ (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
6710
+ );
6711
+ }, [data]);
6712
+ const points = useMemo(() => {
6713
+ if (sortedData.length === 0) return [];
6714
+ const values = sortedData.map((d) => d.value);
6715
+ const minVal = Math.min(...values);
6716
+ const maxVal = Math.max(...values);
6717
+ const range = maxVal - minVal || 1;
6718
+ const padding = 20;
6719
+ const chartWidth = width - padding * 2;
6720
+ const chartHeight = height - padding * 2;
6721
+ return sortedData.map((point, index) => ({
6722
+ x: padding + index / (sortedData.length - 1 || 1) * chartWidth,
6723
+ y: padding + chartHeight - (point.value - minVal) / range * chartHeight,
6724
+ value: point.value,
6725
+ label: point.label
6726
+ }));
6727
+ }, [sortedData, width, height]);
6728
+ const linePath = useMemo(() => {
6729
+ if (points.length === 0) return "";
6730
+ return points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
6731
+ }, [points]);
6732
+ const areaPath = useMemo(() => {
6733
+ if (points.length === 0 || !showArea) return "";
6734
+ const bottom = height - 20;
6735
+ const first = points[0];
6736
+ const last = points[points.length - 1];
6737
+ return `${linePath} L ${last.x} ${bottom} L ${first.x} ${bottom} Z`;
6738
+ }, [linePath, points, height, showArea]);
6739
+ if (data.length === 0) {
6740
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center text-[var(--color-muted-foreground)]", className), style: { width, height }, children: "No data" });
6741
+ }
6742
+ return /* @__PURE__ */ jsx(Box, { className: cn(className), children: /* @__PURE__ */ jsxs(
6743
+ "svg",
6744
+ {
6745
+ viewBox: `0 0 ${width} ${height}`,
6746
+ width: "100%",
6747
+ height: "100%",
6748
+ preserveAspectRatio: "xMidYMid meet",
6749
+ children: [
6750
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
6751
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.3" }),
6752
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
6753
+ ] }) }),
6754
+ showGrid && /* @__PURE__ */ jsxs(Fragment, { children: [
6755
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: height * 0.25, x2: width - 20, y2: height * 0.25, stroke: "var(--color-border, #e5e7eb)", strokeWidth: "1" }),
6756
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: height * 0.5, x2: width - 20, y2: height * 0.5, stroke: "var(--color-border, #e5e7eb)", strokeWidth: "1" }),
6757
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: height * 0.75, x2: width - 20, y2: height * 0.75, stroke: "var(--color-border, #e5e7eb)", strokeWidth: "1" })
6758
+ ] }),
6759
+ showArea && areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: `url(#${gradientId})` }),
6760
+ linePath && /* @__PURE__ */ jsx(
6761
+ "path",
6762
+ {
6763
+ d: linePath,
6764
+ fill: "none",
6765
+ stroke: lineColor,
6766
+ strokeWidth: "2",
6767
+ strokeLinejoin: "round",
6768
+ strokeLinecap: "round"
6769
+ }
6770
+ ),
6771
+ points.map((point, index) => /* @__PURE__ */ jsx(
6772
+ "circle",
6773
+ {
6774
+ cx: point.x,
6775
+ cy: point.y,
6776
+ r: "4",
6777
+ fill: lineColor,
6778
+ stroke: "var(--color-background, white)",
6779
+ strokeWidth: "2"
6780
+ },
6781
+ index
6782
+ )),
6783
+ showValues && points.map((point, index) => /* @__PURE__ */ jsx(
6784
+ "text",
6785
+ {
6786
+ x: point.x,
6787
+ y: point.y - 10,
6788
+ textAnchor: "middle",
6789
+ fontSize: "11",
6790
+ fill: "var(--color-foreground, currentColor)",
6791
+ children: point.label ?? point.value
6792
+ },
6793
+ `label-${index}`
6794
+ ))
6795
+ ]
6796
+ }
6797
+ ) });
6798
+ };
6799
+ LineChart.displayName = "LineChart";
6800
+ var sizeMap4 = {
6801
+ sm: { dot: 6, active: 8 },
6802
+ md: { dot: 8, active: 10 },
6803
+ lg: { dot: 10, active: 14 }
6804
+ };
6805
+ var stateColors = {
6806
+ active: "var(--color-primary)",
6807
+ complete: "var(--color-success, #22c55e)",
6808
+ pending: "var(--color-muted, #d4d4d8)"
6809
+ };
6810
+ var ProgressDots = ({
6811
+ count,
6812
+ currentIndex,
6813
+ getState,
6814
+ onDotClick,
6815
+ className,
6816
+ size = "md"
6817
+ }) => {
6818
+ const defaultGetState = useCallback(
6819
+ (index) => {
6820
+ if (index === currentIndex) return "active";
6821
+ return "pending";
6822
+ },
6823
+ [currentIndex]
6824
+ );
6825
+ const resolveState = getState ?? defaultGetState;
6826
+ const dims = sizeMap4[size];
6827
+ return /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", className: cn(className), children: Array.from({ length: count }, (_, index) => {
6828
+ const state = resolveState(index);
6829
+ const isActive = state === "active";
6830
+ const dotSize = isActive ? dims.active : dims.dot;
6831
+ return /* @__PURE__ */ jsx(
6832
+ Box,
6833
+ {
6834
+ className: cn(
6835
+ "rounded-full transition-all duration-200",
6836
+ onDotClick && "cursor-pointer"
6837
+ ),
6838
+ style: {
6839
+ width: dotSize,
6840
+ height: dotSize,
6841
+ backgroundColor: stateColors[state],
6842
+ transform: isActive ? "scale(1.2)" : "scale(1)"
6843
+ },
6844
+ onClick: onDotClick ? () => onDotClick(index) : void 0
6845
+ },
6846
+ index
6847
+ );
6848
+ }) });
6849
+ };
6850
+ ProgressDots.displayName = "ProgressDots";
6851
+ var GROUP_COLORS = [
6852
+ "#3b82f6",
6853
+ // blue-500
6854
+ "#10b981",
6855
+ // emerald-500
6856
+ "#f59e0b",
6857
+ // amber-500
6858
+ "#ef4444",
6859
+ // red-500
6860
+ "#8b5cf6",
6861
+ // violet-500
6862
+ "#ec4899",
6863
+ // pink-500
6864
+ "#06b6d4",
6865
+ // cyan-500
6866
+ "#84cc16"
6867
+ // lime-500
6868
+ ];
6869
+ var DEFAULT_NODE_COLOR = "#3b82f6";
6870
+ var DEFAULT_EDGE_COLOR = "#9ca3af";
6871
+ var DEFAULT_NODE_SIZE = 8;
6872
+ function resolveNodeColor(node, groups) {
6873
+ if (node.color) return node.color;
6874
+ if (node.group) {
6875
+ const idx = groups.indexOf(node.group);
6876
+ return GROUP_COLORS[idx % GROUP_COLORS.length];
6877
+ }
6878
+ return DEFAULT_NODE_COLOR;
6879
+ }
6880
+ var GraphView = ({
6881
+ nodes,
6882
+ edges,
6883
+ onNodeClick,
6884
+ onNodeHover,
6885
+ width: propWidth,
6886
+ height: propHeight,
6887
+ className,
6888
+ showLabels = true,
6889
+ zoomToFit = true
6890
+ }) => {
6891
+ const containerRef = useRef(null);
6892
+ const animRef = useRef(0);
6893
+ const [simNodes, setSimNodes] = useState([]);
6894
+ const [settled, setSettled] = useState(false);
6895
+ const [hoveredId, setHoveredId] = useState(null);
6896
+ const [dimensions, setDimensions] = useState({ width: propWidth ?? 600, height: propHeight ?? 400 });
6897
+ const w = propWidth ?? dimensions.width;
6898
+ const h = propHeight ?? dimensions.height;
6899
+ const groups = useMemo(
6900
+ () => [...new Set(nodes.map((n) => n.group).filter((g) => Boolean(g)))],
6901
+ [nodes]
6902
+ );
6903
+ const connectedIds = useMemo(() => {
6904
+ if (!hoveredId) return /* @__PURE__ */ new Set();
6905
+ const connected = /* @__PURE__ */ new Set([hoveredId]);
6906
+ for (const edge of edges) {
6907
+ if (edge.source === hoveredId) connected.add(edge.target);
6908
+ if (edge.target === hoveredId) connected.add(edge.source);
6909
+ }
6910
+ return connected;
6911
+ }, [hoveredId, edges]);
6912
+ useEffect(() => {
6913
+ if (propWidth && propHeight) return;
6914
+ const el = containerRef.current;
6915
+ if (!el) return;
6916
+ const update = () => {
6917
+ setDimensions({
6918
+ width: el.clientWidth || 600,
6919
+ height: el.clientHeight || 400
6920
+ });
6921
+ };
6922
+ update();
6923
+ window.addEventListener("resize", update);
6924
+ return () => window.removeEventListener("resize", update);
6925
+ }, [propWidth, propHeight]);
6926
+ useEffect(() => {
6927
+ if (nodes.length === 0) {
6928
+ setSimNodes([]);
6929
+ setSettled(true);
6930
+ return;
6931
+ }
6932
+ const initialNodes = nodes.map((n, idx) => {
6933
+ const angle = idx / nodes.length * 2 * Math.PI;
6934
+ const radius = Math.min(w, h) * 0.3;
6935
+ return {
6936
+ id: n.id,
6937
+ label: n.label,
6938
+ color: resolveNodeColor(n, groups),
6939
+ size: n.size ?? DEFAULT_NODE_SIZE,
6940
+ group: n.group,
6941
+ x: w / 2 + radius * Math.cos(angle) + (Math.random() - 0.5) * 20,
6942
+ y: h / 2 + radius * Math.sin(angle) + (Math.random() - 0.5) * 20,
6943
+ vx: 0,
6944
+ vy: 0,
6945
+ fx: 0,
6946
+ fy: 0
6947
+ };
6948
+ });
6949
+ let iterations = 0;
6950
+ const maxIterations = 120;
6951
+ let currentNodes = initialNodes;
6952
+ const tick = () => {
6953
+ const centerX = w / 2;
6954
+ const centerY = h / 2;
6955
+ for (const node of currentNodes) {
6956
+ node.fx = 0;
6957
+ node.fy = 0;
6958
+ }
6959
+ for (let i = 0; i < currentNodes.length; i++) {
6960
+ for (let j = i + 1; j < currentNodes.length; j++) {
6961
+ const a = currentNodes[i];
6962
+ const b = currentNodes[j];
6963
+ const dx = b.x - a.x;
6964
+ const dy = b.y - a.y;
6965
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
6966
+ const force = 800 / (dist * dist);
6967
+ const fx = dx / dist * force;
6968
+ const fy = dy / dist * force;
6969
+ a.fx -= fx;
6970
+ a.fy -= fy;
6971
+ b.fx += fx;
6972
+ b.fy += fy;
6973
+ }
6974
+ }
6975
+ for (const edge of edges) {
6976
+ const source = currentNodes.find((n) => n.id === edge.source);
6977
+ const target = currentNodes.find((n) => n.id === edge.target);
6978
+ if (!source || !target) continue;
6979
+ const dx = target.x - source.x;
6980
+ const dy = target.y - source.y;
6981
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
6982
+ const force = (dist - 100) * 0.05;
6983
+ const fx = dx / dist * force;
6984
+ const fy = dy / dist * force;
6985
+ source.fx += fx;
6986
+ source.fy += fy;
6987
+ target.fx -= fx;
6988
+ target.fy -= fy;
6989
+ }
6990
+ for (const node of currentNodes) {
6991
+ node.fx += (centerX - node.x) * 0.01;
6992
+ node.fy += (centerY - node.y) * 0.01;
6993
+ }
6994
+ const damping = 0.85;
6995
+ const margin = 40;
6996
+ for (const node of currentNodes) {
6997
+ node.vx = (node.vx + node.fx) * damping;
6998
+ node.vy = (node.vy + node.fy) * damping;
6999
+ node.x += node.vx;
7000
+ node.y += node.vy;
7001
+ node.x = Math.max(margin, Math.min(w - margin, node.x));
7002
+ node.y = Math.max(margin, Math.min(h - margin, node.y));
7003
+ }
7004
+ iterations++;
7005
+ setSimNodes([...currentNodes]);
7006
+ if (iterations < maxIterations) {
7007
+ animRef.current = requestAnimationFrame(tick);
7008
+ } else {
7009
+ setSettled(true);
7010
+ }
7011
+ };
7012
+ setSettled(false);
7013
+ animRef.current = requestAnimationFrame(tick);
7014
+ return () => {
7015
+ cancelAnimationFrame(animRef.current);
7016
+ };
7017
+ }, [nodes, edges, w, h, groups]);
7018
+ const viewBox = useMemo(() => {
7019
+ if (!zoomToFit || !settled || simNodes.length === 0) {
7020
+ return `0 0 ${w} ${h}`;
7021
+ }
7022
+ const pad = 60;
7023
+ let minX = Infinity;
7024
+ let minY = Infinity;
7025
+ let maxX = -Infinity;
7026
+ let maxY = -Infinity;
7027
+ for (const node of simNodes) {
7028
+ minX = Math.min(minX, node.x - node.size);
7029
+ minY = Math.min(minY, node.y - node.size);
7030
+ maxX = Math.max(maxX, node.x + node.size);
7031
+ maxY = Math.max(maxY, node.y + node.size);
7032
+ }
7033
+ const fitW = maxX - minX + pad * 2;
7034
+ const fitH = maxY - minY + pad * 2;
7035
+ return `${minX - pad} ${minY - pad} ${fitW} ${fitH}`;
7036
+ }, [zoomToFit, settled, simNodes, w, h]);
7037
+ const nodeMap = useMemo(() => {
7038
+ const map = /* @__PURE__ */ new Map();
7039
+ for (const n of simNodes) {
7040
+ map.set(n.id, n);
7041
+ }
7042
+ return map;
7043
+ }, [simNodes]);
7044
+ const handleNodeMouseEnter = useCallback(
7045
+ (node) => {
7046
+ setHoveredId(node.id);
7047
+ if (onNodeHover) {
7048
+ onNodeHover({ id: node.id, label: node.label, color: node.color, size: node.size, group: node.group });
7049
+ }
7050
+ },
7051
+ [onNodeHover]
7052
+ );
7053
+ const handleNodeMouseLeave = useCallback(() => {
7054
+ setHoveredId(null);
7055
+ if (onNodeHover) {
7056
+ onNodeHover(null);
7057
+ }
7058
+ }, [onNodeHover]);
7059
+ const handleNodeClickInternal = useCallback(
7060
+ (node) => {
7061
+ if (onNodeClick) {
7062
+ onNodeClick({ id: node.id, label: node.label, color: node.color, size: node.size, group: node.group });
7063
+ }
7064
+ },
7065
+ [onNodeClick]
7066
+ );
7067
+ if (nodes.length === 0) {
7068
+ 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" }) });
7069
+ }
7070
+ return /* @__PURE__ */ jsx(
7071
+ Box,
7072
+ {
7073
+ ref: containerRef,
7074
+ className: cn("relative overflow-hidden rounded-lg border border-[var(--color-border)] bg-[var(--color-card)]", className),
7075
+ style: { width: propWidth ?? "100%", height: h },
7076
+ children: /* @__PURE__ */ jsxs(
7077
+ "svg",
7078
+ {
7079
+ width: "100%",
7080
+ height: "100%",
7081
+ viewBox,
7082
+ preserveAspectRatio: "xMidYMid meet",
7083
+ children: [
7084
+ edges.map((edge, idx) => {
7085
+ const source = nodeMap.get(edge.source);
7086
+ const target = nodeMap.get(edge.target);
7087
+ if (!source || !target) return null;
7088
+ const isHighlighted = hoveredId ? connectedIds.has(edge.source) && connectedIds.has(edge.target) : true;
7089
+ return /* @__PURE__ */ jsxs("g", { children: [
7090
+ /* @__PURE__ */ jsx(
7091
+ "line",
7092
+ {
7093
+ x1: source.x,
7094
+ y1: source.y,
7095
+ x2: target.x,
7096
+ y2: target.y,
7097
+ stroke: edge.color ?? DEFAULT_EDGE_COLOR,
7098
+ strokeWidth: 1.5,
7099
+ opacity: isHighlighted ? 0.8 : 0.15
7100
+ }
7101
+ ),
7102
+ showLabels && edge.label && /* @__PURE__ */ jsx(
7103
+ "text",
7104
+ {
7105
+ x: (source.x + target.x) / 2,
7106
+ y: (source.y + target.y) / 2 - 6,
7107
+ textAnchor: "middle",
7108
+ fill: "var(--color-muted-foreground)",
7109
+ fontSize: 9,
7110
+ opacity: isHighlighted ? 0.9 : 0.2,
7111
+ children: edge.label
7112
+ }
7113
+ )
7114
+ ] }, `edge-${idx}`);
7115
+ }),
7116
+ simNodes.map((node) => {
7117
+ const isHighlighted = hoveredId ? connectedIds.has(node.id) : true;
7118
+ const isHovered = hoveredId === node.id;
7119
+ return /* @__PURE__ */ jsxs(
7120
+ "g",
7121
+ {
7122
+ style: { cursor: onNodeClick ? "pointer" : "default" },
7123
+ onMouseEnter: () => handleNodeMouseEnter(node),
7124
+ onMouseLeave: handleNodeMouseLeave,
7125
+ onClick: () => handleNodeClickInternal(node),
7126
+ children: [
7127
+ /* @__PURE__ */ jsx(
7128
+ "circle",
7129
+ {
7130
+ cx: node.x,
7131
+ cy: node.y,
7132
+ r: isHovered ? node.size * 1.4 : node.size,
7133
+ fill: node.color,
7134
+ opacity: isHighlighted ? 1 : 0.3,
7135
+ stroke: isHovered ? "#ffffff" : "none",
7136
+ strokeWidth: isHovered ? 2 : 0
7137
+ }
7138
+ ),
7139
+ showLabels && /* @__PURE__ */ jsx(
7140
+ "text",
7141
+ {
7142
+ x: node.x,
7143
+ y: node.y + node.size + 12,
7144
+ textAnchor: "middle",
7145
+ fill: "var(--color-foreground)",
7146
+ fontSize: 11,
7147
+ fontWeight: isHovered ? "bold" : "normal",
7148
+ opacity: isHighlighted ? 0.9 : 0.2,
7149
+ children: node.label ?? node.id
7150
+ }
7151
+ )
7152
+ ]
7153
+ },
7154
+ node.id
7155
+ );
7156
+ })
7157
+ ]
7158
+ }
7159
+ )
7160
+ }
7161
+ );
7162
+ };
7163
+ GraphView.displayName = "GraphView";
7164
+ function fieldLabel(key) {
7165
+ return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
7166
+ }
7167
+ function statusVariant(value) {
7168
+ const v = value.toLowerCase();
7169
+ if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
7170
+ if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
7171
+ if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
7172
+ if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
7173
+ return "default";
7174
+ }
7175
+ function formatDate(value) {
7176
+ if (!value) return "";
7177
+ const d = new Date(String(value));
7178
+ if (isNaN(d.getTime())) return String(value);
7179
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
7180
+ }
7181
+ function formatValue(value, format) {
7182
+ if (value === void 0 || value === null) return "";
7183
+ switch (format) {
7184
+ case "date":
7185
+ return formatDate(value);
7186
+ case "currency":
7187
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
7188
+ case "number":
7189
+ return typeof value === "number" ? value.toLocaleString() : String(value);
7190
+ case "percent":
7191
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
7192
+ case "boolean":
7193
+ return value ? "Yes" : "No";
7194
+ default:
7195
+ return String(value);
7196
+ }
7197
+ }
7198
+ var gapStyles5 = {
7199
+ none: "gap-0",
7200
+ sm: "gap-2",
7201
+ md: "gap-4",
7202
+ lg: "gap-6",
7203
+ xl: "gap-8"
7204
+ };
7205
+ var DataGrid = ({
7206
+ entity,
7207
+ fields: fieldsProp,
7208
+ columns: columnsProp,
7209
+ itemActions,
7210
+ cols,
7211
+ gap = "md",
7212
+ minCardWidth = 280,
7213
+ className,
7214
+ isLoading = false,
7215
+ error = null,
7216
+ imageField
7217
+ }) => {
7218
+ const eventBus = useEventBus();
7219
+ const { t } = useTranslate();
7220
+ const fields = fieldsProp ?? columnsProp ?? [];
7221
+ const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
7222
+ const titleField = fields.find((f) => f.variant === "h3" || f.variant === "h4") ?? fields[0];
7223
+ const badgeFields = fields.filter((f) => f.variant === "badge" && f !== titleField);
7224
+ const bodyFields = fields.filter((f) => f !== titleField && !badgeFields.includes(f));
7225
+ const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
7226
+ const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
7227
+ const handleActionClick = (action, itemData) => (e) => {
7228
+ e.stopPropagation();
7229
+ eventBus.emit(`UI:${action.event}`, { row: itemData });
7230
+ };
7231
+ const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
7232
+ const colsClass = cols ? {
7233
+ 1: "grid-cols-1",
7234
+ 2: "sm:grid-cols-2",
7235
+ 3: "sm:grid-cols-2 lg:grid-cols-3",
7236
+ 4: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
7237
+ 5: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
7238
+ 6: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
7239
+ }[cols] : void 0;
7240
+ if (isLoading) {
7241
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
7242
+ }
7243
+ if (error) {
7244
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
7245
+ }
7246
+ if (data.length === 0) {
7247
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
7248
+ }
7249
+ return /* @__PURE__ */ jsx(
7250
+ Box,
7251
+ {
7252
+ className: cn("grid", gapStyles5[gap], colsClass, className),
7253
+ style: gridTemplateColumns ? { gridTemplateColumns } : void 0,
7254
+ children: data.map((item, index) => {
7255
+ const itemData = item;
7256
+ const id = itemData.id || String(index);
7257
+ const titleValue = getNestedValue(itemData, titleField?.name ?? "");
7258
+ return /* @__PURE__ */ jsxs(
7259
+ Box,
7260
+ {
7261
+ "data-entity-row": true,
7262
+ className: cn(
7263
+ "bg-[var(--color-card)] rounded-[var(--radius-lg)]",
7264
+ "border border-[var(--color-border)]",
7265
+ "shadow-[var(--shadow-sm)] hover:shadow-[var(--shadow-hover)]",
7266
+ "hover:border-[var(--color-primary)] transition-all",
7267
+ "flex flex-col"
7268
+ ),
7269
+ children: [
7270
+ imageField && (() => {
7271
+ const imgUrl = getNestedValue(itemData, imageField);
7272
+ if (!imgUrl || typeof imgUrl !== "string") return null;
7273
+ return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-[var(--radius-lg)]", children: /* @__PURE__ */ jsx(
7274
+ "img",
7275
+ {
7276
+ src: imgUrl,
7277
+ alt: titleValue !== void 0 ? String(titleValue) : "",
7278
+ className: "w-full h-full object-cover",
7279
+ loading: "lazy"
7280
+ }
7281
+ ) });
7282
+ })(),
7283
+ /* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
7284
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
7285
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7286
+ titleField?.icon && /* @__PURE__ */ jsx(Icon, { name: titleField.icon, size: "sm", className: "text-[var(--color-primary)] flex-shrink-0" }),
7287
+ /* @__PURE__ */ jsx(
7288
+ Typography,
7289
+ {
7290
+ variant: titleField?.variant === "h3" ? "h3" : "h4",
7291
+ className: "font-semibold truncate",
7292
+ children: String(titleValue)
7293
+ }
7294
+ )
7295
+ ] }),
7296
+ badgeFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
7297
+ const val = getNestedValue(itemData, field.name);
7298
+ if (val === void 0 || val === null) return null;
7299
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7300
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
7301
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant(String(val)), children: String(val) })
7302
+ ] }, field.name);
7303
+ }) })
7304
+ ] }),
7305
+ dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxs(
7306
+ Button,
7307
+ {
7308
+ variant: "ghost",
7309
+ size: "sm",
7310
+ onClick: handleActionClick(action, itemData),
7311
+ "data-testid": `action-${action.event}`,
7312
+ className: "text-[var(--color-error)] hover:bg-[var(--color-error)]/10 px-2",
7313
+ children: [
7314
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs" }),
7315
+ action.label
7316
+ ]
7317
+ },
7318
+ idx
7319
+ )) })
7320
+ ] }) }),
7321
+ bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
7322
+ const value = getNestedValue(itemData, field.name);
7323
+ if (value === void 0 || value === null || value === "") return null;
7324
+ if (field.format === "boolean") {
7325
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
7326
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7327
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
7328
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
7329
+ ] }),
7330
+ /* @__PURE__ */ jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
7331
+ ] }, field.name);
7332
+ }
7333
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
7334
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7335
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
7336
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel(field.name) })
7337
+ ] }),
7338
+ /* @__PURE__ */ jsx(
7339
+ Typography,
7340
+ {
7341
+ variant: field.variant === "caption" ? "caption" : "small",
7342
+ className: "text-right truncate max-w-[60%]",
7343
+ children: formatValue(value, field.format)
7344
+ }
7345
+ )
7346
+ ] }, field.name);
7347
+ }) }) }),
7348
+ 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(
7349
+ Button,
7350
+ {
7351
+ variant: action.variant === "primary" ? "primary" : "ghost",
7352
+ size: "sm",
7353
+ onClick: handleActionClick(action, itemData),
7354
+ "data-testid": `action-${action.event}`,
7355
+ children: [
7356
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
7357
+ action.label
7358
+ ]
7359
+ },
7360
+ idx
7361
+ )) }) })
7362
+ ]
7363
+ },
7364
+ id
7365
+ );
7366
+ })
7367
+ }
7368
+ );
7369
+ };
7370
+ DataGrid.displayName = "DataGrid";
7371
+ function fieldLabel2(key) {
7372
+ return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
7373
+ }
7374
+ function statusVariant2(value) {
7375
+ const v = value.toLowerCase();
7376
+ if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
7377
+ if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
7378
+ if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
7379
+ if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
7380
+ return "default";
7381
+ }
7382
+ function formatDate2(value) {
7383
+ if (!value) return "";
7384
+ const d = new Date(String(value));
7385
+ if (isNaN(d.getTime())) return String(value);
7386
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
7387
+ }
7388
+ function formatValue2(value, format) {
7389
+ if (value === void 0 || value === null) return "";
7390
+ switch (format) {
7391
+ case "date":
7392
+ return formatDate2(value);
7393
+ case "currency":
7394
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
7395
+ case "number":
7396
+ return typeof value === "number" ? value.toLocaleString() : String(value);
7397
+ case "percent":
7398
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
7399
+ case "boolean":
7400
+ return value ? "Yes" : "No";
7401
+ default:
7402
+ return String(value);
7403
+ }
7404
+ }
7405
+ var DataList = ({
7406
+ entity,
7407
+ fields: fieldsProp,
7408
+ columns: columnsProp,
7409
+ itemActions,
7410
+ gap = "none",
7411
+ variant = "default",
7412
+ className,
7413
+ isLoading = false,
7414
+ error = null
7415
+ }) => {
7416
+ const eventBus = useEventBus();
7417
+ const { t } = useTranslate();
7418
+ const fields = fieldsProp ?? columnsProp ?? [];
7419
+ const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
7420
+ const titleField = fields.find((f) => f.variant === "h3" || f.variant === "h4") ?? fields[0];
7421
+ const badgeFields = fields.filter((f) => f.variant === "badge" && f !== titleField);
7422
+ const progressFields = fields.filter((f) => f.variant === "progress");
7423
+ const bodyFields = fields.filter(
7424
+ (f) => f !== titleField && !badgeFields.includes(f) && !progressFields.includes(f)
7425
+ );
7426
+ const handleActionClick = (action, itemData) => (e) => {
7427
+ e.stopPropagation();
7428
+ eventBus.emit(`UI:${action.event}`, { row: itemData });
7429
+ };
7430
+ if (isLoading) {
7431
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
7432
+ }
7433
+ if (error) {
7434
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
7435
+ }
7436
+ if (data.length === 0) {
7437
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
7438
+ }
7439
+ const gapClass = {
7440
+ none: "",
7441
+ sm: "gap-1",
7442
+ md: "gap-2",
7443
+ lg: "gap-4"
7444
+ }[gap];
7445
+ const isCard = variant === "card";
7446
+ const isCompact = variant === "compact";
7447
+ return /* @__PURE__ */ jsx(
7448
+ Box,
7449
+ {
7450
+ className: cn(
7451
+ isCard && "bg-[var(--color-card)] rounded-[var(--radius-xl)] border border-[var(--color-border)] shadow-[var(--shadow-lg)] overflow-hidden",
7452
+ !isCard && gapClass,
7453
+ className
7454
+ ),
7455
+ children: data.map((item, index) => {
7456
+ const itemData = item;
7457
+ const id = itemData.id || String(index);
7458
+ const titleValue = getNestedValue(itemData, titleField?.name ?? "");
7459
+ const isLast = index === data.length - 1;
7460
+ return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, children: [
7461
+ /* @__PURE__ */ jsxs(
7462
+ Box,
7463
+ {
7464
+ className: cn(
7465
+ "group flex items-center gap-4 transition-all duration-200",
7466
+ isCompact ? "px-4 py-2" : "px-6 py-4",
7467
+ "hover:bg-[var(--color-muted)]/80",
7468
+ !isCard && !isCompact && "rounded-[var(--radius-lg)] border border-transparent hover:border-[var(--color-border)]"
7469
+ ),
7470
+ children: [
7471
+ /* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
7472
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
7473
+ titleField?.icon && /* @__PURE__ */ jsx(
7474
+ Icon,
7475
+ {
7476
+ name: titleField.icon,
7477
+ size: isCompact ? "xs" : "sm",
7478
+ className: "text-[var(--color-primary)] flex-shrink-0"
7479
+ }
7480
+ ),
7481
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(
7482
+ Typography,
7483
+ {
7484
+ variant: titleField?.variant === "h3" ? "h3" : "h4",
7485
+ className: cn("font-semibold truncate flex-1", isCompact && "text-sm"),
7486
+ children: String(titleValue)
7487
+ }
7488
+ ),
7489
+ badgeFields.map((field) => {
7490
+ const val = getNestedValue(itemData, field.name);
7491
+ if (val === void 0 || val === null) return null;
7492
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
7493
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
7494
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant2(String(val)), children: String(val) })
7495
+ ] }, field.name);
7496
+ })
7497
+ ] }),
7498
+ bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
7499
+ const value = getNestedValue(itemData, field.name);
7500
+ if (value === void 0 || value === null || value === "") return null;
7501
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
7502
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
7503
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
7504
+ field.label ?? fieldLabel2(field.name),
7505
+ ":"
7506
+ ] }),
7507
+ /* @__PURE__ */ jsx(Typography, { variant: "small", children: formatValue2(value, field.format) })
7508
+ ] }, field.name);
7509
+ }) }),
7510
+ progressFields.map((field) => {
7511
+ const value = getNestedValue(itemData, field.name);
7512
+ if (typeof value !== "number") return null;
7513
+ return /* @__PURE__ */ jsxs(Box, { className: "mt-2 max-w-xs", children: [
7514
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center mb-1", children: [
7515
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-[var(--color-muted-foreground)]" }),
7516
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
7517
+ ] }),
7518
+ /* @__PURE__ */ jsx(ProgressBar, { value, max: 100 })
7519
+ ] }, field.name);
7520
+ })
7521
+ ] }),
7522
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
7523
+ HStack,
7524
+ {
7525
+ gap: "xs",
7526
+ className: cn(
7527
+ "flex-shrink-0 transition-opacity duration-200",
7528
+ "opacity-0 group-hover:opacity-100"
7529
+ ),
7530
+ children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
7531
+ Button,
7532
+ {
7533
+ variant: action.variant ?? "ghost",
7534
+ size: "sm",
7535
+ onClick: handleActionClick(action, itemData),
7536
+ "data-testid": `action-${action.event}`,
7537
+ className: cn(
7538
+ action.variant === "danger" && "text-[var(--color-error)] hover:bg-[var(--color-error)]/10"
7539
+ ),
7540
+ children: [
7541
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
7542
+ action.label
7543
+ ]
7544
+ },
7545
+ idx
7546
+ ))
7547
+ }
7548
+ )
7549
+ ]
7550
+ }
7551
+ ),
7552
+ isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-[var(--color-border)]/40" })
7553
+ ] }, id);
7554
+ })
7555
+ }
7556
+ );
7557
+ };
7558
+ DataList.displayName = "DataList";
7559
+
7560
+ // components/organisms/types.ts
7561
+ var EntityDisplayEvents = {
7562
+ SORT: "SORT",
7563
+ PAGINATE: "PAGINATE",
7564
+ SEARCH: "SEARCH",
7565
+ FILTER: "FILTER",
7566
+ CLEAR_FILTERS: "CLEAR_FILTERS",
7567
+ SELECT: "SELECT",
7568
+ DESELECT: "DESELECT"
7569
+ };
7570
+ function humanizeFieldName(name) {
7571
+ 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();
7572
+ }
7573
+ function normalizeColumns(columns) {
7574
+ return columns.map((col) => {
6439
7575
  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 };
7576
+ const header2 = humanizeFieldName(col);
7577
+ return { key: col, header: header2 };
6442
7578
  }
6443
- return col;
7579
+ const key = col.key ?? col.name ?? "";
7580
+ const header = col.header ?? col.label ?? humanizeFieldName(String(key));
7581
+ return { ...col, key, header };
6444
7582
  });
6445
7583
  }
7584
+ function asBooleanValue(value) {
7585
+ if (typeof value === "boolean") return value;
7586
+ if (value === "true") return true;
7587
+ if (value === "false") return false;
7588
+ return null;
7589
+ }
6446
7590
  function DataTable({
6447
7591
  fields,
6448
7592
  columns,
@@ -6641,8 +7785,7 @@ function DataTable({
6641
7785
  ] }),
6642
7786
  /* @__PURE__ */ jsx(Box, { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
6643
7787
  /* @__PURE__ */ jsx("thead", { className: "bg-[var(--color-table-header)] border-b-2 border-[var(--color-border)]", children: /* @__PURE__ */ jsxs("tr", { children: [
6644
- selectable && // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6645
- /* @__PURE__ */ jsx("th", { className: "w-12 px-4 py-3", children: /* @__PURE__ */ jsx(
7788
+ selectable && /* @__PURE__ */ jsx("th", { className: "w-12 px-4 py-3", children: /* @__PURE__ */ jsx(
6646
7789
  Checkbox,
6647
7790
  {
6648
7791
  checked: allSelected,
@@ -6650,176 +7793,162 @@ function DataTable({
6650
7793
  onChange: handleSelectAll
6651
7794
  }
6652
7795
  ) }),
6653
- normalizedColumns.map((col) => (
6654
- // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6655
- /* @__PURE__ */ jsx(
6656
- "th",
6657
- {
6658
- "data-column": String(col.key),
6659
- className: cn(
6660
- "px-4 py-3 text-left text-xs font-bold text-[var(--color-foreground)] uppercase tracking-wider whitespace-nowrap",
6661
- col.sortable && "cursor-pointer select-none hover:bg-[var(--color-table-row-hover)]"
6662
- ),
6663
- style: { width: col.width },
6664
- onClick: () => col.sortable && handleSort(String(col.key)),
6665
- children: /* @__PURE__ */ jsxs(HStack, { className: "items-center gap-1", children: [
6666
- col.header,
6667
- col.sortable && sortBy === col.key && (sortDirection === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }))
6668
- ] })
6669
- },
6670
- String(col.key)
6671
- )
7796
+ normalizedColumns.map((col) => /* @__PURE__ */ jsx(
7797
+ "th",
7798
+ {
7799
+ "data-column": String(col.key),
7800
+ className: cn(
7801
+ "px-4 py-3 text-left text-xs font-bold text-[var(--color-foreground)] uppercase tracking-wider whitespace-nowrap",
7802
+ col.sortable && "cursor-pointer select-none hover:bg-[var(--color-table-row-hover)]"
7803
+ ),
7804
+ style: { width: col.width },
7805
+ onClick: () => col.sortable && handleSort(String(col.key)),
7806
+ children: /* @__PURE__ */ jsxs(HStack, { className: "items-center gap-1", children: [
7807
+ col.header,
7808
+ col.sortable && sortBy === col.key && (sortDirection === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }))
7809
+ ] })
7810
+ },
7811
+ String(col.key)
6672
7812
  )),
6673
7813
  rowActions && /* @__PURE__ */ jsx("th", { className: "w-12 px-4 py-3" })
6674
7814
  ] }) }),
6675
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-700", children: isLoading ? (
6676
- // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6677
- /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
6678
- "td",
6679
- {
6680
- colSpan: normalizedColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
6681
- className: "px-4 py-12 text-center",
6682
- children: /* @__PURE__ */ jsxs(VStack, { className: "items-center gap-2", children: [
6683
- /* @__PURE__ */ jsx(Spinner, { size: "lg" }),
6684
- /* @__PURE__ */ jsx(
6685
- Typography,
6686
- {
6687
- variant: "small",
6688
- className: "text-[var(--color-muted-foreground)]",
6689
- children: t("common.loading")
6690
- }
6691
- )
6692
- ] })
6693
- }
6694
- ) })
6695
- ) : error ? (
6696
- // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6697
- /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs(
6698
- "td",
6699
- {
6700
- colSpan: normalizedColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
6701
- className: "px-4 py-12 text-center text-[var(--color-error)]",
6702
- children: [
6703
- t("error.generic") + ": ",
6704
- error.message
6705
- ]
6706
- }
6707
- ) })
6708
- ) : items.length === 0 ? (
6709
- // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6710
- /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
6711
- "td",
6712
- {
6713
- colSpan: normalizedColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
6714
- className: "px-4 py-12",
6715
- children: /* @__PURE__ */ jsx(
6716
- EmptyState,
7815
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-700", children: isLoading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
7816
+ "td",
7817
+ {
7818
+ colSpan: normalizedColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
7819
+ className: "px-4 py-12 text-center",
7820
+ children: /* @__PURE__ */ jsxs(VStack, { className: "items-center gap-2", children: [
7821
+ /* @__PURE__ */ jsx(Spinner, { size: "lg" }),
7822
+ /* @__PURE__ */ jsx(
7823
+ Typography,
6717
7824
  {
6718
- icon: emptyIcon,
6719
- title: resolvedEmptyTitle,
6720
- description: resolvedEmptyDescription,
6721
- actionLabel: emptyAction?.label,
6722
- actionEvent: emptyAction?.event
7825
+ variant: "small",
7826
+ className: "text-[var(--color-muted-foreground)]",
7827
+ children: t("common.loading")
6723
7828
  }
6724
7829
  )
6725
- }
6726
- ) })
6727
- ) : items.map((row, rowIndex) => (
6728
- // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6729
- /* @__PURE__ */ jsxs(
6730
- "tr",
6731
- {
6732
- "data-entity-row": true,
6733
- className: cn(
6734
- "border-b border-[var(--color-table-border)] last:border-0 hover:bg-[var(--color-table-row-hover)] transition-colors",
6735
- selectedIds.includes(row.id) && "bg-[var(--color-primary)]/10 font-medium",
6736
- isRowClickable && "cursor-pointer"
6737
- ),
6738
- onClick: () => isRowClickable && handleRowClick(row),
6739
- children: [
6740
- selectable && // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6741
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(
6742
- Checkbox,
7830
+ ] })
7831
+ }
7832
+ ) }) : error ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs(
7833
+ "td",
7834
+ {
7835
+ colSpan: normalizedColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
7836
+ className: "px-4 py-12 text-center text-[var(--color-error)]",
7837
+ children: [
7838
+ t("error.generic") + ": ",
7839
+ error.message
7840
+ ]
7841
+ }
7842
+ ) }) : items.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
7843
+ "td",
7844
+ {
7845
+ colSpan: normalizedColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
7846
+ className: "px-4 py-12",
7847
+ children: /* @__PURE__ */ jsx(
7848
+ EmptyState,
7849
+ {
7850
+ icon: emptyIcon,
7851
+ title: resolvedEmptyTitle,
7852
+ description: resolvedEmptyDescription,
7853
+ actionLabel: emptyAction?.label,
7854
+ actionEvent: emptyAction?.event
7855
+ }
7856
+ )
7857
+ }
7858
+ ) }) : items.map((row, rowIndex) => /* @__PURE__ */ jsxs(
7859
+ "tr",
7860
+ {
7861
+ "data-entity-row": true,
7862
+ className: cn(
7863
+ "border-b border-[var(--color-table-border)] last:border-0 hover:bg-[var(--color-table-row-hover)] transition-colors",
7864
+ selectedIds.includes(row.id) && "bg-[var(--color-primary)]/10 font-medium",
7865
+ isRowClickable && "cursor-pointer"
7866
+ ),
7867
+ onClick: () => isRowClickable && handleRowClick(row),
7868
+ children: [
7869
+ selectable && /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(
7870
+ Checkbox,
7871
+ {
7872
+ checked: selectedIds.includes(row.id),
7873
+ onChange: () => handleSelectRow(row.id)
7874
+ }
7875
+ ) }),
7876
+ normalizedColumns.map((col) => {
7877
+ const cellValue = getNestedValue(
7878
+ row,
7879
+ String(col.key)
7880
+ );
7881
+ return /* @__PURE__ */ jsx(
7882
+ "td",
7883
+ {
7884
+ "data-column": String(col.key),
7885
+ className: "px-4 py-3 text-sm text-[var(--color-foreground)] whitespace-nowrap sm:whitespace-normal",
7886
+ children: col.render ? col.render(cellValue, row, rowIndex) : (() => {
7887
+ const boolVal = asBooleanValue(cellValue);
7888
+ if (boolVal !== null) {
7889
+ return boolVal ? /* @__PURE__ */ jsx(Badge, { variant: "success", children: t("common.yes") }) : /* @__PURE__ */ jsx(Badge, { variant: "neutral", children: t("common.no") });
7890
+ }
7891
+ return String(cellValue ?? "");
7892
+ })()
7893
+ },
7894
+ String(col.key)
7895
+ );
7896
+ }),
7897
+ rowActions && /* @__PURE__ */ jsxs("td", { className: "px-4 py-3 relative", children: [
7898
+ /* @__PURE__ */ jsx(
7899
+ Button,
6743
7900
  {
6744
- checked: selectedIds.includes(row.id),
6745
- onChange: () => handleSelectRow(row.id)
7901
+ variant: "ghost",
7902
+ className: "p-1 rounded hover:bg-[var(--color-muted)]",
7903
+ onClick: (e) => {
7904
+ e.stopPropagation();
7905
+ setOpenActionMenu(
7906
+ openActionMenu === row.id ? null : row.id
7907
+ );
7908
+ },
7909
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "h-4 w-4 text-[var(--color-muted-foreground)]" })
6746
7910
  }
6747
- ) }),
6748
- normalizedColumns.map((col) => {
6749
- const cellValue = getNestedValue(
6750
- row,
6751
- String(col.key)
6752
- );
6753
- return (
6754
- // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6755
- /* @__PURE__ */ jsx(
6756
- "td",
6757
- {
6758
- "data-column": String(col.key),
6759
- className: "px-4 py-3 text-sm text-[var(--color-foreground)] whitespace-nowrap sm:whitespace-normal",
6760
- children: col.render ? col.render(cellValue, row, rowIndex) : String(cellValue ?? "")
6761
- },
6762
- String(col.key)
6763
- )
6764
- );
6765
- }),
6766
- rowActions && // eslint-disable-next-line almadar/no-raw-dom-elements -- native table elements in DataTable
6767
- /* @__PURE__ */ jsxs("td", { className: "px-4 py-3 relative", children: [
7911
+ ),
7912
+ openActionMenu === row.id && /* @__PURE__ */ jsxs(Fragment, { children: [
6768
7913
  /* @__PURE__ */ jsx(
6769
- Button,
7914
+ Box,
6770
7915
  {
6771
- variant: "ghost",
6772
- className: "p-1 rounded hover:bg-[var(--color-muted)]",
7916
+ className: "fixed inset-0 z-40",
6773
7917
  onClick: (e) => {
6774
7918
  e.stopPropagation();
6775
- setOpenActionMenu(
6776
- openActionMenu === row.id ? null : row.id
6777
- );
6778
- },
6779
- children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "h-4 w-4 text-[var(--color-muted-foreground)]" })
7919
+ setOpenActionMenu(null);
7920
+ }
6780
7921
  }
6781
7922
  ),
6782
- openActionMenu === row.id && /* @__PURE__ */ jsxs(Fragment, { children: [
6783
- /* @__PURE__ */ jsx(
6784
- Box,
6785
- {
6786
- className: "fixed inset-0 z-40",
6787
- onClick: (e) => {
6788
- e.stopPropagation();
6789
- setOpenActionMenu(null);
6790
- }
6791
- }
6792
- ),
6793
- /* @__PURE__ */ jsx(VStack, { className: "absolute right-0 mt-1 w-48 bg-[var(--color-card)] rounded-[var(--radius-lg)] shadow-[var(--shadow-lg)] border border-[var(--color-border)] py-1 z-50", children: rowActions.filter(
6794
- (action) => !action.show || action.show(row)
6795
- ).map((action, idx) => /* @__PURE__ */ jsxs(
6796
- Button,
6797
- {
6798
- variant: "ghost",
6799
- "data-event": action.event,
6800
- "data-testid": action.event ? `action-${action.event}` : void 0,
6801
- className: cn(
6802
- "w-full flex items-center gap-2 px-4 py-2 text-sm",
6803
- action.variant === "danger" ? "text-[var(--color-error)] hover:bg-[var(--color-error)]/10" : "text-[var(--color-foreground)] hover:bg-[var(--color-muted)]"
6804
- ),
6805
- onClick: (e) => {
6806
- e.stopPropagation();
6807
- action.onClick(row);
6808
- setOpenActionMenu(null);
6809
- },
6810
- children: [
6811
- action.icon && /* @__PURE__ */ jsx(action.icon, { className: "h-4 w-4" }),
6812
- action.label
6813
- ]
7923
+ /* @__PURE__ */ jsx(VStack, { className: "absolute right-0 mt-1 w-48 bg-[var(--color-card)] rounded-[var(--radius-lg)] shadow-[var(--shadow-lg)] border border-[var(--color-border)] py-1 z-50", children: (rowActions ?? []).filter(
7924
+ (action) => !action.show || action.show(row)
7925
+ ).map((action, idx) => /* @__PURE__ */ jsxs(
7926
+ Button,
7927
+ {
7928
+ variant: "ghost",
7929
+ "data-event": action.event,
7930
+ "data-testid": action.event ? `action-${action.event}` : void 0,
7931
+ className: cn(
7932
+ "w-full flex items-center gap-2 px-4 py-2 text-sm",
7933
+ action.variant === "danger" ? "text-[var(--color-error)] hover:bg-[var(--color-error)]/10" : "text-[var(--color-foreground)] hover:bg-[var(--color-muted)]"
7934
+ ),
7935
+ onClick: (e) => {
7936
+ e.stopPropagation();
7937
+ action.onClick(row);
7938
+ setOpenActionMenu(null);
6814
7939
  },
6815
- idx
6816
- )) })
6817
- ] })
7940
+ children: [
7941
+ action.icon && /* @__PURE__ */ jsx(action.icon, { className: "h-4 w-4" }),
7942
+ action.label
7943
+ ]
7944
+ },
7945
+ idx
7946
+ )) })
6818
7947
  ] })
6819
- ]
6820
- },
6821
- row.id
6822
- )
7948
+ ] })
7949
+ ]
7950
+ },
7951
+ row.id
6823
7952
  )) })
6824
7953
  ] }) }),
6825
7954
  totalCount !== void 0 && totalPages > 1 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 border-t-2 border-[var(--color-border)]", children: /* @__PURE__ */ jsx(
@@ -6861,7 +7990,7 @@ var StatCard = ({
6861
7990
  const labelToUse = propLabel ?? propTitle;
6862
7991
  const eventBus = useEventBus();
6863
7992
  const { t } = useTranslate();
6864
- const handleActionClick = React41__default.useCallback(() => {
7993
+ const handleActionClick = React47__default.useCallback(() => {
6865
7994
  if (action?.event) {
6866
7995
  eventBus.emit(`UI:${action.event}`, {});
6867
7996
  }
@@ -6872,7 +8001,7 @@ var StatCard = ({
6872
8001
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
6873
8002
  const isLoading = externalLoading ?? false;
6874
8003
  const error = externalError;
6875
- const computeMetricValue = React41__default.useCallback(
8004
+ const computeMetricValue = React47__default.useCallback(
6876
8005
  (metric, items) => {
6877
8006
  if (metric.value !== void 0) {
6878
8007
  return metric.value;
@@ -6911,7 +8040,7 @@ var StatCard = ({
6911
8040
  },
6912
8041
  []
6913
8042
  );
6914
- const schemaStats = React41__default.useMemo(() => {
8043
+ const schemaStats = React47__default.useMemo(() => {
6915
8044
  if (!metrics || metrics.length === 0) return null;
6916
8045
  return metrics.map((metric) => ({
6917
8046
  label: metric.label,
@@ -6919,7 +8048,7 @@ var StatCard = ({
6919
8048
  format: metric.format
6920
8049
  }));
6921
8050
  }, [metrics, data, computeMetricValue]);
6922
- const calculatedTrend = React41__default.useMemo(() => {
8051
+ const calculatedTrend = React47__default.useMemo(() => {
6923
8052
  if (manualTrend !== void 0) return manualTrend;
6924
8053
  if (previousValue === void 0 || currentValue === void 0)
6925
8054
  return void 0;
@@ -7055,18 +8184,15 @@ var PageHeader = ({
7055
8184
  info: "bg-[var(--color-info)]/10 text-[var(--color-info)]"
7056
8185
  };
7057
8186
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
7058
- 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: [
8187
+ 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(React47__default.Fragment, { children: [
7059
8188
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
7060
- crumb.href ? (
7061
- // eslint-disable-next-line almadar/no-raw-dom-elements -- semantic anchor with href
7062
- /* @__PURE__ */ jsx(
7063
- "a",
7064
- {
7065
- href: crumb.href,
7066
- className: "text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)]",
7067
- children: crumb.label
7068
- }
7069
- )
8189
+ crumb.href ? /* @__PURE__ */ jsx(
8190
+ "a",
8191
+ {
8192
+ href: crumb.href,
8193
+ className: "text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)]",
8194
+ children: crumb.label
8195
+ }
7070
8196
  ) : /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-[var(--color-foreground)] font-medium", children: crumb.label })
7071
8197
  ] }, idx)) }) }),
7072
8198
  /* @__PURE__ */ jsxs(Box, { className: "flex items-start justify-between gap-4", children: [
@@ -7194,9 +8320,68 @@ function formatFieldValue(value, fieldName) {
7194
8320
  }
7195
8321
  return String(value);
7196
8322
  }
8323
+ var ReactMarkdown2 = lazy(() => import('react-markdown'));
8324
+ function renderRichFieldValue(value, fieldName, fieldType) {
8325
+ if (value === void 0 || value === null) return "\u2014";
8326
+ const str = String(value);
8327
+ switch (fieldType) {
8328
+ case "image":
8329
+ case "url": {
8330
+ if (str.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str.startsWith("data:image/")) {
8331
+ return /* @__PURE__ */ jsx(Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsx(
8332
+ "img",
8333
+ {
8334
+ src: str,
8335
+ alt: formatFieldLabel(fieldName),
8336
+ className: "max-w-full max-h-64 rounded-[var(--radius-md)] object-contain",
8337
+ loading: "lazy"
8338
+ }
8339
+ ) });
8340
+ }
8341
+ return str;
8342
+ }
8343
+ case "markdown":
8344
+ case "richtext":
8345
+ 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 }) }) });
8346
+ case "code":
8347
+ 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 }) }) });
8348
+ case "html":
8349
+ 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 }) });
8350
+ case "date":
8351
+ case "datetime": {
8352
+ const d = new Date(str);
8353
+ if (!isNaN(d.getTime())) {
8354
+ return d.toLocaleDateString(void 0, {
8355
+ year: "numeric",
8356
+ month: "long",
8357
+ day: "numeric",
8358
+ ...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
8359
+ });
8360
+ }
8361
+ return str;
8362
+ }
8363
+ default:
8364
+ return formatFieldValue(value, fieldName);
8365
+ }
8366
+ }
7197
8367
  function normalizeFieldDefs(fields) {
7198
8368
  if (!fields) return [];
7199
- return fields.map((f) => typeof f === "string" ? f : f.key);
8369
+ return fields.map((f) => {
8370
+ if (typeof f === "string") return f;
8371
+ if ("key" in f) return f.key;
8372
+ if ("name" in f) return f.name;
8373
+ return String(f);
8374
+ });
8375
+ }
8376
+ function buildFieldTypeMap(fields) {
8377
+ const map = {};
8378
+ if (!fields) return map;
8379
+ for (const f of fields) {
8380
+ if (typeof f === "object" && "name" in f && "type" in f) {
8381
+ map[f.name] = f.type;
8382
+ }
8383
+ }
8384
+ return map;
7200
8385
  }
7201
8386
  var DetailPanel = ({
7202
8387
  title: propTitle,
@@ -7220,9 +8405,10 @@ var DetailPanel = ({
7220
8405
  const isFieldDefArray = (arr) => {
7221
8406
  if (!arr || arr.length === 0) return false;
7222
8407
  const first = arr[0];
7223
- return typeof first === "string" || typeof first === "object" && first !== null && "key" in first;
8408
+ return typeof first === "string" || typeof first === "object" && first !== null && ("key" in first || "name" in first);
7224
8409
  };
7225
8410
  const effectiveFieldNames = isFieldDefArray(propFields) ? normalizeFieldDefs(propFields) : fieldNames;
8411
+ const fieldTypeMap = isFieldDefArray(propFields) ? buildFieldTypeMap(propFields) : {};
7226
8412
  useCallback(
7227
8413
  (action, data2) => {
7228
8414
  if (action.navigatesTo) {
@@ -7297,7 +8483,7 @@ var DetailPanel = ({
7297
8483
  if (value !== void 0 && value !== null) {
7298
8484
  overviewFields.push({
7299
8485
  label: formatFieldLabel(field),
7300
- value: formatFieldValue(value, field),
8486
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
7301
8487
  icon: getFieldIcon(field)
7302
8488
  });
7303
8489
  }
@@ -7313,7 +8499,7 @@ var DetailPanel = ({
7313
8499
  if (value !== void 0 && value !== null) {
7314
8500
  metricsFields.push({
7315
8501
  label: formatFieldLabel(field),
7316
- value: formatFieldValue(value, field),
8502
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
7317
8503
  icon: getFieldIcon(field)
7318
8504
  });
7319
8505
  }
@@ -7329,7 +8515,7 @@ var DetailPanel = ({
7329
8515
  if (value !== void 0 && value !== null) {
7330
8516
  timelineFields.push({
7331
8517
  label: formatFieldLabel(field),
7332
- value: formatFieldValue(value, field),
8518
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
7333
8519
  icon: getFieldIcon(field)
7334
8520
  });
7335
8521
  }
@@ -7345,7 +8531,7 @@ var DetailPanel = ({
7345
8531
  if (value !== void 0 && value !== null) {
7346
8532
  descFields.push({
7347
8533
  label: formatFieldLabel(field),
7348
- value: String(value),
8534
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
7349
8535
  icon: getFieldIcon(field)
7350
8536
  });
7351
8537
  }
@@ -7385,96 +8571,123 @@ var DetailPanel = ({
7385
8571
  }
7386
8572
  );
7387
8573
  }
7388
- const content = /* @__PURE__ */ jsxs(VStack, { gap: "lg", children: [
7389
- /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
7390
- /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "start", children: [
7391
- /* @__PURE__ */ jsxs(VStack, { gap: "sm", flex: true, className: "min-w-0", children: [
7392
- avatar,
7393
- /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
7394
- subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle }),
7395
- normalizedData && effectiveFieldNames && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: effectiveFieldNames.filter(
7396
- (f) => f.toLowerCase().includes("status") || f.toLowerCase().includes("priority")
7397
- ).map((field) => {
7398
- const value = getNestedValue(normalizedData, field);
7399
- if (!value) return null;
7400
- return /* @__PURE__ */ jsx(
7401
- Badge,
7402
- {
7403
- variant: getBadgeVariant(field, String(value)),
7404
- children: String(value)
7405
- },
7406
- field
7407
- );
7408
- }) }),
7409
- status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
7410
- ] }),
7411
- slideOver && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleClose, icon: X })
7412
- ] }),
8574
+ const allFields = [];
8575
+ if (sections) {
8576
+ for (const section of sections) {
8577
+ for (const field of section.fields) {
8578
+ if (typeof field === "string") {
8579
+ const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
8580
+ allFields.push({
8581
+ label: formatFieldLabel(field),
8582
+ value: renderRichFieldValue(value, field, fieldTypeMap[field]),
8583
+ icon: getFieldIcon(field)
8584
+ });
8585
+ } else {
8586
+ allFields.push(field);
8587
+ }
8588
+ }
8589
+ }
8590
+ }
8591
+ const closeAction = actions?.find(
8592
+ (a) => a.event === "CLOSE" || a.event === "CANCEL" || a.label?.toLowerCase() === "close"
8593
+ );
8594
+ const otherActions = actions?.filter((a) => a !== closeAction) ?? [];
8595
+ const effectiveCloseAction = closeAction ?? { event: void 0};
8596
+ const content = /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
8597
+ /* @__PURE__ */ jsxs(HStack, { justify: "end", align: "center", gap: "xs", children: [
8598
+ otherActions.map((action, idx) => /* @__PURE__ */ jsx(
8599
+ Button,
8600
+ {
8601
+ variant: action.variant || "secondary",
8602
+ size: "sm",
8603
+ action: action.event,
8604
+ actionPayload: { row: normalizedData },
8605
+ icon: action.icon,
8606
+ "data-testid": action.event ? `action-${action.event}` : void 0,
8607
+ children: action.label
8608
+ },
8609
+ idx
8610
+ )),
8611
+ /* @__PURE__ */ jsx(
8612
+ Button,
8613
+ {
8614
+ variant: "ghost",
8615
+ size: "sm",
8616
+ action: effectiveCloseAction.event,
8617
+ actionPayload: { row: normalizedData },
8618
+ onClick: effectiveCloseAction.event ? void 0 : handleClose,
8619
+ icon: X,
8620
+ "data-testid": effectiveCloseAction.event ? `action-${effectiveCloseAction.event}` : "action-close"
8621
+ }
8622
+ )
8623
+ ] }),
8624
+ avatar,
8625
+ /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
8626
+ subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle }),
8627
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", wrap: true, children: [
7413
8628
  normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
7414
- (f) => f.toLowerCase().includes("progress") || f.toLowerCase().includes("percent")
8629
+ (f) => f.toLowerCase().includes("status") || f.toLowerCase().includes("priority")
7415
8630
  ).map((field) => {
7416
8631
  const value = getNestedValue(normalizedData, field);
7417
- if (value === void 0 || value === null || typeof value !== "number")
7418
- return null;
7419
- return /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "w-full", children: [
7420
- /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
7421
- /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: formatFieldLabel(field) }),
7422
- /* @__PURE__ */ jsxs(Typography, { variant: "small", weight: "medium", children: [
7423
- value,
7424
- "%"
7425
- ] })
7426
- ] }),
7427
- /* @__PURE__ */ jsx(ProgressBar, { value })
7428
- ] }, field);
7429
- }),
7430
- actions && actions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
7431
- /* @__PURE__ */ jsx(Divider, {}),
7432
- /* @__PURE__ */ jsx(HStack, { gap: "sm", children: actions.map((action, idx) => /* @__PURE__ */ jsx(
7433
- Button,
8632
+ if (!value) return null;
8633
+ return /* @__PURE__ */ jsx(
8634
+ Badge,
7434
8635
  {
7435
- variant: action.variant || "secondary",
7436
- action: action.event,
7437
- actionPayload: { row: normalizedData },
7438
- icon: action.icon,
7439
- "data-testid": action.event ? `action-${action.event}` : void 0,
7440
- children: action.label
8636
+ variant: getBadgeVariant(field, String(value)),
8637
+ children: String(value)
7441
8638
  },
7442
- idx
7443
- )) })
7444
- ] })
7445
- ] }) }),
7446
- sections && sections.map((section, sectionIdx) => /* @__PURE__ */ jsx(Card, { variant: "bordered", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
7447
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "semibold", children: section.title }),
8639
+ field
8640
+ );
8641
+ }),
8642
+ status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
8643
+ ] }),
8644
+ normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
8645
+ (f) => f.toLowerCase().includes("progress") || f.toLowerCase().includes("percent")
8646
+ ).map((field) => {
8647
+ const value = getNestedValue(normalizedData, field);
8648
+ if (value === void 0 || value === null || typeof value !== "number")
8649
+ return null;
8650
+ return /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "w-full", children: [
8651
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
8652
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: formatFieldLabel(field) }),
8653
+ /* @__PURE__ */ jsxs(Typography, { variant: "small", weight: "medium", children: [
8654
+ value,
8655
+ "%"
8656
+ ] })
8657
+ ] }),
8658
+ /* @__PURE__ */ jsx(ProgressBar, { value })
8659
+ ] }, field);
8660
+ }),
8661
+ allFields.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
7448
8662
  /* @__PURE__ */ jsx(Divider, {}),
7449
- /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "250px", maxCols: 2, gap: "lg", children: section.fields.map((field, fieldIdx) => {
7450
- const fieldKey = typeof field === "string" ? field : void 0;
7451
- const resolved = typeof field === "string" ? { label: formatFieldLabel(field), value: normalizedData ? formatFieldValue(getNestedValue(normalizedData, field), field) : "\u2014", icon: getFieldIcon(field) } : field;
7452
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "start", "data-field": fieldKey, children: [
7453
- resolved.icon && /* @__PURE__ */ jsx(
7454
- Icon,
8663
+ /* @__PURE__ */ jsx(SimpleGrid, { minChildWidth: "250px", maxCols: 2, gap: "lg", children: allFields.map((field, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "start", children: [
8664
+ field.icon && /* @__PURE__ */ jsx(
8665
+ Icon,
8666
+ {
8667
+ icon: field.icon,
8668
+ size: "md",
8669
+ className: "text-[var(--color-muted-foreground)] mt-1"
8670
+ }
8671
+ ),
8672
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", flex: true, className: "min-w-0", children: [
8673
+ /* @__PURE__ */ jsx(
8674
+ Typography,
7455
8675
  {
7456
- icon: resolved.icon,
7457
- size: "md",
7458
- className: "text-[var(--color-muted-foreground)] mt-1"
8676
+ variant: "small",
8677
+ color: "secondary",
8678
+ weight: "medium",
8679
+ children: field.label
7459
8680
  }
7460
8681
  ),
7461
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", flex: true, className: "min-w-0", children: [
7462
- /* @__PURE__ */ jsx(
7463
- Typography,
7464
- {
7465
- variant: "small",
7466
- color: "secondary",
7467
- weight: "medium",
7468
- children: resolved.label
7469
- }
7470
- ),
7471
- /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children: resolved.value || "\u2014" })
7472
- ] })
7473
- ] }, fieldIdx);
7474
- }) })
7475
- ] }) }, sectionIdx)),
7476
- footer && /* @__PURE__ */ jsx(Card, { variant: "bordered", children: footer })
7477
- ] });
8682
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children: field.value || "\u2014" })
8683
+ ] })
8684
+ ] }, idx)) })
8685
+ ] }),
8686
+ footer && /* @__PURE__ */ jsxs(Fragment, { children: [
8687
+ /* @__PURE__ */ jsx(Divider, {}),
8688
+ footer
8689
+ ] })
8690
+ ] }) });
7478
8691
  return /* @__PURE__ */ jsx(
7479
8692
  Box,
7480
8693
  {
@@ -7508,7 +8721,7 @@ var layoutStyles = {
7508
8721
  horizontal: "flex flex-row flex-wrap items-end",
7509
8722
  inline: "flex flex-row flex-wrap items-center"
7510
8723
  };
7511
- var gapStyles5 = {
8724
+ var gapStyles6 = {
7512
8725
  sm: "gap-2",
7513
8726
  md: "gap-4",
7514
8727
  lg: "gap-6"
@@ -7602,11 +8815,12 @@ var Form = ({
7602
8815
  const resolvedSubmitLabel = submitLabel ?? t("common.save");
7603
8816
  const resolvedCancelLabel = cancelLabel ?? t("common.cancel");
7604
8817
  const normalizedInitialData = initialData ?? {};
7605
- const entityName = typeof entity === "string" ? entity : entity?.name;
7606
- const entityDerivedFields = React41__default.useMemo(() => {
8818
+ const resolvedEntity = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
8819
+ const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
8820
+ const entityDerivedFields = React47__default.useMemo(() => {
7607
8821
  if (fields && fields.length > 0) return void 0;
7608
- if (!entity || typeof entity === "string") return void 0;
7609
- return entity.fields.map(
8822
+ if (!resolvedEntity) return void 0;
8823
+ return resolvedEntity.fields.map(
7610
8824
  (f) => ({
7611
8825
  name: f.name,
7612
8826
  type: f.type,
@@ -7622,14 +8836,14 @@ var Form = ({
7622
8836
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
7623
8837
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
7624
8838
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
7625
- const [formData, setFormData] = React41__default.useState(
8839
+ const [formData, setFormData] = React47__default.useState(
7626
8840
  normalizedInitialData
7627
8841
  );
7628
- const [collapsedSections, setCollapsedSections] = React41__default.useState(
8842
+ const [collapsedSections, setCollapsedSections] = React47__default.useState(
7629
8843
  /* @__PURE__ */ new Set()
7630
8844
  );
7631
8845
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
7632
- const evalContext = React41__default.useMemo(
8846
+ const evalContext = React47__default.useMemo(
7633
8847
  () => ({
7634
8848
  formValues: formData,
7635
8849
  globalVariables: externalContext?.globalVariables ?? {},
@@ -7638,13 +8852,13 @@ var Form = ({
7638
8852
  }),
7639
8853
  [formData, externalContext]
7640
8854
  );
7641
- React41__default.useEffect(() => {
8855
+ React47__default.useEffect(() => {
7642
8856
  const data = initialData;
7643
8857
  if (data && Object.keys(data).length > 0) {
7644
8858
  setFormData(data);
7645
8859
  }
7646
8860
  }, [initialData]);
7647
- const processCalculations = React41__default.useCallback(
8861
+ const processCalculations = React47__default.useCallback(
7648
8862
  (changedFieldId, newFormData) => {
7649
8863
  if (!hiddenCalculations.length) return;
7650
8864
  const context = {
@@ -7669,7 +8883,7 @@ var Form = ({
7669
8883
  },
7670
8884
  [hiddenCalculations, externalContext, eventBus]
7671
8885
  );
7672
- const checkViolations = React41__default.useCallback(
8886
+ const checkViolations = React47__default.useCallback(
7673
8887
  (changedFieldId, newFormData) => {
7674
8888
  if (!violationTriggers.length) return;
7675
8889
  const context = {
@@ -7706,7 +8920,7 @@ var Form = ({
7706
8920
  processCalculations(name, newFormData);
7707
8921
  checkViolations(name, newFormData);
7708
8922
  };
7709
- const isFieldVisible = React41__default.useCallback(
8923
+ const isFieldVisible = React47__default.useCallback(
7710
8924
  (fieldName) => {
7711
8925
  const condition = conditionalFields[fieldName];
7712
8926
  if (!condition) return true;
@@ -7714,7 +8928,7 @@ var Form = ({
7714
8928
  },
7715
8929
  [conditionalFields, evalContext]
7716
8930
  );
7717
- const isSectionVisible = React41__default.useCallback(
8931
+ const isSectionVisible = React47__default.useCallback(
7718
8932
  (section) => {
7719
8933
  if (!section.condition) return true;
7720
8934
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -7746,7 +8960,7 @@ var Form = ({
7746
8960
  eventBus.emit(`UI:${onCancel}`);
7747
8961
  }
7748
8962
  };
7749
- const renderField = React41__default.useCallback(
8963
+ const renderField = React47__default.useCallback(
7750
8964
  (field) => {
7751
8965
  const fieldName = field.name || field.field;
7752
8966
  if (!fieldName) return null;
@@ -7767,7 +8981,7 @@ var Form = ({
7767
8981
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
7768
8982
  );
7769
8983
  const effectiveFields = entityDerivedFields ?? fields;
7770
- const normalizedFields = React41__default.useMemo(() => {
8984
+ const normalizedFields = React47__default.useMemo(() => {
7771
8985
  if (!effectiveFields || effectiveFields.length === 0) return [];
7772
8986
  return effectiveFields.map((field) => {
7773
8987
  if (typeof field === "string") {
@@ -7776,7 +8990,7 @@ var Form = ({
7776
8990
  return field;
7777
8991
  });
7778
8992
  }, [effectiveFields]);
7779
- const schemaFields = React41__default.useMemo(() => {
8993
+ const schemaFields = React47__default.useMemo(() => {
7780
8994
  if (normalizedFields.length === 0) return null;
7781
8995
  if (isDebugEnabled()) {
7782
8996
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -7786,7 +9000,7 @@ var Form = ({
7786
9000
  }
7787
9001
  return normalizedFields.map(renderField).filter(Boolean);
7788
9002
  }, [normalizedFields, renderField, entityName, conditionalFields]);
7789
- const sectionElements = React41__default.useMemo(() => {
9003
+ const sectionElements = React47__default.useMemo(() => {
7790
9004
  if (!sections || sections.length === 0) return null;
7791
9005
  return sections.map((section) => {
7792
9006
  if (!isSectionVisible(section)) {
@@ -7963,47 +9177,44 @@ var Form = ({
7963
9177
  );
7964
9178
  }
7965
9179
  }
7966
- return (
7967
- // eslint-disable-next-line almadar/no-raw-dom-elements -- native <form> needed for onSubmit semantics
7968
- /* @__PURE__ */ jsxs(
7969
- "form",
7970
- {
7971
- className: cn(layoutStyles[layout], gapStyles5[gap], className),
7972
- onSubmit: handleSubmit,
7973
- ...props,
7974
- children: [
7975
- error && /* @__PURE__ */ jsx(Alert, { variant: "error", className: "mb-4", children: error.message || t("error.occurred") }),
7976
- sectionElements && sectionElements.length > 0 && /* @__PURE__ */ jsx(VStack, { gap: gap === "sm" ? "sm" : gap === "lg" ? "lg" : "md", children: sectionElements }),
7977
- schemaFields,
7978
- children,
7979
- (schemaFields && schemaFields.length > 0 || sectionElements && sectionElements.length > 0) && /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "pt-4", children: [
7980
- /* @__PURE__ */ jsx(
7981
- Button,
7982
- {
7983
- type: "submit",
7984
- variant: "primary",
7985
- disabled: isLoading,
7986
- "data-event": submitEvent,
7987
- "data-testid": `action-${submitEvent}`,
7988
- children: isLoading ? t("form.saving") : resolvedSubmitLabel
7989
- }
7990
- ),
7991
- shouldShowCancel && /* @__PURE__ */ jsx(
7992
- Button,
7993
- {
7994
- type: "button",
7995
- variant: "secondary",
7996
- onClick: handleCancel,
7997
- disabled: isLoading,
7998
- "data-event": cancelEvent,
7999
- "data-testid": `action-${cancelEvent}`,
8000
- children: resolvedCancelLabel
8001
- }
8002
- )
8003
- ] })
8004
- ]
8005
- }
8006
- )
9180
+ return /* @__PURE__ */ jsxs(
9181
+ "form",
9182
+ {
9183
+ className: cn(layoutStyles[layout], gapStyles6[gap], className),
9184
+ onSubmit: handleSubmit,
9185
+ ...props,
9186
+ children: [
9187
+ error && /* @__PURE__ */ jsx(Alert, { variant: "error", className: "mb-4", children: error.message || t("error.occurred") }),
9188
+ sectionElements && sectionElements.length > 0 && /* @__PURE__ */ jsx(VStack, { gap: gap === "sm" ? "sm" : gap === "lg" ? "lg" : "md", children: sectionElements }),
9189
+ schemaFields,
9190
+ children,
9191
+ (schemaFields && schemaFields.length > 0 || sectionElements && sectionElements.length > 0) && /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "pt-4", children: [
9192
+ /* @__PURE__ */ jsx(
9193
+ Button,
9194
+ {
9195
+ type: "submit",
9196
+ variant: "primary",
9197
+ disabled: isLoading,
9198
+ "data-event": submitEvent,
9199
+ "data-testid": `action-${submitEvent}`,
9200
+ children: isLoading ? t("form.saving") : resolvedSubmitLabel
9201
+ }
9202
+ ),
9203
+ shouldShowCancel && /* @__PURE__ */ jsx(
9204
+ Button,
9205
+ {
9206
+ type: "button",
9207
+ variant: "secondary",
9208
+ onClick: handleCancel,
9209
+ disabled: isLoading,
9210
+ "data-event": cancelEvent,
9211
+ "data-testid": `action-${cancelEvent}`,
9212
+ children: resolvedCancelLabel
9213
+ }
9214
+ )
9215
+ ] })
9216
+ ]
9217
+ }
8007
9218
  );
8008
9219
  };
8009
9220
  function formatDateValue(value) {
@@ -8037,9 +9248,37 @@ function formatDateTimeValue(value) {
8037
9248
  Form.displayName = "Form";
8038
9249
  function normalizeFields(fields) {
8039
9250
  if (!fields) return [];
8040
- return fields.map((f) => typeof f === "string" ? f : f.key);
9251
+ return fields.map((f) => typeof f === "string" ? f : f.key ?? f.name ?? "");
8041
9252
  }
8042
- var gapStyles6 = {
9253
+ function fieldLabel3(key) {
9254
+ return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
9255
+ }
9256
+ function asBooleanValue2(value) {
9257
+ if (typeof value === "boolean") return value;
9258
+ if (value === "true") return true;
9259
+ if (value === "false") return false;
9260
+ return null;
9261
+ }
9262
+ var STATUS_FIELDS = /* @__PURE__ */ new Set(["status", "state", "priority", "type", "category", "role", "level", "tier"]);
9263
+ function isDateField(key) {
9264
+ const lower = key.toLowerCase();
9265
+ return lower.includes("date") || lower.includes("time") || lower.endsWith("at") || lower.endsWith("_at");
9266
+ }
9267
+ function formatDate3(value) {
9268
+ if (!value) return "";
9269
+ const d = new Date(String(value));
9270
+ if (isNaN(d.getTime())) return String(value);
9271
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
9272
+ }
9273
+ function statusVariant3(value) {
9274
+ const v = value.toLowerCase();
9275
+ if (["active", "completed", "done", "approved", "published", "resolved", "open"].includes(v)) return "success";
9276
+ if (["pending", "in_progress", "in-progress", "review", "draft", "processing"].includes(v)) return "warning";
9277
+ if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed"].includes(v)) return "error";
9278
+ if (["new", "created", "scheduled", "queued"].includes(v)) return "info";
9279
+ return "default";
9280
+ }
9281
+ var gapStyles7 = {
8043
9282
  none: "gap-0",
8044
9283
  sm: "gap-2",
8045
9284
  md: "gap-4",
@@ -8071,7 +9310,8 @@ var CardGrid = ({
8071
9310
  fieldNames,
8072
9311
  columns,
8073
9312
  itemActions,
8074
- showTotal = true
9313
+ showTotal = true,
9314
+ imageField
8075
9315
  }) => {
8076
9316
  const eventBus = useEventBus();
8077
9317
  const { t } = useTranslate();
@@ -8083,6 +9323,28 @@ var CardGrid = ({
8083
9323
  const handlePageChange = (newPage) => {
8084
9324
  eventBus.emit("UI:PAGINATE", { page: newPage, pageSize });
8085
9325
  };
9326
+ const titleField = effectiveFieldNames?.[0];
9327
+ const statusField = effectiveFieldNames?.find((f) => STATUS_FIELDS.has(f.toLowerCase()));
9328
+ const bodyFields = effectiveFieldNames?.filter((f) => f !== titleField && f !== statusField) ?? [];
9329
+ const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
9330
+ const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
9331
+ const handleActionClick = (action, itemData) => (e) => {
9332
+ e.stopPropagation();
9333
+ if (action.navigatesTo) {
9334
+ const url = action.navigatesTo.replace(/\{\{row\.(\w+(?:\.\w+)*)\}\}/g, (_, field) => {
9335
+ const value = getNestedValue(itemData, field);
9336
+ return value !== void 0 && value !== null ? String(value) : "";
9337
+ });
9338
+ eventBus.emit("UI:NAVIGATE", { url, row: itemData });
9339
+ return;
9340
+ }
9341
+ if (action.event) {
9342
+ eventBus.emit(`UI:${action.event}`, { row: itemData });
9343
+ }
9344
+ if (action.onClick) {
9345
+ action.onClick(itemData);
9346
+ }
9347
+ };
8086
9348
  const renderContent = () => {
8087
9349
  if (children) {
8088
9350
  return children;
@@ -8097,62 +9359,85 @@ var CardGrid = ({
8097
9359
  ] }) });
8098
9360
  }
8099
9361
  if (normalizedData.length === 0) {
8100
- 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" }) });
9362
+ 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" }) });
8101
9363
  }
8102
9364
  return normalizedData.map((item, index) => {
8103
9365
  const itemData = item;
8104
9366
  const id = itemData.id || String(index);
8105
- const cardFields = effectiveFieldNames || Object.keys(itemData).slice(0, 3);
8106
- const handleActionClick = (action) => (e) => {
8107
- e.stopPropagation();
8108
- if (action.navigatesTo) {
8109
- const url = action.navigatesTo.replace(/\{\{row\.(\w+(?:\.\w+)*)\}\}/g, (_, field) => {
8110
- const value = getNestedValue(itemData, field);
8111
- return value !== void 0 && value !== null ? String(value) : "";
8112
- });
8113
- eventBus.emit("UI:NAVIGATE", { url, row: itemData });
8114
- return;
8115
- }
8116
- if (action.event) {
8117
- eventBus.emit(`UI:${action.event}`, { row: itemData });
8118
- }
8119
- if (action.onClick) {
8120
- action.onClick(itemData);
8121
- }
8122
- };
9367
+ const titleValue = titleField ? getNestedValue(itemData, titleField) : void 0;
9368
+ const statusValue = statusField ? getNestedValue(itemData, statusField) : void 0;
8123
9369
  return /* @__PURE__ */ jsxs(
8124
9370
  Box,
8125
9371
  {
8126
9372
  "data-entity-row": true,
8127
9373
  className: cn(
8128
- "bg-[var(--color-card)] rounded-[var(--radius-lg)] border border-[var(--color-border)] p-4 shadow-[var(--shadow-sm)]",
8129
- "cursor-pointer hover:border-[var(--color-primary)] transition-colors"
9374
+ "bg-[var(--color-card)] rounded-[var(--radius-lg)] border border-[var(--color-border)]",
9375
+ "shadow-[var(--shadow-sm)] hover:shadow-[var(--shadow-hover)]",
9376
+ "cursor-pointer hover:border-[var(--color-primary)] transition-all",
9377
+ "flex flex-col"
8130
9378
  ),
8131
9379
  action: "VIEW",
8132
9380
  actionPayload: { row: itemData },
8133
9381
  children: [
8134
- cardFields.map((field) => {
8135
- const value = getNestedValue(itemData, field);
8136
- if (value === void 0 || value === null) return null;
8137
- return /* @__PURE__ */ jsxs(Box, { className: "mb-2 last:mb-0", children: [
8138
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "uppercase", children: field }),
8139
- /* @__PURE__ */ jsx(Typography, { variant: "small", children: String(value) })
8140
- ] }, field);
8141
- }),
8142
- 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) => {
8143
- const buttonVariant = action.variant || "secondary";
8144
- return /* @__PURE__ */ jsx(
9382
+ imageField && (() => {
9383
+ const imgUrl = getNestedValue(itemData, imageField);
9384
+ if (!imgUrl || typeof imgUrl !== "string") return null;
9385
+ return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-[var(--radius-lg)]", children: /* @__PURE__ */ jsx(
9386
+ "img",
9387
+ {
9388
+ src: imgUrl,
9389
+ alt: titleValue !== void 0 ? String(titleValue) : "",
9390
+ className: "w-full h-full object-cover",
9391
+ loading: "lazy"
9392
+ }
9393
+ ) });
9394
+ })(),
9395
+ /* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
9396
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
9397
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "font-semibold truncate", children: String(titleValue) }),
9398
+ statusValue !== void 0 && statusValue !== null && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(statusValue)), children: String(statusValue) }) })
9399
+ ] }),
9400
+ dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, actionIdx) => /* @__PURE__ */ jsx(
8145
9401
  Button,
8146
9402
  {
8147
- variant: buttonVariant,
9403
+ variant: "ghost",
8148
9404
  size: "sm",
8149
- onClick: handleActionClick(action),
9405
+ onClick: handleActionClick(action, itemData),
8150
9406
  "data-testid": action.event ? `action-${action.event}` : void 0,
9407
+ className: "text-[var(--color-error)] hover:bg-[var(--color-error)]/10 px-2",
8151
9408
  children: action.label
8152
9409
  },
8153
9410
  actionIdx
8154
- );
8155
- }) })
9411
+ )) })
9412
+ ] }) }),
9413
+ bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
9414
+ const value = getNestedValue(itemData, field);
9415
+ if (value === void 0 || value === null || value === "") return null;
9416
+ const boolVal = asBooleanValue2(value);
9417
+ if (boolVal !== null) {
9418
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between", children: [
9419
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fieldLabel3(field) }),
9420
+ boolVal ? /* @__PURE__ */ jsx(Badge, { variant: "success", children: t("common.yes") || "Yes" }) : /* @__PURE__ */ jsx(Badge, { variant: "neutral", children: t("common.no") || "No" })
9421
+ ] }, field);
9422
+ }
9423
+ const displayValue = isDateField(field) ? formatDate3(value) : STATUS_FIELDS.has(field.toLowerCase()) ? void 0 : String(value);
9424
+ if (!displayValue) return null;
9425
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between", children: [
9426
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fieldLabel3(field) }),
9427
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-right truncate max-w-[60%]", children: displayValue })
9428
+ ] }, field);
9429
+ }) }) }),
9430
+ 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(
9431
+ Button,
9432
+ {
9433
+ variant: action.variant === "primary" ? "primary" : "ghost",
9434
+ size: "sm",
9435
+ onClick: handleActionClick(action, itemData),
9436
+ "data-testid": action.event ? `action-${action.event}` : void 0,
9437
+ children: action.label
9438
+ },
9439
+ actionIdx
9440
+ )) }) })
8156
9441
  ]
8157
9442
  },
8158
9443
  id
@@ -8165,7 +9450,7 @@ var CardGrid = ({
8165
9450
  {
8166
9451
  className: cn(
8167
9452
  "grid",
8168
- gapStyles6[gap],
9453
+ gapStyles7[gap],
8169
9454
  alignStyles4[alignItems],
8170
9455
  maxCols === 1 && "grid-cols-1",
8171
9456
  maxCols === 2 && "sm:grid-cols-2",
@@ -8194,7 +9479,7 @@ var CardGrid = ({
8194
9479
  CardGrid.displayName = "CardGrid";
8195
9480
  function MasterDetail({
8196
9481
  entity,
8197
- masterFields = [],
9482
+ masterFields,
8198
9483
  detailFields: _detailFields,
8199
9484
  // Captured but not used here - detail handled separately
8200
9485
  loading: externalLoading,
@@ -8209,6 +9494,7 @@ function MasterDetail({
8209
9494
  return /* @__PURE__ */ jsx(
8210
9495
  DataTable,
8211
9496
  {
9497
+ fields: masterFields,
8212
9498
  columns: masterFields,
8213
9499
  entity,
8214
9500
  isLoading: loading || isLoading,
@@ -8280,7 +9566,7 @@ function GridPattern({
8280
9566
  style,
8281
9567
  children
8282
9568
  }) {
8283
- return /* @__PURE__ */ jsx(Grid2, { cols, gap, rowGap, colGap, className, style, children });
9569
+ return /* @__PURE__ */ jsx(Grid, { cols, gap, rowGap, colGap, className, style, children });
8284
9570
  }
8285
9571
  GridPattern.displayName = "GridPattern";
8286
9572
  function CenterPattern({
@@ -8297,14 +9583,14 @@ function SpacerPattern({ size = "flex" }) {
8297
9583
  if (size === "flex") {
8298
9584
  return /* @__PURE__ */ jsx(Spacer, {});
8299
9585
  }
8300
- const sizeMap4 = {
9586
+ const sizeMap5 = {
8301
9587
  xs: "0.25rem",
8302
9588
  sm: "0.5rem",
8303
9589
  md: "1rem",
8304
9590
  lg: "1.5rem",
8305
9591
  xl: "2rem"
8306
9592
  };
8307
- return /* @__PURE__ */ jsx(Box, { style: { width: sizeMap4[size], height: sizeMap4[size], flexShrink: 0 } });
9593
+ return /* @__PURE__ */ jsx(Box, { style: { width: sizeMap5[size], height: sizeMap5[size], flexShrink: 0 } });
8308
9594
  }
8309
9595
  SpacerPattern.displayName = "SpacerPattern";
8310
9596
  function DividerPattern({
@@ -8408,19 +9694,16 @@ function LinkPattern({
8408
9694
  emit(`UI:${onClick}`, { href });
8409
9695
  }
8410
9696
  };
8411
- return (
8412
- // eslint-disable-next-line almadar/no-raw-dom-elements -- semantic anchor with href
8413
- /* @__PURE__ */ jsx(
8414
- "a",
8415
- {
8416
- href: href ?? "#",
8417
- target: external ? "_blank" : void 0,
8418
- rel: external ? "noopener noreferrer" : void 0,
8419
- onClick: onClick ? handleClick : void 0,
8420
- className,
8421
- children: label
8422
- }
8423
- )
9697
+ return /* @__PURE__ */ jsx(
9698
+ "a",
9699
+ {
9700
+ href: href ?? "#",
9701
+ target: external ? "_blank" : void 0,
9702
+ rel: external ? "noopener noreferrer" : void 0,
9703
+ onClick: onClick ? handleClick : void 0,
9704
+ className,
9705
+ children: label
9706
+ }
8424
9707
  );
8425
9708
  }
8426
9709
  LinkPattern.displayName = "LinkPattern";
@@ -8491,19 +9774,16 @@ function ImagePattern({
8491
9774
  objectFit = "cover",
8492
9775
  className
8493
9776
  }) {
8494
- return (
8495
- // eslint-disable-next-line almadar/no-raw-dom-elements -- semantic img with src/alt
8496
- /* @__PURE__ */ jsx(
8497
- "img",
8498
- {
8499
- src,
8500
- alt,
8501
- width,
8502
- height,
8503
- className,
8504
- style: { objectFit }
8505
- }
8506
- )
9777
+ return /* @__PURE__ */ jsx(
9778
+ "img",
9779
+ {
9780
+ src,
9781
+ alt,
9782
+ width,
9783
+ height,
9784
+ className,
9785
+ style: { objectFit }
9786
+ }
8507
9787
  );
8508
9788
  }
8509
9789
  ImagePattern.displayName = "ImagePattern";
@@ -8571,7 +9851,7 @@ function InputPattern({
8571
9851
  className
8572
9852
  }) {
8573
9853
  const { emit } = useEventBus();
8574
- const [localValue, setLocalValue] = React41__default.useState(value);
9854
+ const [localValue, setLocalValue] = React47__default.useState(value);
8575
9855
  const handleChange = (e) => {
8576
9856
  setLocalValue(e.target.value);
8577
9857
  if (onChange) {
@@ -8608,7 +9888,7 @@ function TextareaPattern({
8608
9888
  className
8609
9889
  }) {
8610
9890
  const { emit } = useEventBus();
8611
- const [localValue, setLocalValue] = React41__default.useState(value);
9891
+ const [localValue, setLocalValue] = React47__default.useState(value);
8612
9892
  const handleChange = (e) => {
8613
9893
  setLocalValue(e.target.value);
8614
9894
  if (onChange) {
@@ -8639,7 +9919,7 @@ function SelectPattern({
8639
9919
  className
8640
9920
  }) {
8641
9921
  const { emit } = useEventBus();
8642
- const [localValue, setLocalValue] = React41__default.useState(value);
9922
+ const [localValue, setLocalValue] = React47__default.useState(value);
8643
9923
  const handleChange = (e) => {
8644
9924
  setLocalValue(e.target.value);
8645
9925
  if (onChange) {
@@ -8668,7 +9948,7 @@ function CheckboxPattern({
8668
9948
  className
8669
9949
  }) {
8670
9950
  const { emit } = useEventBus();
8671
- const [localChecked, setLocalChecked] = React41__default.useState(checked);
9951
+ const [localChecked, setLocalChecked] = React47__default.useState(checked);
8672
9952
  const handleChange = (e) => {
8673
9953
  setLocalChecked(e.target.checked);
8674
9954
  if (onChange) {
@@ -8782,7 +10062,7 @@ function MenuPattern({
8782
10062
  ...item,
8783
10063
  onClick: () => emit(`UI:${item.event}`, {})
8784
10064
  }));
8785
- return /* @__PURE__ */ jsx(Menu2, { items: menuItems, trigger, position, className });
10065
+ return /* @__PURE__ */ jsx(Menu, { items: menuItems, trigger, position, className });
8786
10066
  }
8787
10067
  MenuPattern.displayName = "MenuPattern";
8788
10068
  function AccordionPattern({
@@ -8961,30 +10241,24 @@ function CustomPattern({
8961
10241
  }
8962
10242
  );
8963
10243
  case "a":
8964
- return (
8965
- // eslint-disable-next-line almadar/no-raw-dom-elements -- semantic anchor with href
8966
- /* @__PURE__ */ jsx(
8967
- "a",
8968
- {
8969
- href: href ?? "#",
8970
- target: external ? "_blank" : void 0,
8971
- rel: external ? "noopener noreferrer" : void 0,
8972
- ...commonProps,
8973
- children: renderContent
8974
- }
8975
- )
10244
+ return /* @__PURE__ */ jsx(
10245
+ "a",
10246
+ {
10247
+ href: href ?? "#",
10248
+ target: external ? "_blank" : void 0,
10249
+ rel: external ? "noopener noreferrer" : void 0,
10250
+ ...commonProps,
10251
+ children: renderContent
10252
+ }
8976
10253
  );
8977
10254
  case "img":
8978
- return (
8979
- // eslint-disable-next-line almadar/no-raw-dom-elements -- semantic img with src/alt
8980
- /* @__PURE__ */ jsx(
8981
- "img",
8982
- {
8983
- src,
8984
- alt: alt ?? "",
8985
- ...commonProps
8986
- }
8987
- )
10255
+ return /* @__PURE__ */ jsx(
10256
+ "img",
10257
+ {
10258
+ src,
10259
+ alt: alt ?? "",
10260
+ ...commonProps
10261
+ }
8988
10262
  );
8989
10263
  case "input":
8990
10264
  return /* @__PURE__ */ jsx(
@@ -9075,7 +10349,7 @@ function SuspenseConfigProvider({
9075
10349
  config,
9076
10350
  children
9077
10351
  }) {
9078
- return React41__default.createElement(
10352
+ return React47__default.createElement(
9079
10353
  SuspenseConfigContext.Provider,
9080
10354
  { value: config },
9081
10355
  children
@@ -9252,6 +10526,9 @@ function UISlotComponent({
9252
10526
  if (pattern === "clear") {
9253
10527
  return null;
9254
10528
  }
10529
+ if (isPortalSlot(slot)) {
10530
+ return /* @__PURE__ */ jsx(CompiledPortal, { slot, className, pattern, sourceTrait, children });
10531
+ }
9255
10532
  return /* @__PURE__ */ jsx(
9256
10533
  Box,
9257
10534
  {
@@ -9302,6 +10579,70 @@ function UISlotComponent({
9302
10579
  }
9303
10580
  );
9304
10581
  }
10582
+ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
10583
+ const [portalRoot, setPortalRoot] = useState(null);
10584
+ const eventBus = useUISlots();
10585
+ useEffect(() => {
10586
+ let root = document.getElementById("ui-slot-portal-root");
10587
+ if (!root) {
10588
+ root = document.createElement("div");
10589
+ root.id = "ui-slot-portal-root";
10590
+ document.body.appendChild(root);
10591
+ }
10592
+ setPortalRoot(root);
10593
+ }, []);
10594
+ const handleDismiss = () => {
10595
+ eventBus.clear(slot);
10596
+ };
10597
+ if (!portalRoot) return null;
10598
+ let wrapper;
10599
+ switch (slot) {
10600
+ case "modal":
10601
+ wrapper = /* @__PURE__ */ jsx(Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, children: /* @__PURE__ */ jsx(
10602
+ Box,
10603
+ {
10604
+ className: cn("ui-slot", `ui-slot-${slot}`, className),
10605
+ "data-pattern": pattern,
10606
+ "data-source-trait": sourceTrait,
10607
+ children
10608
+ }
10609
+ ) });
10610
+ break;
10611
+ case "drawer":
10612
+ wrapper = /* @__PURE__ */ jsx(Drawer, { isOpen: true, onClose: handleDismiss, position: "right", children: /* @__PURE__ */ jsx(
10613
+ Box,
10614
+ {
10615
+ className: cn("ui-slot", `ui-slot-${slot}`, className),
10616
+ "data-pattern": pattern,
10617
+ "data-source-trait": sourceTrait,
10618
+ children
10619
+ }
10620
+ ) });
10621
+ break;
10622
+ case "toast":
10623
+ wrapper = /* @__PURE__ */ jsx(Box, { className: "fixed top-4 right-4 z-50", children: /* @__PURE__ */ jsx(
10624
+ Box,
10625
+ {
10626
+ className: cn("ui-slot", `ui-slot-${slot}`, className),
10627
+ "data-pattern": pattern,
10628
+ "data-source-trait": sourceTrait,
10629
+ children
10630
+ }
10631
+ ) });
10632
+ break;
10633
+ default:
10634
+ wrapper = /* @__PURE__ */ jsx(
10635
+ Box,
10636
+ {
10637
+ className: cn("ui-slot", `ui-slot-${slot}`, className),
10638
+ "data-pattern": pattern,
10639
+ "data-source-trait": sourceTrait,
10640
+ children
10641
+ }
10642
+ );
10643
+ }
10644
+ return createPortal(wrapper, portalRoot);
10645
+ }
9305
10646
  function SlotPortal({
9306
10647
  slot,
9307
10648
  content,
@@ -9489,4 +10830,4 @@ function UISlotRenderer({
9489
10830
  }
9490
10831
  UISlotRenderer.displayName = "UISlotRenderer";
9491
10832
 
9492
- 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 };
10833
+ export { Accordion, Alert, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, Card, Card2, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Center, ChartLegend, Checkbox, CodeBlock, ConditionalWrapper, Container, ControlButton, 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, 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, StatCard, StateIndicator, SuspenseConfigProvider, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Toast, Tooltip, Typography, UISlotComponent, UISlotRenderer, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite };