@almadar/ui 5.154.0 → 5.156.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.
package/dist/avl/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import * as React94 from 'react';
3
3
  import React94__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId } from 'react';
4
- import { getAllPages, matchPathAmong, CurrentPagePathProvider, NavStackProvider, OrbitalProvider, EventBusContext, useTraitScopeChain, useNavStack, ServerBridgeProvider, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, useServerBridge, EntityBindingContext, useEntitySchema, useEntitySchemaOptional, useEntityBindingSnapshot, TraitScopeProvider, useTraitScope, useCurrentPagePath, useGameAudioContextOptional } from '@almadar/ui/providers';
4
+ import { getAllPages, matchPathAmong, CurrentPagePathProvider, NavStackProvider, OrbitalProvider, EventBusContext, useTraitScopeChain, useNavStack, ServerBridgeProvider, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, useServerBridge, EntityBindingContext, useEntitySchema, RenderSlotProvider, useEntitySchemaOptional, useEntityBindingSnapshot, TraitScopeProvider, useTraitScope, useCurrentPagePath, useRenderSlot, useGameAudioContextOptional } from '@almadar/ui/providers';
5
5
  import { createLogger, setNamespaceLevel, isLogLevelEnabled } from '@almadar/logger';
6
6
  import ELK from 'elkjs/lib/elk.bundled.js';
7
7
  import { MarkerType, useReactFlow, Handle, Position, getBezierPath, EdgeLabelRenderer, useNodeId, ReactFlowProvider, BaseEdge, useNodesState, useEdgesState, ReactFlow, Controls, Background, BackgroundVariant } from '@xyflow/react';
@@ -9,7 +9,7 @@ import { useTranslate } from '@almadar/ui/hooks';
9
9
  import { InMemoryPersistence, StateMachineManager, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, createServerEffectHandlers, EffectExecutor, createContextFromBindings, createTickScheduler, isValidCronExpression, parseDurationString, normalizeCallSiteConfigToValues, interpolateValue } from '@almadar/runtime';
10
10
  import { FieldTypeSchema, isInlineTrait, isPageReference, buildResolvedTraitConfigs, schemaToIR, getPage, mergeEntityFrame, isCircuitEvent, applyListenPayloadMapping, walkSExpr, isRenderBindingMarker, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER, isFileValue, ANIMATION_NAMES } from '@almadar/core';
11
11
  import * as LucideIcons2 from 'lucide-react';
12
- import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ArrowLeft, ZoomOut, ZoomIn, Download, DollarSign, ChevronDown, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, ChevronUp, Tag, User } from 'lucide-react';
12
+ import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ArrowLeft, ZoomOut, ZoomIn, Download, DollarSign, ChevronDown, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, ChevronUp } from 'lucide-react';
13
13
  import { createPortal } from 'react-dom';
14
14
  import { UISlotProvider, useUISlots, useTheme } from '@almadar/ui/context';
15
15
  import { evaluateGuard, evaluateListenPayloadExpr, evaluate, createMinimalContext, executeEffects } from '@almadar/evaluator';
