@almadar/ui 5.131.0 → 5.132.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.
@@ -612,6 +612,26 @@ var init_useDragReorder = __esm({
612
612
  "use client";
613
613
  }
614
614
  });
615
+ function useMediaQuery(query) {
616
+ const subscribe = React82.useCallback(
617
+ (onChange) => {
618
+ const mql = window.matchMedia(query);
619
+ mql.addEventListener("change", onChange);
620
+ return () => mql.removeEventListener("change", onChange);
621
+ },
622
+ [query]
623
+ );
624
+ return React82.useSyncExternalStore(
625
+ subscribe,
626
+ () => window.matchMedia(query).matches,
627
+ () => false
628
+ );
629
+ }
630
+ var init_useMediaQuery = __esm({
631
+ "hooks/useMediaQuery.ts"() {
632
+ "use client";
633
+ }
634
+ });
615
635
  function useInfiniteScroll(onLoadMore, options = {}) {
616
636
  const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
617
637
  const observerRef = React82.useRef(null);
@@ -2372,6 +2392,8 @@ var init_Badge = __esm({
2372
2392
  };
2373
2393
  const iconPx = size === "lg" ? 20 : 16;
2374
2394
  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;
2395
+ const hasText = Boolean(children) || amount != null || label !== void 0 && label !== null && label !== "";
2396
+ if (!hasText && !resolvedIcon && !onRemove) return null;
2375
2397
  return /* @__PURE__ */ jsxRuntime.jsxs(
2376
2398
  "span",
2377
2399
  {
@@ -5694,11 +5716,13 @@ var init_TrendIndicator = __esm({
5694
5716
  size = "md",
5695
5717
  ...props
5696
5718
  }, ref) => {
5697
- const dir = resolveDirection(value, direction);
5719
+ const hasValue = typeof value === "number" && Number.isFinite(value);
5720
+ if (!hasValue && !direction) return null;
5721
+ const dir = resolveDirection(hasValue ? value : void 0, direction);
5698
5722
  const colorClass = resolveColor(dir, invert);
5699
5723
  const iconName = iconNameMap[dir];
5700
5724
  const styles = sizeStyles6[size];
5701
- const formattedValue = value !== void 0 ? `${value > 0 ? "+" : ""}${value}%` : void 0;
5725
+ const formattedValue = hasValue ? `${value > 0 ? "+" : ""}${value}%` : void 0;
5702
5726
  const ariaLabel = label ?? (formattedValue ? `${dir} ${formattedValue}` : dir);
5703
5727
  return /* @__PURE__ */ jsxRuntime.jsxs(
5704
5728
  "span",
@@ -17755,26 +17779,19 @@ var init_BookViewer = __esm({
17755
17779
  function BoxPattern({
17756
17780
  p,
17757
17781
  m,
17758
- bg = "transparent",
17759
- border = false,
17760
- radius = "none",
17761
- shadow = "none",
17762
- className,
17763
- style,
17764
- children
17782
+ radius,
17783
+ isLoading: _isLoading,
17784
+ error: _error,
17785
+ entity: _entity,
17786
+ ...boxProps
17765
17787
  }) {
17766
17788
  return /* @__PURE__ */ jsxRuntime.jsx(
17767
17789
  Box,
17768
17790
  {
17769
- padding: p,
17770
- margin: m,
17771
- bg,
17772
- border,
17773
- rounded: radius,
17774
- shadow,
17775
- className,
17776
- style,
17777
- children
17791
+ padding: boxProps.padding ?? p,
17792
+ margin: boxProps.margin ?? m,
17793
+ rounded: boxProps.rounded ?? radius,
17794
+ ...boxProps
17778
17795
  }
17779
17796
  );
17780
17797
  }
@@ -21384,17 +21401,19 @@ var init_DashboardLayout = __esm({
21384
21401
  const [sidebarOpen, setSidebarOpen] = React82.useState(false);
21385
21402
  const [userMenuOpen, setUserMenuOpen] = React82.useState(false);
21386
21403
  const layoutRef = React82.useRef(null);
21387
- const [isMobile, setIsMobile] = React82.useState(false);
21404
+ const [layoutWidth, setLayoutWidth] = React82.useState(null);
21388
21405
  React82.useEffect(() => {
21389
21406
  const el = layoutRef.current;
21390
21407
  if (!el || typeof ResizeObserver === "undefined") return;
21391
21408
  const ro = new ResizeObserver((entries) => {
21392
21409
  const w = entries[0]?.contentRect.width ?? el.clientWidth;
21393
- setIsMobile(w < 1024);
21410
+ setLayoutWidth(w);
21394
21411
  });
21395
21412
  ro.observe(el);
21396
21413
  return () => ro.disconnect();
21397
21414
  }, []);
21415
+ const isMobile = layoutWidth !== null && layoutWidth < 768;
21416
+ const isRail = layoutWidth !== null && layoutWidth >= 768 && layoutWidth < 1024;
21398
21417
  React82.useEffect(() => {
21399
21418
  if (!isMobile && sidebarOpen) setSidebarOpen(false);
21400
21419
  }, [isMobile, sidebarOpen]);
@@ -21427,7 +21446,8 @@ var init_DashboardLayout = __esm({
21427
21446
  {
21428
21447
  as: "aside",
21429
21448
  className: cn(
21430
- "z-30 w-64 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
21449
+ "z-30 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
21450
+ isRail ? "w-16" : "w-64",
21431
21451
  "flex flex-col"
21432
21452
  ),
21433
21453
  style: isMobile ? {
@@ -21443,10 +21463,10 @@ var init_DashboardLayout = __esm({
21443
21463
  HStack,
21444
21464
  {
21445
21465
  align: "center",
21446
- justify: "between",
21447
- className: "h-16 px-4 border-b border-border dark:border-border",
21466
+ justify: isRail ? "center" : "between",
21467
+ className: cn("h-16 border-b border-border dark:border-border", isRail ? "px-2" : "px-4"),
21448
21468
  children: [
21449
- /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to: "/", className: "flex items-center gap-2", children: [
21469
+ /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to: "/", className: "flex items-center gap-2", title: isRail ? appName : void 0, children: [
21450
21470
  logo || /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-8 h-8 bg-primary rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
21451
21471
  Typography,
21452
21472
  {
@@ -21456,7 +21476,7 @@ var init_DashboardLayout = __esm({
21456
21476
  children: appName.charAt(0).toUpperCase()
21457
21477
  }
21458
21478
  ) }),
21459
- /* @__PURE__ */ jsxRuntime.jsx(
21479
+ !isRail && /* @__PURE__ */ jsxRuntime.jsx(
21460
21480
  Typography,
21461
21481
  {
21462
21482
  variant: "label",
@@ -21483,12 +21503,13 @@ var init_DashboardLayout = __esm({
21483
21503
  {
21484
21504
  as: "nav",
21485
21505
  gap: "none",
21486
- className: "flex-1 px-3 py-4 space-y-1 overflow-y-auto",
21506
+ className: cn("flex-1 py-4 space-y-1 overflow-y-auto", isRail ? "px-2" : "px-3"),
21487
21507
  children: navItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
21488
21508
  NavLink,
21489
21509
  {
21490
21510
  item,
21491
- currentPath: activePath
21511
+ currentPath: activePath,
21512
+ compact: isRail
21492
21513
  },
21493
21514
  item.href
21494
21515
  ))
@@ -21743,13 +21764,40 @@ var init_DashboardLayout = __esm({
21743
21764
  DashboardLayout.displayName = "DashboardLayout";
21744
21765
  NavLink = ({
21745
21766
  item,
21746
- currentPath
21767
+ currentPath,
21768
+ compact = false
21747
21769
  }) => {
21748
21770
  const isActive = currentPath === item.href || currentPath.startsWith(item.href + "/");
21749
21771
  const iconClassName = cn(
21750
21772
  "h-5 w-5",
21751
21773
  isActive ? "text-primary-foreground" : "text-muted-foreground"
21752
21774
  );
21775
+ if (compact) {
21776
+ return /* @__PURE__ */ jsxRuntime.jsx(
21777
+ reactRouterDom.Link,
21778
+ {
21779
+ to: item.href,
21780
+ title: item.label,
21781
+ "aria-label": item.label,
21782
+ className: cn(
21783
+ "flex items-center justify-center px-2 py-2 rounded-lg transition-colors",
21784
+ isActive ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"
21785
+ ),
21786
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { as: "span", className: "relative inline-flex", children: [
21787
+ 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() }),
21788
+ item.badge && /* @__PURE__ */ jsxRuntime.jsx(
21789
+ Badge,
21790
+ {
21791
+ variant: isActive ? "primary" : "default",
21792
+ size: "sm",
21793
+ className: "absolute -top-2 -right-2 px-1 py-0 text-[10px] leading-4",
21794
+ children: item.badge
21795
+ }
21796
+ )
21797
+ ] })
21798
+ }
21799
+ );
21800
+ }
21753
21801
  return /* @__PURE__ */ jsxRuntime.jsxs(
21754
21802
  reactRouterDom.Link,
21755
21803
  {
@@ -22815,40 +22863,55 @@ function DataGrid({
22815
22863
  {
22816
22864
  "data-entity-row": true,
22817
22865
  "data-entity-id": id,
22818
- className: cn(isSelected && "ring-2 ring-primary rounded-lg"),
22866
+ className: cn("relative group/rowactions", isSelected && "ring-2 ring-primary rounded-lg"),
22819
22867
  children: [
22820
22868
  children(itemData, index),
22821
- 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: [
22822
- (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
22823
- Button,
22824
- {
22825
- variant: action.variant === "primary" ? "primary" : "ghost",
22826
- size: "sm",
22827
- onClick: handleActionClick(action, itemData),
22828
- "data-testid": `action-${action.event}`,
22829
- "data-row-id": String(itemData.id),
22830
- className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
22831
- children: [
22832
- action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
22833
- action.label
22834
- ]
22835
- },
22836
- idx
22837
- )),
22838
- maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
22869
+ 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: [
22870
+ /* @__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: [
22871
+ (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
22872
+ Button,
22873
+ {
22874
+ variant: action.variant === "primary" ? "primary" : "ghost",
22875
+ size: "sm",
22876
+ onClick: handleActionClick(action, itemData),
22877
+ "data-testid": `action-${action.event}`,
22878
+ "data-row-id": String(itemData.id),
22879
+ className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
22880
+ children: [
22881
+ action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
22882
+ action.label
22883
+ ]
22884
+ },
22885
+ idx
22886
+ )),
22887
+ maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
22888
+ Menu,
22889
+ {
22890
+ position: "bottom-end",
22891
+ 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" }) }),
22892
+ items: actionDefs.slice(maxInlineActions).map((action) => ({
22893
+ label: action.label,
22894
+ icon: action.icon,
22895
+ event: action.event,
22896
+ onClick: () => fireAction(action, itemData)
22897
+ }))
22898
+ }
22899
+ )
22900
+ ] }),
22901
+ /* @__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(
22839
22902
  Menu,
22840
22903
  {
22841
22904
  position: "bottom-end",
22842
22905
  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" }) }),
22843
- items: actionDefs.slice(maxInlineActions).map((action) => ({
22906
+ items: actionDefs.map((action) => ({
22844
22907
  label: action.label,
22845
22908
  icon: action.icon,
22846
22909
  event: action.event,
22847
22910
  onClick: () => fireAction(action, itemData)
22848
22911
  }))
22849
22912
  }
22850
- )
22851
- ] }) })
22913
+ ) })
22914
+ ] })
22852
22915
  ]
22853
22916
  },
22854
22917
  id
@@ -22884,7 +22947,7 @@ function DataGrid({
22884
22947
  }
22885
22948
  ) });
22886
22949
  })(),
22887
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
22950
+ /* @__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: [
22888
22951
  selectable && /* @__PURE__ */ jsxRuntime.jsx(
22889
22952
  "input",
22890
22953
  {
@@ -22917,78 +22980,77 @@ function DataGrid({
22917
22980
  ] }, field.name);
22918
22981
  }) })
22919
22982
  ] }),
22920
- dangerActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
22921
- Button,
22922
- {
22923
- variant: "ghost",
22924
- size: "sm",
22925
- onClick: handleActionClick(action, itemData),
22926
- "data-testid": `action-${action.event}`,
22927
- "data-row-id": String(itemData.id),
22928
- "aria-label": action.label,
22929
- title: action.label,
22930
- className: "text-error hover:text-error hover:bg-error/10 px-2",
22931
- children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
22932
- },
22933
- idx
22934
- )) })
22935
- ] }) }),
22936
- 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) => {
22937
- const value = getNestedValue(itemData, field.name);
22938
- if (value === void 0 || value === null || value === "") return null;
22939
- if (field.format === "boolean") {
22940
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
22941
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
22942
- field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
22943
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
22944
- ] }),
22945
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
22946
- ] }, field.name);
22947
- }
22948
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
22949
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
22950
- field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
22951
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
22952
- ] }),
22953
- /* @__PURE__ */ jsxRuntime.jsx(
22954
- Typography,
22983
+ (primaryActions.length > 0 || dangerActions.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "flex-shrink-0", children: [
22984
+ (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
22985
+ Button,
22955
22986
  {
22956
- variant: field.variant === "caption" ? "caption" : "small",
22957
- className: "text-right truncate max-w-[60%]",
22958
- children: formatValue(value, field.format)
22987
+ variant: action.variant === "primary" ? "primary" : "ghost",
22988
+ size: "sm",
22989
+ onClick: handleActionClick(action, itemData),
22990
+ "data-testid": `action-${action.event}`,
22991
+ "data-row-id": String(itemData.id),
22992
+ "aria-label": action.label,
22993
+ title: action.label,
22994
+ className: cn(
22995
+ action.variant === "primary" ? void 0 : "text-muted-foreground hover:text-foreground",
22996
+ action.icon && "px-2"
22997
+ ),
22998
+ children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
22999
+ },
23000
+ idx
23001
+ )),
23002
+ maxInlineActions != null && primaryActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
23003
+ Menu,
23004
+ {
23005
+ position: "bottom-end",
23006
+ 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" }) }),
23007
+ items: primaryActions.slice(maxInlineActions).map((action) => ({
23008
+ label: action.label,
23009
+ icon: action.icon,
23010
+ event: action.event,
23011
+ onClick: () => fireAction(action, itemData)
23012
+ }))
22959
23013
  }
22960
- )
22961
- ] }, field.name);
22962
- }) }) }),
22963
- 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: [
22964
- (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
22965
- Button,
22966
- {
22967
- variant: action.variant === "primary" ? "primary" : "ghost",
22968
- size: "sm",
22969
- onClick: handleActionClick(action, itemData),
22970
- "data-testid": `action-${action.event}`,
22971
- "data-row-id": String(itemData.id),
22972
- children: [
22973
- action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
22974
- action.label
22975
- ]
22976
- },
22977
- idx
22978
- )),
22979
- maxInlineActions != null && primaryActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
22980
- Menu,
22981
- {
22982
- position: "bottom-end",
22983
- 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" }) }),
22984
- items: primaryActions.slice(maxInlineActions).map((action) => ({
22985
- label: action.label,
22986
- icon: action.icon,
22987
- event: action.event,
22988
- onClick: () => fireAction(action, itemData)
22989
- }))
23014
+ ),
23015
+ dangerActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
23016
+ Button,
23017
+ {
23018
+ variant: "ghost",
23019
+ size: "sm",
23020
+ onClick: handleActionClick(action, itemData),
23021
+ "data-testid": `action-${action.event}`,
23022
+ "data-row-id": String(itemData.id),
23023
+ "aria-label": action.label,
23024
+ title: action.label,
23025
+ className: "text-error hover:text-error hover:bg-error/10 px-2",
23026
+ children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
23027
+ },
23028
+ `danger-${idx}`
23029
+ ))
23030
+ ] })
23031
+ ] }) }),
23032
+ bodyFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 pt-2 pb-4 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
23033
+ bodyFields.filter((f3) => f3.variant === "caption" && f3.format !== "boolean").map((field) => {
23034
+ const value = getNestedValue(itemData, field.name);
23035
+ if (value === void 0 || value === null || value === "") return null;
23036
+ return /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", className: "line-clamp-2", children: formatValue(value, field.format) }, field.name);
23037
+ }),
23038
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: "flex-wrap gap-y-1", children: bodyFields.filter((f3) => f3.variant !== "caption" || f3.format === "boolean").map((field) => {
23039
+ const value = getNestedValue(itemData, field.name);
23040
+ if (value === void 0 || value === null || value === "") return null;
23041
+ if (field.format === "boolean") {
23042
+ return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
23043
+ field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
23044
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) }),
23045
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
23046
+ ] }, field.name);
22990
23047
  }
