@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.
@@ -1894,6 +1894,8 @@ var init_Badge = __esm({
1894
1894
  };
1895
1895
  const iconPx = size === "lg" ? 20 : 16;
1896
1896
  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;
1897
+ const hasText = Boolean(children) || amount != null || label !== void 0 && label !== null && label !== "";
1898
+ if (!hasText && !resolvedIcon && !onRemove) return null;
1897
1899
  return /* @__PURE__ */ jsxRuntime.jsxs(
1898
1900
  "span",
1899
1901
  {
@@ -5216,11 +5218,13 @@ var init_TrendIndicator = __esm({
5216
5218
  size = "md",
5217
5219
  ...props
5218
5220
  }, ref) => {
5219
- const dir = resolveDirection(value, direction);
5221
+ const hasValue = typeof value === "number" && Number.isFinite(value);
5222
+ if (!hasValue && !direction) return null;
5223
+ const dir = resolveDirection(hasValue ? value : void 0, direction);
5220
5224
  const colorClass = resolveColor(dir, invert);
5221
5225
  const iconName = iconNameMap[dir];
5222
5226
  const styles = sizeStyles6[size];
5223
- const formattedValue = value !== void 0 ? `${value > 0 ? "+" : ""}${value}%` : void 0;
5227
+ const formattedValue = hasValue ? `${value > 0 ? "+" : ""}${value}%` : void 0;
5224
5228
  const ariaLabel = label ?? (formattedValue ? `${dir} ${formattedValue}` : dir);
5225
5229
  return /* @__PURE__ */ jsxRuntime.jsxs(
5226
5230
  "span",
@@ -18120,26 +18124,19 @@ var init_BookViewer = __esm({
18120
18124
  function BoxPattern({
18121
18125
  p,
18122
18126
  m,
18123
- bg = "transparent",
18124
- border = false,
18125
- radius = "none",
18126
- shadow = "none",
18127
- className,
18128
- style,
18129
- children
18127
+ radius,
18128
+ isLoading: _isLoading,
18129
+ error: _error,
18130
+ entity: _entity,
18131
+ ...boxProps
18130
18132
  }) {
18131
18133
  return /* @__PURE__ */ jsxRuntime.jsx(
18132
18134
  Box,
18133
18135
  {
18134
- padding: p,
18135
- margin: m,
18136
- bg,
18137
- border,
18138
- rounded: radius,
18139
- shadow,
18140
- className,
18141
- style,
18142
- children
18136
+ padding: boxProps.padding ?? p,
18137
+ margin: boxProps.margin ?? m,
18138
+ rounded: boxProps.rounded ?? radius,
18139
+ ...boxProps
18143
18140
  }
18144
18141
  );
18145
18142
  }
@@ -21830,17 +21827,19 @@ var init_DashboardLayout = __esm({
21830
21827
  const [sidebarOpen, setSidebarOpen] = React84.useState(false);
21831
21828
  const [userMenuOpen, setUserMenuOpen] = React84.useState(false);
21832
21829
  const layoutRef = React84.useRef(null);
21833
- const [isMobile, setIsMobile] = React84.useState(false);
21830
+ const [layoutWidth, setLayoutWidth] = React84.useState(null);
21834
21831
  React84.useEffect(() => {
21835
21832
  const el = layoutRef.current;
21836
21833
  if (!el || typeof ResizeObserver === "undefined") return;
21837
21834
  const ro = new ResizeObserver((entries) => {
21838
21835
  const w = entries[0]?.contentRect.width ?? el.clientWidth;
21839
- setIsMobile(w < 1024);
21836
+ setLayoutWidth(w);
21840
21837
  });
21841
21838
  ro.observe(el);
21842
21839
  return () => ro.disconnect();
21843
21840
  }, []);
21841
+ const isMobile = layoutWidth !== null && layoutWidth < 768;
21842
+ const isRail = layoutWidth !== null && layoutWidth >= 768 && layoutWidth < 1024;
21844
21843
  React84.useEffect(() => {
21845
21844
  if (!isMobile && sidebarOpen) setSidebarOpen(false);
21846
21845
  }, [isMobile, sidebarOpen]);
@@ -21873,7 +21872,8 @@ var init_DashboardLayout = __esm({
21873
21872
  {
21874
21873
  as: "aside",
21875
21874
  className: cn(
21876
- "z-30 w-64 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
21875
+ "z-30 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
21876
+ isRail ? "w-16" : "w-64",
21877
21877
  "flex flex-col"
21878
21878
  ),
21879
21879
  style: isMobile ? {
@@ -21889,10 +21889,10 @@ var init_DashboardLayout = __esm({
21889
21889
  HStack,
21890
21890
  {
21891
21891
  align: "center",
21892
- justify: "between",
21893
- className: "h-16 px-4 border-b border-border dark:border-border",
21892
+ justify: isRail ? "center" : "between",
21893
+ className: cn("h-16 border-b border-border dark:border-border", isRail ? "px-2" : "px-4"),
21894
21894
  children: [
21895
- /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to: "/", className: "flex items-center gap-2", children: [
21895
+ /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to: "/", className: "flex items-center gap-2", title: isRail ? appName : void 0, children: [
21896
21896
  logo || /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-8 h-8 bg-primary rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
21897
21897
  Typography,
21898
21898
  {
@@ -21902,7 +21902,7 @@ var init_DashboardLayout = __esm({
21902
21902
  children: appName.charAt(0).toUpperCase()
21903
21903
  }
21904
21904
  ) }),
21905
- /* @__PURE__ */ jsxRuntime.jsx(
21905
+ !isRail && /* @__PURE__ */ jsxRuntime.jsx(
21906
21906
  Typography,
21907
21907
  {
21908
21908
  variant: "label",
@@ -21929,12 +21929,13 @@ var init_DashboardLayout = __esm({
21929
21929
  {
21930
21930
  as: "nav",
21931
21931
  gap: "none",
21932
- className: "flex-1 px-3 py-4 space-y-1 overflow-y-auto",
21932
+ className: cn("flex-1 py-4 space-y-1 overflow-y-auto", isRail ? "px-2" : "px-3"),
21933
21933
  children: navItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
21934
21934
  NavLink,
21935
21935
  {
21936
21936
  item,
21937
- currentPath: activePath
21937
+ currentPath: activePath,
21938
+ compact: isRail
21938
21939
  },
21939
21940
  item.href
21940
21941
  ))
@@ -22189,13 +22190,40 @@ var init_DashboardLayout = __esm({
22189
22190
  DashboardLayout.displayName = "DashboardLayout";
22190
22191
  NavLink = ({
22191
22192
  item,
22192
- currentPath
22193
+ currentPath,
22194
+ compact = false
22193
22195
  }) => {
22194
22196
  const isActive = currentPath === item.href || currentPath.startsWith(item.href + "/");
22195
22197
  const iconClassName = cn(
22196
22198
  "h-5 w-5",
22197
22199
  isActive ? "text-primary-foreground" : "text-muted-foreground"
22198
22200
  );
22201
+ if (compact) {
22202
+ return /* @__PURE__ */ jsxRuntime.jsx(
22203
+ reactRouterDom.Link,
22204
+ {
22205
+ to: item.href,
22206
+ title: item.label,
22207
+ "aria-label": item.label,
22208
+ className: cn(
22209
+ "flex items-center justify-center px-2 py-2 rounded-lg transition-colors",
22210
+ isActive ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"
22211
+ ),
22212
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { as: "span", className: "relative inline-flex", children: [
22213
+ 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() }),
22214
+ item.badge && /* @__PURE__ */ jsxRuntime.jsx(
22215
+ Badge,
22216
+ {
22217
+ variant: isActive ? "primary" : "default",
22218
+ size: "sm",
22219
+ className: "absolute -top-2 -right-2 px-1 py-0 text-[10px] leading-4",
22220
+ children: item.badge
22221
+ }
22222
+ )
22223
+ ] })
22224
+ }
22225
+ );
22226
+ }
22199
22227
  return /* @__PURE__ */ jsxRuntime.jsxs(
22200
22228
  reactRouterDom.Link,
22201
22229
  {
@@ -23261,40 +23289,55 @@ function DataGrid({
23261
23289
  {
23262
23290
  "data-entity-row": true,
23263
23291
  "data-entity-id": id,
23264
- className: cn(isSelected && "ring-2 ring-primary rounded-lg"),
23292
+ className: cn("relative group/rowactions", isSelected && "ring-2 ring-primary rounded-lg"),
23265
23293
  children: [
23266
23294
  children(itemData, index),
23267
- 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: [
23268
- (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
23269
- Button,
23270
- {
23271
- variant: action.variant === "primary" ? "primary" : "ghost",
23272
- size: "sm",
23273
- onClick: handleActionClick(action, itemData),
23274
- "data-testid": `action-${action.event}`,
23275
- "data-row-id": String(itemData.id),
23276
- className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
23277
- children: [
23278
- action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
23279
- action.label
23280
- ]
23281
- },
23282
- idx
23283
- )),
23284
- maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
23295
+ 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: [
23296
+ /* @__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: [
23297
+ (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
23298
+ Button,
23299
+ {
23300
+ variant: action.variant === "primary" ? "primary" : "ghost",
23301
+ size: "sm",
23302
+ onClick: handleActionClick(action, itemData),
23303
+ "data-testid": `action-${action.event}`,
23304
+ "data-row-id": String(itemData.id),
23305
+ className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
23306
+ children: [
23307
+ action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
23308
+ action.label
23309
+ ]
23310
+ },
23311
+ idx
23312
+ )),
23313
+ maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
23314
+ Menu,
23315
+ {
23316
+ position: "bottom-end",
23317
+ 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" }) }),
23318
+ items: actionDefs.slice(maxInlineActions).map((action) => ({
23319
+ label: action.label,
23320
+ icon: action.icon,
23321
+ event: action.event,
23322
+ onClick: () => fireAction(action, itemData)
23323
+ }))
23324
+ }
23325
+ )
23326
+ ] }),
23327
+ /* @__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(
23285
23328
  Menu,
23286
23329
  {
23287
23330
  position: "bottom-end",
23288
23331
  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" }) }),
23289
- items: actionDefs.slice(maxInlineActions).map((action) => ({
23332
+ items: actionDefs.map((action) => ({
23290
23333
  label: action.label,
23291
23334
  icon: action.icon,
23292
23335
  event: action.event,
23293
23336
  onClick: () => fireAction(action, itemData)
23294
23337
  }))
23295
23338
  }
23296
- )
23297
- ] }) })
23339
+ ) })
23340
+ ] })
23298
23341
  ]
23299
23342
  },
23300
23343
  id
@@ -23330,7 +23373,7 @@ function DataGrid({
23330
23373
  }
23331
23374
  ) });
23332
23375
  })(),
23333
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
23376
+ /* @__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: [
23334
23377
  selectable && /* @__PURE__ */ jsxRuntime.jsx(
23335
23378
  "input",
23336
23379
  {
@@ -23363,78 +23406,77 @@ function DataGrid({
23363
23406
  ] }, field.name);
23364
23407
  }) })
23365
23408
  ] }),
23366
- dangerActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
23367
- Button,
23368
- {
23369
- variant: "ghost",
23370
- size: "sm",
23371
- onClick: handleActionClick(action, itemData),
23372
- "data-testid": `action-${action.event}`,
23373
- "data-row-id": String(itemData.id),
23374
- "aria-label": action.label,
23375
- title: action.label,
23376
- className: "text-error hover:text-error hover:bg-error/10 px-2",
23377
- children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
23378
- },
23379
- idx
23380
- )) })
23381
- ] }) }),
23382
- 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) => {
23383
- const value = getNestedValue(itemData, field.name);
23384
- if (value === void 0 || value === null || value === "") return null;
23385
- if (field.format === "boolean") {
23386
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
23387
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
23388
- field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
23389
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
23390
- ] }),
23391
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
23392
- ] }, field.name);
23393
- }
23394
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
23395
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
23396
- field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
23397
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
23398
- ] }),
23399
- /* @__PURE__ */ jsxRuntime.jsx(
23400
- Typography,
23409
+ (primaryActions.length > 0 || dangerActions.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "flex-shrink-0", children: [
23410
+ (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
23411
+ Button,
23412
+ {
23413
+ variant: action.variant === "primary" ? "primary" : "ghost",
23414
+ size: "sm",
23415
+ onClick: handleActionClick(action, itemData),
23416
+ "data-testid": `action-${action.event}`,
23417
+ "data-row-id": String(itemData.id),
23418
+ "aria-label": action.label,
23419
+ title: action.label,
23420
+ className: cn(
23421
+ action.variant === "primary" ? void 0 : "text-muted-foreground hover:text-foreground",
23422
+ action.icon && "px-2"
23423
+ ),
23424
+ children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
23425
+ },
23426
+ idx
23427
+ )),
23428
+ maxInlineActions != null && primaryActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
23429
+ Menu,
23401
23430
  {
23402
- variant: field.variant === "caption" ? "caption" : "small",
23403
- className: "text-right truncate max-w-[60%]",
23404
- children: formatValue(value, field.format)
23431
+ position: "bottom-end",
23432
+ 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" }) }),
23433
+ items: primaryActions.slice(maxInlineActions).map((action) => ({
23434
+ label: action.label,
23435
+ icon: action.icon,
23436
+ event: action.event,
23437
+ onClick: () => fireAction(action, itemData)
23438
+ }))
23405
23439
  }
23406
- )
23407
- ] }, field.name);
23408
- }) }) }),
23409
- 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: [
23410
- (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
23411
- Button,
23412
- {
23413
- variant: action.variant === "primary" ? "primary" : "ghost",
23414
- size: "sm",
23415
- onClick: handleActionClick(action, itemData),
23416
- "data-testid": `action-${action.event}`,
23417
- "data-row-id": String(itemData.id),
23418
- children: [
23419
- action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
23420
- action.label
23421
- ]
23422
- },
23423
- idx
23424
- )),
23425
- maxInlineActions != null && primaryActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
23426
- Menu,
23427
- {
23428
- position: "bottom-end",
23429
- 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" }) }),
23430
- items: primaryActions.slice(maxInlineActions).map((action) => ({
23431
- label: action.label,
23432
- icon: action.icon,
23433
- event: action.event,
23434
- onClick: () => fireAction(action, itemData)
23435
- }))
23440
+ ),
23441
+ dangerActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
23442
+ Button,
23443
+ {
23444
+ variant: "ghost",
23445
+ size: "sm",
23446
+ onClick: handleActionClick(action, itemData),
23447
+ "data-testid": `action-${action.event}`,
23448
+ "data-row-id": String(itemData.id),
23449
+ "aria-label": action.label,
23450
+ title: action.label,
23451
+ className: "text-error hover:text-error hover:bg-error/10 px-2",
23452
+ children: action.icon ? renderIconInput(action.icon, { size: "xs" }) : action.label
23453
+ },
23454
+ `danger-${idx}`
23455
+ ))
23456
+ ] })
23457
+ ] }) }),
23458
+ bodyFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 pt-2 pb-4 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
23459
+ bodyFields.filter((f3) => f3.variant === "caption" && f3.format !== "boolean").map((field) => {
23460
+ const value = getNestedValue(itemData, field.name);
23461
+ if (value === void 0 || value === null || value === "") return null;
23462
+ return /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", className: "line-clamp-2", children: formatValue(value, field.format) }, field.name);
23463
+ }),
23464
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: "flex-wrap gap-y-1", children: bodyFields.filter((f3) => f3.variant !== "caption" || f3.format === "boolean").map((field) => {
23465
+ const value = getNestedValue(itemData, field.name);
23466
+ if (value === void 0 || value === null || value === "") return null;
23467
+ if (field.format === "boolean") {
23468
+ return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
23469
+ field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
23470
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) }),
23471
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
23472
+ ] }, field.name);
23436
23473
  }
