@almadar/ui 5.151.0 → 5.153.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.
Files changed (35) hide show
  1. package/dist/{UISlotContext-D8_SoDsD.d.cts → UISlotContext-BlRDbHDy.d.cts} +1 -1
  2. package/dist/{UISlotContext-C1FsU9GB.d.ts → UISlotContext-CB89mv7N.d.ts} +1 -1
  3. package/dist/avl/index.cjs +749 -116
  4. package/dist/avl/index.js +752 -119
  5. package/dist/{avl-schema-parser-Cx_4SVg9.d.ts → avl-schema-parser-CLIm28Wa.d.ts} +1 -1
  6. package/dist/{avl-schema-parser-CVzkNzg7.d.cts → avl-schema-parser-Do_LPV1o.d.cts} +1 -1
  7. package/dist/{cn-DJTUjk1M.d.ts → cn-CFurBb2q.d.ts} +1 -1
  8. package/dist/{cn-BnAJZcNb.d.cts → cn-TH-RHihd.d.cts} +1 -1
  9. package/dist/components/index.cjs +751 -116
  10. package/dist/components/index.d.cts +114 -16
  11. package/dist/components/index.d.ts +114 -16
  12. package/dist/components/index.js +754 -120
  13. package/dist/context/index.d.cts +2 -2
  14. package/dist/context/index.d.ts +2 -2
  15. package/dist/hooks/index.d.cts +1 -1
  16. package/dist/hooks/index.d.ts +1 -1
  17. package/dist/lib/drawable/three/index.cjs +212 -0
  18. package/dist/lib/drawable/three/index.d.cts +3 -3
  19. package/dist/lib/drawable/three/index.d.ts +3 -3
  20. package/dist/lib/drawable/three/index.js +212 -0
  21. package/dist/lib/index.cjs +11 -2
  22. package/dist/lib/index.d.cts +10 -3
  23. package/dist/lib/index.d.ts +10 -3
  24. package/dist/lib/index.js +11 -3
  25. package/dist/{paintDispatch-CxdLjHQq.d.ts → paintDispatch-B5n2DTB-.d.ts} +178 -2
  26. package/dist/{paintDispatch-BjZjUbcb.d.cts → paintDispatch-DgBctxIq.d.cts} +178 -2
  27. package/dist/providers/index.cjs +749 -116
  28. package/dist/providers/index.js +752 -119
  29. package/dist/runtime/index.cjs +749 -116
  30. package/dist/runtime/index.d.cts +2 -2
  31. package/dist/runtime/index.d.ts +2 -2
  32. package/dist/runtime/index.js +752 -119
  33. package/dist/{useUISlots-BesZYMks.d.cts → useUISlots-GNwGLlW2.d.cts} +1 -1
  34. package/dist/{useUISlots-BesZYMks.d.ts → useUISlots-GNwGLlW2.d.ts} +1 -1
  35. package/package.json +4 -4
@@ -4,11 +4,11 @@ import { EventBusContext, useTraitScopeChain, useEntitySchemaOptional, useEntity
4
4
  export { EntitySchemaProvider, ServerBridgeProvider, TraitContext, TraitProvider, useEntitySchema, useEntitySchemaOptional, useServerBridge, useTrait, useTraitContext } from '@almadar/ui/providers';
5
5
  import { createLogger, setNamespaceLevel, isLogLevelEnabled } from '@almadar/logger';
6
6
  import { StateMachineManager, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, createServerEffectHandlers, EffectExecutor, createContextFromBindings, createTickScheduler, isValidCronExpression, parseDurationString, InMemoryPersistence, normalizeCallSiteConfigToValues, interpolateValue } from '@almadar/runtime';
7
- import { mergeEntityFrame, isCircuitEvent, applyListenPayloadMapping, schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1, walkSExpr, buildResolvedTraitConfigs, isRenderBindingMarker, isInlineTrait, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER, ANIMATION_NAMES } from '@almadar/core';
7
+ import { mergeEntityFrame, isCircuitEvent, applyListenPayloadMapping, schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1, walkSExpr, buildResolvedTraitConfigs, isRenderBindingMarker, isFileValue, isInlineTrait, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER, ANIMATION_NAMES } from '@almadar/core';
8
8
  import { clsx } from 'clsx';
9
9
  import { twMerge } from 'tailwind-merge';
10
10
  import * as LucideIcons2 from 'lucide-react';
11
- import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, ChevronDown, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, ChevronUp, Tag, User, DollarSign } from 'lucide-react';
11
+ import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, 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
12
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
13
13
  import { createPortal } from 'react-dom';
14
14
  import { useTranslate } from '@almadar/ui/hooks';
@@ -77,7 +77,7 @@ import { CSS } from '@dnd-kit/utilities';
77
77
  import { ordered, lib } from 'emojilib';
78
78
  import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
79
79
  import { forceSimulation, forceLink, forceManyBody, forceCollide, forceX, forceY } from 'd3-force';
80
- import { isDrawHostPattern, getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/core/patterns';
80
+ import { isDrawHostPattern, getPatternDefinition, getPatternFieldsContract, getComponentForPattern as getComponentForPattern$1 } from '@almadar/core/patterns';
81
81
  import { isKnownStdOperator } from '@almadar/std/registry';
82
82
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
83
83
 
@@ -6171,27 +6171,61 @@ var init_InfiniteScrollSentinel = __esm({
6171
6171
  InfiniteScrollSentinel.displayName = "InfiniteScrollSentinel";
6172
6172
  }
6173
6173
  });
