@almadar/ui 5.155.0 → 5.157.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.
@@ -11609,10 +11609,21 @@ function ControlGrid({
11609
11609
  directionAssets,
11610
11610
  size = "md",
11611
11611
  disabled,
11612
+ visibility = "auto",
11612
11613
  className
11613
11614
  }) {
11614
11615
  const eventBus = useEventBus();
11615
11616
  const [active, setActive] = React94__namespace.useState(/* @__PURE__ */ new Set());
11617
+ const [coarse, setCoarse] = React94__namespace.useState(
11618
+ () => typeof window !== "undefined" && window.matchMedia("(pointer: coarse)").matches
11619
+ );
11620
+ React94__namespace.useEffect(() => {
11621
+ if (visibility !== "auto" || typeof window === "undefined") return;
11622
+ const mq = window.matchMedia("(pointer: coarse)");
11623
+ const onChange = (e) => setCoarse(e.matches);
11624
+ mq.addEventListener("change", onChange);
11625
+ return () => mq.removeEventListener("change", onChange);
11626
+ }, [visibility]);
11616
11627
  const handlePress = React94__namespace.useCallback(
11617
11628
  (id) => {
11618
11629
  setActive((prev) => new Set(prev).add(id));
@@ -11645,6 +11656,7 @@ function ControlGrid({
11645
11656
  },
11646
11657
  [kind, actionEvent, directionEvent, directionReleaseEvents, eventBus, onAction, onDirection]
11647
11658
  );
11659
+ if (visibility === "auto" && !coarse) return null;
11648
11660
  if (kind === "dpad") {
11649
11661
  const ds = dpadSizeMap[size];
11650
11662
  const dir = (d) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -11794,7 +11806,7 @@ function StatBadge({
11794
11806
  assetUrl,
11795
11807
  iconUrl,
11796
11808
  label,
11797
- value = 0,
11809
+ value,
11798
11810
  max,
11799
11811
  format = "number",
11800
11812
  icon,
@@ -11805,6 +11817,7 @@ function StatBadge({
11805
11817
  source: _source,
11806
11818
  field: _field
11807
11819
  }) {
11820
+ const hasValue = value !== void 0 && value !== null;
11808
11821
  const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
11809
11822
  const resolvedAsset = iconUrl ?? assetUrl;
11810
11823
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -11818,8 +11831,8 @@ function StatBadge({
11818
11831
  ),
11819
11832
  children: [
11820
11833
  resolvedAsset ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: resolvedAsset, icon: "image", size: 16, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(Box, { as: "span", className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, className: "w-4 h-4" }) }) : null,
11821
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", className: "text-muted-foreground font-medium", children: label }),
11822
- format === "hearts" && max && /* @__PURE__ */ jsxRuntime.jsx(
11834
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", className: "text-muted-foreground font-medium text-xs", children: label }),
11835
+ hasValue && format === "hearts" && max && /* @__PURE__ */ jsxRuntime.jsx(
11823
11836
  HealthBar,
11824
11837
  {
11825
11838
  current: numValue,
@@ -11828,7 +11841,7 @@ function StatBadge({
11828
11841
  size: size === "lg" ? "md" : "sm"
11829
11842
  }
11830
11843
  ),
11831
- format === "bar" && max && /* @__PURE__ */ jsxRuntime.jsx(
11844
+ hasValue && format === "bar" && max && /* @__PURE__ */ jsxRuntime.jsx(
11832
11845
  HealthBar,
11833
11846
  {
11834
11847
  current: numValue,
@@ -11837,14 +11850,15 @@ function StatBadge({
11837
11850
  size: size === "lg" ? "md" : "sm"
11838
11851
  }
11839
11852
  ),
11840
- format === "number" && /* @__PURE__ */ jsxRuntime.jsx(
11853
+ hasValue && format === "number" && /* @__PURE__ */ jsxRuntime.jsx(
11841
11854
  ScoreDisplay,
11842
11855
  {
11843
11856
  value: numValue,
11844
- size: size === "lg" ? "md" : "sm"
11857
+ size: size === "lg" ? "md" : "sm",
11858
+ className: "font-display"
11845
11859
  }
11846
11860
  ),
11847
- format === "text" && /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", className: "font-bold text-foreground", children: value })
11861
+ hasValue && format === "text" && /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", className: "font-bold text-foreground", children: value })
11848
11862
  ]
11849
11863
  }
11850
11864
  );
@@ -11860,6 +11874,7 @@ var init_StatBadge = __esm({
11860
11874
  init_HealthBar();
11861
11875
  init_ScoreDisplay();
11862
11876
  sizeMap6 = {
11877
+ xs: "text-xs px-1.5 py-0.5",
11863
11878
  sm: "text-xs px-2 py-1",
11864
11879
  md: "text-sm px-3 py-1.5",
11865
11880
  lg: "text-base px-4 py-2"
@@ -11902,6 +11917,7 @@ function GameHud({
11902
11917
  items,
11903
11918
  elements,
11904
11919
  size = "md",
11920
+ variant = "floating",
11905
11921
  className,
11906
11922
  transparent = true
11907
11923
  }) {
@@ -11916,7 +11932,7 @@ function GameHud({
11916
11932
  /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(StatBadge, { ...stat, size }, i)) })
11917
11933
  ] });
11918
11934
  }
11919
- if (position === "top" || position === "bottom") {
11935
+ if ((position === "top" || position === "bottom") && variant === "bar") {
11920
11936
  const mid = Math.ceil(stats.length / 2);
11921
11937
  const leftStats = stats.slice(0, mid);
11922
11938
  const rightStats = stats.slice(mid);
@@ -15137,7 +15153,7 @@ var init_StateJsonView = __esm({
15137
15153
  StateJsonView.displayName = "StateJsonView";
15138
15154
  }
15139
15155
  });
15140
- var FONT_BASE, GAME_FONTS, FONT_FACES, GameShell;
15156
+ var GAME_FONTS, GameShell;
15141
15157
  var init_GameShell = __esm({
15142
15158
  "components/game/templates/GameShell.tsx"() {
15143
15159
  init_cn();
@@ -15145,7 +15161,6 @@ var init_GameShell = __esm({
15145
15161
  init_Card();
15146
15162
  init_Typography();
15147
15163
  init_AtlasImage();
15148
- FONT_BASE = "https://almadar-kflow-assets.web.app/shared/_shared/kenney-fonts/fonts";
15149
15164
  GAME_FONTS = {
15150
15165
  future: "Kenney Future",
15151
15166
  "future-narrow": "Kenney Future Narrow",
@@ -15153,14 +15168,6 @@ var init_GameShell = __esm({
15153
15168
  blocks: "Kenney Blocks",
15154
15169
  mini: "Kenney Mini"
15155
15170
  };
15156
- FONT_FACES = `
15157
- @font-face { font-family: 'Kenney Future'; src: url('${FONT_BASE}/Kenney%20Future.ttf') format('truetype'); font-display: swap; }
15158
- @font-face { font-family: 'Kenney Future Narrow'; src: url('${FONT_BASE}/Kenney%20Future%20Narrow.ttf') format('truetype'); font-display: swap; }
15159
- @font-face { font-family: 'Kenney Pixel'; src: url('${FONT_BASE}/Kenney%20Pixel.ttf') format('truetype'); font-display: swap; }
15160
- @font-face { font-family: 'Kenney Blocks'; src: url('${FONT_BASE}/Kenney%20Blocks.ttf') format('truetype'); font-display: swap; }
15161
- @font-face { font-family: 'Kenney Mini'; src: url('${FONT_BASE}/Kenney%20Mini.ttf') format('truetype'); font-display: swap; }
15162
- .game-shell, .game-shell * { font-family: inherit; }
15163
- `;
15164
15171
  GameShell = ({
15165
15172
  appName = "Game",
15166
15173
  hud,
@@ -15187,10 +15194,12 @@ var init_GameShell = __esm({
15187
15194
  overflow: "hidden",
15188
15195
  background: "var(--color-background, #0a0a0f)",
15189
15196
  color: "var(--color-foreground, #e0e0e0)",
15190
- fontFamily: `'${font}', system-ui, sans-serif`
15197
+ // The fontFamily knob is a scoped override of the theme contract's
15198
+ // display slot: titles/numerics take the game face, body text keeps
15199
+ // the active theme's --font-family-body.
15200
+ "--font-family-display": `'${font}', ui-sans-serif, system-ui, sans-serif`
15191
15201
  },
15192
15202
  children: [
15193
- /* @__PURE__ */ jsxRuntime.jsx("style", { children: FONT_FACES }),
15194
15203
  backgroundAsset && /* @__PURE__ */ jsxRuntime.jsx(
15195
15204
  AtlasPanel,
15196
15205
  {
@@ -15228,6 +15237,7 @@ var init_GameShell = __esm({
15228
15237
  Typography,
15229
15238
  {
15230
15239
  as: "span",
15240
+ className: "font-display",
15231
15241
  style: {
15232
15242
  fontWeight: 700,
15233
15243
  fontSize: "1.05rem",
@@ -15308,6 +15318,11 @@ var init_molecules = __esm({
15308
15318
  init_puzzleObject();
15309
15319
  }
15310
15320
  });
15321
+ function themeBodyFont(el) {
15322
+ if (typeof getComputedStyle !== "function") return "system-ui, sans-serif";
15323
+ const v = getComputedStyle(el).getPropertyValue("--font-family-body").trim();
15324
+ return v || "system-ui, sans-serif";
15325
+ }
15311
15326
  function resolveColor2(color, ctx, fallback) {
15312
15327
  if (!color) return fallback;
15313
15328
  if (color.startsWith("var(")) {
@@ -15496,6 +15511,8 @@ function drawShape(ctx, shape, width, height, allShapes) {
15496
15511
  case "path": {
15497
15512
  if (!shape.path) break;
15498
15513
  const p = new Path2D(shape.path);
15514
+ ctx.lineJoin = "round";
15515
+ ctx.lineCap = "round";
15499
15516
  if (fill) {
15500
15517
  ctx.fillStyle = fill;
15501
15518
  ctx.fill(p);
@@ -15507,7 +15524,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
15507
15524
  case "text": {
15508
15525
  if (shape.x == null || shape.y == null || !shape.text) break;
15509
15526
  ctx.fillStyle = stroke;
15510
- ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
15527
+ ctx.font = `${shape.fontSize ?? 14}px ${themeBodyFont(ctx.canvas)}`;
15511
15528
  ctx.textAlign = shape.align ?? "left";
15512
15529
  ctx.textBaseline = "middle";
15513
15530
  ctx.fillText(shape.text, shape.x, shape.y);
@@ -15704,7 +15721,7 @@ var init_LearningCanvas = __esm({
15704
15721
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
15705
15722
  ctx.clearRect(0, 0, width, height);
15706
15723
  if (backgroundColor) {
15707
- ctx.fillStyle = backgroundColor;
15724
+ ctx.fillStyle = resolveColor2(backgroundColor, ctx, backgroundColor);
15708
15725
  ctx.fillRect(0, 0, width, height);
15709
15726
  }
15710
15727
  for (const shape of derivedShapes) {
@@ -24031,7 +24048,22 @@ function eventStartDate(event, startField) {
24031
24048
  const raw = getNestedValue(event, startField);
24032
24049
  return new Date(raw ?? "");
24033
24050
  }
24034
- function generateDefaultTimeSlots(events2, startField) {
24051
+ function eventEndDate(event, endField) {
24052
+ const raw = getNestedValue(event, endField);
24053
+ if (raw === void 0 || raw === null || raw === "") return null;
24054
+ const end = new Date(raw);
24055
+ return Number.isNaN(end.getTime()) ? null : end;
24056
+ }
24057
+ function eventContinuesInSlot(event, day, slotTime, startField, endField) {
24058
+ const eventStart = eventStartDate(event, startField);
24059
+ const eventEnd = eventEndDate(event, endField);
24060
+ if (eventEnd === null || Number.isNaN(eventStart.getTime())) return false;
24061
+ const [slotHour] = slotTime.split(":").map(Number);
24062
+ const slotStart = new Date(day);
24063
+ slotStart.setHours(slotHour, 0, 0, 0);
24064
+ return slotStart.getTime() > eventStart.getTime() && slotStart.getTime() < eventEnd.getTime();
24065
+ }
24066
+ function generateDefaultTimeSlots(events2, startField, endField) {
24035
24067
  let first = DEFAULT_FIRST_HOUR;
24036
24068
  let last = DEFAULT_LAST_HOUR;
24037
24069
  for (const ev of events2) {
@@ -24040,6 +24072,11 @@ function generateDefaultTimeSlots(events2, startField) {
24040
24072
  const hour = start.getHours();
24041
24073
  if (hour < first) first = hour;
24042
24074
  if (hour > last) last = hour;
24075
+ const end = eventEndDate(ev, endField);
24076
+ if (end && end.toDateString() === start.toDateString()) {
24077
+ const endHour = end.getMinutes() === 0 && end.getSeconds() === 0 ? end.getHours() - 1 : end.getHours();
24078
+ if (endHour > last) last = endHour;
24079
+ }
24043
24080
  }
24044
24081
  const slots = [];
24045
24082
  for (let hour = first; hour <= last; hour++) {
@@ -24068,6 +24105,7 @@ function CalendarGrid({
24068
24105
  dayWindow = "auto",
24069
24106
  titleField = "title",
24070
24107
  startField = "startTime",
24108
+ endField = "endTime",
24071
24109
  colorField = "color",
24072
24110
  children,
24073
24111
  renderItem
@@ -24085,8 +24123,8 @@ function CalendarGrid({
24085
24123
  [resolvedWeekStart]
24086
24124
  );
24087
24125
  const resolvedTimeSlots = React94.useMemo(
24088
- () => timeSlots ?? generateDefaultTimeSlots(evs, startField),
24089
- [timeSlots, evs, startField]
24126
+ () => timeSlots ?? generateDefaultTimeSlots(evs, startField, endField),
24127
+ [timeSlots, evs, startField, endField]
24090
24128
  );
24091
24129
  const visibleCount = useDayWindow(dayWindow);
24092
24130
  const [dayOffset, setDayOffset] = React94.useState(0);
@@ -24246,12 +24284,15 @@ function CalendarGrid({
24246
24284
  const slotEvents = evs.filter(
24247
24285
  (ev) => eventInSlot(ev, day, time, startField)
24248
24286
  );
24287
+ const continuingEvents = evs.filter(
24288
+ (ev) => eventContinuesInSlot(ev, day, time, startField, endField)
24289
+ );
24249
24290
  const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
24250
24291
  return /* @__PURE__ */ jsxRuntime.jsx(
24251
24292
  TimeSlotCell,
24252
24293
  {
24253
24294
  time,
24254
- isOccupied: slotEvents.length > 0,
24295
+ isOccupied: slotEvents.length > 0 || continuingEvents.length > 0,
24255
24296
  onClick: () => handleSlotClick(day, time),
24256
24297
  className: cn(
24257
24298
  "border-l border-border",
@@ -24262,7 +24303,25 @@ function CalendarGrid({
24262
24303
  onPointerUp: clearLongPress,
24263
24304
  onPointerCancel: clearLongPress
24264
24305
  } : {},
24265
- children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "xs", children: slotEvents.map(renderEvent) })
24306
+ children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
24307
+ slotEvents.map(renderEvent),
24308
+ continuingEvents.map((event) => {
24309
+ const color = getNestedValue(event, colorField);
24310
+ return /* @__PURE__ */ jsxRuntime.jsx(
24311
+ Box,
24312
+ {
24313
+ rounded: "sm",
24314
+ border: true,
24315
+ className: cn(
24316
+ "cursor-pointer h-2",
24317
+ color ? cn(color, "opacity-50") : "bg-primary/10 border-primary/20"
24318
+ ),
24319
+ onClick: (e) => handleEventClick(event, e)
24320
+ },
24321
+ `${event.id}-cont`
24322
+ );
24323
+ })
24324
+ ] })
24266
24325
  },
24267
24326
  `${day.toISOString()}-${time}`
24268
24327
  );
@@ -32788,6 +32847,9 @@ var init_MathCanvas = __esm({
32788
32847
  showAxes = true,
32789
32848
  showGrid = true,
32790
32849
  gridStep = 1,
32850
+ backgroundColor,
32851
+ gridColor = "var(--color-border, #9ca3af)",
32852
+ axisColor = "var(--color-muted-foreground, #374151)",
32791
32853
  showTickLabels = false,
32792
32854
  showCurveLabels = false,
32793
32855
  curves = [],
@@ -32842,11 +32904,11 @@ var init_MathCanvas = __esm({
32842
32904
  if (showGrid) {
32843
32905
  for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep) {
32844
32906
  const px = mapX(x);
32845
- out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#9ca3af", opacity: 0.35, lineWidth: 1 });
32907
+ out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: gridColor, opacity: 0.35, lineWidth: 1 });
32846
32908
  }
32847
32909
  for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep) {
32848
32910
  const py = mapY(y);
32849
- out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#9ca3af", opacity: 0.35, lineWidth: 1 });
32911
+ out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: gridColor, opacity: 0.35, lineWidth: 1 });
32850
32912
  }
32851
32913
  }
32852
32914
  if (showTickLabels) {
@@ -32917,8 +32979,8 @@ var init_MathCanvas = __esm({
32917
32979
  });
32918
32980
  }
32919
32981
  if (showAxes) {
32920
- out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: "#374151", lineWidth: 2 });
32921
- out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: "#374151", lineWidth: 2 });
32982
+ out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: axisColor, lineWidth: 2 });
32983
+ out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: axisColor, lineWidth: 2 });
32922
32984
  }
32923
32985
  for (const guide of guides) {
32924
32986
  const color = guide.color ?? "#9ca3af";
@@ -32941,23 +33003,36 @@ var init_MathCanvas = __esm({
32941
33003
  }
32942
33004
  for (const curve of curves) {
32943
33005
  if (!curve.samples || curve.samples.length < 2) continue;
33006
+ let d = "";
33007
+ let penDown = false;
32944
33008
  let lastInRange;
32945
33009
  for (let i = 1; i < curve.samples.length; i++) {
32946
33010
  const a = curve.samples[i - 1];
32947
33011
  const b = curve.samples[i];
32948
- if (a.x < xMin || a.x > xMax || b.x < xMin || b.x > xMax) continue;
32949
- out.push({
32950
- type: "line",
32951
- x1: mapX(a.x),
32952
- y1: mapY(a.y),
32953
- x2: mapX(b.x),
32954
- y2: mapY(b.y),
32955
- color: curve.color ?? "#2563eb",
32956
- lineWidth: 2,
32957
- dash: curve.dash
32958
- });
32959
- lastInRange = b;
32960
- }
33012
+ if (a.x < xMin && b.x < xMin || a.x > xMax && b.x > xMax) {
33013
+ penDown = false;
33014
+ continue;
33015
+ }
33016
+ const clip = (p, q, xLim) => {
33017
+ const t = q.x === p.x ? 0 : (xLim - p.x) / (q.x - p.x);
33018
+ return { x: xLim, y: p.y + t * (q.y - p.y) };
33019
+ };
33020
+ const ca = a.x < xMin ? clip(a, b, xMin) : a.x > xMax ? clip(a, b, xMax) : a;
33021
+ const cb = b.x < xMin ? clip(a, b, xMin) : b.x > xMax ? clip(a, b, xMax) : b;
33022
+ const pax = mapX(ca.x);
33023
+ const pay = mapY(ca.y);
33024
+ d += `${penDown ? "L" : "M"} ${pax} ${pay} L ${mapX(cb.x)} ${mapY(cb.y)} `;
33025
+ penDown = true;
33026
+ if (b.x >= xMin && b.x <= xMax) lastInRange = b;
33027
+ }
33028
+ if (!d) continue;
33029
+ out.push({
33030
+ type: "path",
33031
+ path: d,
33032
+ color: curve.color ?? "#2563eb",
33033
+ lineWidth: 2,
33034
+ dash: curve.dash
33035
+ });
32961
33036
  if (showCurveLabels && curve.label && lastInRange) {
32962
33037
  out.push({
32963
33038
  type: "text",
@@ -33072,6 +33147,8 @@ var init_MathCanvas = __esm({
33072
33147
  showAxes,
33073
33148
  showGrid,
33074
33149
  gridStep,
33150
+ gridColor,
33151
+ axisColor,
33075
33152
  showTickLabels,
33076
33153
  showCurveLabels,
33077
33154
  curves,
@@ -33091,6 +33168,7 @@ var init_MathCanvas = __esm({
33091
33168
  {
33092
33169
  width,
33093
33170
  height,
33171
+ backgroundColor,
33094
33172
  shapes: derivedShapes,
33095
33173
  readouts,
33096
33174
  traces,
@@ -34321,13 +34399,13 @@ var init_MapView = __esm({
34321
34399
  shadowSize: [41, 41]
34322
34400
  });
34323
34401
  L.Marker.prototype.options.icon = defaultIcon;
34324
- const { useEffect: useEffect65, useRef: useRef65, useCallback: useCallback96, useState: useState100 } = React94__namespace.default;
34402
+ const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback96, useState: useState100 } = React94__namespace.default;
34325
34403
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
34326
34404
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
34327
34405
  function MapUpdater({ centerLat, centerLng, zoom }) {
34328
34406
  const map = useMap();
34329
34407
  const prevRef = useRef65({ centerLat, centerLng, zoom });
34330
- useEffect65(() => {
34408
+ useEffect67(() => {
34331
34409
  const prev = prevRef.current;
34332
34410
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
34333
34411
  map.setView([centerLat, centerLng], zoom);
@@ -34338,7 +34416,7 @@ var init_MapView = __esm({
34338
34416
  }
34339
34417
  function MapClickHandler({ onMapClick }) {
34340
34418
  const map = useMap();
34341
- useEffect65(() => {
34419
+ useEffect67(() => {
34342
34420
  if (!onMapClick) return;
34343
34421
  const handler = (e) => {
34344
34422
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -34867,14 +34945,34 @@ var init_UploadDropZone = __esm({
34867
34945
  if (valid.length > 0) {
34868
34946
  onFiles?.(valid);
34869
34947
  if (action) {
34870
- eventBus.emit(`UI:${action}`, {
34871
- ...actionPayload,
34872
- files: valid.map((f3) => ({ name: f3.name, size: f3.size, type: f3.type }))
34948
+ void Promise.all(
34949
+ valid.map(
34950
+ (f3) => new Promise(
34951
+ (resolvePayload, rejectPayload) => {
34952
+ const reader = new FileReader();
34953
+ reader.onload = () => resolvePayload({
34954
+ name: f3.name,
34955
+ size: f3.size,
34956
+ type: f3.type,
34957
+ content: String(reader.result ?? "")
34958
+ });
34959
+ reader.onerror = () => rejectPayload(reader.error);
34960
+ reader.readAsDataURL(f3);
34961
+ }
34962
+ )
34963
+ )
34964
+ ).then((payloadFiles) => {
34965
+ eventBus.emit(`UI:${action}`, {
34966
+ ...actionPayload,
34967
+ files: payloadFiles
34968
+ });
34969
+ }).catch(() => {
34970
+ setError(t("Could not read the selected file"));
34873
34971
  });
34874
34972
  }
34875
34973
  }
34876
34974
  },
34877
- [validateFiles, onFiles, action, actionPayload, eventBus]
34975
+ [validateFiles, onFiles, action, actionPayload, eventBus, t]
34878
34976
  );
34879
34977
  const handleDragOver = (e) => {
34880
34978
  e.preventDefault();
@@ -43982,22 +44080,6 @@ var init_DataTable = __esm({
43982
44080
  DataTable.displayName = "DataTable";
43983
44081
  }
43984
44082
  });
43985
- function getFieldIcon(fieldName) {
43986
- const name = fieldName.toLowerCase();
43987
- if (name.includes("date") || name.includes("time")) return LucideIcons2.Calendar;
43988
- if (name.includes("status")) return LucideIcons2.Tag;
43989
- if (name.includes("priority")) return LucideIcons2.AlertCircle;
43990
- if (name.includes("progress") || name.includes("percent")) return LucideIcons2.TrendingUp;
43991
- if (name.includes("assignee") || name.includes("owner") || name.includes("user") || name.includes("member"))
43992
- return LucideIcons2.User;
43993
- if (name.includes("due")) return LucideIcons2.Clock;
43994
- if (name.includes("complete")) return LucideIcons2.CheckCircle2;
43995
- if (name.includes("budget") || name.includes("cost") || name.includes("price"))
43996
- return LucideIcons2.DollarSign;
43997
- if (name.includes("description") || name.includes("note") || name.includes("comment"))
43998
- return LucideIcons2.FileText;
43999
- return LucideIcons2.Package;
44000
- }
44001
44083
  function getBadgeVariant(fieldName, value) {
44002
44084
  const name = fieldName.toLowerCase();
44003
44085
  const val = String(value).toLowerCase();
@@ -44047,6 +44129,18 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
44047
44129
  }
44048
44130
  ) });
44049
44131
  }
44132
+ if (fieldType === "url" && /^https?:\/\//i.test(str)) {
44133
+ return /* @__PURE__ */ jsxRuntime.jsx(
44134
+ "a",
44135
+ {
44136
+ href: str,
44137
+ target: "_blank",
44138
+ rel: "noreferrer",
44139
+ className: "text-primary hover:underline break-all",
44140
+ children: str
44141
+ }
44142
+ );
44143
+ }
44050
44144
  return str;
44051
44145
  }
44052
44146
  case "markdown":
@@ -44145,6 +44239,23 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
44145
44239
  }
44146
44240
  return str;
44147
44241
  }
44242
+ case "boolean": {
44243
+ if (typeof value === "boolean") return value ? "Yes" : "No";
44244
+ if (str === "true") return "Yes";
44245
+ if (str === "false") return "No";
44246
+ return str;
44247
+ }
44248
+ case "array": {
44249
+ if (Array.isArray(value) && value.length > 0) {
44250
+ return /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", children: String(item) }, i)) });
44251
+ }
44252
+ if (Array.isArray(value)) return "\u2014";
44253
+ return str;
44254
+ }
44255
+ case "email":
44256
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href: `mailto:${str}`, className: "text-primary hover:underline break-all", children: str });
44257
+ case "phone":
44258
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href: `tel:${str}`, className: "text-primary hover:underline", children: str });
44148
44259
  default:
44149
44260
  if (meta?.values && meta.values.length > 0 && meta.values.includes(str)) {
44150
44261
  return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: getBadgeVariant(fieldName, str), children: humanizeEnumValue(str) });
@@ -44217,10 +44328,11 @@ var init_DetailPanel = __esm({
44217
44328
  avatar,
44218
44329
  sections: propSections,
44219
44330
  actions,
44220
- maxInlineActions,
44331
+ maxInlineActions = 2,
44221
44332
  backAction,
44222
44333
  footer,
44223
44334
  slideOver = false,
44335
+ showActions = true,
44224
44336
  className,
44225
44337
  entity,
44226
44338
  fields: propFields,
@@ -44268,9 +44380,6 @@ var init_DetailPanel = __esm({
44268
44380
  },
44269
44381
  [eventBus]
44270
44382
  );
44271
- const handleClose = React94.useCallback(() => {
44272
- eventBus.emit("UI:CLOSE", {});
44273
- }, [eventBus]);
44274
44383
  const entityRecord = Array.isArray(entity) ? entity[0] : entity;
44275
44384
  const data = entityRecord ?? initialData;
44276
44385
  let title = propTitle;
@@ -44284,8 +44393,7 @@ var init_DetailPanel = __esm({
44284
44393
  const value = getNestedValue(normalizedData, field);
44285
44394
  return {
44286
44395
  label: labelFor(field),
44287
- value: formatFieldValue2(value, field),
44288
- icon: getFieldIcon(field)
44396
+ value: formatFieldValue2(value, field)
44289
44397
  };
44290
44398
  }
44291
44399
  return field;
@@ -44319,15 +44427,14 @@ var init_DetailPanel = __esm({
44319
44427
  (f3) => (!titleDerivedFromPrimary || f3 !== primaryField) && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
44320
44428
  );
44321
44429
  sections = [];
44322
- if (statusFields.length > 0 || otherFields.length > 0) {
44430
+ if (otherFields.length > 0) {
44323
44431
  const overviewFields = [];
44324
- [...statusFields, ...otherFields].forEach((field) => {
44432
+ otherFields.forEach((field) => {
44325
44433
  const value = getNestedValue(normalizedData, field);
44326
44434
  if (value !== void 0 && value !== null) {
44327
44435
  overviewFields.push({
44328
44436
  label: labelFor(field),
44329
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44330
- icon: getFieldIcon(field)
44437
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44331
44438
  });
44332
44439
  }
44333
44440
  });
@@ -44342,8 +44449,7 @@ var init_DetailPanel = __esm({
44342
44449
  if (value !== void 0 && value !== null) {
44343
44450
  metricsFields.push({
44344
44451
  label: labelFor(field),
44345
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44346
- icon: getFieldIcon(field)
44452
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44347
44453
  });
44348
44454
  }
44349
44455
  });
@@ -44358,8 +44464,7 @@ var init_DetailPanel = __esm({
44358
44464
  if (value !== void 0 && value !== null) {
44359
44465
  timelineFields.push({
44360
44466
  label: labelFor(field),
44361
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44362
- icon: getFieldIcon(field)
44467
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44363
44468
  });
44364
44469
  }
44365
44470
  });
@@ -44374,8 +44479,7 @@ var init_DetailPanel = __esm({
44374
44479
  if (value !== void 0 && value !== null) {
44375
44480
  descFields.push({
44376
44481
  label: labelFor(field),
44377
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44378
- icon: getFieldIcon(field)
44482
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44379
44483
  });
44380
44484
  }
44381
44485
  });
@@ -44384,6 +44488,15 @@ var init_DetailPanel = __esm({
44384
44488
  }
44385
44489
  }
44386
44490
  }
44491
+ const renderSlot = providers.useRenderSlot();
44492
+ const navStack = providers.useNavStack();
44493
+ const { setCurrentLabel } = navStack;
44494
+ const resolvedTitle = normalizedData ? title : void 0;
44495
+ React94.useEffect(() => {
44496
+ if (renderSlot === "main" && !slideOver && resolvedTitle) {
44497
+ setCurrentLabel(resolvedTitle);
44498
+ }
44499
+ }, [renderSlot, slideOver, resolvedTitle, setCurrentLabel]);
44387
44500
  if (isLoading) {
44388
44501
  return /* @__PURE__ */ jsxRuntime.jsx(
44389
44502
  LoadingState,
@@ -44422,8 +44535,7 @@ var init_DetailPanel = __esm({
44422
44535
  const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
44423
44536
  allFields.push({
44424
44537
  label: labelFor(field),
44425
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
44426
- icon: getFieldIcon(field)
44538
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
44427
44539
  });
44428
44540
  } else {
44429
44541
  allFields.push(field);
@@ -44435,24 +44547,50 @@ var init_DetailPanel = __esm({
44435
44547
  (a) => a.event === "CLOSE" || a.event === "CANCEL" || a.label?.toLowerCase() === "close"
44436
44548
  );
44437
44549
  const otherActions = actions?.filter((a) => a !== closeAction) ?? [];
44438
- const effectiveCloseAction = closeAction ?? { event: void 0};
44439
- const content = /* @__PURE__ */ jsxRuntime.jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", className: "p-6", children: [
44440
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "center", gap: "xs", children: [
44441
- /* @__PURE__ */ jsxRuntime.jsx(HStack, { align: "center", gap: "xs", children: backAction && /* @__PURE__ */ jsxRuntime.jsx(
44442
- Button,
44550
+ const statusBadges = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
44551
+ normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
44552
+ (f3) => f3.toLowerCase().includes("status") || f3.toLowerCase().includes("priority")
44553
+ ).map((field) => {
44554
+ const value = getNestedValue(normalizedData, field);
44555
+ if (!value) return null;
44556
+ return /* @__PURE__ */ jsxRuntime.jsx(
44557
+ Badge,
44443
44558
  {
44444
- variant: backAction.variant || "ghost",
44445
- size: "sm",
44446
- action: backAction.navigatesTo ? void 0 : backAction.event,
44447
- actionPayload: { row: normalizedData },
44448
- onClick: backAction.navigatesTo ? () => handleActionClick(backAction, normalizedData) : void 0,
44449
- icon: backAction.icon ?? LucideIcons2.ArrowLeft,
44450
- "data-testid": backAction.event ? `action-${backAction.event}` : "action-back",
44451
- children: backAction.label
44452
- }
44453
- ) }),
44454
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "end", align: "center", gap: "xs", children: [
44455
- (maxInlineActions != null ? otherActions.slice(0, maxInlineActions) : otherActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
44559
+ variant: getBadgeVariant(field, String(value)),
44560
+ children: humanizeEnumValue(String(value))
44561
+ },
44562
+ field
44563
+ );
44564
+ }),
44565
+ status && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: status.variant ?? "default", children: status.label })
44566
+ ] });
44567
+ const content = /* @__PURE__ */ jsxRuntime.jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", className: "p-6", children: [
44568
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "start", gap: "md", children: [
44569
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", gap: "sm", className: "min-w-0", children: [
44570
+ backAction && /* @__PURE__ */ jsxRuntime.jsx(
44571
+ Button,
44572
+ {
44573
+ variant: backAction.variant || "ghost",
44574
+ size: "sm",
44575
+ action: backAction.navigatesTo ? void 0 : backAction.event,
44576
+ actionPayload: { row: normalizedData },
44577
+ onClick: backAction.navigatesTo ? () => handleActionClick(backAction, normalizedData) : void 0,
44578
+ icon: backAction.icon ?? LucideIcons2.ArrowLeft,
44579
+ "data-testid": backAction.event ? `action-${backAction.event}` : "action-back",
44580
+ children: backAction.label
44581
+ }
44582
+ ),
44583
+ avatar,
44584
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "min-w-0", children: [
44585
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "center", gap: "sm", wrap: true, children: [
44586
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
44587
+ statusBadges
44588
+ ] }),
44589
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: subtitle })
44590
+ ] })
44591
+ ] }),
44592
+ showActions && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "end", align: "center", gap: "xs", className: "shrink-0", children: [
44593
+ otherActions.slice(0, maxInlineActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
44456
44594
  Button,
44457
44595
  {
44458
44596
  variant: action.variant || "secondary",
@@ -44467,7 +44605,7 @@ var init_DetailPanel = __esm({
44467
44605
  },
44468
44606
  idx
44469
44607
  )),
44470
- maxInlineActions != null && otherActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
44608
+ otherActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
44471
44609
  Menu,
44472
44610
  {
44473
44611
  position: "bottom-end",
@@ -44483,40 +44621,20 @@ var init_DetailPanel = __esm({
44483
44621
  }))
44484
44622
  }
44485
44623
  ),
44486
- /* @__PURE__ */ jsxRuntime.jsx(
44624
+ closeAction && /* @__PURE__ */ jsxRuntime.jsx(
44487
44625
  Button,
44488
44626
  {
44489
44627
  variant: "ghost",
44490
44628
  size: "sm",
44491
- action: effectiveCloseAction.event,
44629
+ action: closeAction.event,
44492
44630
  actionPayload: { row: normalizedData },
44493
- onClick: effectiveCloseAction.event ? void 0 : handleClose,
44631
+ onClick: closeAction.event ? void 0 : () => handleActionClick(closeAction, normalizedData),
44494
44632
  icon: LucideIcons2.X,
44495
- "data-testid": effectiveCloseAction.event ? `action-${effectiveCloseAction.event}` : "action-close"
44633
+ "data-testid": closeAction.event ? `action-${closeAction.event}` : "action-close"
44496
44634
  }
44497
44635
  )
44498
44636
  ] })
44499
44637
  ] }),
44500
- avatar,
44501
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
44502
- subtitle && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: subtitle }),
44503
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", wrap: true, children: [
44504
- normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
44505
- (f3) => f3.toLowerCase().includes("status") || f3.toLowerCase().includes("priority")
44506
- ).map((field) => {
44507
- const value = getNestedValue(normalizedData, field);
44508
- if (!value) return null;
44509
- return /* @__PURE__ */ jsxRuntime.jsx(
44510
- Badge,
44511
- {
44512
- variant: getBadgeVariant(field, String(value)),
44513
- children: String(value)
44514
- },
44515
- field
44516
- );
44517
- }),
44518
- status && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: status.variant ?? "default", children: status.label })
44519
- ] }),
44520
44638
  normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
44521
44639
  (f3) => f3.toLowerCase().includes("progress") || f3.toLowerCase().includes("percent")
44522
44640
  ).map((field) => {
@@ -44549,9 +44667,10 @@ var init_DetailPanel = __esm({
44549
44667
  /* @__PURE__ */ jsxRuntime.jsx(
44550
44668
  Typography,
44551
44669
  {
44552
- variant: "small",
44553
- color: "secondary",
44670
+ variant: "caption",
44671
+ color: "muted",
44554
44672
  weight: "medium",
44673
+ className: "uppercase tracking-wider",
44555
44674
  children: field.label
44556
44675
  }
44557
44676
  ),
@@ -44620,7 +44739,7 @@ var init_DrawerSlot = __esm({
44620
44739
  position,
44621
44740
  width: size,
44622
44741
  className,
44623
- children
44742
+ children: /* @__PURE__ */ jsxRuntime.jsx(providers.RenderSlotProvider, { slot: "drawer", children })
44624
44743
  }
44625
44744
  );
44626
44745
  };
@@ -46667,7 +46786,7 @@ var init_ModalSlot = __esm({
46667
46786
  title,
46668
46787
  size,
46669
46788
  className,
46670
- children
46789
+ children: /* @__PURE__ */ jsxRuntime.jsx(providers.RenderSlotProvider, { slot: "modal", children })
46671
46790
  }
46672
46791
  );
46673
46792
  };
@@ -51089,7 +51208,10 @@ function MaybeTraitScope({
51089
51208
  }
51090
51209
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
51091
51210
  }
51092
- function UISlotComponent({
51211
+ function UISlotComponent(props) {
51212
+ return /* @__PURE__ */ jsxRuntime.jsx(providers.RenderSlotProvider, { slot: props.slot, children: /* @__PURE__ */ jsxRuntime.jsx(UISlotComponentInner, { ...props }) });
51213
+ }
51214
+ function UISlotComponentInner({
51093
51215
  slot,
51094
51216
  portal = false,
51095
51217
  position,