@almadar/ui 5.131.0 → 5.133.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.
@@ -5723,6 +5723,8 @@ var init_Badge = __esm({
5723
5723
  };
5724
5724
  const iconPx = size === "lg" ? 20 : 16;
5725
5725
  const resolvedIcon = iconAsset?.url ? /* @__PURE__ */ jsxRuntime.jsx(AtlasImage, { asset: iconAsset, size: iconPx, alt: iconAsset.name ?? iconAsset.category ?? "", className: "flex-shrink-0" }) : typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, className: iconSizes3[size] }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, className: iconSizes3[size] }) : null;
5726
+ const hasText = Boolean(children) || amount != null || label !== void 0 && label !== null && label !== "";
5727
+ if (!hasText && !resolvedIcon && !onRemove) return null;
5726
5728
  return /* @__PURE__ */ jsxRuntime.jsxs(
5727
5729
  "span",
5728
5730
  {
@@ -8960,11 +8962,13 @@ var init_TrendIndicator = __esm({
8960
8962
  size = "md",
8961
8963
  ...props
8962
8964
  }, ref) => {
8963
- const dir = resolveDirection(value, direction);
8965
+ const hasValue = typeof value === "number" && Number.isFinite(value);
8966
+ if (!hasValue && !direction) return null;
8967
+ const dir = resolveDirection(hasValue ? value : void 0, direction);
8964
8968
  const colorClass = resolveColor(dir, invert);
8965
8969
  const iconName = iconNameMap[dir];
8966
8970
  const styles = sizeStyles6[size];
8967
- const formattedValue = value !== void 0 ? `${value > 0 ? "+" : ""}${value}%` : void 0;
8971
+ const formattedValue = hasValue ? `${value > 0 ? "+" : ""}${value}%` : void 0;
8968
8972
  const ariaLabel = label ?? (formattedValue ? `${dir} ${formattedValue}` : dir);
8969
8973
  return /* @__PURE__ */ jsxRuntime.jsxs(
8970
8974
  "span",
@@ -20386,26 +20390,19 @@ var init_BookViewer = __esm({
20386
20390
  function BoxPattern({
20387
20391
  p,
20388
20392
  m,
20389
- bg = "transparent",
20390
- border = false,
20391
- radius = "none",
20392
- shadow = "none",
20393
- className,
20394
- style,
20395
- children
20393
+ radius,
20394
+ isLoading: _isLoading,
20395
+ error: _error,
20396
+ entity: _entity,
20397
+ ...boxProps
20396
20398
  }) {
20397
20399
  return /* @__PURE__ */ jsxRuntime.jsx(
20398
20400
  Box,
20399
20401
  {
20400
- padding: p,
20401
- margin: m,
20402
- bg,
20403
- border,
20404
- rounded: radius,
20405
- shadow,
20406
- className,
20407
- style,
20408
- children
20402
+ padding: boxProps.padding ?? p,
20403
+ margin: boxProps.margin ?? m,
20404
+ rounded: boxProps.rounded ?? radius,
20405
+ ...boxProps
20409
20406
  }
20410
20407
  );
20411
20408
  }
@@ -24096,17 +24093,19 @@ var init_DashboardLayout = __esm({
24096
24093
  const [sidebarOpen, setSidebarOpen] = React91.useState(false);
24097
24094
  const [userMenuOpen, setUserMenuOpen] = React91.useState(false);
24098
24095
  const layoutRef = React91.useRef(null);
24099
- const [isMobile, setIsMobile] = React91.useState(false);
24096
+ const [layoutWidth, setLayoutWidth] = React91.useState(null);
24100
24097
  React91.useEffect(() => {
24101
24098
  const el = layoutRef.current;
24102
24099
  if (!el || typeof ResizeObserver === "undefined") return;
24103
24100
  const ro = new ResizeObserver((entries) => {
24104
24101
  const w = entries[0]?.contentRect.width ?? el.clientWidth;
24105
- setIsMobile(w < 1024);
24102
+ setLayoutWidth(w);
24106
24103
  });
24107
24104
  ro.observe(el);
24108
24105
  return () => ro.disconnect();
24109
24106
  }, []);
24107
+ const isMobile = layoutWidth !== null && layoutWidth < 768;
24108
+ const isRail = layoutWidth !== null && layoutWidth >= 768 && layoutWidth < 1024;
24110
24109
  React91.useEffect(() => {
24111
24110
  if (!isMobile && sidebarOpen) setSidebarOpen(false);
24112
24111
  }, [isMobile, sidebarOpen]);
@@ -24139,7 +24138,8 @@ var init_DashboardLayout = __esm({
24139
24138
  {
24140
24139
  as: "aside",
24141
24140
  className: cn(
24142
- "z-30 w-64 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
24141
+ "z-30 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
24142
+ isRail ? "w-16" : "w-64",
24143
24143
  "flex flex-col"
24144
24144
  ),
24145
24145
  style: isMobile ? {
@@ -24155,10 +24155,10 @@ var init_DashboardLayout = __esm({
24155
24155
  HStack,
24156
24156
  {
24157
24157
  align: "center",
24158
- justify: "between",
24159
- className: "h-16 px-4 border-b border-border dark:border-border",
24158
+ justify: isRail ? "center" : "between",
24159
+ className: cn("h-16 border-b border-border dark:border-border", isRail ? "px-2" : "px-4"),
24160
24160
  children: [
24161
- /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to: "/", className: "flex items-center gap-2", children: [
24161
+ /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to: "/", className: "flex items-center gap-2", title: isRail ? appName : void 0, children: [
24162
24162
  logo || /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-8 h-8 bg-primary rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
24163
24163
  Typography,
24164
24164
  {
@@ -24168,7 +24168,7 @@ var init_DashboardLayout = __esm({
24168
24168
  children: appName.charAt(0).toUpperCase()
24169
24169
  }
24170
24170
  ) }),
24171
- /* @__PURE__ */ jsxRuntime.jsx(
24171
+ !isRail && /* @__PURE__ */ jsxRuntime.jsx(
24172
24172
  Typography,
24173
24173
  {
24174
24174
  variant: "label",
@@ -24195,12 +24195,13 @@ var init_DashboardLayout = __esm({
24195
24195
  {
24196
24196
  as: "nav",
24197
24197
  gap: "none",
24198
- className: "flex-1 px-3 py-4 space-y-1 overflow-y-auto",
24198
+ className: cn("flex-1 py-4 space-y-1 overflow-y-auto", isRail ? "px-2" : "px-3"),
24199
24199
  children: navItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
24200
24200
  NavLink,
24201
24201
  {
24202
24202
  item,
24203
- currentPath: activePath
24203
+ currentPath: activePath,
24204
+ compact: isRail
24204
24205
  },
24205
24206
  item.href
24206
24207
  ))
@@ -24455,13 +24456,40 @@ var init_DashboardLayout = __esm({
24455
24456
  DashboardLayout.displayName = "DashboardLayout";
24456
24457
  NavLink = ({
24457
24458
  item,
24458
- currentPath
24459
+ currentPath,
24460
+ compact = false
24459
24461
  }) => {
24460
24462
  const isActive = currentPath === item.href || currentPath.startsWith(item.href + "/");
24461
24463
  const iconClassName = cn(
24462
24464
  "h-5 w-5",
24463
24465
  isActive ? "text-primary-foreground" : "text-muted-foreground"
24464
24466
  );
24467
+ if (compact) {
24468
+ return /* @__PURE__ */ jsxRuntime.jsx(
24469
+ reactRouterDom.Link,
24470
+ {
24471
+ to: item.href,
24472
+ title: item.label,
24473
+ "aria-label": item.label,
24474
+ className: cn(
24475
+ "flex items-center justify-center px-2 py-2 rounded-lg transition-colors",
24476
+ isActive ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"
24477
+ ),
24478
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { as: "span", className: "relative inline-flex", children: [
24479
+ item.icon ? typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, className: iconClassName }) : /* @__PURE__ */ jsxRuntime.jsx(item.icon, { className: iconClassName }) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "font-semibold", as: "span", children: item.label.charAt(0).toUpperCase() }),
24480
+ item.badge && /* @__PURE__ */ jsxRuntime.jsx(
24481
+ Badge,
24482
+ {
24483
+ variant: isActive ? "primary" : "default",
24484
+ size: "sm",
24485
+ className: "absolute -top-2 -right-2 px-1 py-0 text-[10px] leading-4",
24486
+ children: item.badge
24487
+ }
24488
+ )
24489
+ ] })
24490
+ }
24491
+ );
24492
+ }
24465
24493
  return /* @__PURE__ */ jsxRuntime.jsxs(
24466
24494
  reactRouterDom.Link,
24467
24495
  {
@@ -25527,40 +25555,55 @@ function DataGrid({
25527
25555
  {
25528
25556
  "data-entity-row": true,
25529
25557
  "data-entity-id": id,
25530
- className: cn(isSelected && "ring-2 ring-primary rounded-lg"),
25558
+ className: cn("relative group/rowactions", isSelected && "ring-2 ring-primary rounded-lg"),
25531
25559
  children: [
25532
25560
  children(itemData, index),
25533
- actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-3 border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-end", children: [
25534
- (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
25535
- Button,
25536
- {
25537
- variant: action.variant === "primary" ? "primary" : "ghost",
25538
- size: "sm",
25539
- onClick: handleActionClick(action, itemData),
25540
- "data-testid": `action-${action.event}`,
25541
- "data-row-id": String(itemData.id),
25542
- className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
25543
- children: [
25544
- action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
25545
- action.label
25546
- ]
25547
- },
25548
- idx
25549
- )),
25550
- maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
25561
+ actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "absolute top-2 right-2 z-10 opacity-0 group-hover/rowactions:opacity-100 focus-within:opacity-100 [@media(pointer:coarse)]:opacity-100 transition-opacity duration-fast", children: [
25562
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5 [@media(pointer:coarse)]:hidden", children: [
25563
+ (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
25564
+ Button,
25565
+ {
25566
+ variant: action.variant === "primary" ? "primary" : "ghost",
25567
+ size: "sm",
25568
+ onClick: handleActionClick(action, itemData),
25569
+ "data-testid": `action-${action.event}`,
25570
+ "data-row-id": String(itemData.id),
25571
+ className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
25572
+ children: [
25573
+ action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
25574
+ action.label
25575
+ ]
25576
+ },
25577
+ idx
25578
+ )),
25579
+ maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
25580
+ Menu,
25581
+ {
25582
+ position: "bottom-end",
25583
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
25584
+ items: actionDefs.slice(maxInlineActions).map((action) => ({
25585
+ label: action.label,
25586
+ icon: action.icon,
25587
+ event: action.event,
25588
+ onClick: () => fireAction(action, itemData)
25589
+ }))
25590
+ }
25591
+ )
25592
+ ] }),
25593
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "hidden [@media(pointer:coarse)]:block rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
25551
25594
  Menu,
25552
25595
  {
25553
25596
  position: "bottom-end",
25554
25597
  trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
25555
- items: actionDefs.slice(maxInlineActions).map((action) => ({
25598
+ items: actionDefs.map((action) => ({
25556
25599
  label: action.label,
25557
25600
  icon: action.icon,
25558
25601
  event: action.event,
25559
25602
  onClick: () => fireAction(action, itemData)
25560
25603
  }))
25561
25604
  }
25562
- )
25563
- ] }) })
25605
+ ) })
25606
+ ] })
25564
25607
  ]
25565
25608
  },
25566
25609
  id
@@ -25596,7 +25639,7 @@ function DataGrid({
25596
25639
  }
25597
25640
  ) });
25598
25641
  })(),
25599
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
25642
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-4", bodyFields.length > 0 && "pb-0"), children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
25600
25643
  selectable && /* @__PURE__ */ jsxRuntime.jsx(
25601
25644
  "input",
25602
25645
  {
@@ -25629,78 +25672,77 @@ function DataGrid({
25629
25672
  ] }, field.name);
25630
25673
  }) })
25631
25674
  ] }),