@@ -11533,10 +11533,21 @@ function ControlGrid({
11533
11533
  directionAssets,
11534
11534
  size = "md",
11535
11535
  disabled,
11536
+ visibility = "auto",
11536
11537
  className
11537
11538
  }) {
11538
11539
  const eventBus = useEventBus();
11539
11540
  const [active, setActive] = React94.useState(/* @__PURE__ */ new Set());
11541
+ const [coarse, setCoarse] = React94.useState(
11542
+ () => typeof window !== "undefined" && window.matchMedia("(pointer: coarse)").matches
11543
+ );
11544
+ React94.useEffect(() => {
11545
+ if (visibility !== "auto" || typeof window === "undefined") return;
11546
+ const mq = window.matchMedia("(pointer: coarse)");
11547
+ const onChange = (e) => setCoarse(e.matches);
11548
+ mq.addEventListener("change", onChange);
11549
+ return () => mq.removeEventListener("change", onChange);
11550
+ }, [visibility]);
11540
11551
  const handlePress = React94.useCallback(
11541
11552
  (id) => {
11542
11553
  setActive((prev) => new Set(prev).add(id));
@@ -11569,6 +11580,7 @@ function ControlGrid({
11569
11580
  },
11570
11581
  [kind, actionEvent, directionEvent, directionReleaseEvents, eventBus, onAction, onDirection]
11571
11582
  );
11583
+ if (visibility === "auto" && !coarse) return null;
11572
11584
  if (kind === "dpad") {
11573
11585
  const ds = dpadSizeMap[size];
11574
11586
  const dir = (d) => /* @__PURE__ */ jsx(
@@ -11718,7 +11730,7 @@ function StatBadge({
11718
11730
  assetUrl,
11719
11731
  iconUrl,
11720
11732
  label,
11721
- value = 0,
11733
+ value,
11722
11734
  max,
11723
11735
  format = "number",
11724
11736
  icon,
@@ -11729,6 +11741,7 @@ function StatBadge({
11729
11741
  source: _source,
11730
11742
  field: _field
11731
11743
  }) {
11744
+ const hasValue = value !== void 0 && value !== null;
11732
11745
  const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
11733
11746
  const resolvedAsset = iconUrl ?? assetUrl;
11734
11747
  return /* @__PURE__ */ jsxs(
@@ -11742,8 +11755,8 @@ function StatBadge({
11742
11755
  ),
11743
11756
  children: [
11744
11757
  resolvedAsset ? /* @__PURE__ */ jsx(GameIcon, { assetUrl: resolvedAsset, icon: "image", size: 16, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsx(Box, { as: "span", className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Icon, { icon, className: "w-4 h-4" }) }) : null,
11745
- /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground font-medium", children: label }),
11746
- format === "hearts" && max && /* @__PURE__ */ jsx(
11758
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-muted-foreground font-medium text-xs", children: label }),
11759
+ hasValue && format === "hearts" && max && /* @__PURE__ */ jsx(
11747
11760
  HealthBar,
11748
11761
  {
11749
11762
  current: numValue,
@@ -11752,7 +11765,7 @@ function StatBadge({
11752
11765
  size: size === "lg" ? "md" : "sm"
11753
11766
  }
11754
11767
  ),
11755
- format === "bar" && max && /* @__PURE__ */ jsx(
11768
+ hasValue && format === "bar" && max && /* @__PURE__ */ jsx(
11756
11769
  HealthBar,
11757
11770
  {
11758
11771
  current: numValue,
@@ -11761,14 +11774,15 @@ function StatBadge({
11761
11774
  size: size === "lg" ? "md" : "sm"
11762
11775
  }
11763
11776
  ),
11764
- format === "number" && /* @__PURE__ */ jsx(
11777
+ hasValue && format === "number" && /* @__PURE__ */ jsx(
11765
11778
  ScoreDisplay,
11766
11779
  {
11767
11780
  value: numValue,
11768
- size: size === "lg" ? "md" : "sm"
11781
+ size: size === "lg" ? "md" : "sm",
11782
+ className: "font-display"
11769
11783
  }
11770
11784
  ),
11771
- format === "text" && /* @__PURE__ */ jsx(Typography, { as: "span", className: "font-bold text-foreground", children: value })
11785
+ hasValue && format === "text" && /* @__PURE__ */ jsx(Typography, { as: "span", className: "font-bold text-foreground", children: value })
11772
11786
  ]
11773
11787
  }
11774
11788
  );
@@ -11784,6 +11798,7 @@ var init_StatBadge = __esm({
11784
11798
  init_HealthBar();
11785
11799
  init_ScoreDisplay();
11786
11800
  sizeMap6 = {
11801
+ xs: "text-xs px-1.5 py-0.5",
11787
11802
  sm: "text-xs px-2 py-1",
11788
11803
  md: "text-sm px-3 py-1.5",
11789
11804
  lg: "text-base px-4 py-2"
@@ -11826,6 +11841,7 @@ function GameHud({
11826
11841
  items,
11827
11842
  elements,
11828
11843
  size = "md",
11844
+ variant = "floating",
11829
11845
  className,
11830
11846
  transparent = true
11831
11847
  }) {
@@ -11840,7 +11856,7 @@ function GameHud({
11840
11856
  /* @__PURE__ */ jsx(Box, { position: "absolute", className: "top-4 right-4 flex flex-col gap-2 items-end pointer-events-auto", children: rightStats.map((stat, i) => /* @__PURE__ */ jsx(StatBadge, { ...stat, size }, i)) })
11841
11857
  ] });
11842
11858
  }
11843
- if (position === "top" || position === "bottom") {
11859
+ if ((position === "top" || position === "bottom") && variant === "bar") {
11844
11860
  const mid = Math.ceil(stats.length / 2);
11845
11861
  const leftStats = stats.slice(0, mid);
11846
11862
  const rightStats = stats.slice(mid);
@@ -15061,7 +15077,7 @@ var init_StateJsonView = __esm({
15061
15077
  StateJsonView.displayName = "StateJsonView";
15062
15078
  }
15063
15079
  });
15064
- var FONT_BASE, GAME_FONTS, FONT_FACES, GameShell;
15080
+ var GAME_FONTS, GameShell;
15065
15081
  var init_GameShell = __esm({
15066
15082
  "components/game/templates/GameShell.tsx"() {
15067
15083
  init_cn();
@@ -15069,7 +15085,6 @@ var init_GameShell = __esm({
15069
15085
  init_Card();
15070
15086
  init_Typography();
15071
15087
  init_AtlasImage();
15072
- FONT_BASE = "https://almadar-kflow-assets.web.app/shared/_shared/kenney-fonts/fonts";
15073
15088
  GAME_FONTS = {
15074
15089
  future: "Kenney Future",
15075
15090
  "future-narrow": "Kenney Future Narrow",
@@ -15077,14 +15092,6 @@ var init_GameShell = __esm({
15077
15092
  blocks: "Kenney Blocks",
15078
15093
  mini: "Kenney Mini"
15079
15094
  };
15080
- FONT_FACES = `
15081
- @font-face { font-family: 'Kenney Future'; src: url('${FONT_BASE}/Kenney%20Future.ttf') format('truetype'); font-display: swap; }
15082
- @font-face { font-family: 'Kenney Future Narrow'; src: url('${FONT_BASE}/Kenney%20Future%20Narrow.ttf') format('truetype'); font-display: swap; }
15083
- @font-face { font-family: 'Kenney Pixel'; src: url('${FONT_BASE}/Kenney%20Pixel.ttf') format('truetype'); font-display: swap; }
15084
- @font-face { font-family: 'Kenney Blocks'; src: url('${FONT_BASE}/Kenney%20Blocks.ttf') format('truetype'); font-display: swap; }
15085
- @font-face { font-family: 'Kenney Mini'; src: url('${FONT_BASE}/Kenney%20Mini.ttf') format('truetype'); font-display: swap; }
15086
- .game-shell, .game-shell * { font-family: inherit; }
15087
- `;
15088
15095
  GameShell = ({
15089
15096
  appName = "Game",
15090
15097
  hud,
@@ -15111,10 +15118,12 @@ var init_GameShell = __esm({
15111
15118
  overflow: "hidden",
15112
15119
  background: "var(--color-background, #0a0a0f)",
15113
15120
  color: "var(--color-foreground, #e0e0e0)",
15114
- fontFamily: `'${font}', system-ui, sans-serif`
15121
+ // The fontFamily knob is a scoped override of the theme contract's
15122
+ // display slot: titles/numerics take the game face, body text keeps
15123
+ // the active theme's --font-family-body.
15124
+ "--font-family-display": `'${font}', ui-sans-serif, system-ui, sans-serif`
15115
15125
  },
15116
15126
  children: [
15117
- /* @__PURE__ */ jsx("style", { children: FONT_FACES }),
15118
15127
  backgroundAsset && /* @__PURE__ */ jsx(
15119
15128
  AtlasPanel,
15120
15129
  {
@@ -15152,6 +15161,7 @@ var init_GameShell = __esm({
15152
15161
  Typography,
15153
15162
  {
15154
15163
  as: "span",
15164
+ className: "font-display",
15155
15165
  style: {
15156
15166
  fontWeight: 700,
15157
15167
  fontSize: "1.05rem",
@@ -15232,6 +15242,11 @@ var init_molecules = __esm({
15232
15242
  init_puzzleObject();
15233
15243
  }
15234
15244
  });
15245
+ function themeBodyFont(el) {
15246
+ if (typeof getComputedStyle !== "function") return "system-ui, sans-serif";
15247
+ const v = getComputedStyle(el).getPropertyValue("--font-family-body").trim();
15248
+ return v || "system-ui, sans-serif";
15249
+ }
15235
15250
  function resolveColor2(color, ctx, fallback) {
15236
15251
  if (!color) return fallback;
15237
15252
  if (color.startsWith("var(")) {
@@ -15431,7 +15446,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
15431
15446
  case "text": {
15432
15447
  if (shape.x == null || shape.y == null || !shape.text) break;
15433
15448
  ctx.fillStyle = stroke;
15434
- ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
15449
+ ctx.font = `${shape.fontSize ?? 14}px ${themeBodyFont(ctx.canvas)}`;
15435
15450
  ctx.textAlign = shape.align ?? "left";
15436
15451
  ctx.textBaseline = "middle";
15437
15452
  ctx.fillText(shape.text, shape.x, shape.y);
@@ -23955,7 +23970,22 @@ function eventStartDate(event, startField) {
23955
23970
  const raw = getNestedValue(event, startField);
23956
23971
  return new Date(raw ?? "");
23957
23972
  }
23958
- function generateDefaultTimeSlots(events2, startField) {
23973
+ function eventEndDate(event, endField) {
23974
+ const raw = getNestedValue(event, endField);
23975
+ if (raw === void 0 || raw === null || raw === "") return null;
23976
+ const end = new Date(raw);
23977
+ return Number.isNaN(end.getTime()) ? null : end;
23978
+ }
23979
+ function eventContinuesInSlot(event, day, slotTime, startField, endField) {
23980
+ const eventStart = eventStartDate(event, startField);
23981
+ const eventEnd = eventEndDate(event, endField);
23982
+ if (eventEnd === null || Number.isNaN(eventStart.getTime())) return false;
23983
+ const [slotHour] = slotTime.split(":").map(Number);
23984
+ const slotStart = new Date(day);
23985
+ slotStart.setHours(slotHour, 0, 0, 0);
23986
+ return slotStart.getTime() > eventStart.getTime() && slotStart.getTime() < eventEnd.getTime();
23987
+ }
23988
+ function generateDefaultTimeSlots(events2, startField, endField) {
23959
23989
  let first = DEFAULT_FIRST_HOUR;
23960
23990
  let last = DEFAULT_LAST_HOUR;
23961
23991
  for (const ev of events2) {
@@ -23964,6 +23994,11 @@ function generateDefaultTimeSlots(events2, startField) {
23964
23994
  const hour = start.getHours();
23965
23995
  if (hour < first) first = hour;
23966
23996
  if (hour > last) last = hour;
23997
+ const end = eventEndDate(ev, endField);
23998
+ if (end && end.toDateString() === start.toDateString()) {
23999
+ const endHour = end.getMinutes() === 0 && end.getSeconds() === 0 ? end.getHours() - 1 : end.getHours();
24000
+ if (endHour > last) last = endHour;
24001
+ }
23967
24002
  }
23968
24003
  const slots = [];
23969
24004
  for (let hour = first; hour <= last; hour++) {
@@ -23992,6 +24027,7 @@ function CalendarGrid({
23992
24027
  dayWindow = "auto",
23993
24028
  titleField = "title",
23994
24029
  startField = "startTime",
24030
+ endField = "endTime",
23995
24031
  colorField = "color",
23996
24032
  children,
23997
24033
  renderItem
@@ -24009,8 +24045,8 @@ function CalendarGrid({
24009
24045
  [resolvedWeekStart]
24010
24046
  );
24011
24047
  const resolvedTimeSlots = useMemo(
24012
- () => timeSlots ?? generateDefaultTimeSlots(evs, startField),
24013
- [timeSlots, evs, startField]
24048
+ () => timeSlots ?? generateDefaultTimeSlots(evs, startField, endField),
24049
+ [timeSlots, evs, startField, endField]
24014
24050
  );
24015
24051
  const visibleCount = useDayWindow(dayWindow);
24016
24052
  const [dayOffset, setDayOffset] = useState(0);
@@ -24170,12 +24206,15 @@ function CalendarGrid({
24170
24206
  const slotEvents = evs.filter(
24171
24207
  (ev) => eventInSlot(ev, day, time, startField)
24172
24208
  );
24209
+ const continuingEvents = evs.filter(
24210
+ (ev) => eventContinuesInSlot(ev, day, time, startField, endField)
24211
+ );
24173
24212
  const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
24174
24213
  return /* @__PURE__ */ jsx(
24175
24214
  TimeSlotCell,
24176
24215
  {
24177
24216
  time,
24178
- isOccupied: slotEvents.length > 0,
24217
+ isOccupied: slotEvents.length > 0 || continuingEvents.length > 0,
24179
24218
  onClick: () => handleSlotClick(day, time),
24180
24219
  className: cn(
24181
24220
  "border-l border-border",
@@ -24186,7 +24225,25 @@ function CalendarGrid({
24186
24225
  onPointerUp: clearLongPress,
24187
24226
  onPointerCancel: clearLongPress
24188
24227
  } : {},
24189
- children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: slotEvents.map(renderEvent) })
24228
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
24229
+ slotEvents.map(renderEvent),
24230
+ continuingEvents.map((event) => {
24231
+ const color = getNestedValue(event, colorField);
24232
+ return /* @__PURE__ */ jsx(
24233
+ Box,
24234
+ {
24235
+ rounded: "sm",
24236
+ border: true,
24237
+ className: cn(
24238
+ "cursor-pointer h-2",
24239
+ color ? cn(color, "opacity-50") : "bg-primary/10 border-primary/20"
24240
+ ),
24241
+ onClick: (e) => handleEventClick(event, e)
24242
+ },
24243
+ `${event.id}-cont`
24244
+ );
24245
+ })
24246
+ ] })
24190
24247
  },
24191
24248
  `${day.toISOString()}-${time}`
24192
24249
  );
@@ -34245,13 +34302,13 @@ var init_MapView = __esm({
34245
34302
  shadowSize: [41, 41]
34246
34303
  });
34247
34304
  L.Marker.prototype.options.icon = defaultIcon;
34248
- const { useEffect: useEffect65, useRef: useRef65, useCallback: useCallback96, useState: useState100 } = React94__default;
34305
+ const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback96, useState: useState100 } = React94__default;
34249
34306
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
34250
34307
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
34251
34308
  function MapUpdater({ centerLat, centerLng, zoom }) {
34252
34309
  const map = useMap();
34253
34310
  const prevRef = useRef65({ centerLat, centerLng, zoom });
34254
- useEffect65(() => {
34311
+ useEffect67(() => {
34255
34312
  const prev = prevRef.current;
34256
34313
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
34257
34314
  map.setView([centerLat, centerLng], zoom);
@@ -34262,7 +34319,7 @@ var init_MapView = __esm({
34262
34319
  }
34263
34320
  function MapClickHandler({ onMapClick }) {
34264
34321
  const map = useMap();
34265
- useEffect65(() => {
34322
+ useEffect67(() => {
34266
34323
  if (!onMapClick) return;
34267
34324
  const handler = (e) => {
34268
34325
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -34791,14 +34848,34 @@ var init_UploadDropZone = __esm({
34791
34848
  if (valid.length > 0) {
34792
34849
  onFiles?.(valid);
34793
34850
  if (action) {
34794
- eventBus.emit(`UI:${action}`, {
34795
- ...actionPayload,
34796
- files: valid.map((f3) => ({ name: f3.name, size: f3.size, type: f3.type }))
34851
+ void Promise.all(
34852
+ valid.map(
34853
+ (f3) => new Promise(
34854
+ (resolvePayload, rejectPayload) => {
34855
+ const reader = new FileReader();
34856
+ reader.onload = () => resolvePayload({
34857
+ name: f3.name,
34858
+ size: f3.size,
34859
+ type: f3.type,
34860
+ content: String(reader.result ?? "")
34861
+ });
34862
+ reader.onerror = () => rejectPayload(reader.error);
34863
+ reader.readAsDataURL(f3);
34864
+ }
34865
+ )
34866
+ )
34867
+ ).then((payloadFiles) => {
34868
+ eventBus.emit(`UI:${action}`, {
34869
+ ...actionPayload,
34870
+ files: payloadFiles
34871
+ });
34872
+ }).catch(() => {
34873
+ setError(t("Could not read the selected file"));
34797
34874
  });
34798
34875
  }
34799
34876
  }
34800
34877
  },
34801
- [validateFiles, onFiles, action, actionPayload, eventBus]
34878
+ [validateFiles, onFiles, action, actionPayload, eventBus, t]
34802
34879
  );
34803
34880
  const handleDragOver = (e) => {
34804
34881
  e.preventDefault();
@@ -43906,22 +43983,6 @@ var init_DataTable = __esm({
43906
43983
  DataTable.displayName = "DataTable";
43907
43984
  }
43908
43985
  });
43909
- function getFieldIcon(fieldName) {
43910
- const name = fieldName.toLowerCase();
43911
- if (name.includes("date") || name.includes("time")) return Calendar;
43912
- if (name.includes("status")) return Tag;
43913
- if (name.includes("priority")) return AlertCircle;
43914
- if (name.includes("progress") || name.includes("percent")) return TrendingUp;
43915
- if (name.includes("assignee") || name.includes("owner") || name.includes("user") || name.includes("member"))
43916
- return User;
43917
- if (name.includes("due")) return Clock;
43918
- if (name.includes("complete")) return CheckCircle2;
43919
- if (name.includes("budget") || name.includes("cost") || name.includes("price"))
43920
- return DollarSign;
43921
- if (name.includes("description") || name.includes("note") || name.includes("comment"))
43922
- return FileText;
43923
- return Package;
43924
- }
43925
43986
  function getBadgeVariant(fieldName, value) {
43926
43987
  const name = fieldName.toLowerCase();
43927
43988
  const val = String(value).toLowerCase();
@@ -43971,6 +44032,18 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
43971
44032
  }
43972
44033
  ) });
43973
44034
  }
44035
+ if (fieldType === "url" && /^https?:\/\//i.test(str)) {
44036
+ return /* @__PURE__ */ jsx(
44037
+ "a",
44038
+ {
44039
+ href: str,
44040
+ target: "_blank",
44041
+ rel: "noreferrer",
44042
+ className: "text-primary hover:underline break-all",
44043
+ children: str
44044
+ }
44045
+ );
44046
+ }
43974
44047
  return str;
43975
44048
  }
43976
44049
  case "markdown":
@@ -44069,6 +44142,23 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
44069
44142
  }
44070
44143
  return str;
44071
44144
  }
44145
+ case "boolean": {
44146
+ if (typeof value === "boolean") return value ? "Yes" : "No";
44147
+ if (str === "true") return "Yes";
44148
+ if (str === "false") return "No";
44149
+ return str;
44150
+ }
44151
+ case "array": {
44152
+ if (Array.isArray(value) && value.length > 0) {
44153
+ return /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: value.map((item, i) => /* @__PURE__ */ jsx(Badge, { variant: "default", children: String(item) }, i)) });
44154
+ }
44155
+ if (Array.isArray(value)) return "\u2014";
44156
+ return str;
44157
+ }
44158
+ case "email":
44159
+ return /* @__PURE__ */ jsx("a", { href: `mailto:${str}`, className: "text-primary hover:underline break-all", children: str });
44160
+ case "phone":
44161
+ return /* @__PURE__ */ jsx("a", { href: `tel:${str}`, className: "text-primary hover:underline", children: str });
44072
44162
  default:
44073
44163
  if (meta?.values && meta.values.length > 0 && meta.values.includes(str)) {
44074
44164
  return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(fieldName, str), children: humanizeEnumValue(str) });
@@ -44141,10 +44231,11 @@ var init_DetailPanel = __esm({
44141
44231
  avatar,
44142
44232
  sections: propSections,
44143
44233
  actions,
44144
- maxInlineActions,
44234
+ maxInlineActions = 2,
44145
44235
  backAction,
44146
44236
  footer,
44147
44237
  slideOver = false,
44238
+ showActions = true,
44148
44239
  className,
44149
44240
  entity,
44150
44241
  fields: propFields,
@@ -44192,9 +44283,6 @@ var init_DetailPanel = __esm({
44192
44283
  },
44193
44284
  [eventBus]
44194
44285
  );
44195
- const handleClose = useCallback(() => {
44196
- eventBus.emit("UI:CLOSE", {});
44197
- }, [eventBus]);
44198
44286
  const entityRecord = Array.isArray(entity) ? entity[0] : entity;
44199
44287
  const data = entityRecord ?? initialData;
44200
44288
  let title = propTitle;
@@ -44208,8 +44296,7 @@ var init_DetailPanel = __esm({
44208
44296
  const value = getNestedValue(normalizedData, field);
44209
44297
  return {
44210
44298
  label: labelFor(field),
44211
- value: formatFieldValue2(value, field),
44212
- icon: getFieldIcon(field)
44299
+ value: formatFieldValue2(value, field)
44213
44300
  };
44214
44301
  }
44215
44302
  return field;
@@ -44243,15 +44330,14 @@ var init_DetailPanel = __esm({
44243
44330
  (f3) => (!titleDerivedFromPrimary || f3 !== primaryField) && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
44244
44331
  );
44245
44332
  sections = [];
44246
- if (statusFields.length > 0 || otherFields.length > 0) {
44333
+ if (otherFields.length > 0) {
44247
44334
  const overviewFields = [];
44248
- [...statusFields, ...otherFields].forEach((field) => {
44335
+ otherFields.forEach((field) => {
44249
44336
  const value = getNestedValue(normalizedData, field);
44250
44337
  if (value !== void 0 && value !== null) {
44251
44338
  overviewFields.push({
44252
44339
  label: labelFor(field),
44253
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44254
- icon: getFieldIcon(field)
44340
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44255
44341
  });
44256
44342
  }
44257
44343
  });
@@ -44266,8 +44352,7 @@ var init_DetailPanel = __esm({
44266
44352
  if (value !== void 0 && value !== null) {
44267
44353
  metricsFields.push({
44268
44354
  label: labelFor(field),
44269
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44270
- icon: getFieldIcon(field)
44355
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44271
44356
  });
44272
44357
  }
44273
44358
  });
@@ -44282,8 +44367,7 @@ var init_DetailPanel = __esm({
44282
44367
  if (value !== void 0 && value !== null) {
44283
44368
  timelineFields.push({
44284
44369
  label: labelFor(field),
44285
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44286
- icon: getFieldIcon(field)
44370
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44287
44371
  });
44288
44372
  }
44289
44373
  });
@@ -44298,8 +44382,7 @@ var init_DetailPanel = __esm({
44298
44382
  if (value !== void 0 && value !== null) {
44299
44383
  descFields.push({
44300
44384
  label: labelFor(field),
44301
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44302
- icon: getFieldIcon(field)
44385
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44303
44386
  });
44304
44387
  }
44305
44388
  });
@@ -44308,6 +44391,15 @@ var init_DetailPanel = __esm({
44308
44391
  }
44309
44392
  }
44310
44393
  }
44394
+ const renderSlot = useRenderSlot();
44395
+ const navStack = useNavStack();
44396
+ const { setCurrentLabel } = navStack;
44397
+ const resolvedTitle = normalizedData ? title : void 0;
44398
+ useEffect(() => {
44399
+ if (renderSlot === "main" && !slideOver && resolvedTitle) {
44400
+ setCurrentLabel(resolvedTitle);
44401
+ }
44402
+ }, [renderSlot, slideOver, resolvedTitle, setCurrentLabel]);
44311
44403
  if (isLoading) {
44312
44404
  return /* @__PURE__ */ jsx(
44313
44405
  LoadingState,
@@ -44346,8 +44438,7 @@ var init_DetailPanel = __esm({
44346
44438
  const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
44347
44439
  allFields.push({
44348
44440
  label: labelFor(field),
44349
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44350
- icon: getFieldIcon(field)
44441
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44351
44442
  });
44352
44443
  } else {
44353
44444
  allFields.push(field);
@@ -44359,24 +44450,50 @@ var init_DetailPanel = __esm({
44359
44450
  (a) => a.event === "CLOSE" || a.event === "CANCEL" || a.label?.toLowerCase() === "close"
44360
44451
  );
44361
44452
  const otherActions = actions?.filter((a) => a !== closeAction) ?? [];
44362
- const effectiveCloseAction = closeAction ?? { event: void 0};
44363
- const content = /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
44364
- /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", gap: "xs", children: [
44365
- /* @__PURE__ */ jsx(HStack, { align: "center", gap: "xs", children: backAction && /* @__PURE__ */ jsx(
44366
- Button,
44453
+ const statusBadges = /* @__PURE__ */ jsxs(Fragment, { children: [
44454
+ normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
44455
+ (f3) => f3.toLowerCase().includes("status") || f3.toLowerCase().includes("priority")
44456
+ ).map((field) => {
44457
+ const value = getNestedValue(normalizedData, field);
44458
+ if (!value) return null;
44459
+ return /* @__PURE__ */ jsx(
44460
+ Badge,
44367
44461
  {
44368
- variant: backAction.variant || "ghost",
44369
- size: "sm",
44370
- action: backAction.navigatesTo ? void 0 : backAction.event,
44371
- actionPayload: { row: normalizedData },
44372
- onClick: backAction.navigatesTo ? () => handleActionClick(backAction, normalizedData) : void 0,
44373
- icon: backAction.icon ?? ArrowLeft,
44374
- "data-testid": backAction.event ? `action-${backAction.event}` : "action-back",
44375
- children: backAction.label
44376
- }
44377
- ) }),
44378
- /* @__PURE__ */ jsxs(HStack, { justify: "end", align: "center", gap: "xs", children: [
44379
- (maxInlineActions != null ? otherActions.slice(0, maxInlineActions) : otherActions).map((action, idx) => /* @__PURE__ */ jsx(
44462
+ variant: getBadgeVariant(field, String(value)),
44463
+ children: humanizeEnumValue(String(value))
44464
+ },
44465
+ field
44466
+ );
44467
+ }),
44468
+ status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
44469
+ ] });
44470
+ const content = /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
44471
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "start", gap: "md", children: [
44472
+ /* @__PURE__ */ jsxs(HStack, { align: "start", gap: "sm", className: "min-w-0", children: [
44473
+ backAction && /* @__PURE__ */ jsx(
44474
+ Button,
44475
+ {
44476
+ variant: backAction.variant || "ghost",
44477
+ size: "sm",
44478
+ action: backAction.navigatesTo ? void 0 : backAction.event,
44479
+ actionPayload: { row: normalizedData },
44480
+ onClick: backAction.navigatesTo ? () => handleActionClick(backAction, normalizedData) : void 0,
44481
+ icon: backAction.icon ?? ArrowLeft,
44482
+ "data-testid": backAction.event ? `action-${backAction.event}` : "action-back",
44483
+ children: backAction.label
44484
+ }
44485
+ ),
44486
+ avatar,
44487
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "min-w-0", children: [
44488
+ /* @__PURE__ */ jsxs(HStack, { align: "center", gap: "sm", wrap: true, children: [
44489
+ /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
44490
+ statusBadges
44491
+ ] }),
44492
+ subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle })
44493
+ ] })
44494
+ ] }),
44495
+ showActions && /* @__PURE__ */ jsxs(HStack, { justify: "end", align: "center", gap: "xs", className: "shrink-0", children: [
44496
+ otherActions.slice(0, maxInlineActions).map((action, idx) => /* @__PURE__ */ jsx(
44380
44497
  Button,
44381
44498
  {
44382
44499
  variant: action.variant || "secondary",
@@ -44391,7 +44508,7 @@ var init_DetailPanel = __esm({
44391
44508
  },
44392
44509
  idx
44393
44510
  )),
44394
- maxInlineActions != null && otherActions.length > maxInlineActions && /* @__PURE__ */ jsx(
44511
+ otherActions.length > maxInlineActions && /* @__PURE__ */ jsx(
44395
44512
  Menu,
44396
44513
  {
44397
44514
  position: "bottom-end",
@@ -44407,40 +44524,20 @@ var init_DetailPanel = __esm({
44407
44524
  }))
44408
44525
  }
44409
44526
  ),
44410
- /* @__PURE__ */ jsx(
44527
+ closeAction && /* @__PURE__ */ jsx(
44411
44528
  Button,
44412
44529
  {
44413
44530
  variant: "ghost",
44414
44531
  size: "sm",
44415
- action: effectiveCloseAction.event,
44532
+ action: closeAction.event,
44416
44533
  actionPayload: { row: normalizedData },
44417
- onClick: effectiveCloseAction.event ? void 0 : handleClose,
44534
+ onClick: closeAction.event ? void 0 : () => handleActionClick(closeAction, normalizedData),
44418
44535
  icon: X,
44419
- "data-testid": effectiveCloseAction.event ? `action-${effectiveCloseAction.event}` : "action-close"
44536
+ "data-testid": closeAction.event ? `action-${closeAction.event}` : "action-close"
44420
44537
  }
44421
44538
  )
44422
44539
  ] })
44423
44540
  ] }),
44424
- avatar,
44425
- /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
44426
- subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle }),
44427
- /* @__PURE__ */ jsxs(HStack, { gap: "xs", wrap: true, children: [
44428
- normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
44429
- (f3) => f3.toLowerCase().includes("status") || f3.toLowerCase().includes("priority")
44430
- ).map((field) => {
44431
- const value = getNestedValue(normalizedData, field);
44432
- if (!value) return null;
44433
- return /* @__PURE__ */ jsx(
44434
- Badge,
44435
- {
44436
- variant: getBadgeVariant(field, String(value)),
44437
- children: String(value)
44438
- },
44439
- field
44440
- );
44441
- }),
44442
- status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
44443
- ] }),
44444
44541
  normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
44445
44542
  (f3) => f3.toLowerCase().includes("progress") || f3.toLowerCase().includes("percent")
44446
44543
  ).map((field) => {
@@ -44473,9 +44570,10 @@ var init_DetailPanel = __esm({
44473
44570
  /* @__PURE__ */ jsx(
44474
44571
  Typography,
44475
44572
  {
44476
- variant: "small",
44477
- color: "secondary",
44573
+ variant: "caption",
44574
+ color: "muted",
44478
44575
  weight: "medium",
44576
+ className: "uppercase tracking-wider",
44479
44577
  children: field.label
44480
44578
  }
44481
44579
  ),
@@ -44544,7 +44642,7 @@ var init_DrawerSlot = __esm({
44544
44642
  position,
44545
44643
  width: size,
44546
44644
  className,
44547
- children
44645
+ children: /* @__PURE__ */ jsx(RenderSlotProvider, { slot: "drawer", children })
44548
44646
  }
44549
44647
  );
44550
44648
  };
@@ -46591,7 +46689,7 @@ var init_ModalSlot = __esm({
46591
46689
  title,
46592
46690
  size,
46593
46691
  className,
46594
- children
46692
+ children: /* @__PURE__ */ jsx(RenderSlotProvider, { slot: "modal", children })
46595
46693
  }
46596
46694
  );
46597
46695
  };
@@ -51013,7 +51111,10 @@ function MaybeTraitScope({
51013
51111
  }
51014
51112
  return /* @__PURE__ */ jsx(Fragment, { children });
51015
51113
  }
51016
- function UISlotComponent({
51114
+ function UISlotComponent(props) {
51115
+ return /* @__PURE__ */ jsx(RenderSlotProvider, { slot: props.slot, children: /* @__PURE__ */ jsx(UISlotComponentInner, { ...props }) });
51116
+ }
51117
+ function UISlotComponentInner({
51017
51118
  slot,
51018
51119
  portal = false,
51019
51120
  position,