6174
- function createParticles(count) {
6175
- return Array.from({ length: count }, () => {
6176
- particleIdCounter += 1;
6177
- return {
6178
- id: particleIdCounter,
6179
- color: CONFETTI_COLORS[Math.floor(Math.random() * CONFETTI_COLORS.length)],
6180
- left: 30 + Math.random() * 40,
6181
- delay: Math.random() * 300,
6182
- angle: Math.random() * 360,
6183
- distance: 40 + Math.random() * 80,
6184
- rotation: Math.random() * 720 - 360,
6185
- size: 4 + Math.random() * 6
6186
- };
6187
- });
6174
+
6175
+ // components/core/atoms/fx.ts
6176
+ function resolveFxView(item, presets) {
6177
+ const row = presets?.find((p) => p.type === item.type);
6178
+ if (!row) return item;
6179
+ return {
6180
+ ...item,
6181
+ space: item.space ?? row.space,
6182
+ effect: item.effect ?? row.effect,
6183
+ color: item.color ?? row.color,
6184
+ size: item.size ?? row.size,
6185
+ vx: item.vx ?? row.vx,
6186
+ vy: item.vy ?? row.vy,
6187
+ vz: item.vz ?? row.vz,
6188
+ particleCount: item.particleCount ?? row.particleCount,
6189
+ shape: row.shape,
6190
+ count: row.count,
6191
+ glow: row.glow,
6192
+ gravity: row.gravity,
6193
+ color2: row.color2
6194
+ };
6188
6195
  }
6189
- var CONFETTI_COLORS, particleIdCounter, ConfettiEffect;
6190
- var init_ConfettiEffect = __esm({
6191
- "components/core/atoms/ConfettiEffect.tsx"() {
6192
- "use client";
6193
- init_cn();
6194
- init_Box();
6196
+ function fxLifecycle(item, epochNowMs, tickMs) {
6197
+ const maxTtl = Math.max(item.maxTtl ?? item.ttl, item.ttl, 1);
6198
+ const lifeMs = maxTtl * tickMs;
6199
+ const ageMs = item.bornAt !== void 0 && epochNowMs > 0 ? Math.max(0, epochNowMs - item.bornAt) : (1 - item.ttl / maxTtl) * lifeMs;
6200
+ const progress = Math.min(1, Math.max(0, ageMs / lifeMs));
6201
+ return { lifeMs, ageMs, progress, fade: 1 - progress };
6202
+ }
6203
+ function fxHash01(seed, salt) {
6204
+ let h = 2166136261 ^ salt;
6205
+ for (let i = 0; i < seed.length; i++) {
6206
+ h ^= seed.charCodeAt(i);
6207
+ h = Math.imul(h, 16777619);
6208
+ }
6209
+ h ^= h >>> 13;
6210
+ h = Math.imul(h, 1274126177);
6211
+ h ^= h >>> 16;
6212
+ return (h >>> 0) / 4294967296;
6213
+ }
6214
+ function createConfettiParticles(count, seed) {
6215
+ return Array.from({ length: count }, (_, i) => ({
6216
+ id: i,
6217
+ color: CONFETTI_COLORS[Math.floor(fxHash01(seed, i * 7 + 1) * CONFETTI_COLORS.length)],
6218
+ left: 30 + fxHash01(seed, i * 7 + 2) * 40,
6219
+ delay: fxHash01(seed, i * 7 + 3) * 300,
6220
+ angle: fxHash01(seed, i * 7 + 4) * 360,
6221
+ distance: 40 + fxHash01(seed, i * 7 + 5) * 80,
6222
+ rotation: fxHash01(seed, i * 7 + 6) * 720 - 360,
6223
+ size: 4 + fxHash01(seed, i * 7 + 7) * 6
6224
+ }));
6225
+ }
6226
+ var CONFETTI_COLORS, CONFETTI_BURST_KEYFRAMES;
6227
+ var init_fx = __esm({
6228
+ "components/core/atoms/fx.ts"() {
6195
6229
  CONFETTI_COLORS = [
6196
6230
  "var(--color-primary)",
6197
6231
  "var(--color-success)",
@@ -6200,7 +6234,30 @@ var init_ConfettiEffect = __esm({
6200
6234
  "gold",
6201
6235
  "dodgerblue"
6202
6236
  ];
6203
- particleIdCounter = 0;
6237
+ CONFETTI_BURST_KEYFRAMES = `
6238
+ @keyframes confetti-burst {
6239
+ 0% {
6240
+ opacity: 1;
6241
+ transform: translate(0, 0) rotate(0deg) scale(1);
6242
+ }
6243
+ 70% {
6244
+ opacity: 1;
6245
+ }
6246
+ 100% {
6247
+ opacity: 0;
6248
+ transform: translate(var(--confetti-tx), var(--confetti-ty)) rotate(var(--confetti-rotate)) scale(0.5);
6249
+ }
6250
+ }
6251
+ `;
6252
+ }
6253
+ });
6254
+ var ConfettiEffect;
6255
+ var init_ConfettiEffect = __esm({
6256
+ "components/core/atoms/ConfettiEffect.tsx"() {
6257
+ "use client";
6258
+ init_cn();
6259
+ init_Box();
6260
+ init_fx();
6204
6261
  ConfettiEffect = ({
6205
6262
  trigger,
6206
6263
  duration = 2e3,
@@ -6209,11 +6266,13 @@ var init_ConfettiEffect = __esm({
6209
6266
  }) => {
6210
6267
  const [particles, setParticles] = useState([]);
6211
6268
  const previousTriggerRef = useRef(false);
6269
+ const burstRef = useRef(0);
6212
6270
  useEffect(() => {
6213
6271
  const wasFalse = !previousTriggerRef.current;
6214
6272
  previousTriggerRef.current = trigger;
6215
6273
  if (trigger && wasFalse) {
6216
- const newParticles = createParticles(particleCount);
6274
+ burstRef.current += 1;
6275
+ const newParticles = createConfettiParticles(particleCount, `confetti-${burstRef.current}`);
6217
6276
  setParticles(newParticles);
6218
6277
  const timer = window.setTimeout(() => {
6219
6278
  setParticles([]);
@@ -6261,21 +6320,7 @@ var init_ConfettiEffect = __esm({
6261
6320
  p.id
6262
6321
  );
6263
6322
  }),
6264
- /* @__PURE__ */ jsx("style", { children: `
6265
- @keyframes confetti-burst {
6266
- 0% {
6267
- opacity: 1;
6268
- transform: translate(0, 0) rotate(0deg) scale(1);
6269
- }
6270
- 70% {
6271
- opacity: 1;
6272
- }
6273
- 100% {
6274
- opacity: 0;
6275
- transform: translate(var(--confetti-tx), var(--confetti-ty)) rotate(var(--confetti-rotate)) scale(0.5);
6276
- }
6277
- }
6278
- ` })
6323
+ /* @__PURE__ */ jsx("style", { children: CONFETTI_BURST_KEYFRAMES })
6279
6324
  ]
6280
6325
  }
6281
6326
  );
@@ -9724,7 +9769,7 @@ var init_DrawShape = __esm({
9724
9769
  const cx = p.x + (node.offsetX ?? 0) * tw;
9725
9770
  const cy = p.y + (node.offsetY ?? 0) * tw;
9726
9771
  const rx = (node.radiusX ?? 0) * tw;
9727
- const ry = (node.radiusY ?? rx) * tw;
9772
+ const ry = (node.radiusY ?? node.radiusX ?? 0) * tw;
9728
9773
  if (pxFill) painter.fillEllipse(cx, cy, rx, ry, pxFill);
9729
9774
  if (patFill) painter.fillEllipse(cx, cy, rx, ry, patFill);
9730
9775
  if (pxStroke) painter.strokeEllipse(cx, cy, rx, ry, pxStroke, strokePx);
@@ -9914,6 +9959,172 @@ var init_DrawTextLayer = __esm({
9914
9959
  };
9915
9960
  }
9916
9961
  });
9962
+
9963
+ // components/game/molecules/DrawFxLayer.tsx
9964
+ function fxPosition(view, dim, ageSec) {
9965
+ const g = view.gravity ?? 0;
9966
+ const fall = 0.5 * g * ageSec * ageSec;
9967
+ {
9968
+ const base2 = view.position ?? { x: view.x, y: view.z ?? view.y ?? 0 };
9969
+ if (!Number.isFinite(base2.x) || !Number.isFinite(base2.y)) return void 0;
9970
+ return {
9971
+ x: base2.x + (view.vx ?? 0) * ageSec,
9972
+ y: base2.y + (view.vz ?? 0) * ageSec + fall
9973
+ };
9974
+ }
9975
+ }
9976
+ function sparkShape(view, pos, i, fade, progress) {
9977
+ const size = view.size ?? 0.5;
9978
+ const angle = fxHash01(view.id, i * 3) * Math.PI * 2;
9979
+ const dist = size * (0.4 + 0.6 * fxHash01(view.id, i * 3 + 1)) * easeOut2(progress);
9980
+ const r = size * (0.06 + 0.06 * fxHash01(view.id, i * 3 + 2));
9981
+ const color = view.color ?? DEFAULT_SPARK_COLOR;
9982
+ return {
9983
+ type: "draw-shape",
9984
+ shape: "ellipse",
9985
+ position: { ...pos, x: pos.x + Math.cos(angle) * dist, y: pos.y + Math.sin(angle) * dist },
9986
+ anchor: "center",
9987
+ radiusX: r,
9988
+ fill: color,
9989
+ blendMode: "lighter",
9990
+ opacity: fade,
9991
+ ...view.glow ? { shadow: { color, blur: view.glow } } : {}
9992
+ };
9993
+ }
9994
+ function proceduralShapes(view, pos, fade, progress) {
9995
+ const size = view.size ?? 0.5;
9996
+ const color = view.color ?? DEFAULT_SPARK_COLOR;
9997
+ switch (view.shape ?? "spark") {
9998
+ case "ring": {
9999
+ return [
10000
+ {
10001
+ type: "draw-shape",
10002
+ shape: "ellipse",
10003
+ position: pos,
10004
+ anchor: "center",
10005
+ radiusX: size * easeOut2(progress),
10006
+ stroke: view.color2 ?? color,
10007
+ strokeWidth: 2,
10008
+ blendMode: "lighter",
10009
+ opacity: fade,
10010
+ ...view.glow ? { shadow: { color, blur: view.glow } } : {}
10011
+ }
10012
+ ];
10013
+ }
10014
+ case "puff": {
10015
+ const count = view.count ?? 3;
10016
+ return Array.from({ length: count }, (_, i) => {
10017
+ const angle = fxHash01(view.id, i * 5) * Math.PI * 2;
10018
+ const drift = size * 0.3 * fxHash01(view.id, i * 5 + 1) * easeOut2(progress);
10019
+ return {
10020
+ type: "draw-shape",
10021
+ shape: "ellipse",
10022
+ position: { ...pos, x: pos.x + Math.cos(angle) * drift, y: pos.y + Math.sin(angle) * drift },
10023
+ anchor: "center",
10024
+ radiusX: size * (0.15 + 0.35 * progress) * (0.7 + 0.6 * fxHash01(view.id, i * 5 + 2)),
10025
+ fill: i === 0 && view.color2 ? view.color2 : color,
10026
+ opacity: fade * 0.6,
10027
+ ...view.glow ? { shadow: { color, blur: view.glow } } : {}
10028
+ };
10029
+ });
10030
+ }
10031
+ case "streak": {
10032
+ const count = view.count ?? 5;
10033
+ return Array.from({ length: count }, (_, i) => {
10034
+ const angle = fxHash01(view.id, i * 3) * Math.PI * 2;
10035
+ const inner = size * (0.2 + 0.8 * easeOut2(progress)) * (0.6 + 0.4 * fxHash01(view.id, i * 3 + 1));
10036
+ const len = size * 0.35;
10037
+ return {
10038
+ type: "draw-shape",
10039
+ shape: "ellipse",
10040
+ position: pos,
10041
+ anchor: "center",
10042
+ offsetX: inner + len / 2,
10043
+ offsetY: 0,
10044
+ radiusX: len / 2,
10045
+ radiusY: size * 0.04,
10046
+ rotate: angle,
10047
+ fill: color,
10048
+ blendMode: "lighter",
10049
+ opacity: fade,
10050
+ ...view.glow ? { shadow: { color, blur: view.glow } } : {}
10051
+ };
10052
+ });
10053
+ }
10054
+ default: {
10055
+ const count = view.count ?? 6;
10056
+ return Array.from({ length: count }, (_, i) => sparkShape(view, pos, i, fade, progress));
10057
+ }
10058
+ }
10059
+ }
10060
+ function expandFxItem(view, node, epochNowMs, dim) {
10061
+ if (view.space === "screen") return [];
10062
+ const tickMs = node.tickMs ?? DEFAULT_TICK_MS;
10063
+ const { ageMs, progress, fade } = fxLifecycle(view, epochNowMs, tickMs);
10064
+ if (progress >= 1) return [];
10065
+ const pos = fxPosition(view, dim, ageMs / 1e3);
10066
+ if (!pos) return [];
10067
+ const out = [];
10068
+ const artItems = node.art?.[view.type]?.["idle"];
10069
+ const sprite = node.sprites?.[view.type];
10070
+ if (Array.isArray(artItems)) {
10071
+ out.push({
10072
+ type: "draw-group",
10073
+ position: pos,
10074
+ opacity: fade,
10075
+ ...view.size !== void 0 ? { scale: view.size } : {},
10076
+ items: artItems
10077
+ });
10078
+ } else if (sprite?.url) {
10079
+ const spriteSize = view.size ?? 0.6;
10080
+ out.push({
10081
+ type: "draw-sprite",
10082
+ position: pos,
10083
+ asset: sprite,
10084
+ anchor: "center",
10085
+ width: spriteSize,
10086
+ height: spriteSize,
10087
+ opacity: fade
10088
+ });
10089
+ } else {
10090
+ out.push(...proceduralShapes(view, pos, fade, progress));
10091
+ }
10092
+ if (view.message) {
10093
+ const text = {
10094
+ type: "draw-text",
10095
+ text: view.message,
10096
+ position: pos,
10097
+ offsetY: -(0.15 + 0.55 * progress),
10098
+ color: view.color ?? node.textColor ?? DEFAULT_TEXT_COLOR,
10099
+ opacity: fade
10100
+ };
10101
+ out.push(text);
10102
+ }
10103
+ return out;
10104
+ }
10105
+ function expandFxLayer(node, epochNowMs, dim) {
10106
+ if (!Array.isArray(node.items)) return [];
10107
+ const out = [];
10108
+ for (const item of node.items) {
10109
+ if (!item || typeof item.id !== "string") continue;
10110
+ out.push(...expandFxItem(resolveFxView(item, node.presets), node, epochNowMs, dim));
10111
+ }
10112
+ return out;
10113
+ }
10114
+ function DrawFxLayer(_props) {
10115
+ return null;
10116
+ }
10117
+ var DEFAULT_TICK_MS, DEFAULT_TEXT_COLOR, DEFAULT_SPARK_COLOR, easeOut2;
10118
+ var init_DrawFxLayer = __esm({
10119
+ "components/game/molecules/DrawFxLayer.tsx"() {
10120
+ "use client";
10121
+ init_fx();
10122
+ DEFAULT_TICK_MS = 500;
10123
+ DEFAULT_TEXT_COLOR = "#ffe066";
10124
+ DEFAULT_SPARK_COLOR = "#ffffff";
10125
+ easeOut2 = (t) => 1 - (1 - t) * (1 - t);
10126
+ }
10127
+ });
9917
10128
  function paintDrawable(painter, node, dctx) {
9918
10129
  switch (node.type) {
9919
10130
  case "draw-sprite":
@@ -9961,6 +10172,11 @@ function paintDrawable(painter, node, dctx) {
9961
10172
  case "draw-text-layer":
9962
10173
  paintTextLayer(painter, node, dctx);
9963
10174
  break;
10175
+ case "draw-fx-layer": {
10176
+ const epochNow = dctx.time > 0 && typeof performance !== "undefined" ? performance.timeOrigin + dctx.time : 0;
10177
+ for (const child of expandFxLayer(node, epochNow, "2d")) paintDrawable(painter, child, dctx);
10178
+ break;
10179
+ }
9964
10180
  }
9965
10181
  }
9966
10182
  var paint2dLog, warnedUnsupported2d, warnUnsupported2d;
@@ -9975,6 +10191,7 @@ var init_paintDispatch = __esm({
9975
10191
  init_DrawSpriteLayer();
9976
10192
  init_DrawShapeLayer();
9977
10193
  init_DrawTextLayer();
10194
+ init_DrawFxLayer();
9978
10195
  paint2dLog = createLogger("almadar:ui:drawable-2d");
9979
10196
  warnedUnsupported2d = /* @__PURE__ */ new Set();
9980
10197
  warnUnsupported2d = (kind) => {
@@ -10223,6 +10440,7 @@ function Canvas2D({
10223
10440
  return isAnimatedGroup(node) || Array.isArray(node.items) && node.items.some(drawableIsAnimated);
10224
10441
  if (node.type === "draw-shape-layer") return Array.isArray(node.items) && node.items.some(isAnimatedShape);
10225
10442
  if (node.type === "draw-sprite-layer") return Array.isArray(node.items) && node.items.some(isAnimatedSprite);
10443
+ if (node.type === "draw-fx-layer") return Array.isArray(node.items) && node.items.length > 0;
10226
10444
  return false;
10227
10445
  };
10228
10446
  const animRafRef = useRef(0);
@@ -13853,7 +14071,7 @@ var init_AlgoGraphCanvas = __esm({
13853
14071
  }
13854
14072
  const badgeGeoms = [];
13855
14073
  for (const g of nodeGeoms) {
13856
- if (!g.badge) continue;
14074
+ if (!g.badge || g.badge.text === "") continue;
13857
14075
  const w = Math.min(42, Math.max(18, g.badge.text.length * 6 + 10));
13858
14076
  badgeGeoms.push({
13859
14077
  cx: g.x + g.radius * 0.75,
@@ -13919,7 +14137,7 @@ var init_AlgoGraphCanvas = __esm({
13919
14137
  };
13920
14138
  }
13921
14139
  });
13922
- var DEFAULT_BAR_COLOR, DEFAULT_CELL_COLOR, DEFAULT_POINTER_COLOR, POINTER_BAND, TOP_PAD, PANEL_FAMILY_ORDER, RANGE_COLOR_DEFAULT, RANGE_FILL_OPACITY, BRACKET_TOP_OFFSET, BRACKET_ROW_H, BRACKET_TICK_H, BRACKET_LABEL_OFFSET, SLOT_EMPTY_FILL, SLOT_EMPTY_STROKE, SLOT_FILLED_STROKE, SLOT_HIGHLIGHT_DEFAULT, SLOT_VALUE_TEXT_COLOR, FRAME_ACTIVE_COLOR, FRAME_RETURNING_COLOR, FRAME_DONE_COLOR, FRAME_LABEL_COLOR, FRAME_DETAIL_COLOR, FRAME_TWO_LINE_MIN_H, BUCKET_INDEX_FILL, BUCKET_INDEX_STROKE, BUCKET_INDEX_TEXT, BUCKET_ENTRY_TEXT, BUCKET_ENTRY_DEFAULT, BUCKET_ENTRY_HIGHLIGHT, BUCKET_ENTRY_PROBING, BUCKET_ENTRY_MIN_W, BUCKET_ENTRY_MAX_W, AXIS_LABEL_COLOR, AXIS_LABEL_FONT_SIZE, CORNER_TEXT_COLOR, CORNER_FONT_SIZE, CORNER_MIN_CELL, CORNER_INSET_X, CORNER_INSET_Y, AUX_PRIMARY_RATIO, AUX_LABEL_BAND, AUX_BASELINE_PAD, AlgorithmCanvas;
14140
+ var DEFAULT_BAR_COLOR, DEFAULT_CELL_COLOR, DEFAULT_POINTER_COLOR, POINTER_BAND, TOP_PAD, PANEL_FAMILY_ORDER, RANGE_COLOR_DEFAULT, RANGE_FILL_OPACITY, BRACKET_TOP_OFFSET, BRACKET_ROW_H, BRACKET_TICK_H, BRACKET_LABEL_OFFSET, SLOT_EMPTY_FILL, SLOT_EMPTY_STROKE, SLOT_FILLED_STROKE, SLOT_HIGHLIGHT_DEFAULT, SLOT_VALUE_TEXT_COLOR, FRAME_ACTIVE_COLOR, FRAME_RETURNING_COLOR, FRAME_DONE_COLOR, FRAME_RIM_COLOR, FRAME_LABEL_COLOR, FRAME_DETAIL_COLOR, FRAME_TWO_LINE_MIN_H, FRAME_STRIP_H, FRAME_GAP, FRAME_BOTTOM_PAD, FRAME_MIN_H, BUCKET_INDEX_FILL, BUCKET_INDEX_STROKE, BUCKET_INDEX_TEXT, BUCKET_ENTRY_TEXT, BUCKET_ENTRY_DEFAULT, BUCKET_ENTRY_HIGHLIGHT, BUCKET_ENTRY_PROBING, BUCKET_ENTRY_MIN_W, BUCKET_ENTRY_MAX_W, AXIS_LABEL_COLOR, AXIS_LABEL_FONT_SIZE, CORNER_TEXT_COLOR, CORNER_FONT_SIZE, CORNER_MIN_CELL, CORNER_INSET_X, CORNER_INSET_Y, AUX_PRIMARY_RATIO, AUX_LABEL_BAND, AUX_BASELINE_PAD, AlgorithmCanvas;
13923
14141
  var init_AlgorithmCanvas = __esm({
13924
14142
  "components/learning/molecules/AlgorithmCanvas.tsx"() {
13925
14143
  "use client";
@@ -13946,9 +14164,18 @@ var init_AlgorithmCanvas = __esm({
13946
14164
  FRAME_ACTIVE_COLOR = "#3b82f6";
13947
14165
  FRAME_RETURNING_COLOR = "#f59e0b";
13948
14166
  FRAME_DONE_COLOR = "#94a3b8";
14167
+ FRAME_RIM_COLOR = {
14168
+ active: "#1d4ed8",
14169
+ returning: "#b45309",
14170
+ done: "#64748b"
14171
+ };
13949
14172
  FRAME_LABEL_COLOR = "#ffffff";
13950
14173
  FRAME_DETAIL_COLOR = "#e2e8f0";
13951
14174
  FRAME_TWO_LINE_MIN_H = 22;
14175
+ FRAME_STRIP_H = 44;
14176
+ FRAME_GAP = 6;
14177
+ FRAME_BOTTOM_PAD = 8;
14178
+ FRAME_MIN_H = 12;
13952
14179
  BUCKET_INDEX_FILL = "#e2e8f0";
13953
14180
  BUCKET_INDEX_STROKE = "#9ca3af";
13954
14181
  BUCKET_INDEX_TEXT = "#374151";
@@ -14445,14 +14672,18 @@ var init_AlgorithmCanvas = __esm({
14445
14672
  if (frames.length > 0) {
14446
14673
  const panelYFrames = panelY.frames;
14447
14674
  const n = frames.length;
14448
- const frameH = panelHeight / n;
14675
+ const maxStride = (panelHeight - FRAME_BOTTOM_PAD - TOP_PAD) / n;
14676
+ const stride = Math.min(FRAME_STRIP_H + FRAME_GAP, maxStride);
14677
+ const frameH = Math.max(FRAME_MIN_H, stride - FRAME_GAP);
14449
14678
  const x = 8;
14450
14679
  const w = width - 16;
14680
+ const bottom = panelYFrames + panelHeight - FRAME_BOTTOM_PAD;
14451
14681
  frames.forEach((f3, i) => {
14452
- const y = panelYFrames + panelHeight - (i + 1) * frameH;
14682
+ const y = bottom - i * stride - frameH;
14453
14683
  const state = f3.state ?? "active";
14454
14684
  const fill = state === "returning" ? f3.color ?? FRAME_RETURNING_COLOR : state === "done" ? f3.color ?? FRAME_DONE_COLOR : f3.color ?? FRAME_ACTIVE_COLOR;
14455
- out.push({ type: "rect", id: `frame-${i}`, x, y, width: w, height: frameH, color: fill, fill });
14685
+ const rim = f3.color ?? FRAME_RIM_COLOR[state] ?? FRAME_RIM_COLOR.active;
14686
+ out.push({ type: "rect", id: `frame-${i}`, x, y, width: w, height: frameH, color: rim, fill });
14456
14687
  if (frameH >= FRAME_TWO_LINE_MIN_H) {
14457
14688
  out.push({
14458
14689
  type: "text",
@@ -14460,14 +14691,14 @@ var init_AlgorithmCanvas = __esm({
14460
14691
  y: y + frameH * 0.35,
14461
14692
  text: f3.label,
14462
14693
  color: FRAME_LABEL_COLOR,
14463
- fontSize: 10,
14694
+ fontSize: 11,
14464
14695
  align: "left"
14465
14696
  });
14466
14697
  if (f3.detail) {
14467
14698
  out.push({
14468
14699
  type: "text",
14469
14700
  x: 16,
14470
- y: y + frameH * 0.7,
14701
+ y: y + frameH * 0.72,
14471
14702
  text: f3.detail,
14472
14703
  color: FRAME_DETAIL_COLOR,
14473
14704
  fontSize: 10,
@@ -20930,8 +21161,6 @@ var init_ButtonGroup = __esm({
20930
21161
  ButtonGroup.displayName = "ButtonGroup";
20931
21162
  }
20932
21163
  });
20933
-
20934
- // lib/getNestedValue.ts
20935
21164
  function getNestedValue(obj, path) {
20936
21165
  if (obj === null || obj === void 0 || !path) {
20937
21166
  return void 0;
@@ -20952,6 +21181,15 @@ function getNestedValue(obj, path) {
20952
21181
  }
20953
21182
  return value;
20954
21183
  }
21184
+ function resolveImageUrl(value) {
21185
+ if (typeof value === "string") {
21186
+ return value;
21187
+ }
21188
+ if (isFileValue(value)) {
21189
+ return value.url;
21190
+ }
21191
+ return void 0;
21192
+ }
20955
21193
  var init_getNestedValue = __esm({
20956
21194
  "lib/getNestedValue.ts"() {
20957
21195
  }
@@ -21589,8 +21827,8 @@ var init_CardGrid = __esm({
21589
21827
  actionPayload: { row: itemData },
21590
21828
  children: [
21591
21829
  imageField && (() => {
21592
- const imgUrl = getNestedValue(itemData, imageField);
21593
- if (!imgUrl || typeof imgUrl !== "string") return null;
21830
+ const imgUrl = resolveImageUrl(getNestedValue(itemData, imageField));
21831
+ if (!imgUrl) return null;
21594
21832
  return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-lg", children: /* @__PURE__ */ jsx(
21595
21833
  "img",
21596
21834
  {
@@ -25606,8 +25844,8 @@ function DataGrid({
25606
25844
  ),
25607
25845
  children: [
25608
25846
  imageField && (() => {
25609
- const imgUrl = getNestedValue(itemData, imageField);
25610
- if (!imgUrl || typeof imgUrl !== "string") return null;
25847
+ const imgUrl = resolveImageUrl(getNestedValue(itemData, imageField));
25848
+ if (!imgUrl) return null;
25611
25849
  return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-lg", children: /* @__PURE__ */ jsx(
25612
25850
  "img",
25613
25851
  {
@@ -27597,6 +27835,196 @@ var init_PageTransition = __esm({
27597
27835
  PageTransition.displayName = "PageTransition";
27598
27836
  }
27599
27837
  });
27838
+ function ConfettiBurst({ item, lifeMs }) {
27839
+ const particles = createConfettiParticles(item.particleCount ?? 30, item.id);
27840
+ const left = (item.x ?? 0.5) * 100;
27841
+ const top = (item.z ?? item.y ?? 0.4) * 100;
27842
+ return /* @__PURE__ */ jsx(Box, { position: "absolute", style: { left: `${left}%`, top: `${top}%` }, children: particles.map((p) => {
27843
+ const rad = p.angle * Math.PI / 180;
27844
+ const tx = Math.cos(rad) * p.distance * (item.size ?? 1);
27845
+ const ty = Math.sin(rad) * p.distance * (item.size ?? 1) - 20;
27846
+ return /* @__PURE__ */ jsx(
27847
+ Box,
27848
+ {
27849
+ className: "absolute rounded-sm",
27850
+ style: {
27851
+ left: (p.left - 50) * 2,
27852
+ top: -10,
27853
+ width: p.size,
27854
+ height: p.size,
27855
+ backgroundColor: item.color ?? p.color,
27856
+ animation: `confetti-burst ${Math.max(lifeMs - p.delay, 200)}ms ease-out ${p.delay}ms forwards`,
27857
+ opacity: 0,
27858
+ "--confetti-tx": `${tx}px`,
27859
+ "--confetti-ty": `${ty}px`,
27860
+ "--confetti-rotate": `${p.rotation}deg`
27861
+ }
27862
+ },
27863
+ p.id
27864
+ );
27865
+ }) });
27866
+ }
27867
+ function SparkleBurst({ item, lifeMs }) {
27868
+ const count = item.particleCount ?? 8;
27869
+ const scale = item.size ?? 1;
27870
+ const left = (item.x ?? 0.5) * 100;
27871
+ const top = (item.z ?? item.y ?? 0.4) * 100;
27872
+ return /* @__PURE__ */ jsx(Box, { position: "absolute", style: { left: `${left}%`, top: `${top}%` }, children: Array.from({ length: count }, (_, i) => {
27873
+ const dx = (fxHash01(item.id, i * 4) - 0.5) * 160 * scale;
27874
+ const dy = (fxHash01(item.id, i * 4 + 1) - 0.5) * 120 * scale;
27875
+ const dot = (4 + fxHash01(item.id, i * 4 + 2) * 5) * scale;
27876
+ const delay = fxHash01(item.id, i * 4 + 3) * lifeMs * 0.4;
27877
+ return /* @__PURE__ */ jsx(
27878
+ Box,
27879
+ {
27880
+ className: "absolute rounded-full",
27881
+ style: {
27882
+ left: dx,
27883
+ top: dy,
27884
+ width: dot,
27885
+ height: dot,
27886
+ backgroundColor: item.color ?? "gold",
27887
+ opacity: 0,
27888
+ animation: `fx-overlay-sparkle ${Math.max(lifeMs - delay, 200)}ms ease-in-out ${delay}ms forwards`
27889
+ }
27890
+ },
27891
+ i
27892
+ );
27893
+ }) });
27894
+ }
27895
+ function OverlayFxNode({ item, tickMs }) {
27896
+ const lifeMs = lifeMsOf(item, tickMs);
27897
+ switch (item.effect ?? "sparkle") {
27898
+ case "confetti":
27899
+ return /* @__PURE__ */ jsx(ConfettiBurst, { item, lifeMs });
27900
+ case "flash":
27901
+ return /* @__PURE__ */ jsx(
27902
+ Box,
27903
+ {
27904
+ position: "absolute",
27905
+ className: "inset-0",
27906
+ style: {
27907
+ backgroundColor: item.color ?? "#ffffff",
27908
+ opacity: 0,
27909
+ animation: `fx-overlay-flash ${lifeMs}ms ease-out forwards`
27910
+ }
27911
+ }
27912
+ );
27913
+ case "streak-glow":
27914
+ return /* @__PURE__ */ jsx(
27915
+ Box,
27916
+ {
27917
+ position: "absolute",
27918
+ className: "inset-0",
27919
+ style: {
27920
+ boxShadow: `inset 0 0 ${60 * (item.size ?? 1)}px ${item.color ?? "var(--color-warning)"}`,
27921
+ opacity: 0,
27922
+ animation: `fx-overlay-glow ${lifeMs}ms ease-in-out forwards`
27923
+ }
27924
+ }
27925
+ );
27926
+ case "float-text": {
27927
+ if (!item.message) return null;
27928
+ return /* @__PURE__ */ jsx(
27929
+ Box,
27930
+ {
27931
+ position: "absolute",
27932
+ style: {
27933
+ left: `${(item.x ?? 0.5) * 100}%`,
27934
+ top: `${(item.z ?? item.y ?? 0.4) * 100}%`,
27935
+ color: item.color ?? "var(--color-success)",
27936
+ fontWeight: 700,
27937
+ fontSize: 16 * (item.size ?? 1),
27938
+ textShadow: "0 1px 2px rgba(0,0,0,0.4)",
27939
+ opacity: 0,
27940
+ animation: `fx-overlay-float ${lifeMs}ms ease-out forwards`,
27941
+ whiteSpace: "nowrap"
27942
+ },
27943
+ children: item.message
27944
+ }
27945
+ );
27946
+ }
27947
+ case "shake":
27948
+ return null;
27949
+ default:
27950
+ return /* @__PURE__ */ jsx(SparkleBurst, { item, lifeMs });
27951
+ }
27952
+ }
27953
+ var DEFAULT_TICK_MS2, FX_OVERLAY_KEYFRAMES, lifeMsOf, FxOverlay;
27954
+ var init_FxOverlay = __esm({
27955
+ "components/core/molecules/FxOverlay.tsx"() {
27956
+ "use client";
27957
+ init_cn();
27958
+ init_Box();
27959
+ init_fx();
27960
+ DEFAULT_TICK_MS2 = 500;
27961
+ FX_OVERLAY_KEYFRAMES = `
27962
+ ${CONFETTI_BURST_KEYFRAMES}
27963
+ @keyframes fx-overlay-flash {
27964
+ 0% { opacity: 0.75; }
27965
+ 100% { opacity: 0; }
27966
+ }
27967
+ @keyframes fx-overlay-glow {
27968
+ 0% { opacity: 0.9; }
27969
+ 60% { opacity: 0.6; }
27970
+ 100% { opacity: 0; }
27971
+ }
27972
+ @keyframes fx-overlay-sparkle {
27973
+ 0% { opacity: 0; transform: scale(0); }
27974
+ 30% { opacity: 1; transform: scale(1); }
27975
+ 100% { opacity: 0; transform: scale(0.3); }
27976
+ }
27977
+ @keyframes fx-overlay-float {
27978
+ 0% { opacity: 0; transform: translate(-50%, 8px); }
27979
+ 15% { opacity: 1; }
27980
+ 100% { opacity: 0; transform: translate(-50%, -40px); }
27981
+ }
27982
+ @keyframes fx-overlay-shake {
27983
+ 0% { transform: translateX(0); }
27984
+ 15% { transform: translateX(-6px); }
27985
+ 30% { transform: translateX(5px); }
27986
+ 45% { transform: translateX(-4px); }
27987
+ 60% { transform: translateX(3px); }
27988
+ 75% { transform: translateX(-2px); }
27989
+ 100% { transform: translateX(0); }
27990
+ }
27991
+ `;
27992
+ lifeMsOf = (it, tickMs) => Math.max(it.maxTtl ?? it.ttl, it.ttl, 1) * tickMs;
27993
+ FxOverlay = ({ items, tickMs = DEFAULT_TICK_MS2, children, className }) => {
27994
+ const screenItems = (Array.isArray(items) ? items : []).filter(
27995
+ (it) => Boolean(it) && typeof it.id === "string" && it.space !== "world"
27996
+ );
27997
+ const shakeItem = [...screenItems].reverse().find((it) => it.effect === "shake");
27998
+ const overlay = /* @__PURE__ */ jsxs(
27999
+ Box,
28000
+ {
28001
+ position: "absolute",
28002
+ className: cn("inset-0 pointer-events-none overflow-hidden z-50", !children && className),
28003
+ "aria-hidden": "true",
28004
+ children: [
28005
+ screenItems.map((it) => /* @__PURE__ */ jsx(OverlayFxNode, { item: it, tickMs }, it.id)),
28006
+ /* @__PURE__ */ jsx("style", { children: FX_OVERLAY_KEYFRAMES })
28007
+ ]
28008
+ }
28009
+ );
28010
+ if (children !== void 0 && children !== null) {
28011
+ return /* @__PURE__ */ jsxs(Box, { position: "relative", className, children: [
28012
+ /* @__PURE__ */ jsx(
28013
+ Box,
28014
+ {
28015
+ style: shakeItem ? { animation: `fx-overlay-shake ${Math.min(lifeMsOf(shakeItem, tickMs), 600)}ms ease-in-out` } : void 0,
28016
+ children
28017
+ },
28018
+ shakeItem?.id ?? "steady"
28019
+ ),
28020
+ overlay
28021
+ ] });
28022
+ }
28023
+ return overlay;
28024
+ };
28025
+ FxOverlay.displayName = "FxOverlay";
28026
+ }
28027
+ });
27600
28028
  function computePopoverStyle(position, triggerRect, popoverWidth) {
27601
28029
  if (position === "left" || position === "right") {
27602
28030
  return {
@@ -28153,7 +28581,7 @@ var init_SearchInput = __esm({
28153
28581
  /* @__PURE__ */ jsx(
28154
28582
  Input,
28155
28583
  {
28156
- type: "text",
28584
+ type: "search",
28157
28585
  value: searchValue,
28158
28586
  onChange: handleChange,
28159
28587
  placeholder: resolvedPlaceholder,
@@ -29479,6 +29907,7 @@ var MathCanvas;
29479
29907
  var init_MathCanvas = __esm({
29480
29908
  "components/learning/molecules/MathCanvas.tsx"() {
29481
29909
  "use client";
29910
+ init_useEventBus();
29482
29911
  init_atoms();
29483
29912
  init_Stack();
29484
29913
  init_LearningCanvas();
@@ -29510,9 +29939,32 @@ var init_MathCanvas = __esm({
29510
29939
  interactive = false,
29511
29940
  animate = false,
29512
29941
  onShapeClick,
29942
+ keyMap,
29943
+ keyUpMap,
29513
29944
  isLoading,
29514
29945
  error
29515
29946
  }) => {
29947
+ const eventBus = useEventBus();
29948
+ useEffect(() => {
29949
+ if (!keyMap && !keyUpMap) return;
29950
+ const onDown = (e) => {
29951
+ const ev = keyMap?.[e.code];
29952
+ if (ev) {
29953
+ eventBus.emit(`UI:${ev}`, {});
29954
+ e.preventDefault();
29955
+ }
29956
+ };
29957
+ const onUp = (e) => {
29958
+ const ev = keyUpMap?.[e.code];
29959
+ if (ev) eventBus.emit(`UI:${ev}`, {});
29960
+ };
29961
+ window.addEventListener("keydown", onDown);
29962
+ window.addEventListener("keyup", onUp);
29963
+ return () => {
29964
+ window.removeEventListener("keydown", onDown);
29965
+ window.removeEventListener("keyup", onUp);
29966
+ };
29967
+ }, [keyMap, keyUpMap, eventBus]);
29516
29968
  const derivedShapes = useMemo(() => {
29517
29969
  const out = [];
29518
29970
  const margin = 24;
@@ -29525,11 +29977,11 @@ var init_MathCanvas = __esm({
29525
29977
  if (showGrid) {
29526
29978
  for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep) {
29527
29979
  const px = mapX(x);
29528
- out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#e5e7eb", lineWidth: 1 });
29980
+ out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#9ca3af", opacity: 0.35, lineWidth: 1 });
29529
29981
  }
29530
29982
  for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep) {
29531
29983
  const py = mapY(y);
29532
- out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#e5e7eb", lineWidth: 1 });
29984
+ out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#9ca3af", opacity: 0.35, lineWidth: 1 });
29533
29985
  }
29534
29986
  }
29535
29987
  if (showTickLabels) {
@@ -29578,7 +30030,7 @@ var init_MathCanvas = __esm({
29578
30030
  x: mapX((first.x + last.x) / 2),
29579
30031
  y: (mapY(region.samples[mid].y) + mapY(baseline)) / 2,
29580
30032
  text: region.label,
29581
- color: "#111827",
30033
+ color,
29582
30034
  fontSize: 11
29583
30035
  });
29584
30036
  }
@@ -29611,14 +30063,14 @@ var init_MathCanvas = __esm({
29611
30063
  const px = mapX(guide.at);
29612
30064
  out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color, dash });
29613
30065
  if (guide.label) {
29614
- out.push({ type: "text", x: px + 4, y: margin + 10, text: guide.label, color: "#111827", fontSize: 11 });
30066
+ out.push({ type: "text", x: px + 4, y: margin + 10, text: guide.label, color, fontSize: 11 });
29615
30067
  }
29616
30068
  } else {
29617
30069
  if (guide.at < yMin || guide.at > yMax) continue;
29618
30070
  const py = mapY(guide.at);
29619
30071
  out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color, dash });
29620
30072
  if (guide.label) {
29621
- out.push({ type: "text", x: width - margin - 4, y: py - 8, text: guide.label, color: "#111827", fontSize: 11, align: "right" });
30073
+ out.push({ type: "text", x: width - margin - 4, y: py - 8, text: guide.label, color, fontSize: 11, align: "right" });
29622
30074
  }
29623
30075
  }
29624
30076
  }
@@ -29684,7 +30136,7 @@ var init_MathCanvas = __esm({
29684
30136
  x: (x1 + x2) / 2,
29685
30137
  y: xAxisY - peak - 8,
29686
30138
  text: hop.label,
29687
- color: "#111827",
30139
+ color,
29688
30140
  fontSize: 10,
29689
30141
  align: "center"
29690
30142
  });
@@ -29711,7 +30163,7 @@ var init_MathCanvas = __esm({
29711
30163
  x: mapX(angle.x + 1.35 * radius * Math.cos(rad)),
29712
30164
  y: mapY(angle.y + 1.35 * radius * Math.sin(rad)),
29713
30165
  text: angle.label,
29714
- color: "#111827",
30166
+ color,
29715
30167
  fontSize: 11,
29716
30168
  align: "center"
29717
30169
  });
@@ -29729,7 +30181,7 @@ var init_MathCanvas = __esm({
29729
30181
  fill: isOpen ? "#ffffff" : p.color ?? "#dc2626"
29730
30182
  });
29731
30183
  if (p.label) {
29732
- out.push({ type: "text", x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: "#111827", fontSize: 12 });
30184
+ out.push({ type: "text", x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: p.color ?? "#111827", fontSize: 12 });
29733
30185
  }
29734
30186
  }
29735
30187
  for (const v of vectors) {
@@ -29740,7 +30192,7 @@ var init_MathCanvas = __esm({
29740
30192
  const y2 = mapY(v.y + v.vy);
29741
30193
  out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
29742
30194
  if (v.label) {
29743
- out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: "#111827", fontSize: 12 });
30195
+ out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: v.color ?? "#7c3aed", fontSize: 12 });
29744
30196
  }
29745
30197
  }
29746
30198
  out.push(...shapes);
@@ -31004,13 +31456,13 @@ var init_MapView = __esm({
31004
31456
  shadowSize: [41, 41]
31005
31457
  });
31006
31458
  L.Marker.prototype.options.icon = defaultIcon;
31007
- const { useEffect: useEffect60, useRef: useRef63, useCallback: useCallback90, useState: useState92 } = React85__default;
31459
+ const { useEffect: useEffect61, useRef: useRef63, useCallback: useCallback90, useState: useState92 } = React85__default;
31008
31460
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
31009
31461
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
31010
31462
  function MapUpdater({ centerLat, centerLng, zoom }) {
31011
31463
  const map = useMap();
31012
31464
  const prevRef = useRef63({ centerLat, centerLng, zoom });
31013
- useEffect60(() => {
31465
+ useEffect61(() => {
31014
31466
  const prev = prevRef.current;
31015
31467
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
31016
31468
  map.setView([centerLat, centerLng], zoom);
@@ -31021,7 +31473,7 @@ var init_MapView = __esm({
31021
31473
  }
31022
31474
  function MapClickHandler({ onMapClick }) {
31023
31475
  const map = useMap();
31024
- useEffect60(() => {
31476
+ useEffect61(() => {
31025
31477
  if (!onMapClick) return;
31026
31478
  const handler = (e) => {
31027
31479
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -37699,6 +38151,7 @@ var init_PageHeader = __esm({
37699
38151
  className
37700
38152
  }) => {
37701
38153
  const eventBus = useEventBus();
38154
+ const statusBadge = typeof status === "string" ? status ? { label: status } : void 0 : status;
37702
38155
  const handleBack = () => {
37703
38156
  eventBus.emit(`UI:${backEvent}`);
37704
38157
  };
@@ -37746,15 +38199,15 @@ var init_PageHeader = __esm({
37746
38199
  /* @__PURE__ */ jsxs(Box, { children: [
37747
38200
  /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-3", children: [
37748
38201
  /* @__PURE__ */ jsx(Typography, { variant: "h1", className: "text-2xl font-bold text-foreground", children: title != null ? String(title) : "" }),
37749
- status && /* @__PURE__ */ jsx(
38202
+ statusBadge && /* @__PURE__ */ jsx(
37750
38203
  Typography,
37751
38204
  {
37752
38205
  variant: "small",
37753
38206
  className: cn(
37754
38207
  "px-2.5 py-1 rounded-full text-xs font-medium",
37755
- statusColors2[status.variant || "default"]
38208
+ statusColors2[statusBadge.variant || "default"]
37756
38209
  ),
37757
- children: status.label
38210
+ children: statusBadge.label
37758
38211
  }
37759
38212
  )
37760
38213
  ] }),
@@ -40983,7 +41436,7 @@ function formatFieldValue2(value, fieldName) {
40983
41436
  }
40984
41437
  return String(value);
40985
41438
  }
40986
- function renderRichFieldValue(value, fieldName, fieldType) {
41439
+ function renderRichFieldValue(value, fieldName, fieldType, meta) {
40987
41440
  if (value === void 0 || value === null) return "\u2014";
40988
41441
  const str = String(value);
40989
41442
  switch (fieldType) {
@@ -41050,19 +41503,58 @@ function renderRichFieldValue(value, fieldName, fieldType) {
41050
41503
  }
41051
41504
  );
41052
41505
  case "date":
41053
- case "datetime": {
41506
+ case "datetime":
41507
+ case "timestamp": {
41054
41508
  const d = new Date(str);
41055
41509
  if (!isNaN(d.getTime())) {
41056
41510
  return d.toLocaleDateString(void 0, {
41057
41511
  year: "numeric",
41058
41512
  month: "long",
41059
41513
  day: "numeric",
41060
- ...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
41514
+ ...fieldType !== "date" ? { hour: "2-digit", minute: "2-digit" } : {}
41061
41515
  });
41062
41516
  }
41063
41517
  return str;
41064
41518
  }
41519
+ case "money": {
41520
+ const n = typeof value === "number" ? value : Number(str);
41521
+ if (!isNaN(n)) {
41522
+ return new Intl.NumberFormat(void 0, {
41523
+ style: "currency",
41524
+ currency: "USD"
41525
+ }).format(n);
41526
+ }
41527
+ return str;
41528
+ }
41529
+ case "relation": {
41530
+ const match = meta?.options?.find((opt) => opt.value === str);
41531
+ return match ? match.label : str;
41532
+ }
41533
+ case "file": {
41534
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
41535
+ const file = value;
41536
+ const label = typeof file.name === "string" && file.name ? file.name : "file";
41537
+ const size = typeof file.sizeBytes === "number" ? ` \xB7 ${formatFileSize(file.sizeBytes)}` : "";
41538
+ return /* @__PURE__ */ jsxs(
41539
+ "a",
41540
+ {
41541
+ href: typeof file.url === "string" ? file.url : void 0,
41542
+ download: label,
41543
+ className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-muted px-2 py-1 text-sm text-foreground no-underline hover:bg-accent",
41544
+ children: [
41545
+ /* @__PURE__ */ jsx(Icon, { icon: FileText, size: "sm", className: "text-muted-foreground" }),
41546
+ label,
41547
+ size && /* @__PURE__ */ jsx(Typography, { as: "span", variant: "caption", color: "muted", children: size })
41548
+ ]
41549
+ }
41550
+ );
41551
+ }
41552
+ return str;
41553
+ }
41065
41554
  default:
41555
+ if (meta?.values && meta.values.length > 0 && meta.values.includes(str)) {
41556
+ return /* @__PURE__ */ jsx(Badge, { variant: getBadgeVariant(fieldName, str), children: humanizeEnumValue(str) });
41557
+ }
41066
41558
  return formatFieldValue2(value, fieldName);
41067
41559
  }
41068
41560
  }
@@ -41089,8 +41581,18 @@ function buildFieldTypeMap(fields) {
41089
41581
  const map = {};
41090
41582
  if (!fields) return map;
41091
41583
  for (const f3 of fields) {
41092
- if (typeof f3 === "object" && "name" in f3 && "type" in f3) {
41093
- map[f3.name] = f3.type;
41584
+ if (typeof f3 === "object" && f3.type !== void 0) {
41585
+ map["name" in f3 ? f3.name : f3.key] = f3.type;
41586
+ }
41587
+ }
41588
+ return map;
41589
+ }
41590
+ function buildFieldMetaMap(fields) {
41591
+ const map = {};
41592
+ if (!fields) return map;
41593
+ for (const f3 of fields) {
41594
+ if (typeof f3 === "object" && (f3.type !== void 0 || f3.values !== void 0 || f3.relation !== void 0)) {
41595
+ map["name" in f3 ? f3.name : f3.key] = { type: f3.type, values: f3.values, relation: f3.relation };
41094
41596
  }
41095
41597
  }
41096
41598
  return map;
@@ -41110,6 +41612,7 @@ var init_DetailPanel = __esm({
41110
41612
  init_format();
41111
41613
  init_getNestedValue();
41112
41614
  init_useEventBus();
41615
+ init_UploadDropZone();
41113
41616
  formatFieldLabel = humanizeFieldName;
41114
41617
  ReactMarkdown2 = lazy(() => import('react-markdown'));
41115
41618
  DetailPanel = ({
@@ -41119,6 +41622,7 @@ var init_DetailPanel = __esm({
41119
41622
  avatar,
41120
41623
  sections: propSections,
41121
41624
  actions,
41625
+ backAction,
41122
41626
  footer,
41123
41627
  slideOver = false,
41124
41628
  className,
@@ -41127,7 +41631,8 @@ var init_DetailPanel = __esm({
41127
41631
  fieldNames,
41128
41632
  initialData,
41129
41633
  isLoading = false,
41130
- error
41634
+ error,
41635
+ relationsData
41131
41636
  }) => {
41132
41637
  const eventBus = useEventBus();
41133
41638
  const { t } = useTranslate();
@@ -41138,8 +41643,15 @@ var init_DetailPanel = __esm({
41138
41643
  };
41139
41644
  const effectiveFieldNames = isFieldDefArray(propFields) ? normalizeFieldDefs(propFields) : fieldNames;
41140
41645
  const fieldTypeMap = isFieldDefArray(propFields) ? buildFieldTypeMap(propFields) : {};
41646
+ const fieldMetaMap = isFieldDefArray(propFields) ? buildFieldMetaMap(propFields) : {};
41141
41647
  const fieldLabelMap = isFieldDefArray(propFields) ? buildFieldLabelMap(propFields) : {};
41142
41648
  const labelFor = (field) => fieldLabelMap[field] ?? formatFieldLabel(field);
41649
+ const metaFor = (field) => {
41650
+ const base = fieldMetaMap[field];
41651
+ const options = relationsData?.[field];
41652
+ if (!base && !options) return void 0;
41653
+ return { ...base, options };
41654
+ };
41143
41655
  const handleActionClick = useCallback(
41144
41656
  (action, data2) => {
41145
41657
  if (action.navigatesTo) {
@@ -41218,7 +41730,7 @@ var init_DetailPanel = __esm({
41218
41730
  if (value !== void 0 && value !== null) {
41219
41731
  overviewFields.push({
41220
41732
  label: labelFor(field),
41221
- value: renderRichFieldValue(value, field, fieldTypeMap[field]),
41733
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
41222
41734
  icon: getFieldIcon(field)
41223
41735
  });
41224
41736
  }
@@ -41234,7 +41746,7 @@ var init_DetailPanel = __esm({
41234
41746
  if (value !== void 0 && value !== null) {
41235
41747
  metricsFields.push({
41236
41748
  label: labelFor(field),
41237
- value: renderRichFieldValue(value, field, fieldTypeMap[field]),
41749
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
41238
41750
  icon: getFieldIcon(field)
41239
41751
  });
41240
41752
  }
@@ -41250,7 +41762,7 @@ var init_DetailPanel = __esm({
41250
41762
  if (value !== void 0 && value !== null) {
41251
41763
  timelineFields.push({
41252
41764
  label: labelFor(field),
41253
- value: renderRichFieldValue(value, field, fieldTypeMap[field]),
41765
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
41254
41766
  icon: getFieldIcon(field)
41255
41767
  });
41256
41768
  }
@@ -41266,7 +41778,7 @@ var init_DetailPanel = __esm({
41266
41778
  if (value !== void 0 && value !== null) {
41267
41779
  descFields.push({
41268
41780
  label: labelFor(field),
41269
- value: renderRichFieldValue(value, field, fieldTypeMap[field]),
41781
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
41270
41782
  icon: getFieldIcon(field)
41271
41783
  });
41272
41784
  }
@@ -41314,7 +41826,7 @@ var init_DetailPanel = __esm({
41314
41826
  const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
41315
41827
  allFields.push({
41316
41828
  label: labelFor(field),
41317
- value: renderRichFieldValue(value, field, fieldTypeMap[field]),
41829
+ value: renderRichFieldValue(value, field, fieldTypeMap[field], metaFor(field)),
41318
41830
  icon: getFieldIcon(field)
41319
41831
  });
41320
41832
  } else {
@@ -41329,34 +41841,49 @@ var init_DetailPanel = __esm({
41329
41841
  const otherActions = actions?.filter((a) => a !== closeAction) ?? [];
41330
41842
  const effectiveCloseAction = closeAction ?? { event: void 0};
41331
41843
  const content = /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
41332
- /* @__PURE__ */ jsxs(HStack, { justify: "end", align: "center", gap: "xs", children: [
41333
- otherActions.map((action, idx) => /* @__PURE__ */ jsx(
41334
- Button,
41335
- {
41336
- variant: action.variant || "secondary",
41337
- size: "sm",
41338
- action: action.navigatesTo ? void 0 : action.event,
41339
- actionPayload: { row: normalizedData },
41340
- onClick: action.navigatesTo ? () => handleActionClick(action, normalizedData) : void 0,
41341
- icon: action.icon,
41342
- "data-testid": action.event ? `action-${action.event}` : void 0,
41343
- "data-row-id": normalizedData?.id !== void 0 ? String(normalizedData.id) : void 0,
41344
- children: action.label
41345
- },
41346
- idx
41347
- )),
41348
- /* @__PURE__ */ jsx(
41844
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", gap: "xs", children: [
41845
+ /* @__PURE__ */ jsx(HStack, { align: "center", gap: "xs", children: backAction && /* @__PURE__ */ jsx(
41349
41846
  Button,
41350
41847
  {
41351
- variant: "ghost",
41848
+ variant: backAction.variant || "ghost",
41352
41849
  size: "sm",
41353
- action: effectiveCloseAction.event,
41850
+ action: backAction.navigatesTo ? void 0 : backAction.event,
41354
41851
  actionPayload: { row: normalizedData },
41355
- onClick: effectiveCloseAction.event ? void 0 : handleClose,
41356
- icon: X,
41357
- "data-testid": effectiveCloseAction.event ? `action-${effectiveCloseAction.event}` : "action-close"
41852
+ onClick: backAction.navigatesTo ? () => handleActionClick(backAction, normalizedData) : void 0,
41853
+ icon: backAction.icon ?? ArrowLeft,
41854
+ "data-testid": backAction.event ? `action-${backAction.event}` : "action-back",
41855
+ children: backAction.label
41358
41856
  }
41359
- )
41857
+ ) }),
41858
+ /* @__PURE__ */ jsxs(HStack, { justify: "end", align: "center", gap: "xs", children: [
41859
+ otherActions.map((action, idx) => /* @__PURE__ */ jsx(
41860
+ Button,
41861
+ {
41862
+ variant: action.variant || "secondary",
41863
+ size: "sm",
41864
+ action: action.navigatesTo ? void 0 : action.event,
41865
+ actionPayload: { row: normalizedData },
41866
+ onClick: action.navigatesTo ? () => handleActionClick(action, normalizedData) : void 0,
41867
+ icon: action.icon,
41868
+ "data-testid": action.event ? `action-${action.event}` : void 0,
41869
+ "data-row-id": normalizedData?.id !== void 0 ? String(normalizedData.id) : void 0,
41870
+ children: action.label
41871
+ },
41872
+ idx
41873
+ )),
41874
+ /* @__PURE__ */ jsx(
41875
+ Button,
41876
+ {
41877
+ variant: "ghost",
41878
+ size: "sm",
41879
+ action: effectiveCloseAction.event,
41880
+ actionPayload: { row: normalizedData },
41881
+ onClick: effectiveCloseAction.event ? void 0 : handleClose,
41882
+ icon: X,
41883
+ "data-testid": effectiveCloseAction.event ? `action-${effectiveCloseAction.event}` : "action-close"
41884
+ }
41885
+ )
41886
+ ] })
41360
41887
  ] }),
41361
41888
  avatar,
41362
41889
  /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
@@ -41671,6 +42198,10 @@ function determineInputType(field) {
41671
42198
  return "password";
41672
42199
  case "url":
41673
42200
  return "url";
42201
+ case "file":
42202
+ return "file";
42203
+ case "money":
42204
+ return "currency";
41674
42205
  case "number":
41675
42206
  case "integer":
41676
42207
  case "float":
@@ -41732,6 +42263,7 @@ var init_Form = __esm({
41732
42263
  init_Typography();
41733
42264
  init_Icon();
41734
42265
  init_RelationSelect();
42266
+ init_UploadDropZone();
41735
42267
  init_Alert();
41736
42268
  init_useEventBus();
41737
42269
  init_debug();
@@ -41774,6 +42306,7 @@ var init_Form = __esm({
41774
42306
  cancelEvent = "CANCEL",
41775
42307
  relationsData = {},
41776
42308
  relationsLoading = {},
42309
+ fieldOverrides,
41777
42310
  // Inspection form extensions - may come as boolean true from generated code (meaning enabled but config loaded separately)
41778
42311
  conditionalFields: conditionalFieldsRaw = {},
41779
42312
  hiddenCalculations: hiddenCalculationsRaw = [],
@@ -42020,7 +42553,8 @@ var init_Form = __esm({
42020
42553
  label,
42021
42554
  field.required && /* @__PURE__ */ jsx(Typography, { as: "span", color: "error", className: "ml-1", children: "*" })
42022
42555
  ] }),
42023
- renderFieldInput(field, fieldName, inputType, currentValue, label)
42556
+ renderFieldInput(field, fieldName, inputType, currentValue, label),
42557
+ field.hint && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: field.hint })
42024
42558
  ] }, fieldName);
42025
42559
  },
42026
42560
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
@@ -42036,6 +42570,7 @@ var init_Form = __esm({
42036
42570
  name: field,
42037
42571
  type: entityField.type,
42038
42572
  required: entityField.required,
42573
+ hint: entityField.description,
42039
42574
  // EntityField.default is typed `unknown` upstream — safe cast: schema defaults are always FieldValues.
42040
42575
  defaultValue: entityField.default,
42041
42576
  // EntityField is a discriminated union — `values` lives on Scalar/Enum, `relation` lives on Relation.
@@ -42048,8 +42583,18 @@ var init_Form = __esm({
42048
42583
  return { name: field, type: "string" };
42049
42584
  }
42050
42585
  return field;
42586
+ }).map((field) => {
42587
+ const fieldName = field.name || field.field;
42588
+ const override = fieldOverrides?.find((o) => o.name === fieldName);
42589
+ if (!override) return field;
42590
+ return {
42591
+ ...field,
42592
+ ...override.label !== void 0 ? { label: override.label } : {},
42593
+ ...override.placeholder !== void 0 ? { placeholder: override.placeholder } : {},
42594
+ ...override.hint !== void 0 ? { hint: override.hint } : {}
42595
+ };
42051
42596
  });
42052
- }, [effectiveFields, resolvedEntity]);
42597
+ }, [effectiveFields, resolvedEntity, fieldOverrides]);
42053
42598
  const schemaFields = React85__default.useMemo(() => {
42054
42599
  if (normalizedFields.length === 0) return null;
42055
42600
  if (isDebugEnabled()) {
@@ -42173,6 +42718,44 @@ var init_Form = __esm({
42173
42718
  max: field.max
42174
42719
  }
42175
42720
  );
42721
+ case "currency":
42722
+ return /* @__PURE__ */ jsx(
42723
+ Input,
42724
+ {
42725
+ ...commonProps,
42726
+ type: "number",
42727
+ step: "0.01",
42728
+ icon: DollarSign,
42729
+ value: currentValue !== void 0 && currentValue !== "" ? String(currentValue) : "",
42730
+ onChange: (e) => handleChange(
42731
+ fieldName,
42732
+ e.target.value ? Number(e.target.value) : void 0
42733
+ ),
42734
+ min: field.min,
42735
+ max: field.max
42736
+ }
42737
+ );
42738
+ case "file":
42739
+ return /* @__PURE__ */ jsx(
42740
+ UploadDropZone,
42741
+ {
42742
+ accept: field.pattern,
42743
+ maxFiles: 1,
42744
+ disabled: isLoading,
42745
+ onFiles: (files) => {
42746
+ const f3 = files[0];
42747
+ if (!f3) return;
42748
+ const reader = new FileReader();
42749
+ reader.onload = () => handleChange(fieldName, {
42750
+ name: f3.name,
42751
+ mimeType: f3.type,
42752
+ sizeBytes: f3.size,
42753
+ url: typeof reader.result === "string" ? reader.result : ""
42754
+ });
42755
+ reader.readAsDataURL(f3);
42756
+ }
42757
+ }
42758
+ );
42176
42759
  case "date":
42177
42760
  return /* @__PURE__ */ jsx(
42178
42761
  Input,
@@ -43205,6 +43788,7 @@ var COLUMN_CLASSES, ASPECT_CLASSES, MediaGallery;
43205
43788
  var init_MediaGallery = __esm({
43206
43789
  "components/core/organisms/MediaGallery.tsx"() {
43207
43790
  "use client";
43791
+ init_getNestedValue();
43208
43792
  init_cn();
43209
43793
  init_atoms();
43210
43794
  init_Stack();
@@ -43273,9 +43857,9 @@ var init_MediaGallery = __esm({
43273
43857
  return entityData.map((record, idx) => {
43274
43858
  return {
43275
43859
  id: String(record.id ?? idx),
43276
- src: String(record.src ?? ("url" in record ? record.url : "") ?? ("image" in record ? record.image : "") ?? ""),
43860
+ src: resolveImageUrl(record.src ?? ("url" in record ? record.url : void 0) ?? ("image" in record ? record.image : void 0)) ?? "",
43277
43861
  alt: record.alt ? String(record.alt) : void 0,
43278
- thumbnail: record.thumbnail ? String(record.thumbnail) : void 0,
43862
+ thumbnail: resolveImageUrl(record.thumbnail),
43279
43863
  caption: record.caption ? String(record.caption) : "title" in record ? String(record.title) : void 0
43280
43864
  };
43281
43865
  });
@@ -47162,6 +47746,7 @@ var init_component_registry_generated = __esm({
47162
47746
  init_DocSidebar();
47163
47747
  init_DocTOC();
47164
47748
  init_DocumentViewer();
47749
+ init_DrawFxLayer();
47165
47750
  init_DrawGroup();
47166
47751
  init_DrawMesh();
47167
47752
  init_DrawShape();
@@ -47192,6 +47777,7 @@ var init_component_registry_generated = __esm({
47192
47777
  init_FormField();
47193
47778
  init_FormSection();
47194
47779
  init_FormSectionHeader();
47780
+ init_FxOverlay();
47195
47781
  init_GameAudioToggle();
47196
47782
  init_GameHud();
47197
47783
  init_GameIcon();
@@ -47432,6 +48018,7 @@ var init_component_registry_generated = __esm({
47432
48018
  "DocSidebar": DocSidebar,
47433
48019
  "DocTOC": DocTOC,
47434
48020
  "DocumentViewer": DocumentViewer,
48021
+ "DrawFxLayer": DrawFxLayer,
47435
48022
  "DrawGroup": DrawGroup,
47436
48023
  "DrawMesh": DrawMesh,
47437
48024
  "DrawShape": DrawShape,
@@ -47462,6 +48049,7 @@ var init_component_registry_generated = __esm({
47462
48049
  "FormField": FormField,
47463
48050
  "FormLayout": FormLayout,
47464
48051
  "FormSectionHeader": FormSectionHeader,
48052
+ "FxOverlay": FxOverlay,
47465
48053
  "GameAudioToggle": GameAudioToggle,
47466
48054
  "GameHud": GameHud,
47467
48055
  "GameIcon": GameIcon,
@@ -47637,7 +48225,8 @@ __export(UISlotRenderer_exports, {
47637
48225
  SlotContentRenderer: () => SlotContentRenderer,
47638
48226
  SuspenseConfigProvider: () => SuspenseConfigProvider,
47639
48227
  UISlotComponent: () => UISlotComponent,
47640
- UISlotRenderer: () => UISlotRenderer
48228
+ UISlotRenderer: () => UISlotRenderer,
48229
+ renderPatternValue: () => renderPatternValue
47641
48230
  });
47642
48231
  function SuspenseConfigProvider({
47643
48232
  config,
@@ -47673,6 +48262,9 @@ function enrichFormFields(fields, entityDef) {
47673
48262
  type: entityField.type,
47674
48263
  required: entityField.required ?? false
47675
48264
  };
48265
+ if (entityField.description) {
48266
+ enriched.hint = entityField.description;
48267
+ }
47676
48268
  if (entityField.values && entityField.values.length > 0) {
47677
48269
  enriched.values = entityField.values;
47678
48270
  } else if (entityField.enumValues && entityField.enumValues.length > 0) {
@@ -47696,6 +48288,9 @@ function enrichFormFields(fields, entityDef) {
47696
48288
  if (entityField.required && !("required" in obj)) {
47697
48289
  enriched.required = true;
47698
48290
  }
48291
+ if (entityField.description && !obj.hint && !obj.help) {
48292
+ enriched.hint = entityField.description;
48293
+ }
47699
48294
  if (!obj.values && !obj.options) {
47700
48295
  if (entityField.values && entityField.values.length > 0) {
47701
48296
  enriched.values = entityField.values;
@@ -47711,6 +48306,32 @@ function enrichFormFields(fields, entityDef) {
47711
48306
  return field;
47712
48307
  });
47713
48308
  }
48309
+ function enrichDetailFields(fields, entityDef) {
48310
+ const fieldMap = new Map(entityDef.fields.map((f3) => [f3.name, f3]));
48311
+ const metaFor = (name) => {
48312
+ const entityField = fieldMap.get(name);
48313
+ if (!entityField) return void 0;
48314
+ const meta = { type: entityField.type };
48315
+ const values = entityField.values ?? entityField.enumValues;
48316
+ if (values && values.length > 0) meta.values = values;
48317
+ if (entityField.relation) meta.relation = entityField.relation.entity;
48318
+ return meta;
48319
+ };
48320
+ return fields.map((field) => {
48321
+ if (typeof field === "string") {
48322
+ const meta = metaFor(field);
48323
+ return meta ? { key: field, ...meta } : field;
48324
+ }
48325
+ if (field && typeof field === "object" && !Array.isArray(field) && !React85__default.isValidElement(field) && !(field instanceof Date)) {
48326
+ const obj = field;
48327
+ const fieldName = typeof obj.key === "string" ? obj.key : typeof obj.name === "string" ? obj.name : void 0;
48328
+ if (!fieldName || obj.type) return field;
48329
+ const meta = metaFor(fieldName);
48330
+ return meta ? { ...obj, ...meta } : field;
48331
+ }
48332
+ return field;
48333
+ });
48334
+ }
47714
48335
  function renderContainedPortal(t, slot, content, onDismiss) {
47715
48336
  const slotContent = /* @__PURE__ */ jsx(MaybeTraitScope, { sourceTrait: content.sourceTrait, children: /* @__PURE__ */ jsx(SlotContentRenderer, { content, onDismiss }) });
47716
48337
  const slotId = `slot-${slot}`;
@@ -48220,6 +48841,24 @@ function isPatternConfig(value) {
48220
48841
  const record = value;
48221
48842
  return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
48222
48843
  }
48844
+ function renderPatternValue(value) {
48845
+ if (value === null || value === void 0) return null;
48846
+ if (typeof value === "boolean" || typeof value === "function") return null;
48847
+ if (typeof value === "number") return value;
48848
+ if (typeof value === "string") return renderPatternChildren(value, () => {
48849
+ });
48850
+ if (value instanceof Date) return value.toLocaleString();
48851
+ if (React85__default.isValidElement(value)) return value;
48852
+ if (Array.isArray(value)) {
48853
+ return value.map((item, index) => /* @__PURE__ */ jsx(React85__default.Fragment, { children: renderPatternValue(item) }, index));
48854
+ }
48855
+ if (isPatternConfig(value)) {
48856
+ const { type, ...props } = value;
48857
+ return renderPatternChildren({ type, props }, () => {
48858
+ });
48859
+ }
48860
+ return null;
48861
+ }
48223
48862
  function isPlainConfigObject(value) {
48224
48863
  if (React85__default.isValidElement(value)) return false;
48225
48864
  if (value instanceof Date) return false;
@@ -48421,9 +49060,9 @@ function SlotContentRenderer({
48421
49060
  finalProps.fields = keys.map((k, i) => ({ name: k, variant: i === 0 ? "h4" : "body" }));
48422
49061
  }
48423
49062
  }
48424
- const isFormPattern = FORM_PATTERNS.has(content.pattern) || content.pattern.includes("form");
48425
- if (isFormPattern && entityDef && Array.isArray(finalProps.fields) && finalProps.fields[0] !== "fn") {
48426
- finalProps.fields = enrichFormFields([...finalProps.fields], entityDef);
49063
+ const fieldsContract = getPatternFieldsContract(content.pattern) ?? (getPatternDefinition(content.pattern) === null && content.pattern.includes("form") ? "form" : void 0);
49064
+ if (fieldsContract && entityDef && Array.isArray(finalProps.fields) && finalProps.fields[0] !== "fn") {
49065
+ finalProps.fields = fieldsContract === "form" ? enrichFormFields([...finalProps.fields], entityDef) : enrichDetailFields([...finalProps.fields], entityDef);
48427
49066
  }
48428
49067
  const acceptsChildren = PATTERNS_WITH_CHILDREN.has(content.pattern);
48429
49068
  return /* @__PURE__ */ jsx(
@@ -48533,7 +49172,7 @@ function UISlotRenderer({
48533
49172
  }
48534
49173
  return wrapped;
48535
49174
  }
48536
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, FORM_PATTERNS, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN;
49175
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN;
48537
49176
  var init_UISlotRenderer = __esm({
48538
49177
  "components/core/organisms/UISlotRenderer.tsx"() {
48539
49178
  "use client";
@@ -48564,12 +49203,6 @@ var init_UISlotRenderer = __esm({
48564
49203
  modal: "form",
48565
49204
  drawer: "form"
48566
49205
  };
48567
- FORM_PATTERNS = /* @__PURE__ */ new Set([
48568
- "form",
48569
- "form-section",
48570
- "inline-edit-form",
48571
- "wizard-step"
48572
- ]);
48573
49206
  SELF_OVERLAY_PATTERNS = /* @__PURE__ */ new Set(["modal", "confirm-dialog"]);
48574
49207
  CONTENT_NODE_SLOTS = /* @__PURE__ */ new Set([
48575
49208
  "logo",