25632
- dangerActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
25633
- Button,
25634
- {
25635
- variant: "ghost",
25636
- size: "sm",
25637
- onClick: handleActionClick(action, itemData),
25638
- "data-testid": `action-${action.event}`,
25639
- "data-row-id": String(itemData.id),
25640
- "aria-label": action.label,
25641
- title: action.label,
25642
- className: "text-error hover:text-error hover:bg-error/10 px-2",
25643
- children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
25644
- },
25645
- idx
25646
- )) })
25647
- ] }) }),
25648
- bodyFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
25649
- const value = getNestedValue(itemData, field.name);
25650
- if (value === void 0 || value === null || value === "") return null;
25651
- if (field.format === "boolean") {
25652
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
25653
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
25654
- field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
25655
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
25656
- ] }),
25657
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
25658
- ] }, field.name);
25659
- }
25660
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
25661
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
25662
- field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
25663
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
25664
- ] }),
25665
- /* @__PURE__ */ jsxRuntime.jsx(
25666
- Typography,
25675
+ (primaryActions.length > 0 || dangerActions.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "flex-shrink-0", children: [
25676
+ (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
25677
+ Button,
25678
+ {
25679
+ variant: action.variant === "primary" ? "primary" : "ghost",
25680
+ size: "sm",
25681
+ onClick: handleActionClick(action, itemData),
25682
+ "data-testid": `action-${action.event}`,
25683
+ "data-row-id": String(itemData.id),
25684
+ "aria-label": action.label,
25685
+ title: action.label,
25686
+ className: cn(
25687
+ action.variant === "primary" ? void 0 : "text-muted-foreground hover:text-foreground",
25688
+ action.icon && "px-2"
25689
+ ),
25690
+ children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
25691
+ },
25692
+ idx
25693
+ )),
25694
+ maxInlineActions != null && primaryActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
25695
+ Menu,
25667
25696
  {
25668
- variant: field.variant === "caption" ? "caption" : "small",
25669
- className: "text-right truncate max-w-[60%]",
25670
- children: formatValue(value, field.format)
25697
+ position: "bottom-end",
25698
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
25699
+ items: primaryActions.slice(maxInlineActions).map((action) => ({
25700
+ label: action.label,
25701
+ icon: action.icon,
25702
+ event: action.event,
25703
+ onClick: () => fireAction(action, itemData)
25704
+ }))
25671
25705
  }
25672
- )
25673
- ] }, field.name);
25674
- }) }) }),
25675
- primaryActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-end flex-wrap", children: [
25676
- (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
25677
- Button,
25678
- {
25679
- variant: action.variant === "primary" ? "primary" : "ghost",
25680
- size: "sm",
25681
- onClick: handleActionClick(action, itemData),
25682
- "data-testid": `action-${action.event}`,
25683
- "data-row-id": String(itemData.id),
25684
- children: [
25685
- action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
25686
- action.label
25687
- ]
25688
- },
25689
- idx
25690
- )),
25691
- maxInlineActions != null && primaryActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
25692
- Menu,
25693
- {
25694
- position: "bottom-end",
25695
- trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
25696
- items: primaryActions.slice(maxInlineActions).map((action) => ({
25697
- label: action.label,
25698
- icon: action.icon,
25699
- event: action.event,
25700
- onClick: () => fireAction(action, itemData)
25701
- }))
25706
+ ),
25707
+ dangerActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
25708
+ Button,
25709
+ {
25710
+ variant: "ghost",
25711
+ size: "sm",
25712
+ onClick: handleActionClick(action, itemData),
25713
+ "data-testid": `action-${action.event}`,
25714
+ "data-row-id": String(itemData.id),
25715
+ "aria-label": action.label,
25716
+ title: action.label,
25717
+ className: "text-error hover:text-error hover:bg-error/10 px-2",
25718
+ children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
25719
+ },
25720
+ `danger-${idx}`
25721
+ ))
25722
+ ] })
25723
+ ] }) }),
25724
+ bodyFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 pt-2 pb-4 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
25725
+ bodyFields.filter((f3) => f3.variant === "caption" && f3.format !== "boolean").map((field) => {
25726
+ const value = getNestedValue(itemData, field.name);
25727
+ if (value === void 0 || value === null || value === "") return null;
25728
+ return /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", className: "line-clamp-2", children: formatValue(value, field.format) }, field.name);
25729
+ }),
25730
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: "flex-wrap gap-y-1", children: bodyFields.filter((f3) => f3.variant !== "caption" || f3.format === "boolean").map((field) => {
25731
+ const value = getNestedValue(itemData, field.name);
25732
+ if (value === void 0 || value === null || value === "") return null;
25733
+ if (field.format === "boolean") {
25734
+ return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
25735
+ field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
25736
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) }),
25737
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
25738
+ ] }, field.name);
25702
25739
  }