22991
- )
23048
+ return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
23049
+ field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
23050
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: (field.label ?? fieldLabel2(field.name)) + ":" }),
23051
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", children: formatValue(value, field.format) })
23052
+ ] }, field.name);
23053
+ }) })
22992
23054
  ] }) })
22993
23055
  ]
22994
23056
  },
@@ -23336,11 +23398,29 @@ function DataList({
23336
23398
  const wrapDnd = (node) => dnd.isZone ? /* @__PURE__ */ jsxRuntime.jsx(dnd.SortableItem, { id: dndId, children: node }, dndId) : node;
23337
23399
  if (hasRenderProp) {
23338
23400
  const id2 = itemData.id || String(index);
23401
+ const actions = renderItemActions(itemData);
23339
23402
  return wrapDnd(
23340
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
23341
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group flex items-stretch gap-2", children: [
23342
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
23343
- renderItemActions(itemData)
23403
+ /* @__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: [
23404
+ children(itemData, index),
23405
+ 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: [
23406
+ /* @__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 }),
23407
+ /* @__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(
23408
+ Menu,
23409
+ {
23410
+ position: "bottom-end",
23411
+ 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" }) }),
23412
+ items: (itemActions ?? []).map((action) => ({
23413
+ label: action.label,
23414
+ icon: action.icon,
23415
+ event: action.event,
23416
+ variant: action.variant === "danger" ? "danger" : "default",
23417
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
23418
+ id: itemData.id,
23419
+ row: itemData
23420
+ })
23421
+ }))
23422
+ }
23423
+ ) })
23344
23424
  ] }),
23345
23425
  isCard && !isLast && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mx-6 border-b border-border/40" })
23346
23426
  ] }, id2)
@@ -23380,7 +23460,7 @@ function DataList({
23380
23460
  ] }, field.name);
23381
23461
  })
23382
23462
  ] }),
23383
- bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
23463
+ bodyFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: cn("flex-wrap", isCompact ? "mt-0.5" : "mt-1.5"), children: bodyFields.map((field) => {
23384
23464
  const value = getNestedValue(itemData, field.name);
23385
23465
  if (value === void 0 || value === null || value === "") return null;
23386
23466
  return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
@@ -26912,7 +26992,7 @@ var init_MapView = __esm({
26912
26992
  shadowSize: [41, 41]
26913
26993
  });
26914
26994
  L.Marker.prototype.options.icon = defaultIcon;
26915
- const { useEffect: useEffect59, useRef: useRef60, useCallback: useCallback87, useState: useState89 } = React82__namespace.default;
26995
+ const { useEffect: useEffect59, useRef: useRef60, useCallback: useCallback88, useState: useState89 } = React82__namespace.default;
26916
26996
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
26917
26997
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
26918
26998
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -26958,7 +27038,7 @@ var init_MapView = __esm({
26958
27038
  }) {
26959
27039
  const eventBus = useEventBus2();
26960
27040
  const [clickedPosition, setClickedPosition] = useState89(null);
26961
- const handleMapClick = useCallback87((lat, lng) => {
27041
+ const handleMapClick = useCallback88((lat, lng) => {
26962
27042
  if (showClickedPin) {
26963
27043
  setClickedPosition({ lat, lng });
26964
27044
  }
@@ -26967,7 +27047,7 @@ var init_MapView = __esm({
26967
27047
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
26968
27048
  }
26969
27049
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
26970
- const handleMarkerClick = useCallback87((marker) => {
27050
+ const handleMarkerClick = useCallback88((marker) => {
26971
27051
  onMarkerClick?.(marker);
26972
27052
  if (markerClickEvent) {
26973
27053
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -27849,6 +27929,7 @@ function TableView({
27849
27929
  const hasMore = pageSize > 0 && visibleCount < ordered.length;
27850
27930
  const hasRenderProp = typeof children === "function";
27851
27931
  const idField = dndItemIdField ?? "id";
27932
+ const isCoarsePointer = useMediaQuery("(pointer: coarse)");
27852
27933
  const selected = selectedIds ? new Set(selectedIds) : localSelected;
27853
27934
  const emitSelection = (next) => {
27854
27935
  if (!selectedIds) setLocalSelected(next);
@@ -27881,6 +27962,17 @@ function TableView({
27881
27962
  };
27882
27963
  eventBus.emit(`UI:${action.event}`, payload);
27883
27964
  };
27965
+ const colFloors = React82__namespace.default.useMemo(
27966
+ () => colDefs.map((col) => {
27967
+ const longest = data.reduce((widest, row) => {
27968
+ const cell = formatCell(asFieldValue(getNestedValue(row, col.field ?? col.key)), col.format);
27969
+ return Math.max(widest, cell.length);
27970
+ }, columnLabel(col).length);
27971
+ const chrome = col.format === "badge" ? BADGE_CHROME_CH : 0;
27972
+ return Math.min(longest + chrome, MAX_MEASURED_COL_CH);
27973
+ }),
27974
+ [colDefs, data]
27975
+ );
27884
27976
  if (isLoading) {
27885
27977
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
27886
27978
  }
@@ -27893,20 +27985,10 @@ function TableView({
27893
27985
  }
27894
27986
  const lk = LOOKS[look];
27895
27987
  const hasActions = Boolean(itemActions && itemActions.length > 0);
27896
- const inlineActionCount = hasActions ? maxInlineActions != null ? Math.min(itemActions.length, maxInlineActions) : itemActions.length : 0;
27897
- const hasOverflowActions = hasActions && maxInlineActions != null && itemActions.length > maxInlineActions;
27988
+ const effectiveMaxInline = isCoarsePointer ? 0 : maxInlineActions;
27989
+ const inlineActionCount = hasActions ? effectiveMaxInline != null ? Math.min(itemActions.length, effectiveMaxInline) : itemActions.length : 0;
27990
+ const hasOverflowActions = hasActions && effectiveMaxInline != null && itemActions.length > effectiveMaxInline;
27898
27991
  const actionsTrack = hasActions ? `${inlineActionCount * 6 + (hasOverflowActions ? 3 : 0)}rem` : null;
27899
- const colFloors = React82__namespace.default.useMemo(
27900
- () => colDefs.map((col) => {
27901
- const longest = data.reduce((widest, row) => {
27902
- const cell = formatCell(asFieldValue(getNestedValue(row, col.field ?? col.key)), col.format);
27903
- return Math.max(widest, cell.length);
27904
- }, columnLabel(col).length);
27905
- const chrome = col.format === "badge" ? BADGE_CHROME_CH : 0;
27906
- return Math.min(longest + chrome, MAX_MEASURED_COL_CH);
27907
- }),
27908
- [colDefs, data]
27909
- );
27910
27992
  const gridTemplateColumns = [
27911
27993
  selectable ? "auto" : null,
27912
27994
  ...colDefs.map((c, i) => c.width ?? `minmax(${colFloors[i]}ch, 1fr)`),
@@ -27995,7 +28077,7 @@ function TableView({
27995
28077
  if (col.format === "badge" && raw != null && raw !== "") {
27996
28078
  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);
27997
28079
  }
27998
- return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: formatCell(raw, col.format) }) }, col.key);
28080
+ 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);
27999
28081
  }),
28000
28082
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
28001
28083
  HStack,
@@ -28009,15 +28091,15 @@ function TableView({
28009
28091
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
28010
28092
  ),
28011
28093
  children: [
28012
- (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28094
+ (effectiveMaxInline != null ? itemActions.slice(0, effectiveMaxInline) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28013
28095
  Button,
28014
28096
  {
28015
- variant: action.variant ?? "ghost",
28097
+ variant: action.variant === "primary" ? "primary" : "ghost",
28016
28098
  size: "sm",
28017
28099
  onClick: handleActionClick(action, row),
28018
28100
  "data-testid": `action-${action.event}`,
28019
28101
  "data-row-id": String(row.id),
28020
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
28102
+ className: cn(action.variant === "danger" && "text-error hover:text-error hover:bg-error/10"),
28021
28103
  children: [
28022
28104
  action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
28023
28105
  action.label
@@ -28025,12 +28107,12 @@ function TableView({
28025
28107
  },
28026
28108
  i
28027
28109
  )),
28028
- maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
28110
+ effectiveMaxInline != null && itemActions.length > effectiveMaxInline && /* @__PURE__ */ jsxRuntime.jsx(
28029
28111
  Menu,
28030
28112
  {
28031
28113
  position: "bottom-end",
28032
28114
  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" }) }),
28033
- items: itemActions.slice(maxInlineActions).map((action) => ({
28115
+ items: itemActions.slice(effectiveMaxInline).map((action) => ({
28034
28116
  label: action.label,
28035
28117
  icon: action.icon,
28036
28118
  event: action.event,
@@ -28083,6 +28165,7 @@ var init_TableView = __esm({
28083
28165
  init_cn();
28084
28166
  init_getNestedValue();
28085
28167
  init_useEventBus();
28168
+ init_useMediaQuery();
28086
28169
  init_Box();
28087
28170
  init_Stack();
28088
28171
  init_Typography();
@@ -28107,7 +28190,7 @@ var init_TableView = __esm({
28107
28190
  semibold: "font-semibold"
28108
28191
  };
28109
28192
  LOOKS = {
28110
- dense: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: false, divider: true },
28193
+ dense: { rowPad: "px-card-md py-2", headPad: "px-card-md py-2", striped: false, divider: true },
28111
28194
  spacious: { rowPad: "px-card-lg py-card-md", headPad: "px-card-lg py-card-sm", striped: false, divider: true },
28112
28195
  striped: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: true, divider: false },
28113
28196
  borderless: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: false, divider: false },
@@ -39026,27 +39109,24 @@ var init_MasterDetailLayout = __esm({
39026
39109
  masterClassName,
39027
39110
  detailClassName
39028
39111
  }) => {
39029
- masterWidth.endsWith("%") ? parseInt(masterWidth, 10) : 30;
39030
39112
  return /* @__PURE__ */ jsxRuntime.jsxs(
39031
39113
  "div",
39032
39114
  {
39033
- className: cn("flex h-full w-full", className),
39034
- style: {
39035
- display: "grid",
39036
- gridTemplateColumns: masterWidth.endsWith("%") ? `${masterWidth} 1fr` : `${masterWidth} 1fr`
39037
- },
39115
+ className: cn("w-full h-full md:grid md:grid-cols-[var(--master-detail-cols)]", className),
39116
+ style: { "--master-detail-cols": `${masterWidth} 1fr` },
39038
39117
  children: [
39039
39118
  /* @__PURE__ */ jsxRuntime.jsx(
39040
39119
  "div",
39041
39120
  {
39042
39121
  className: cn(
39043
- "border-r-2 border-border overflow-auto",
39122
+ "border-r border-border overflow-auto",
39123
+ hasSelection && "hidden md:block",
39044
39124
  masterClassName
39045
39125
  ),
39046
39126
  children: master
39047
39127
  }
39048
39128
  ),
39049
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-auto", detailClassName), children: hasSelection ? detail : emptyDetail || /* @__PURE__ */ jsxRuntime.jsx(DefaultEmptyDetail, {}) })
39129
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-auto", !hasSelection && "hidden md:block", detailClassName), children: hasSelection ? detail : emptyDetail || /* @__PURE__ */ jsxRuntime.jsx(DefaultEmptyDetail, {}) })
39050
39130
  ]
39051
39131
  }
39052
39132
  );