@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.
@@ -8496,6 +8496,11 @@ var init_ComponentPatterns = __esm({
8496
8496
  AlertPattern.displayName = "AlertPattern";
8497
8497
  }
8498
8498
  });
8499
+ function themeBodyFont(el) {
8500
+ if (typeof getComputedStyle !== "function") return "system-ui, sans-serif";
8501
+ const v = getComputedStyle(el).getPropertyValue("--font-family-body").trim();
8502
+ return v || "system-ui, sans-serif";
8503
+ }
8499
8504
  function resolveColor2(color, ctx, fallback) {
8500
8505
  if (!color) return fallback;
8501
8506
  if (color.startsWith("var(")) {
@@ -8684,6 +8689,8 @@ function drawShape(ctx, shape, width, height, allShapes) {
8684
8689
  case "path": {
8685
8690
  if (!shape.path) break;
8686
8691
  const p = new Path2D(shape.path);
8692
+ ctx.lineJoin = "round";
8693
+ ctx.lineCap = "round";
8687
8694
  if (fill) {
8688
8695
  ctx.fillStyle = fill;
8689
8696
  ctx.fill(p);
@@ -8695,7 +8702,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
8695
8702
  case "text": {
8696
8703
  if (shape.x == null || shape.y == null || !shape.text) break;
8697
8704
  ctx.fillStyle = stroke;
8698
- ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
8705
+ ctx.font = `${shape.fontSize ?? 14}px ${themeBodyFont(ctx.canvas)}`;
8699
8706
  ctx.textAlign = shape.align ?? "left";
8700
8707
  ctx.textBaseline = "middle";
8701
8708
  ctx.fillText(shape.text, shape.x, shape.y);
@@ -8892,7 +8899,7 @@ var init_LearningCanvas = __esm({
8892
8899
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
8893
8900
  ctx.clearRect(0, 0, width, height);
8894
8901
  if (backgroundColor) {
8895
- ctx.fillStyle = backgroundColor;
8902
+ ctx.fillStyle = resolveColor2(backgroundColor, ctx, backgroundColor);
8896
8903
  ctx.fillRect(0, 0, width, height);
8897
8904
  }
8898
8905
  for (const shape of derivedShapes) {
@@ -16567,7 +16574,22 @@ function eventStartDate(event, startField) {
16567
16574
  const raw = getNestedValue(event, startField);
16568
16575
  return new Date(raw ?? "");
16569
16576
  }
16570
- function generateDefaultTimeSlots(events2, startField) {
16577
+ function eventEndDate(event, endField) {
16578
+ const raw = getNestedValue(event, endField);
16579
+ if (raw === void 0 || raw === null || raw === "") return null;
16580
+ const end = new Date(raw);
16581
+ return Number.isNaN(end.getTime()) ? null : end;
16582
+ }
16583
+ function eventContinuesInSlot(event, day, slotTime, startField, endField) {
16584
+ const eventStart = eventStartDate(event, startField);
16585
+ const eventEnd = eventEndDate(event, endField);
16586
+ if (eventEnd === null || Number.isNaN(eventStart.getTime())) return false;
16587
+ const [slotHour] = slotTime.split(":").map(Number);
16588
+ const slotStart = new Date(day);
16589
+ slotStart.setHours(slotHour, 0, 0, 0);
16590
+ return slotStart.getTime() > eventStart.getTime() && slotStart.getTime() < eventEnd.getTime();
16591
+ }
16592
+ function generateDefaultTimeSlots(events2, startField, endField) {
16571
16593
  let first = DEFAULT_FIRST_HOUR;
16572
16594
  let last = DEFAULT_LAST_HOUR;
16573
16595
  for (const ev of events2) {
@@ -16576,6 +16598,11 @@ function generateDefaultTimeSlots(events2, startField) {
16576
16598
  const hour = start.getHours();
16577
16599
  if (hour < first) first = hour;
16578
16600
  if (hour > last) last = hour;
16601
+ const end = eventEndDate(ev, endField);
16602
+ if (end && end.toDateString() === start.toDateString()) {
16603
+ const endHour = end.getMinutes() === 0 && end.getSeconds() === 0 ? end.getHours() - 1 : end.getHours();
16604
+ if (endHour > last) last = endHour;
16605
+ }
16579
16606
  }
16580
16607
  const slots = [];
16581
16608
  for (let hour = first; hour <= last; hour++) {
@@ -16604,6 +16631,7 @@ function CalendarGrid({
16604
16631
  dayWindow = "auto",
16605
16632
  titleField = "title",
16606
16633
  startField = "startTime",
16634
+ endField = "endTime",
16607
16635
  colorField = "color",
16608
16636
  children,
16609
16637
  renderItem
@@ -16621,8 +16649,8 @@ function CalendarGrid({
16621
16649
  [resolvedWeekStart]
16622
16650
  );
16623
16651
  const resolvedTimeSlots = React77.useMemo(
16624
- () => timeSlots ?? generateDefaultTimeSlots(evs, startField),
16625
- [timeSlots, evs, startField]
16652
+ () => timeSlots ?? generateDefaultTimeSlots(evs, startField, endField),
16653
+ [timeSlots, evs, startField, endField]
16626
16654
  );
16627
16655
  const visibleCount = useDayWindow(dayWindow);
16628
16656
  const [dayOffset, setDayOffset] = React77.useState(0);
@@ -16782,12 +16810,15 @@ function CalendarGrid({
16782
16810
  const slotEvents = evs.filter(
16783
16811
  (ev) => eventInSlot(ev, day, time, startField)
16784
16812
  );
16813
+ const continuingEvents = evs.filter(
16814
+ (ev) => eventContinuesInSlot(ev, day, time, startField, endField)
16815
+ );
16785
16816
  const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
16786
16817
  return /* @__PURE__ */ jsxRuntime.jsx(
16787
16818
  TimeSlotCell,
16788
16819
  {
16789
16820
  time,
16790
- isOccupied: slotEvents.length > 0,
16821
+ isOccupied: slotEvents.length > 0 || continuingEvents.length > 0,
16791
16822
  onClick: () => handleSlotClick(day, time),
16792
16823
  className: cn(
16793
16824
  "border-l border-border",
@@ -16798,7 +16829,25 @@ function CalendarGrid({
16798
16829
  onPointerUp: clearLongPress,
16799
16830
  onPointerCancel: clearLongPress
16800
16831
  } : {},
16801
- children: /* @__PURE__ */ jsxRuntime.jsx(exports.VStack, { gap: "xs", children: slotEvents.map(renderEvent) })
16832
+ children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", children: [
16833
+ slotEvents.map(renderEvent),
16834
+ continuingEvents.map((event) => {
16835
+ const color = getNestedValue(event, colorField);
16836
+ return /* @__PURE__ */ jsxRuntime.jsx(
16837
+ exports.Box,
16838
+ {
16839
+ rounded: "sm",
16840
+ border: true,
16841
+ className: cn(
16842
+ "cursor-pointer h-2",
16843
+ color ? cn(color, "opacity-50") : "bg-primary/10 border-primary/20"
16844
+ ),
16845
+ onClick: (e) => handleEventClick(event, e)
16846
+ },
16847
+ `${event.id}-cont`
16848
+ );
16849
+ })
16850
+ ] })
16802
16851
  },
16803
16852
  `${day.toISOString()}-${time}`
16804
16853
  );
@@ -22005,10 +22054,21 @@ function ControlGrid({
22005
22054
  directionAssets,
22006
22055
  size = "md",
22007
22056
  disabled,
22057
+ visibility = "auto",
22008
22058
  className
22009
22059
  }) {
22010
22060
  const eventBus = useEventBus();
22011
22061
  const [active, setActive] = React77__namespace.useState(/* @__PURE__ */ new Set());
22062
+ const [coarse, setCoarse] = React77__namespace.useState(
22063
+ () => typeof window !== "undefined" && window.matchMedia("(pointer: coarse)").matches
22064
+ );
22065
+ React77__namespace.useEffect(() => {
22066
+ if (visibility !== "auto" || typeof window === "undefined") return;
22067
+ const mq = window.matchMedia("(pointer: coarse)");
22068
+ const onChange = (e) => setCoarse(e.matches);
22069
+ mq.addEventListener("change", onChange);
22070
+ return () => mq.removeEventListener("change", onChange);
22071
+ }, [visibility]);
22012
22072
  const handlePress = React77__namespace.useCallback(
22013
22073
  (id) => {
22014
22074
  setActive((prev) => new Set(prev).add(id));
@@ -22041,6 +22101,7 @@ function ControlGrid({
22041
22101
  },
22042
22102
  [kind, actionEvent, directionEvent, directionReleaseEvents, eventBus, onAction, onDirection]
22043
22103
  );
22104
+ if (visibility === "auto" && !coarse) return null;
22044
22105
  if (kind === "dpad") {
22045
22106
  const ds = dpadSizeMap[size];
22046
22107
  const dir = (d) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -25451,6 +25512,7 @@ function currentValue(decl, override) {
25451
25512
  function TextLikeControl({
25452
25513
  field,
25453
25514
  numeric,
25515
+ secret,
25454
25516
  value,
25455
25517
  onCommit
25456
25518
  }) {
@@ -25468,7 +25530,7 @@ function TextLikeControl({
25468
25530
  return /* @__PURE__ */ jsxRuntime.jsx(
25469
25531
  exports.Input,
25470
25532
  {
25471
- inputType: numeric ? "number" : "text",
25533
+ inputType: secret ? "password" : numeric ? "number" : "text",
25472
25534
  value: draft,
25473
25535
  onChange: (e) => setDraft(e.target.value),
25474
25536
  onBlur: commit,
@@ -25529,6 +25591,8 @@ function FieldControl({
25529
25591
  );
25530
25592
  } else if (decl.type === "number") {
25531
25593
  control = /* @__PURE__ */ jsxRuntime.jsx(TextLikeControl, { field: name, numeric: true, value, onCommit: onChange });
25594
+ } else if (core.isSecretConfigType(decl.type)) {
25595
+ control = /* @__PURE__ */ jsxRuntime.jsx(TextLikeControl, { field: name, numeric: false, secret: true, value, onCommit: onChange });
25532
25596
  } else if (decl.type === "string") {
25533
25597
  control = /* @__PURE__ */ jsxRuntime.jsx(TextLikeControl, { field: name, numeric: false, value, onCommit: onChange });
25534
25598
  } else if (decl.type === "node") {
@@ -25568,7 +25632,7 @@ var init_PropertyInspector = __esm({
25568
25632
  init_JsonTreeEditor();
25569
25633
  init_NodeSlotEditor();
25570
25634
  TIER_ORDER = ["presentation", "domain", "policy", "infra", "internal"];
25571
- SCALAR_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "icon", "asset", "Asset"]);
25635
+ SCALAR_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "icon", "asset", "Asset", "secret"]);
25572
25636
  exports.PropertyInspector = ({
25573
25637
  config,
25574
25638
  values,
@@ -29556,7 +29620,7 @@ function StatBadge({
29556
29620
  assetUrl,
29557
29621
  iconUrl,
29558
29622
  label,
29559
- value = 0,
29623
+ value,
29560
29624
  max,
29561
29625
  format = "number",
29562
29626
  icon,
@@ -29567,6 +29631,7 @@ function StatBadge({
29567
29631
  source: _source,
29568
29632
  field: _field
29569
29633
  }) {
29634
+ const hasValue = value !== void 0 && value !== null;
29570
29635
  const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
29571
29636
  const resolvedAsset = iconUrl ?? assetUrl;
29572
29637
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -29580,8 +29645,8 @@ function StatBadge({
29580
29645
  ),
29581
29646
  children: [
29582
29647
  resolvedAsset ? /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: resolvedAsset, icon: "image", size: 16, className: "flex-shrink-0" }) : icon ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, className: "w-4 h-4" }) }) : null,
29583
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground font-medium", children: label }),
29584
- format === "hearts" && max && /* @__PURE__ */ jsxRuntime.jsx(
29648
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "text-muted-foreground font-medium text-xs", children: label }),
29649
+ hasValue && format === "hearts" && max && /* @__PURE__ */ jsxRuntime.jsx(
29585
29650
  HealthBar,
29586
29651
  {
29587
29652
  current: numValue,
@@ -29590,7 +29655,7 @@ function StatBadge({
29590
29655
  size: size === "lg" ? "md" : "sm"
29591
29656
  }
29592
29657
  ),
29593
- format === "bar" && max && /* @__PURE__ */ jsxRuntime.jsx(
29658
+ hasValue && format === "bar" && max && /* @__PURE__ */ jsxRuntime.jsx(
29594
29659
  HealthBar,
29595
29660
  {
29596
29661
  current: numValue,
@@ -29599,14 +29664,15 @@ function StatBadge({
29599
29664
  size: size === "lg" ? "md" : "sm"
29600
29665
  }
29601
29666
  ),
29602
- format === "number" && /* @__PURE__ */ jsxRuntime.jsx(
29667
+ hasValue && format === "number" && /* @__PURE__ */ jsxRuntime.jsx(
29603
29668
  ScoreDisplay,
29604
29669
  {
29605
29670
  value: numValue,
29606
- size: size === "lg" ? "md" : "sm"
29671
+ size: size === "lg" ? "md" : "sm",
29672
+ className: "font-display"
29607
29673
  }
29608
29674
  ),
29609
- format === "text" && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "font-bold text-foreground", children: value })
29675
+ hasValue && format === "text" && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { as: "span", className: "font-bold text-foreground", children: value })
29610
29676
  ]
29611
29677
  }
29612
29678
  );
@@ -29622,6 +29688,7 @@ var init_StatBadge = __esm({
29622
29688
  init_HealthBar();
29623
29689
  init_ScoreDisplay();
29624
29690
  sizeMap7 = {
29691
+ xs: "text-xs px-1.5 py-0.5",
29625
29692
  sm: "text-xs px-2 py-1",
29626
29693
  md: "text-sm px-3 py-1.5",
29627
29694
  lg: "text-base px-4 py-2"
@@ -29664,6 +29731,7 @@ function GameHud({
29664
29731
  items,
29665
29732
  elements,
29666
29733
  size = "md",
29734
+ variant = "floating",
29667
29735
  className,
29668
29736
  transparent = true
29669
29737
  }) {
@@ -29678,7 +29746,7 @@ function GameHud({
29678
29746
  /* @__PURE__ */ jsxRuntime.jsx(exports.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)) })
29679
29747
  ] });
29680
29748
  }
29681
- if (position === "top" || position === "bottom") {
29749
+ if ((position === "top" || position === "bottom") && variant === "bar") {
29682
29750
  const mid = Math.ceil(stats.length / 2);
29683
29751
  const leftStats = stats.slice(0, mid);
29684
29752
  const rightStats = stats.slice(mid);
@@ -31335,7 +31403,7 @@ var init_physicsPresets = __esm({
31335
31403
  ];
31336
31404
  }
31337
31405
  });
31338
- var FONT_BASE, GAME_FONTS, FONT_FACES; exports.GameShell = void 0;
31406
+ var GAME_FONTS; exports.GameShell = void 0;
31339
31407
  var init_GameShell = __esm({
31340
31408
  "components/game/templates/GameShell.tsx"() {
31341
31409
  init_cn();
@@ -31343,7 +31411,6 @@ var init_GameShell = __esm({
31343
31411
  init_Card();
31344
31412
  init_Typography();
31345
31413
  init_AtlasImage();
31346
- FONT_BASE = "https://almadar-kflow-assets.web.app/shared/_shared/kenney-fonts/fonts";
31347
31414
  GAME_FONTS = {
31348
31415
  future: "Kenney Future",
31349
31416
  "future-narrow": "Kenney Future Narrow",
@@ -31351,14 +31418,6 @@ var init_GameShell = __esm({
31351
31418
  blocks: "Kenney Blocks",
31352
31419
  mini: "Kenney Mini"
31353
31420
  };
31354
- FONT_FACES = `
31355
- @font-face { font-family: 'Kenney Future'; src: url('${FONT_BASE}/Kenney%20Future.ttf') format('truetype'); font-display: swap; }
31356
- @font-face { font-family: 'Kenney Future Narrow'; src: url('${FONT_BASE}/Kenney%20Future%20Narrow.ttf') format('truetype'); font-display: swap; }
31357
- @font-face { font-family: 'Kenney Pixel'; src: url('${FONT_BASE}/Kenney%20Pixel.ttf') format('truetype'); font-display: swap; }
31358
- @font-face { font-family: 'Kenney Blocks'; src: url('${FONT_BASE}/Kenney%20Blocks.ttf') format('truetype'); font-display: swap; }
31359
- @font-face { font-family: 'Kenney Mini'; src: url('${FONT_BASE}/Kenney%20Mini.ttf') format('truetype'); font-display: swap; }
31360
- .game-shell, .game-shell * { font-family: inherit; }
31361
- `;
31362
31421
  exports.GameShell = ({
31363
31422
  appName = "Game",
31364
31423
  hud,
@@ -31385,10 +31444,12 @@ var init_GameShell = __esm({
31385
31444
  overflow: "hidden",
31386
31445
  background: "var(--color-background, #0a0a0f)",
31387
31446
  color: "var(--color-foreground, #e0e0e0)",
31388
- fontFamily: `'${font}', system-ui, sans-serif`
31447
+ // The fontFamily knob is a scoped override of the theme contract's
31448
+ // display slot: titles/numerics take the game face, body text keeps
31449
+ // the active theme's --font-family-body.
31450
+ "--font-family-display": `'${font}', ui-sans-serif, system-ui, sans-serif`
31389
31451
  },
31390
31452
  children: [
31391
- /* @__PURE__ */ jsxRuntime.jsx("style", { children: FONT_FACES }),
31392
31453
  backgroundAsset && /* @__PURE__ */ jsxRuntime.jsx(
31393
31454
  AtlasPanel,
31394
31455
  {
@@ -31426,6 +31487,7 @@ var init_GameShell = __esm({
31426
31487
  exports.Typography,
31427
31488
  {
31428
31489
  as: "span",
31490
+ className: "font-display",
31429
31491
  style: {
31430
31492
  fontWeight: 700,
31431
31493
  fontSize: "1.05rem",
@@ -31558,6 +31620,9 @@ var init_MathCanvas = __esm({
31558
31620
  showAxes = true,
31559
31621
  showGrid = true,
31560
31622
  gridStep = 1,
31623
+ backgroundColor,
31624
+ gridColor = "var(--color-border, #9ca3af)",
31625
+ axisColor = "var(--color-muted-foreground, #374151)",
31561
31626
  showTickLabels = false,
31562
31627
  showCurveLabels = false,
31563
31628
  curves = [],
@@ -31612,11 +31677,11 @@ var init_MathCanvas = __esm({
31612
31677
  if (showGrid) {
31613
31678
  for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep) {
31614
31679
  const px = mapX(x);
31615
- out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#9ca3af", opacity: 0.35, lineWidth: 1 });
31680
+ out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: gridColor, opacity: 0.35, lineWidth: 1 });
31616
31681
  }
31617
31682
  for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep) {
31618
31683
  const py = mapY(y);
31619
- out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#9ca3af", opacity: 0.35, lineWidth: 1 });
31684
+ out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: gridColor, opacity: 0.35, lineWidth: 1 });
31620
31685
  }
31621
31686
  }
31622
31687
  if (showTickLabels) {
@@ -31687,8 +31752,8 @@ var init_MathCanvas = __esm({
31687
31752
  });
31688
31753
  }
31689
31754
  if (showAxes) {
31690
- out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: "#374151", lineWidth: 2 });
31691
- out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: "#374151", lineWidth: 2 });
31755
+ out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: axisColor, lineWidth: 2 });
31756
+ out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: axisColor, lineWidth: 2 });
31692
31757
  }
31693
31758
  for (const guide of guides) {
31694
31759
  const color = guide.color ?? "#9ca3af";
@@ -31711,23 +31776,36 @@ var init_MathCanvas = __esm({
31711
31776
  }
31712
31777
  for (const curve of curves) {
31713
31778
  if (!curve.samples || curve.samples.length < 2) continue;
31779
+ let d = "";
31780
+ let penDown = false;
31714
31781
  let lastInRange;
31715
31782
  for (let i = 1; i < curve.samples.length; i++) {
31716
31783
  const a = curve.samples[i - 1];
31717
31784
  const b = curve.samples[i];
31718
- if (a.x < xMin || a.x > xMax || b.x < xMin || b.x > xMax) continue;
31719
- out.push({
31720
- type: "line",
31721
- x1: mapX(a.x),
31722
- y1: mapY(a.y),
31723
- x2: mapX(b.x),
31724
- y2: mapY(b.y),
31725
- color: curve.color ?? "#2563eb",
31726
- lineWidth: 2,
31727
- dash: curve.dash
31728
- });
31729
- lastInRange = b;
31730
- }
31785
+ if (a.x < xMin && b.x < xMin || a.x > xMax && b.x > xMax) {
31786
+ penDown = false;
31787
+ continue;
31788
+ }
31789
+ const clip = (p, q, xLim) => {
31790
+ const t = q.x === p.x ? 0 : (xLim - p.x) / (q.x - p.x);
31791
+ return { x: xLim, y: p.y + t * (q.y - p.y) };
31792
+ };
31793
+ const ca = a.x < xMin ? clip(a, b, xMin) : a.x > xMax ? clip(a, b, xMax) : a;
31794
+ const cb = b.x < xMin ? clip(a, b, xMin) : b.x > xMax ? clip(a, b, xMax) : b;
31795
+ const pax = mapX(ca.x);
31796
+ const pay = mapY(ca.y);
31797
+ d += `${penDown ? "L" : "M"} ${pax} ${pay} L ${mapX(cb.x)} ${mapY(cb.y)} `;
31798
+ penDown = true;
31799
+ if (b.x >= xMin && b.x <= xMax) lastInRange = b;
31800
+ }
31801
+ if (!d) continue;
31802
+ out.push({
31803
+ type: "path",
31804
+ path: d,
31805
+ color: curve.color ?? "#2563eb",
31806
+ lineWidth: 2,
31807
+ dash: curve.dash
31808
+ });
31731
31809
  if (showCurveLabels && curve.label && lastInRange) {
31732
31810
  out.push({
31733
31811
  type: "text",
@@ -31842,6 +31920,8 @@ var init_MathCanvas = __esm({
31842
31920
  showAxes,
31843
31921
  showGrid,
31844
31922
  gridStep,
31923
+ gridColor,
31924
+ axisColor,
31845
31925
  showTickLabels,
31846
31926
  showCurveLabels,
31847
31927
  curves,
@@ -31861,6 +31941,7 @@ var init_MathCanvas = __esm({
31861
31941
  {
31862
31942
  width,
31863
31943
  height,
31944
+ backgroundColor,
31864
31945
  shapes: derivedShapes,
31865
31946
  readouts,
31866
31947
  traces,
@@ -33091,13 +33172,13 @@ var init_MapView = __esm({
33091
33172
  shadowSize: [41, 41]
33092
33173
  });
33093
33174
  L.Marker.prototype.options.icon = defaultIcon;
33094
- const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback108, useState: useState104 } = React77__namespace.default;
33175
+ const { useEffect: useEffect69, useRef: useRef65, useCallback: useCallback108, useState: useState104 } = React77__namespace.default;
33095
33176
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
33096
33177
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
33097
33178
  function MapUpdater({ centerLat, centerLng, zoom }) {
33098
33179
  const map = useMap();
33099
33180
  const prevRef = useRef65({ centerLat, centerLng, zoom });
33100
- useEffect67(() => {
33181
+ useEffect69(() => {
33101
33182
  const prev = prevRef.current;
33102
33183
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
33103
33184
  map.setView([centerLat, centerLng], zoom);
@@ -33108,7 +33189,7 @@ var init_MapView = __esm({
33108
33189
  }
33109
33190
  function MapClickHandler({ onMapClick }) {
33110
33191
  const map = useMap();
33111
- useEffect67(() => {
33192
+ useEffect69(() => {
33112
33193
  if (!onMapClick) return;
33113
33194
  const handler = (e) => {
33114
33195
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -33637,14 +33718,34 @@ var init_UploadDropZone = __esm({
33637
33718
  if (valid.length > 0) {
33638
33719
  onFiles?.(valid);
33639
33720
  if (action) {
33640
- eventBus.emit(`UI:${action}`, {
33641
- ...actionPayload,
33642
- files: valid.map((f3) => ({ name: f3.name, size: f3.size, type: f3.type }))
33721
+ void Promise.all(
33722
+ valid.map(
33723
+ (f3) => new Promise(
33724
+ (resolvePayload, rejectPayload) => {
33725
+ const reader = new FileReader();
33726
+ reader.onload = () => resolvePayload({
33727
+ name: f3.name,
33728
+ size: f3.size,
33729
+ type: f3.type,
33730
+ content: String(reader.result ?? "")
33731
+ });
33732
+ reader.onerror = () => rejectPayload(reader.error);
33733
+ reader.readAsDataURL(f3);
33734
+ }
33735
+ )
33736
+ )
33737
+ ).then((payloadFiles) => {
33738
+ eventBus.emit(`UI:${action}`, {
33739
+ ...actionPayload,
33740
+ files: payloadFiles
33741
+ });
33742
+ }).catch(() => {
33743
+ setError(t("Could not read the selected file"));
33643
33744
  });
33644
33745
  }
33645
33746
  }
33646
33747
  },
33647
- [validateFiles, onFiles, action, actionPayload, eventBus]
33748
+ [validateFiles, onFiles, action, actionPayload, eventBus, t]
33648
33749
  );
33649
33750
  const handleDragOver = (e) => {
33650
33751
  e.preventDefault();
@@ -43386,22 +43487,6 @@ var init_DataTable = __esm({
43386
43487
  DataTable.displayName = "DataTable";
43387
43488
  }
43388
43489
  });
43389
- function getFieldIcon(fieldName) {
43390
- const name = fieldName.toLowerCase();
43391
- if (name.includes("date") || name.includes("time")) return LucideIcons2.Calendar;
43392
- if (name.includes("status")) return LucideIcons2.Tag;
43393
- if (name.includes("priority")) return LucideIcons2.AlertCircle;
43394
- if (name.includes("progress") || name.includes("percent")) return LucideIcons2.TrendingUp;
43395
- if (name.includes("assignee") || name.includes("owner") || name.includes("user") || name.includes("member"))
43396
- return LucideIcons2.User;
43397
- if (name.includes("due")) return LucideIcons2.Clock;
43398
- if (name.includes("complete")) return LucideIcons2.CheckCircle2;
43399
- if (name.includes("budget") || name.includes("cost") || name.includes("price"))
43400
- return LucideIcons2.DollarSign;
43401
- if (name.includes("description") || name.includes("note") || name.includes("comment"))
43402
- return LucideIcons2.FileText;
43403
- return LucideIcons2.Package;
43404
- }
43405
43490
  function getBadgeVariant(fieldName, value) {
43406
43491
  const name = fieldName.toLowerCase();
43407
43492
  const val = String(value).toLowerCase();
@@ -43451,6 +43536,18 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
43451
43536
  }
43452
43537
  ) });
43453
43538
  }
43539
+ if (fieldType === "url" && /^https?:\/\//i.test(str2)) {
43540
+ return /* @__PURE__ */ jsxRuntime.jsx(
43541
+ "a",
43542
+ {
43543
+ href: str2,
43544
+ target: "_blank",
43545
+ rel: "noreferrer",
43546
+ className: "text-primary hover:underline break-all",
43547
+ children: str2
43548
+ }
43549
+ );
43550
+ }
43454
43551
  return str2;
43455
43552
  }
43456
43553
  case "markdown":
@@ -43549,6 +43646,23 @@ function renderRichFieldValue(value, fieldName, fieldType, meta) {
43549
43646
  }
43550
43647
  return str2;
43551
43648
  }
43649
+ case "boolean": {
43650
+ if (typeof value === "boolean") return value ? "Yes" : "No";
43651
+ if (str2 === "true") return "Yes";
43652
+ if (str2 === "false") return "No";
43653
+ return str2;
43654
+ }
43655
+ case "array": {
43656
+ if (Array.isArray(value) && value.length > 0) {
43657
+ return /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", wrap: true, children: value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: "default", children: String(item) }, i)) });
43658
+ }
43659
+ if (Array.isArray(value)) return "\u2014";
43660
+ return str2;
43661
+ }
43662
+ case "email":
43663
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href: `mailto:${str2}`, className: "text-primary hover:underline break-all", children: str2 });
43664
+ case "phone":
43665
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href: `tel:${str2}`, className: "text-primary hover:underline", children: str2 });
43552
43666
  default:
43553
43667
  if (meta?.values && meta.values.length > 0 && meta.values.includes(str2)) {
43554
43668
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: getBadgeVariant(fieldName, str2), children: humanizeEnumValue(str2) });
@@ -43621,10 +43735,11 @@ var init_DetailPanel = __esm({
43621
43735
  avatar,
43622
43736
  sections: propSections,
43623
43737
  actions,
43624
- maxInlineActions,
43738
+ maxInlineActions = 2,
43625
43739
  backAction,
43626
43740
  footer,
43627
43741
  slideOver = false,
43742
+ showActions = true,
43628
43743
  className,
43629
43744
  entity,
43630
43745
  fields: propFields,
@@ -43672,9 +43787,6 @@ var init_DetailPanel = __esm({
43672
43787
  },
43673
43788
  [eventBus]
43674
43789
  );
43675
- const handleClose = React77.useCallback(() => {
43676
- eventBus.emit("UI:CLOSE", {});
43677
- }, [eventBus]);
43678
43790
  const entityRecord = Array.isArray(entity) ? entity[0] : entity;
43679
43791
  const data = entityRecord ?? initialData;
43680
43792
  let title = propTitle;
@@ -43688,8 +43800,7 @@ var init_DetailPanel = __esm({
43688
43800
  const value = getNestedValue(normalizedData, field);
43689
43801
  return {
43690
43802
  label: labelFor(field),
43691
- value: formatFieldValue2(value, field),
43692
- icon: getFieldIcon(field)
43803
+ value: formatFieldValue2(value, field)
43693
43804
  };
43694
43805
  }
43695
43806
  return field;
@@ -43723,15 +43834,14 @@ var init_DetailPanel = __esm({
43723
43834
  (f3) => (!titleDerivedFromPrimary || f3 !== primaryField) && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
43724
43835
  );
43725
43836
  sections = [];
43726
- if (statusFields.length > 0 || otherFields.length > 0) {
43837
+ if (otherFields.length > 0) {
43727
43838
  const overviewFields = [];
43728
- [...statusFields, ...otherFields].forEach((field) => {
43839
+ otherFields.forEach((field) => {
43729
43840
  const value = getNestedValue(normalizedData, field);
43730
43841
  if (value !== void 0 && value !== null) {
43731
43842
  overviewFields.push({
43732
43843
  label: labelFor(field),
43733
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
43734
- icon: getFieldIcon(field)
43844
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
43735
43845
  });
43736
43846
  }
43737
43847
  });
@@ -43746,8 +43856,7 @@ var init_DetailPanel = __esm({
43746
43856
  if (value !== void 0 && value !== null) {
43747
43857
  metricsFields.push({
43748
43858
  label: labelFor(field),
43749
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
43750
- icon: getFieldIcon(field)
43859
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
43751
43860
  });
43752
43861
  }
43753
43862
  });
@@ -43762,8 +43871,7 @@ var init_DetailPanel = __esm({
43762
43871
  if (value !== void 0 && value !== null) {
43763
43872
  timelineFields.push({
43764
43873
  label: labelFor(field),
43765
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
43766
- icon: getFieldIcon(field)
43874
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
43767
43875
  });
43768
43876
  }
43769
43877
  });
@@ -43778,8 +43886,7 @@ var init_DetailPanel = __esm({
43778
43886
  if (value !== void 0 && value !== null) {
43779
43887
  descFields.push({
43780
43888
  label: labelFor(field),
43781
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
43782
- icon: getFieldIcon(field)
43889
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
43783
43890
  });
43784
43891
  }
43785
43892
  });
@@ -43788,6 +43895,15 @@ var init_DetailPanel = __esm({
43788
43895
  }
43789
43896
  }
43790
43897
  }
43898
+ const renderSlot = providers.useRenderSlot();
43899
+ const navStack = providers.useNavStack();
43900
+ const { setCurrentLabel } = navStack;
43901
+ const resolvedTitle = normalizedData ? title : void 0;
43902
+ React77.useEffect(() => {
43903
+ if (renderSlot === "main" && !slideOver && resolvedTitle) {
43904
+ setCurrentLabel(resolvedTitle);
43905
+ }
43906
+ }, [renderSlot, slideOver, resolvedTitle, setCurrentLabel]);
43791
43907
  if (isLoading) {
43792
43908
  return /* @__PURE__ */ jsxRuntime.jsx(
43793
43909
  exports.LoadingState,
@@ -43826,8 +43942,7 @@ var init_DetailPanel = __esm({
43826
43942
  const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
43827
43943
  allFields.push({
43828
43944
  label: labelFor(field),
43829
- value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
43830
- icon: getFieldIcon(field)
43945
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field))
43831
43946
  });
43832
43947
  } else {
43833
43948
  allFields.push(field);
@@ -43839,24 +43954,50 @@ var init_DetailPanel = __esm({
43839
43954
  (a) => a.event === "CLOSE" || a.event === "CANCEL" || a.label?.toLowerCase() === "close"
43840
43955
  );
43841
43956
  const otherActions = actions?.filter((a) => a !== closeAction) ?? [];
43842
- const effectiveCloseAction = closeAction ?? { event: void 0};
43843
- const content = /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { variant: "elevated", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "md", className: "p-6", children: [
43844
- /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { justify: "between", align: "center", gap: "xs", children: [
43845
- /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { align: "center", gap: "xs", children: backAction && /* @__PURE__ */ jsxRuntime.jsx(
43846
- exports.Button,
43957
+ const statusBadges = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
43958
+ normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
43959
+ (f3) => f3.toLowerCase().includes("status") || f3.toLowerCase().includes("priority")
43960
+ ).map((field) => {
43961
+ const value = getNestedValue(normalizedData, field);
43962
+ if (!value) return null;
43963
+ return /* @__PURE__ */ jsxRuntime.jsx(
43964
+ exports.Badge,
43847
43965
  {
43848
- variant: backAction.variant || "ghost",
43849
- size: "sm",
43850
- action: backAction.navigatesTo ? void 0 : backAction.event,
43851
- actionPayload: { row: normalizedData },
43852
- onClick: backAction.navigatesTo ? () => handleActionClick(backAction, normalizedData) : void 0,
43853
- icon: backAction.icon ?? LucideIcons2.ArrowLeft,
43854
- "data-testid": backAction.event ? `action-${backAction.event}` : "action-back",
43855
- children: backAction.label
43856
- }
43857
- ) }),
43858
- /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { justify: "end", align: "center", gap: "xs", children: [
43859
- (maxInlineActions != null ? otherActions.slice(0, maxInlineActions) : otherActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
43966
+ variant: getBadgeVariant(field, String(value)),
43967
+ children: humanizeEnumValue(String(value))
43968
+ },
43969
+ field
43970
+ );
43971
+ }),
43972
+ status && /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: status.variant ?? "default", children: status.label })
43973
+ ] });
43974
+ const content = /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { variant: "elevated", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "md", className: "p-6", children: [
43975
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { justify: "between", align: "start", gap: "md", children: [
43976
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { align: "start", gap: "sm", className: "min-w-0", children: [
43977
+ backAction && /* @__PURE__ */ jsxRuntime.jsx(
43978
+ exports.Button,
43979
+ {
43980
+ variant: backAction.variant || "ghost",
43981
+ size: "sm",
43982
+ action: backAction.navigatesTo ? void 0 : backAction.event,
43983
+ actionPayload: { row: normalizedData },
43984
+ onClick: backAction.navigatesTo ? () => handleActionClick(backAction, normalizedData) : void 0,
43985
+ icon: backAction.icon ?? LucideIcons2.ArrowLeft,
43986
+ "data-testid": backAction.event ? `action-${backAction.event}` : "action-back",
43987
+ children: backAction.label
43988
+ }
43989
+ ),
43990
+ avatar,
43991
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", className: "min-w-0", children: [
43992
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { align: "center", gap: "sm", wrap: true, children: [
43993
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
43994
+ statusBadges
43995
+ ] }),
43996
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: subtitle })
43997
+ ] })
43998
+ ] }),
43999
+ showActions && /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { justify: "end", align: "center", gap: "xs", className: "shrink-0", children: [
44000
+ otherActions.slice(0, maxInlineActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsx(
43860
44001
  exports.Button,
43861
44002
  {
43862
44003
  variant: action.variant || "secondary",
@@ -43871,7 +44012,7 @@ var init_DetailPanel = __esm({
43871
44012
  },
43872
44013
  idx
43873
44014
  )),
43874
- maxInlineActions != null && otherActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
44015
+ otherActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
43875
44016
  exports.Menu,
43876
44017
  {
43877
44018
  position: "bottom-end",
@@ -43887,40 +44028,20 @@ var init_DetailPanel = __esm({
43887
44028
  }))
43888
44029
  }
43889
44030
  ),
43890
- /* @__PURE__ */ jsxRuntime.jsx(
44031
+ closeAction && /* @__PURE__ */ jsxRuntime.jsx(
43891
44032
  exports.Button,
43892
44033
  {
43893
44034
  variant: "ghost",
43894
44035
  size: "sm",
43895
- action: effectiveCloseAction.event,
44036
+ action: closeAction.event,
43896
44037
  actionPayload: { row: normalizedData },
43897
- onClick: effectiveCloseAction.event ? void 0 : handleClose,
44038
+ onClick: closeAction.event ? void 0 : () => handleActionClick(closeAction, normalizedData),
43898
44039
  icon: LucideIcons2.X,
43899
- "data-testid": effectiveCloseAction.event ? `action-${effectiveCloseAction.event}` : "action-close"
44040
+ "data-testid": closeAction.event ? `action-${closeAction.event}` : "action-close"
43900
44041
  }
43901
44042
  )
43902
44043
  ] })
43903
44044
  ] }),
43904
- avatar,
43905
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
43906
- subtitle && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: subtitle }),
43907
- /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", wrap: true, children: [
43908
- normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
43909
- (f3) => f3.toLowerCase().includes("status") || f3.toLowerCase().includes("priority")
43910
- ).map((field) => {
43911
- const value = getNestedValue(normalizedData, field);
43912
- if (!value) return null;
43913
- return /* @__PURE__ */ jsxRuntime.jsx(
43914
- exports.Badge,
43915
- {
43916
- variant: getBadgeVariant(field, String(value)),
43917
- children: String(value)
43918
- },
43919
- field
43920
- );
43921
- }),
43922
- status && /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: status.variant ?? "default", children: status.label })
43923
- ] }),
43924
44045
  normalizedData && effectiveFieldNames && effectiveFieldNames.filter(
43925
44046
  (f3) => f3.toLowerCase().includes("progress") || f3.toLowerCase().includes("percent")
43926
44047
  ).map((field) => {
@@ -43953,9 +44074,10 @@ var init_DetailPanel = __esm({
43953
44074
  /* @__PURE__ */ jsxRuntime.jsx(
43954
44075
  exports.Typography,
43955
44076
  {
43956
- variant: "small",
43957
- color: "secondary",
44077
+ variant: "caption",
44078
+ color: "muted",
43958
44079
  weight: "medium",
44080
+ className: "uppercase tracking-wider",
43959
44081
  children: field.label
43960
44082
  }
43961
44083
  ),
@@ -44024,7 +44146,7 @@ var init_DrawerSlot = __esm({
44024
44146
  position,
44025
44147
  width: size,
44026
44148
  className,
44027
- children
44149
+ children: /* @__PURE__ */ jsxRuntime.jsx(providers.RenderSlotProvider, { slot: "drawer", children })
44028
44150
  }
44029
44151
  );
44030
44152
  };
@@ -46071,7 +46193,7 @@ var init_ModalSlot = __esm({
46071
46193
  title,
46072
46194
  size,
46073
46195
  className,
46074
- children
46196
+ children: /* @__PURE__ */ jsxRuntime.jsx(providers.RenderSlotProvider, { slot: "modal", children })
46075
46197
  }
46076
46198
  );
46077
46199
  };
@@ -50474,7 +50596,10 @@ function MaybeTraitScope({
50474
50596
  }
50475
50597
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
50476
50598
  }
50477
- function UISlotComponent({
50599
+ function UISlotComponent(props) {
50600
+ return /* @__PURE__ */ jsxRuntime.jsx(providers.RenderSlotProvider, { slot: props.slot, children: /* @__PURE__ */ jsxRuntime.jsx(UISlotComponentInner, { ...props }) });
50601
+ }
50602
+ function UISlotComponentInner({
50478
50603
  slot,
50479
50604
  portal = false,
50480
50605
  position,