25703
- )
25740
+ return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
25741
+ field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
25742
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: (field.label ?? fieldLabel2(field.name)) + ":" }),
25743
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", children: formatValue(value, field.format) })
25744
+ ] }, field.name);
25745
+ }) })
25704
25746
  ] }) })
25705
25747
  ]
25706
25748
  },
@@ -26048,11 +26090,29 @@ function DataList({
26048
26090
  const wrapDnd = (node) => dnd.isZone ? /* @__PURE__ */ jsxRuntime.jsx(dnd.SortableItem, { id: dndId, children: node }, dndId) : node;
26049
26091
  if (hasRenderProp) {
26050
26092
  const id2 = itemData.id || String(index);
26093
+ const actions = renderItemActions(itemData);
26051
26094
  return wrapDnd(
26052
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
26053
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group flex items-stretch gap-2", children: [
26054
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
26055
- renderItemActions(itemData)
26095
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn("relative group/rowactions", itemClickEvent && "cursor-pointer"), children: [
26096
+ children(itemData, index),
26097
+ actions && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "absolute top-2 right-2 z-10 opacity-0 group-hover/rowactions:opacity-100 focus-within:opacity-100 [@media(pointer:coarse)]:opacity-100 transition-opacity duration-fast", children: [
26098
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5 [@media(pointer:coarse)]:hidden", children: actions }),
26099
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "hidden [@media(pointer:coarse)]:block rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
26100
+ Menu,
26101
+ {
26102
+ position: "bottom-end",
26103
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
26104
+ items: (itemActions ?? []).map((action) => ({
26105
+ label: action.label,
26106
+ icon: action.icon,
26107
+ event: action.event,
26108
+ variant: action.variant === "danger" ? "danger" : "default",
26109
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
26110
+ id: itemData.id,
26111
+ row: itemData
26112
+ })
26113
+ }))
26114
+ }
26115
+ ) })
26056
26116
  ] }),