23437
- )
23474
+ return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
23475
+ field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
23476
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: (field.label ?? fieldLabel2(field.name)) + ":" }),
23477
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", children: formatValue(value, field.format) })
23478
+ ] }, field.name);
23479
+ }) })
23438
23480
  ] }) })
23439
23481
  ]
23440
23482
  },
@@ -23782,11 +23824,29 @@ function DataList({
23782
23824
  const wrapDnd = (node) => dnd.isZone ? /* @__PURE__ */ jsxRuntime.jsx(dnd.SortableItem, { id: dndId, children: node }, dndId) : node;
23783
23825
  if (hasRenderProp) {
23784
23826
  const id2 = itemData.id || String(index);
23827
+ const actions = renderItemActions(itemData);
23785
23828
  return wrapDnd(
23786
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: itemClickEvent ? handleRowClick(itemData) : void 0, className: cn(itemClickEvent && "cursor-pointer"), children: [
23787
- /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group flex items-stretch gap-2", children: [
23788
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
23789
- renderItemActions(itemData)
23829
+ /* @__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: [
23830
+ children(itemData, index),
23831
+ 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: [
23832
+ /* @__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 }),
23833
+ /* @__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(
23834
+ Menu,
23835
+ {
23836
+ position: "bottom-end",
23837
+ 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" }) }),
23838
+ items: (itemActions ?? []).map((action) => ({
23839
+ label: action.label,
23840
+ icon: action.icon,
23841
+ event: action.event,
23842
+ variant: action.variant === "danger" ? "danger" : "default",
23843
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
23844
+ id: itemData.id,
23845
+ row: itemData
23846
+ })
23847
+ }))
23848
+ }
23849
+ ) })
23790
23850
  ] }),
23791
23851
  isCard && !isLast && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mx-6 border-b border-border/40" })
23792
23852
  ] }, id2)
@@ -23826,7 +23886,7 @@ function DataList({
23826
23886
  ] }, field.name);
23827
23887
  })
23828
23888
  ] }),
23829
- bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
23889
+ bodyFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: cn("flex-wrap", isCompact ? "mt-0.5" : "mt-1.5"), children: bodyFields.map((field) => {
23830
23890
  const value = getNestedValue(itemData, field.name);
23831
23891
  if (value === void 0 || value === null || value === "") return null;
23832
23892
  return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
@@ -27422,7 +27482,7 @@ var init_MapView = __esm({
27422
27482
  shadowSize: [41, 41]
27423
27483
  });
27424
27484
  L.Marker.prototype.options.icon = defaultIcon;
27425
- const { useEffect: useEffect62, useRef: useRef60, useCallback: useCallback93, useState: useState91 } = React84__namespace.default;
27485
+ const { useEffect: useEffect62, useRef: useRef60, useCallback: useCallback94, useState: useState91 } = React84__namespace.default;
27426
27486
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
27427
27487
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
27428
27488
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -27468,7 +27528,7 @@ var init_MapView = __esm({
27468
27528
  }) {
27469
27529
  const eventBus = useEventBus2();
27470
27530
  const [clickedPosition, setClickedPosition] = useState91(null);
27471
- const handleMapClick = useCallback93((lat, lng) => {
27531
+ const handleMapClick = useCallback94((lat, lng) => {
27472
27532
  if (showClickedPin) {
27473
27533
  setClickedPosition({ lat, lng });
27474
27534
  }
@@ -27477,7 +27537,7 @@ var init_MapView = __esm({
27477
27537
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
27478
27538
  }
27479
27539
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
27480
- const handleMarkerClick = useCallback93((marker) => {
27540
+ const handleMarkerClick = useCallback94((marker) => {
27481
27541
  onMarkerClick?.(marker);
27482
27542
  if (markerClickEvent) {
27483
27543
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -28253,6 +28313,26 @@ var init_Lightbox = __esm({
28253
28313
  Lightbox.displayName = "Lightbox";
28254
28314
  }
28255
28315
  });
28316
+ function useMediaQuery(query) {
28317
+ const subscribe = React84.useCallback(
28318
+ (onChange) => {
28319
+ const mql = window.matchMedia(query);
28320
+ mql.addEventListener("change", onChange);
28321
+ return () => mql.removeEventListener("change", onChange);
28322
+ },
28323
+ [query]
28324
+ );
28325
+ return React84.useSyncExternalStore(
28326
+ subscribe,
28327
+ () => window.matchMedia(query).matches,
28328
+ () => false
28329
+ );
28330
+ }
28331
+ var init_useMediaQuery = __esm({
28332
+ "hooks/useMediaQuery.ts"() {
28333
+ "use client";
28334
+ }
28335
+ });
28256
28336
  function renderIconInput3(icon, props) {
28257
28337
  return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, ...props });
28258
28338
  }
@@ -28359,6 +28439,7 @@ function TableView({
28359
28439
  const hasMore = pageSize > 0 && visibleCount < ordered.length;
28360
28440
  const hasRenderProp = typeof children === "function";
28361
28441
  const idField = dndItemIdField ?? "id";
28442
+ const isCoarsePointer = useMediaQuery("(pointer: coarse)");
28362
28443
  const selected = selectedIds ? new Set(selectedIds) : localSelected;
28363
28444
  const emitSelection = (next) => {
28364
28445
  if (!selectedIds) setLocalSelected(next);
@@ -28391,6 +28472,17 @@ function TableView({
28391
28472
  };
28392
28473
  eventBus.emit(`UI:${action.event}`, payload);
28393
28474
  };
28475
+ const colFloors = React84__namespace.default.useMemo(
28476
+ () => colDefs.map((col) => {
28477
+ const longest = data.reduce((widest, row) => {
28478
+ const cell = formatCell(asFieldValue(getNestedValue(row, col.field ?? col.key)), col.format);
28479
+ return Math.max(widest, cell.length);
28480
+ }, columnLabel(col).length);
28481
+ const chrome = col.format === "badge" ? BADGE_CHROME_CH : 0;
28482
+ return Math.min(longest + chrome, MAX_MEASURED_COL_CH);
28483
+ }),
28484
+ [colDefs, data]
28485
+ );
28394
28486
  if (isLoading) {
28395
28487
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
28396
28488
  }
@@ -28403,20 +28495,10 @@ function TableView({
28403
28495
  }
28404
28496
  const lk = LOOKS[look];
28405
28497
  const hasActions = Boolean(itemActions && itemActions.length > 0);
28406
- const inlineActionCount = hasActions ? maxInlineActions != null ? Math.min(itemActions.length, maxInlineActions) : itemActions.length : 0;
28407
- const hasOverflowActions = hasActions && maxInlineActions != null && itemActions.length > maxInlineActions;
28498
+ const effectiveMaxInline = isCoarsePointer ? 0 : maxInlineActions;
28499
+ const inlineActionCount = hasActions ? effectiveMaxInline != null ? Math.min(itemActions.length, effectiveMaxInline) : itemActions.length : 0;
28500
+ const hasOverflowActions = hasActions && effectiveMaxInline != null && itemActions.length > effectiveMaxInline;
28408
28501
  const actionsTrack = hasActions ? `${inlineActionCount * 6 + (hasOverflowActions ? 3 : 0)}rem` : null;
28409
- const colFloors = React84__namespace.default.useMemo(
28410
- () => colDefs.map((col) => {
28411
- const longest = data.reduce((widest, row) => {
28412
- const cell = formatCell(asFieldValue(getNestedValue(row, col.field ?? col.key)), col.format);
28413
- return Math.max(widest, cell.length);
28414
- }, columnLabel(col).length);
28415
- const chrome = col.format === "badge" ? BADGE_CHROME_CH : 0;
28416
- return Math.min(longest + chrome, MAX_MEASURED_COL_CH);
28417
- }),
28418
- [colDefs, data]
28419
- );
28420
28502
  const gridTemplateColumns = [
28421
28503
  selectable ? "auto" : null,
28422
28504
  ...colDefs.map((c, i) => c.width ?? `minmax(${colFloors[i]}ch, 1fr)`),
@@ -28505,7 +28587,7 @@ function TableView({
28505
28587
  if (col.format === "badge" && raw != null && raw !== "") {
28506
28588
  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);
28507
28589
  }
28508
- return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: formatCell(raw, col.format) }) }, col.key);
28590
+ 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);
28509
28591
  }),
28510
28592
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
28511
28593
  HStack,
@@ -28519,15 +28601,15 @@ function TableView({
28519
28601
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
28520
28602
  ),
28521
28603
  children: [
28522
- (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28604
+ (effectiveMaxInline != null ? itemActions.slice(0, effectiveMaxInline) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28523
28605
  Button,
28524
28606
  {
28525
- variant: action.variant ?? "ghost",
28607
+ variant: action.variant === "primary" ? "primary" : "ghost",
28526
28608
  size: "sm",
28527
28609
  onClick: handleActionClick(action, row),
28528
28610
  "data-testid": `action-${action.event}`,
28529
28611
  "data-row-id": String(row.id),
28530
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
28612
+ className: cn(action.variant === "danger" && "text-error hover:text-error hover:bg-error/10"),
28531
28613
  children: [
28532
28614
  action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
28533
28615
  action.label
@@ -28535,12 +28617,12 @@ function TableView({
28535
28617
  },
28536
28618
  i
28537
28619
  )),
28538
- maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
28620
+ effectiveMaxInline != null && itemActions.length > effectiveMaxInline && /* @__PURE__ */ jsxRuntime.jsx(
28539
28621
  Menu,
28540
28622
  {
28541
28623
  position: "bottom-end",
28542
28624
  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" }) }),
28543
- items: itemActions.slice(maxInlineActions).map((action) => ({
28625
+ items: itemActions.slice(effectiveMaxInline).map((action) => ({
28544
28626
  label: action.label,
28545
28627
  icon: action.icon,
28546
28628
  event: action.event,
@@ -28593,6 +28675,7 @@ var init_TableView = __esm({
28593
28675
  init_cn();
28594
28676
  init_getNestedValue();
28595
28677
  init_useEventBus();
28678
+ init_useMediaQuery();
28596
28679
  init_Box();
28597
28680
  init_Stack();
28598
28681
  init_Typography();
@@ -28617,7 +28700,7 @@ var init_TableView = __esm({
28617
28700
  semibold: "font-semibold"
28618
28701
  };
28619
28702
  LOOKS = {
28620
- dense: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: false, divider: true },
28703
+ dense: { rowPad: "px-card-md py-2", headPad: "px-card-md py-2", striped: false, divider: true },
28621
28704
  spacious: { rowPad: "px-card-lg py-card-md", headPad: "px-card-lg py-card-sm", striped: false, divider: true },
28622
28705
  striped: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: true, divider: false },
28623
28706
  borderless: { rowPad: "px-card-md py-card-sm", headPad: "px-card-md py-card-sm", striped: false, divider: false },
@@ -37071,7 +37154,17 @@ function DataTable({
37071
37154
  const currentPageSize = pageSize ?? 20;
37072
37155
  const total = totalCount ?? items.length;
37073
37156
  const totalPages = Math.ceil(total / currentPageSize);
37074
- const rowActions = externalRowActions ?? itemActions?.filter((a) => a.placement !== "bulk").map((action) => ({
37157
+ const withEventClick = (action) => {
37158
+ if (action.onClick || !action.event) return action;
37159
+ const event = action.event;
37160
+ return {
37161
+ ...action,
37162
+ onClick: (row) => {
37163
+ eventBus.emit(`UI:${event}`, { row });
37164
+ }
37165
+ };
37166
+ };
37167
+ const rowActions = (externalRowActions ?? itemActions?.filter((a) => a.placement !== "bulk").map((action) => ({
37075
37168
  label: action.label,
37076
37169
  icon: action.icon,
37077
37170
  variant: action.variant,
@@ -37091,7 +37184,17 @@ function DataTable({
37091
37184
  });
37092
37185
  }
37093
37186
  }
37094
- }));
37187
+ })))?.map(withEventClick);
37188
+ const normalizedBulkActions = bulkActions?.map((action) => {
37189
+ if (action.onClick || !action.event) return action;
37190
+ const event = action.event;
37191
+ return {
37192
+ ...action,
37193
+ onClick: (selectedRows2) => {
37194
+ eventBus.emit(`UI:${event}`, { rows: selectedRows2 });
37195
+ }
37196
+ };
37197
+ });
37095
37198
  const viewAction = itemActions?.find(
37096
37199
  (a) => a.event === "VIEW" || a.navigatesTo
37097
37200
  );
@@ -37199,7 +37302,7 @@ function DataTable({
37199
37302
  }
37200
37303
  )
37201
37304
  ] }),
37202
- 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: [
37305
+ 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: [
37203
37306
  /* @__PURE__ */ jsxRuntime.jsx(
37204
37307
  Typography,
37205
37308
  {
@@ -37210,13 +37313,13 @@ function DataTable({
37210
37313
  })
37211
37314
  }
37212
37315
  ),
37213
- /* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap gap-2", children: bulkActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
37316
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap gap-2", children: normalizedBulkActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
37214
37317
  Button,
37215
37318
  {
37216
37319
  variant: action.variant === "danger" ? "danger" : "secondary",
37217
37320
  size: "sm",
37218
37321
  leftIcon: action.icon,
37219
- onClick: () => action.onClick(selectedRows),
37322
+ onClick: () => action.onClick?.(selectedRows),
37220
37323
  children: action.label
37221
37324
  },
37222
37325
  idx
@@ -37378,7 +37481,7 @@ function DataTable({
37378
37481
  ),
37379
37482
  onClick: (e) => {
37380
37483
  e.stopPropagation();
37381
- action.onClick(row);
37484
+ action.onClick?.(row);
37382
37485
  setOpenActionMenu(null);
37383
37486
  },
37384
37487
  children: [
@@ -39674,27 +39777,24 @@ var init_MasterDetailLayout = __esm({
39674
39777
  masterClassName,
39675
39778
  detailClassName
39676
39779
  }) => {
39677
- masterWidth.endsWith("%") ? parseInt(masterWidth, 10) : 30;
39678
39780
  return /* @__PURE__ */ jsxRuntime.jsxs(
39679
39781
  "div",
39680
39782
  {
39681
- className: cn("flex h-full w-full", className),
39682
- style: {
39683
- display: "grid",
39684
- gridTemplateColumns: masterWidth.endsWith("%") ? `${masterWidth} 1fr` : `${masterWidth} 1fr`
39685
- },
39783
+ className: cn("w-full h-full md:grid md:grid-cols-[var(--master-detail-cols)]", className),
39784
+ style: { "--master-detail-cols": `${masterWidth} 1fr` },
39686
39785
  children: [
39687
39786
  /* @__PURE__ */ jsxRuntime.jsx(
39688
39787
  "div",
39689
39788
  {
39690
39789
  className: cn(
39691
- "border-r-2 border-border overflow-auto",
39790
+ "border-r border-border overflow-auto",
39791
+ hasSelection && "hidden md:block",
39692
39792
  masterClassName
39693
39793
  ),
39694
39794
  children: master
39695
39795
  }
39696
39796
  ),
39697
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-auto", detailClassName), children: hasSelection ? detail : emptyDetail || /* @__PURE__ */ jsxRuntime.jsx(DefaultEmptyDetail, {}) })
39797
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-auto", !hasSelection && "hidden md:block", detailClassName), children: hasSelection ? detail : emptyDetail || /* @__PURE__ */ jsxRuntime.jsx(DefaultEmptyDetail, {}) })
39698
39798
  ]
39699
39799
  }
39700
39800
  );