26057
26117
  isCard && !isLast && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mx-6 border-b border-border/40" })
26058
26118
  ] }, id2)
@@ -26092,7 +26152,7 @@ function DataList({
26092
26152
  ] }, field.name);
26093
26153
  })
26094
26154
  ] }),
26095
- bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
26155
+ bodyFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: cn("flex-wrap", isCompact ? "mt-0.5" : "mt-1.5"), children: bodyFields.map((field) => {
26096
26156
  const value = getNestedValue(itemData, field.name);
26097
26157
  if (value === void 0 || value === null || value === "") return null;
26098
26158
  return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
@@ -29688,7 +29748,7 @@ var init_MapView = __esm({
29688
29748
  shadowSize: [41, 41]
29689
29749
  });
29690
29750
  L.Marker.prototype.options.icon = defaultIcon;
29691
- const { useEffect: useEffect63, useRef: useRef62, useCallback: useCallback93, useState: useState97 } = React91__namespace.default;
29751
+ const { useEffect: useEffect63, useRef: useRef62, useCallback: useCallback94, useState: useState97 } = React91__namespace.default;
29692
29752
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29693
29753
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29694
29754
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -29734,7 +29794,7 @@ var init_MapView = __esm({
29734
29794
  }) {
29735
29795
  const eventBus = useEventBus2();
29736
29796
  const [clickedPosition, setClickedPosition] = useState97(null);
29737
- const handleMapClick = useCallback93((lat, lng) => {
29797
+ const handleMapClick = useCallback94((lat, lng) => {
29738
29798
  if (showClickedPin) {
29739
29799
  setClickedPosition({ lat, lng });
29740
29800
  }
@@ -29743,7 +29803,7 @@ var init_MapView = __esm({
29743
29803
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
29744
29804
  }
29745
29805
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
29746
- const handleMarkerClick = useCallback93((marker) => {
29806
+ const handleMarkerClick = useCallback94((marker) => {
29747
29807
  onMarkerClick?.(marker);
29748
29808
  if (markerClickEvent) {
29749
29809
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -30519,6 +30579,26 @@ var init_Lightbox = __esm({
30519
30579
  Lightbox.displayName = "Lightbox";
30520
30580
  }
30521
30581
  });
30582
+ function useMediaQuery(query) {
30583
+ const subscribe = React91.useCallback(
30584
+ (onChange) => {
30585
+ const mql = window.matchMedia(query);
30586
+ mql.addEventListener("change", onChange);
30587
+ return () => mql.removeEventListener("change", onChange);
30588
+ },
30589
+ [query]
30590
+ );
30591
+ return React91.useSyncExternalStore(
30592
+ subscribe,
30593
+ () => window.matchMedia(query).matches,
30594
+ () => false
30595
+ );
30596
+ }
30597
+ var init_useMediaQuery = __esm({
30598
+ "hooks/useMediaQuery.ts"() {
30599
+ "use client";
30600
+ }
30601
+ });
30522
30602
  function renderIconInput3(icon, props) {
30523
30603
  return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, ...props });
30524
30604
  }
@@ -30625,6 +30705,7 @@ function TableView({
30625
30705
  const hasMore = pageSize > 0 && visibleCount < ordered.length;
30626
30706
  const hasRenderProp = typeof children === "function";
30627
30707
  const idField = dndItemIdField ?? "id";
30708
+ const isCoarsePointer = useMediaQuery("(pointer: coarse)");
30628
30709
  const selected = selectedIds ? new Set(selectedIds) : localSelected;
30629
30710
  const emitSelection = (next) => {
30630
30711
  if (!selectedIds) setLocalSelected(next);
@@ -30657,6 +30738,17 @@ function TableView({
30657
30738
  };
30658
30739
  eventBus.emit(`UI:${action.event}`, payload);
30659
30740
  };
30741
+ const colFloors = React91__namespace.default.useMemo(
30742
+ () => colDefs.map((col) => {
30743
+ const longest = data.reduce((widest, row) => {
30744
+ const cell = formatCell(asFieldValue(getNestedValue(row, col.field ?? col.key)), col.format);
30745
+ return Math.max(widest, cell.length);
30746
+ }, columnLabel(col).length);
30747
+ const chrome = col.format === "badge" ? BADGE_CHROME_CH : 0;
30748
+ return Math.min(longest + chrome, MAX_MEASURED_COL_CH);
30749
+ }),
30750
+ [colDefs, data]
30751
+ );
30660
30752
  if (isLoading) {
30661
30753
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
30662
30754
  }
@@ -30669,20 +30761,10 @@ function TableView({
30669
30761
  }
30670
30762
  const lk = LOOKS[look];
30671
30763
  const hasActions = Boolean(itemActions && itemActions.length > 0);
30672
- const inlineActionCount = hasActions ? maxInlineActions != null ? Math.min(itemActions.length, maxInlineActions) : itemActions.length : 0;
30673
- const hasOverflowActions = hasActions && maxInlineActions != null && itemActions.length > maxInlineActions;
30764
+ const effectiveMaxInline = isCoarsePointer ? 0 : maxInlineActions;
30765
+ const inlineActionCount = hasActions ? effectiveMaxInline != null ? Math.min(itemActions.length, effectiveMaxInline) : itemActions.length : 0;
30766
+ const hasOverflowActions = hasActions && effectiveMaxInline != null && itemActions.length > effectiveMaxInline;
30674
30767
  const actionsTrack = hasActions ? `${inlineActionCount * 6 + (hasOverflowActions ? 3 : 0)}rem` : null;
30675
- const colFloors = React91__namespace.default.useMemo(
30676
- () => colDefs.map((col) => {
30677
- const longest = data.reduce((widest, row) => {
30678
- const cell = formatCell(asFieldValue(getNestedValue(row, col.field ?? col.key)), col.format);
30679
- return Math.max(widest, cell.length);
30680
- }, columnLabel(col).length);
30681
- const chrome = col.format === "badge" ? BADGE_CHROME_CH : 0;
30682
- return Math.min(longest + chrome, MAX_MEASURED_COL_CH);
30683
- }),
30684
- [colDefs, data]
30685
- );
30686
30768
  const gridTemplateColumns = [
30687
30769
  selectable ? "auto" : null,
30688
30770
  ...colDefs.map((c, i) => c.width ?? `minmax(${colFloors[i]}ch, 1fr)`),
@@ -30771,7 +30853,7 @@ function TableView({
30771
30853
  if (col.format === "badge" && raw != null && raw !== "") {
30772
30854
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: statusVariant4(String(raw)), size: "sm", className: "whitespace-nowrap", children: String(raw) }) }, col.key);
30773
30855
  }
30774
- return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: formatCell(raw, col.format) }) }, col.key);
30856
+ return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format) }) }, col.key);
30775
30857
  }),
30776
30858
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
30777
30859
  HStack,
@@ -30785,15 +30867,15 @@ function TableView({
30785
30867
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
30786
30868
  ),
30787
30869
  children: [
30788
- (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
30870
+ (effectiveMaxInline != null ? itemActions.slice(0, effectiveMaxInline) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
30789
30871
  Button,
30790
30872
  {
30791
- variant: action.variant ?? "ghost",
30873
+ variant: action.variant === "primary" ? "primary" : "ghost",
30792
30874
  size: "sm",
30793
30875
  onClick: handleActionClick(action, row),
30794
30876
  "data-testid": `action-${action.event}`,
30795
30877
  "data-row-id": String(row.id),
30796
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
30878
+ className: cn(action.variant === "danger" && "text-error hover:text-error hover:bg-error/10"),
30797
30879
  children: [
30798
30880
  action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
30799
30881
  action.label
@@ -30801,12 +30883,12 @@ function TableView({
30801
30883
  },
30802
30884
  i
30803
30885
  )),
30804
- maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
30886
+ effectiveMaxInline != null && itemActions.length > effectiveMaxInline && /* @__PURE__ */ jsxRuntime.jsx(
30805
30887
  Menu,
30806
30888
  {
30807
30889
  position: "bottom-end",
30808
30890
  trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
30809
- items: itemActions.slice(maxInlineActions).map((action) => ({
30891
+ items: itemActions.slice(effectiveMaxInline).map((action) => ({
30810
30892
  label: action.label,
30811
30893
  icon: action.icon,
30812
30894
  event: action.event,
@@ -30859,6 +30941,7 @@ var init_TableView = __esm({
30859
30941
  init_cn();
30860
30942
  init_getNestedValue();
30861
30943
  init_useEventBus();
30944
+ init_useMediaQuery();
30862
30945
  init_Box();
30863
30946
  init_Stack();
30864
30947
  init_Typography();
@@ -30883,7 +30966,7 @@ var init_TableView = __esm({
30883
30966
  semibold: "font-semibold"
30884
30967
  };
30885
30968
  LOOKS = {
30886
- dense: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: false, divider: true },
30969
+ dense: { rowPad: "px-card-md py-2", headPad: "px-card-md py-2", striped: false, divider: true },
30887
30970
  spacious: { rowPad: "px-card-lg py-card-md", headPad: "px-card-lg py-card-sm", striped: false, divider: true },
30888
30971
  striped: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: true, divider: false },
30889
30972
  borderless: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: false, divider: false },
@@ -38928,7 +39011,17 @@ function DataTable({
38928
39011
  const currentPageSize = pageSize ?? 20;
38929
39012
  const total = totalCount ?? items.length;
38930
39013
  const totalPages = Math.ceil(total / currentPageSize);
38931
- const rowActions = externalRowActions ?? itemActions?.filter((a) => a.placement !== "bulk").map((action) => ({
39014
+ const withEventClick = (action) => {
39015
+ if (action.onClick || !action.event) return action;
39016
+ const event = action.event;
39017
+ return {
39018
+ ...action,
39019
+ onClick: (row) => {
39020
+ eventBus.emit(`UI:${event}`, { row });
39021
+ }
39022
+ };
39023
+ };
39024
+ const rowActions = (externalRowActions ?? itemActions?.filter((a) => a.placement !== "bulk").map((action) => ({
38932
39025
  label: action.label,
38933
39026
  icon: action.icon,
38934
39027
  variant: action.variant,
@@ -38948,7 +39041,17 @@ function DataTable({
38948
39041
  });
38949
39042
  }
38950
39043
  }
38951
- }));
39044
+ })))?.map(withEventClick);
39045
+ const normalizedBulkActions = bulkActions?.map((action) => {
39046
+ if (action.onClick || !action.event) return action;
39047
+ const event = action.event;
39048
+ return {
39049
+ ...action,
39050
+ onClick: (selectedRows2) => {
39051
+ eventBus.emit(`UI:${event}`, { rows: selectedRows2 });
39052
+ }
39053
+ };
39054
+ });
38952
39055
  const viewAction = itemActions?.find(
38953
39056
  (a) => a.event === "VIEW" || a.navigatesTo
38954
39057
  );
@@ -39056,7 +39159,7 @@ function DataTable({
39056
39159
  }
39057
39160
  )
39058
39161
  ] }),
39059
- bulkActions && selectedIds.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center gap-2 pl-0 sm:pl-3 border-l-0 sm:border-l border-border", children: [
39162
+ normalizedBulkActions && selectedIds.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center gap-2 pl-0 sm:pl-3 border-l-0 sm:border-l border-border", children: [
39060
39163
  /* @__PURE__ */ jsxRuntime.jsx(
39061
39164
  Typography,
39062
39165
  {
@@ -39067,13 +39170,13 @@ function DataTable({
39067
39170
  })
39068
39171
  }
39069
39172
  ),
39070
- /* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap gap-2", children: bulkActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
39173
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap gap-2", children: normalizedBulkActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
39071
39174
  Button,
39072
39175
  {
39073
39176
  variant: action.variant === "danger" ? "danger" : "secondary",
39074
39177
  size: "sm",
39075
39178
  leftIcon: action.icon,
39076
- onClick: () => action.onClick(selectedRows),
39179
+ onClick: () => action.onClick?.(selectedRows),
39077
39180
  children: action.label
39078
39181
  },
39079
39182
  idx
@@ -39235,7 +39338,7 @@ function DataTable({
39235
39338
  ),
39236
39339
  onClick: (e) => {
39237
39340
  e.stopPropagation();
39238
- action.onClick(row);
39341
+ action.onClick?.(row);
39239
39342
  setOpenActionMenu(null);
39240
39343
  },
39241
39344
  children: [
@@ -41531,27 +41634,24 @@ var init_MasterDetailLayout = __esm({
41531
41634
  masterClassName,
41532
41635
  detailClassName
41533
41636
  }) => {
41534
- masterWidth.endsWith("%") ? parseInt(masterWidth, 10) : 30;
41535
41637
  return /* @__PURE__ */ jsxRuntime.jsxs(
41536
41638
  "div",
41537
41639
  {
41538
- className: cn("flex h-full w-full", className),
41539
- style: {
41540
- display: "grid",
41541
- gridTemplateColumns: masterWidth.endsWith("%") ? `${masterWidth} 1fr` : `${masterWidth} 1fr`
41542
- },
41640
+ className: cn("w-full h-full md:grid md:grid-cols-[var(--master-detail-cols)]", className),
41641
+ style: { "--master-detail-cols": `${masterWidth} 1fr` },
41543
41642
  children: [
41544
41643
  /* @__PURE__ */ jsxRuntime.jsx(
41545
41644
  "div",
41546
41645
  {
41547
41646
  className: cn(
41548
- "border-r-2 border-border overflow-auto",
41647
+ "border-r border-border overflow-auto",
41648
+ hasSelection && "hidden md:block",
41549
41649
  masterClassName
41550
41650
  ),
41551
41651
  children: master
41552
41652
  }
41553
41653
  ),
41554
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-auto", detailClassName), children: hasSelection ? detail : emptyDetail || /* @__PURE__ */ jsxRuntime.jsx(DefaultEmptyDetail, {}) })
41654
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-auto", !hasSelection && "hidden md:block", detailClassName), children: hasSelection ? detail : emptyDetail || /* @__PURE__ */ jsxRuntime.jsx(DefaultEmptyDetail, {}) })
41555
41655
  ]
41556
41656
  }
41557
41657
  );