@almadar/ui 6.12.0 → 6.14.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 (47) hide show
  1. package/dist/{UserContext-g_LcDiGN.d.cts → CurrentPagePathContext-J1lqjvAq.d.cts} +2 -97
  2. package/dist/{UserContext-g_LcDiGN.d.ts → CurrentPagePathContext-J1lqjvAq.d.ts} +2 -97
  3. package/dist/{EntityBindingContext-D5lRu6p1.d.cts → EntityBindingContext-BMz9xiBa.d.cts} +2 -3
  4. package/dist/{EntityBindingContext-D5lRu6p1.d.ts → EntityBindingContext-BMz9xiBa.d.ts} +2 -3
  5. package/dist/{GameAudioProvider-D8GynTNq.d.cts → GameAudioProvider-Cpw_lMPY.d.cts} +1 -1
  6. package/dist/{GameAudioProvider-Dozqx4sL.d.ts → GameAudioProvider-DIjFiy70.d.ts} +1 -1
  7. package/dist/UserContext-D566nfWA.d.cts +99 -0
  8. package/dist/UserContext-D566nfWA.d.ts +99 -0
  9. package/dist/avl/index.cjs +571 -70
  10. package/dist/avl/index.d.cts +1 -1
  11. package/dist/avl/index.d.ts +1 -1
  12. package/dist/avl/index.js +573 -72
  13. package/dist/{avl-schema-parser-PVu8rgsy.d.cts → avl-schema-parser-B25PL-a8.d.cts} +1 -1
  14. package/dist/{avl-schema-parser-DX-aVCCm.d.ts → avl-schema-parser-CM0pQo8E.d.ts} +1 -1
  15. package/dist/components/index.cjs +564 -117
  16. package/dist/components/index.d.cts +8 -24
  17. package/dist/components/index.d.ts +8 -24
  18. package/dist/components/index.js +566 -118
  19. package/dist/context/index.d.cts +2 -1
  20. package/dist/context/index.d.ts +2 -1
  21. package/dist/lib/drawable/three/index.cjs +126 -3
  22. package/dist/lib/drawable/three/index.d.cts +3 -3
  23. package/dist/lib/drawable/three/index.d.ts +3 -3
  24. package/dist/lib/drawable/three/index.js +126 -3
  25. package/dist/lib/index.cjs +1 -4
  26. package/dist/lib/index.d.cts +2 -2
  27. package/dist/lib/index.d.ts +2 -2
  28. package/dist/lib/index.js +1 -4
  29. package/dist/{offline-executor-QUdKOj7f.d.cts → offline-executor-DdV2o0Zu.d.cts} +4 -19
  30. package/dist/{offline-executor-QUdKOj7f.d.ts → offline-executor-DdV2o0Zu.d.ts} +4 -19
  31. package/dist/{paintDispatch-CK5uwYEq.d.cts → paintDispatch-Dh1pgljl.d.cts} +79 -1
  32. package/dist/{paintDispatch-CK5uwYEq.d.ts → paintDispatch-Dh1pgljl.d.ts} +79 -1
  33. package/dist/providers/index.cjs +558 -62
  34. package/dist/providers/index.d.cts +10 -9
  35. package/dist/providers/index.d.ts +10 -9
  36. package/dist/providers/index.js +559 -63
  37. package/dist/renderer/index.cjs +0 -15
  38. package/dist/renderer/index.d.cts +4 -9
  39. package/dist/renderer/index.d.ts +4 -9
  40. package/dist/renderer/index.js +1 -15
  41. package/dist/runtime/index.cjs +573 -81
  42. package/dist/runtime/index.d.cts +14 -11
  43. package/dist/runtime/index.d.ts +14 -11
  44. package/dist/runtime/index.js +575 -83
  45. package/dist/{verificationRegistry-D8bHWD8Q.d.ts → verificationRegistry-Cwa52VyK.d.ts} +1 -1
  46. package/dist/{verificationRegistry-BLsjb1oU.d.cts → verificationRegistry-DTrKDRoa.d.cts} +1 -1
  47. package/package.json +4 -4
@@ -7856,7 +7856,7 @@ var init_DialogueBubble = __esm({
7856
7856
  init_Typography();
7857
7857
  init_GameIcon();
7858
7858
  DEFAULT_PORTRAIT = {
7859
- url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
7859
+ url: "https://almadar-kflow-assets.web.app/shared/ui-winter-ski-board/default/units/hero/hero.png",
7860
7860
  role: "effect",
7861
7861
  category: "character"
7862
7862
  };
@@ -9180,6 +9180,14 @@ function createWebPainter(ctx, onAssetLoad) {
9180
9180
  ctx.drawImage(img, dest.x, dest.y, dw, dh);
9181
9181
  }
9182
9182
  },
9183
+ blitTransformed(tex, src, affine) {
9184
+ const img = imageByHandle.get(tex);
9185
+ if (!img) return;
9186
+ ctx.save();
9187
+ ctx.transform(affine[0], affine[1], affine[2], affine[3], affine[4], affine[5]);
9188
+ ctx.drawImage(img, src.x, src.y, src.w, src.h, src.x, src.y, src.w, src.h);
9189
+ ctx.restore();
9190
+ },
9183
9191
  fillRect(x, y, w, h, style) {
9184
9192
  ctx.fillStyle = toCanvasStyle(style);
9185
9193
  ctx.fillRect(x, y, w, h);
@@ -9686,6 +9694,271 @@ var init_DrawGroup = __esm({
9686
9694
  init_registry();
9687
9695
  }
9688
9696
  });
9697
+
9698
+ // lib/skinning.ts
9699
+ function composeAffine(a, b) {
9700
+ return [
9701
+ a[0] * b[0] + a[2] * b[1],
9702
+ a[1] * b[0] + a[3] * b[1],
9703
+ a[0] * b[2] + a[2] * b[3],
9704
+ a[1] * b[2] + a[3] * b[3],
9705
+ a[0] * b[4] + a[2] * b[5] + a[4],
9706
+ a[1] * b[4] + a[3] * b[5] + a[5]
9707
+ ];
9708
+ }
9709
+ function invertAffine(m) {
9710
+ const det = m[0] * m[3] - m[1] * m[2];
9711
+ if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return IDENTITY;
9712
+ const inv = 1 / det;
9713
+ return [
9714
+ m[3] * inv,
9715
+ -m[1] * inv,
9716
+ -m[2] * inv,
9717
+ m[0] * inv,
9718
+ (m[2] * m[5] - m[3] * m[4]) * inv,
9719
+ (m[1] * m[4] - m[0] * m[5]) * inv
9720
+ ];
9721
+ }
9722
+ function applyAffine(m, x, y) {
9723
+ return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
9724
+ }
9725
+ function rotationAbout(pivot, degrees) {
9726
+ const r = degrees * Math.PI / 180;
9727
+ const cos = Math.cos(r);
9728
+ const sin = Math.sin(r);
9729
+ const [px, py] = pivot;
9730
+ return [cos, sin, -sin, cos, px - cos * px + sin * py, py - sin * px - cos * py];
9731
+ }
9732
+ function computeWorldMatrices(bones, pose) {
9733
+ const indexByName = /* @__PURE__ */ new Map();
9734
+ bones.forEach((b, i) => indexByName.set(b.name, i));
9735
+ const world = new Array(bones.length);
9736
+ const visiting = /* @__PURE__ */ new Set();
9737
+ const resolve = (i) => {
9738
+ const cached = world[i];
9739
+ if (cached) return cached;
9740
+ if (visiting.has(i)) return IDENTITY;
9741
+ visiting.add(i);
9742
+ const b = bones[i];
9743
+ const parentIndex = b.parent === null ? void 0 : indexByName.get(b.parent);
9744
+ const parentWorld = parentIndex === void 0 ? IDENTITY : resolve(parentIndex);
9745
+ const local = rotationAbout(b.pivot, pose[b.name] ?? 0);
9746
+ const m = composeAffine(parentWorld, local);
9747
+ visiting.delete(i);
9748
+ world[i] = m;
9749
+ return m;
9750
+ };
9751
+ return bones.map((_, i) => resolve(i));
9752
+ }
9753
+ function skinVertices(mesh, bindWorld, curWorld) {
9754
+ const skinMats = /* @__PURE__ */ new Map();
9755
+ const skinMat = (bone) => {
9756
+ let m = skinMats.get(bone);
9757
+ if (!m) {
9758
+ m = composeAffine(curWorld[bone] ?? IDENTITY, invertAffine(bindWorld[bone] ?? IDENTITY));
9759
+ skinMats.set(bone, m);
9760
+ }
9761
+ return m;
9762
+ };
9763
+ return mesh.vertices.map((v) => {
9764
+ if (v.weights.length === 0) return [v.x, v.y];
9765
+ let x = 0;
9766
+ let y = 0;
9767
+ for (const { bone, w } of v.weights) {
9768
+ const [bx, by] = applyAffine(skinMat(bone), v.x, v.y);
9769
+ x += w * bx;
9770
+ y += w * by;
9771
+ }
9772
+ return [x, y];
9773
+ });
9774
+ }
9775
+ function triangleAffine(src, dst) {
9776
+ const [s0, s1, s2] = src;
9777
+ const det = s0[0] * (s1[1] - s2[1]) + s1[0] * (s2[1] - s0[1]) + s2[0] * (s0[1] - s1[1]);
9778
+ if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return null;
9779
+ const [d0, d1, d2] = dst;
9780
+ const a = (d0[0] * (s1[1] - s2[1]) + d1[0] * (s2[1] - s0[1]) + d2[0] * (s0[1] - s1[1])) / det;
9781
+ const c = (d0[0] * (s2[0] - s1[0]) + d1[0] * (s0[0] - s2[0]) + d2[0] * (s1[0] - s0[0])) / det;
9782
+ const e = (d0[0] * (s1[0] * s2[1] - s2[0] * s1[1]) + d1[0] * (s2[0] * s0[1] - s0[0] * s2[1]) + d2[0] * (s0[0] * s1[1] - s1[0] * s0[1])) / det;
9783
+ const b = (d0[1] * (s1[1] - s2[1]) + d1[1] * (s2[1] - s0[1]) + d2[1] * (s0[1] - s1[1])) / det;
9784
+ const d = (d0[1] * (s2[0] - s1[0]) + d1[1] * (s0[0] - s2[0]) + d2[1] * (s1[0] - s0[0])) / det;
9785
+ const f3 = (d0[1] * (s1[0] * s2[1] - s2[0] * s1[1]) + d1[1] * (s2[0] * s0[1] - s0[0] * s2[1]) + d2[1] * (s0[0] * s1[1] - s1[0] * s0[1])) / det;
9786
+ return [a, b, c, d, e, f3];
9787
+ }
9788
+ function isRigBundle(json) {
9789
+ return json.mesh !== void 0 || json.bones !== void 0;
9790
+ }
9791
+ function getRigBundle(url, onReady) {
9792
+ if (meshCache.has(url)) return meshCache.get(url) ?? void 0;
9793
+ meshCache.set(url, void 0);
9794
+ fetch(url).then((r) => {
9795
+ if (!r.ok) throw new Error(`rigbundle fetch failed: HTTP ${r.status}`);
9796
+ return r.json();
9797
+ }).then((json) => {
9798
+ const ok = isRigBundle(json) || Array.isArray(json.vertices);
9799
+ if (!ok) throw new Error("rigbundle payload is neither a SkinMesh nor a rigbundle");
9800
+ meshCache.set(url, json);
9801
+ onReady();
9802
+ }).catch(() => {
9803
+ meshCache.set(url, null);
9804
+ onReady();
9805
+ });
9806
+ return void 0;
9807
+ }
9808
+ function skinMeshFailed(url) {
9809
+ return meshCache.get(url) === null;
9810
+ }
9811
+ function vertexBounds(points) {
9812
+ if (points.length === 0) return null;
9813
+ let minX = Infinity;
9814
+ let minY = Infinity;
9815
+ let maxX = -Infinity;
9816
+ let maxY = -Infinity;
9817
+ for (const [x, y] of points) {
9818
+ if (x < minX) minX = x;
9819
+ if (y < minY) minY = y;
9820
+ if (x > maxX) maxX = x;
9821
+ if (y > maxY) maxY = y;
9822
+ }
9823
+ return { minX, minY, maxX, maxY };
9824
+ }
9825
+ var IDENTITY, meshCache;
9826
+ var init_skinning = __esm({
9827
+ "lib/skinning.ts"() {
9828
+ IDENTITY = [1, 0, 0, 1, 0, 0];
9829
+ meshCache = /* @__PURE__ */ new Map();
9830
+ }
9831
+ });
9832
+ function warnMissingOnce2(reason, node) {
9833
+ const key = `${reason}:${node.asset.url}:${String(node.meshUrl)}`;
9834
+ if (loggedMissing2.has(key)) return;
9835
+ loggedMissing2.add(key);
9836
+ skinnedLog.warn("draw-skinned-mesh unresolvable \u2014 painting fallback", { reason, url: node.asset.url, meshUrl: node.meshUrl });
9837
+ }
9838
+ function dominantBone(v) {
9839
+ let best = -1;
9840
+ let bestW = 0;
9841
+ for (const { bone, w } of v.weights) {
9842
+ if (w > bestW) {
9843
+ bestW = w;
9844
+ best = bone;
9845
+ }
9846
+ }
9847
+ return best;
9848
+ }
9849
+ function resolveSkinPose(node, clip) {
9850
+ const effectiveClip = clip ?? node.clip;
9851
+ if (effectiveClip && node.frame !== void 0 && effectiveClip.frames.length > 0) {
9852
+ return effectiveClip.frames[node.frame % effectiveClip.frames.length];
9853
+ }
9854
+ return node.pose ?? {};
9855
+ }
9856
+ function resolveRig(node, dctx) {
9857
+ const fetched = node.meshUrl ? getRigBundle(node.meshUrl, dctx.invalidate) : void 0;
9858
+ if (node.meshUrl && fetched === void 0) return void 0;
9859
+ const rb = fetched && isRigBundle(fetched) ? fetched : void 0;
9860
+ const mesh = node.mesh ?? rb?.mesh ?? (!rb ? fetched : void 0);
9861
+ if (!mesh) return void 0;
9862
+ const bones = node.bones.length > 0 ? node.bones : rb?.bones ?? [];
9863
+ if (bones.length === 0) return void 0;
9864
+ const clip = node.clip ?? (node.clipName ? rb?.clips?.[node.clipName] : void 0);
9865
+ return { mesh, bones, clip };
9866
+ }
9867
+ function meshHasPixelUVs(mesh) {
9868
+ const cached = pixelUVByMesh.get(mesh);
9869
+ if (cached !== void 0) return cached;
9870
+ let pixel = false;
9871
+ for (const v of mesh.vertices) {
9872
+ if (v.u < 0 || v.u > 1 || v.v < 0 || v.v > 1) {
9873
+ pixel = true;
9874
+ break;
9875
+ }
9876
+ }
9877
+ pixelUVByMesh.set(mesh, pixel);
9878
+ return pixel;
9879
+ }
9880
+ function paintMeshPass(painter, node, bones, mesh, tex, dctx, pose, opacity) {
9881
+ const bindWorld = computeWorldMatrices(bones, {});
9882
+ const curWorld = computeWorldMatrices(bones, pose);
9883
+ const skinned = skinVertices(mesh, bindWorld, curWorld);
9884
+ const origin = dctx.projector.project(node.position);
9885
+ const tw = dctx.projector.tileWidth;
9886
+ painter.save();
9887
+ if (opacity !== 1) painter.setAlpha(opacity);
9888
+ for (const [i0, i1, i2] of mesh.triangles) {
9889
+ const v0 = mesh.vertices[i0];
9890
+ const v1 = mesh.vertices[i1];
9891
+ const v2 = mesh.vertices[i2];
9892
+ const p0 = skinned[i0];
9893
+ const p1 = skinned[i1];
9894
+ const p2 = skinned[i2];
9895
+ if (!v0 || !v1 || !v2 || !p0 || !p1 || !p2) continue;
9896
+ const dst = [
9897
+ [origin.x + p0[0] * tw, origin.y + p0[1] * tw],
9898
+ [origin.x + p1[0] * tw, origin.y + p1[1] * tw],
9899
+ [origin.x + p2[0] * tw, origin.y + p2[1] * tw]
9900
+ ];
9901
+ if (node.weightsOverlay || !tex) {
9902
+ if (!node.weightsOverlay) continue;
9903
+ const bone = dominantBone(v0);
9904
+ painter.fillPoly(
9905
+ dst.map(([x, y]) => ({ x, y })),
9906
+ WEIGHT_PALETTE[(bone % WEIGHT_PALETTE.length + WEIGHT_PALETTE.length) % WEIGHT_PALETTE.length]
9907
+ );
9908
+ continue;
9909
+ }
9910
+ const pixelUV = meshHasPixelUVs(mesh);
9911
+ const uv = pixelUV ? [[v0.u, v0.v], [v1.u, v1.v], [v2.u, v2.v]] : [
9912
+ [v0.u * tex.width, v0.v * tex.height],
9913
+ [v1.u * tex.width, v1.v * tex.height],
9914
+ [v2.u * tex.width, v2.v * tex.height]
9915
+ ];
9916
+ const affine = triangleAffine(uv, dst);
9917
+ if (!affine) continue;
9918
+ painter.save();
9919
+ painter.clipPath(`M ${dst[0][0]} ${dst[0][1]} L ${dst[1][0]} ${dst[1][1]} L ${dst[2][0]} ${dst[2][1]} Z`);
9920
+ painter.blitTransformed(tex, { x: 0, y: 0, w: tex.width, h: tex.height }, affine);
9921
+ painter.restore();
9922
+ }
9923
+ painter.restore();
9924
+ }
9925
+ function DrawSkinnedMesh(props) {
9926
+ const register = React89.useContext(DrawableRegistryContext);
9927
+ if (register) register({ ...props, type: "draw-skinned-mesh" });
9928
+ return null;
9929
+ }
9930
+ var skinnedLog, loggedMissing2, WEIGHT_PALETTE, pixelUVByMesh, paintSkinnedMesh;
9931
+ var init_DrawSkinnedMesh = __esm({
9932
+ "components/game/atoms/DrawSkinnedMesh.tsx"() {
9933
+ "use client";
9934
+ init_imageCache();
9935
+ init_contract();
9936
+ init_registry();
9937
+ init_skinning();
9938
+ skinnedLog = logger.createLogger("almadar:ui:draw-skinned-mesh");
9939
+ loggedMissing2 = /* @__PURE__ */ new Set();
9940
+ WEIGHT_PALETTE = Array.from({ length: 10 }, (_, i) => `hsl(${i * 36 % 360}, 70%, 55%)`);
9941
+ pixelUVByMesh = /* @__PURE__ */ new WeakMap();
9942
+ paintSkinnedMesh = (painter, node, dctx) => {
9943
+ if (!isValidScenePos(node.position)) return;
9944
+ const rig = resolveRig(node, dctx);
9945
+ if (!rig) {
9946
+ if (node.meshUrl && skinMeshFailed(node.meshUrl)) warnMissingOnce2("mesh-failed", node);
9947
+ else if (!node.mesh && !node.meshUrl) warnMissingOnce2("mesh-missing", node);
9948
+ return;
9949
+ }
9950
+ const tex = node.weightsOverlay ? null : painter.resolveTexture(node.asset.url);
9951
+ if (!node.weightsOverlay && !tex) {
9952
+ if (getImageStatus(node.asset.url) === "failed") warnMissingOnce2("texture-failed", node);
9953
+ return;
9954
+ }
9955
+ if (node.ghost && rig.clip && rig.clip.frames.length > 0) {
9956
+ paintMeshPass(painter, node, rig.bones, rig.mesh, tex, dctx, rig.clip.frames[node.ghost.frame % rig.clip.frames.length], node.ghost.opacity);
9957
+ }
9958
+ paintMeshPass(painter, node, rig.bones, rig.mesh, tex, dctx, resolveSkinPose(node, rig.clip), node.opacity ?? 1);
9959
+ };
9960
+ }
9961
+ });
9689
9962
  function applyMeshAnimation(node, timeMs) {
9690
9963
  const anim = node.animation;
9691
9964
  if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return null;
@@ -10010,6 +10283,9 @@ function paintDrawable(painter, node, dctx) {
10010
10283
  case "draw-mesh":
10011
10284
  warnUnsupported2d("draw-mesh");
10012
10285
  break;
10286
+ case "draw-skinned-mesh":
10287
+ paintSkinnedMesh(painter, node, dctx);
10288
+ break;
10013
10289
  case "draw-sprite-layer":
10014
10290
  paintSpriteLayer(painter, node, dctx);
10015
10291
  break;
@@ -10034,6 +10310,7 @@ var init_paintDispatch = __esm({
10034
10310
  init_DrawShape();
10035
10311
  init_DrawText();
10036
10312
  init_DrawGroup();
10313
+ init_DrawSkinnedMesh();
10037
10314
  init_DrawMesh();
10038
10315
  init_DrawSpriteLayer();
10039
10316
  init_DrawShapeLayer();
@@ -10054,6 +10331,21 @@ function shapeDrawnItem(n) {
10054
10331
  if (n.shape !== "rect") return { pos: n.position, id: n.id };
10055
10332
  return { pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotate };
10056
10333
  }
10334
+ function skinnedMeshDrawnItem(n) {
10335
+ const mesh = n.mesh;
10336
+ if (!mesh || n.bones.length === 0) return { pos: n.position, id: n.id };
10337
+ const bindWorld = computeWorldMatrices(n.bones, {});
10338
+ const curWorld = computeWorldMatrices(n.bones, resolveSkinPose(n));
10339
+ const bounds = vertexBounds(skinVertices(mesh, bindWorld, curWorld));
10340
+ if (!bounds) return { pos: n.position, id: n.id };
10341
+ return {
10342
+ pos: { ...n.position, x: n.position.x + bounds.minX, y: n.position.y + bounds.minY },
10343
+ id: n.id,
10344
+ anchor: "top-left",
10345
+ width: bounds.maxX - bounds.minX,
10346
+ height: bounds.maxY - bounds.minY
10347
+ };
10348
+ }
10057
10349
  function collectDrawnItems(nodes) {
10058
10350
  const out = [];
10059
10351
  for (const n of nodes) {
@@ -10064,6 +10356,9 @@ function collectDrawnItems(nodes) {
10064
10356
  case "draw-shape":
10065
10357
  if (isValidScenePos(n.position)) out.push(shapeDrawnItem(n));
10066
10358
  break;
10359
+ case "draw-skinned-mesh":
10360
+ if (isValidScenePos(n.position)) out.push(skinnedMeshDrawnItem(n));
10361
+ break;
10067
10362
  case "draw-text":
10068
10363
  case "draw-group":
10069
10364
  case "draw-mesh":
@@ -10131,6 +10426,8 @@ function rotatePoint(p, center, radians) {
10131
10426
  var init_hitTest = __esm({
10132
10427
  "lib/drawable/hitTest.ts"() {
10133
10428
  init_contract();
10429
+ init_DrawSkinnedMesh();
10430
+ init_skinning();
10134
10431
  }
10135
10432
  });
10136
10433
  function normalizeBackdrop(bg) {
@@ -11320,7 +11617,7 @@ var init_StateIndicator = __esm({
11320
11617
  init_cn();
11321
11618
  init_GameIcon();
11322
11619
  DEFAULT_ASSET_URL = {
11323
- url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
11620
+ url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-dungeon-board/default/features/chest/chest.png",
11324
11621
  role: "ui",
11325
11622
  category: "state"
11326
11623
  };
@@ -12936,11 +13233,6 @@ function executeEffect(effect, config) {
12936
13233
  executeNavigate(path, params, config);
12937
13234
  break;
12938
13235
  }
12939
- case "notify": {
12940
- const [message, options] = args;
12941
- executeNotify(message, options, config);
12942
- break;
12943
- }
12944
13236
  case "emit": {
12945
13237
  const [event, payload] = args;
12946
13238
  executeEmit(event, payload, config);
@@ -12956,9 +13248,6 @@ function executeRenderUI(slot, patternConfig, config) {
12956
13248
  function executeNavigate(path, params, config) {
12957
13249
  config.navigate(path, params);
12958
13250
  }
12959
- function executeNotify(message, options, config) {
12960
- config.notify(message, options);
12961
- }
12962
13251
  function executeEmit(event, payload, config) {
12963
13252
  config.eventBus.emit(event, payload);
12964
13253
  }
@@ -13246,7 +13535,6 @@ var init_offline_executor = __esm({
13246
13535
  // Client effects - execute immediately
13247
13536
  case "render-ui":
13248
13537
  case "navigate":
13249
- case "notify":
13250
13538
  case "emit":
13251
13539
  clientEffects.push(effect);
13252
13540
  break;
@@ -15674,7 +15962,6 @@ var init_avl_atom_types = __esm({
15674
15962
  "persist": "data",
15675
15963
  "fetch": "data",
15676
15964
  "emit": "communication",
15677
- "notify": "communication",
15678
15965
  "call-service": "communication",
15679
15966
  "spawn": "lifecycle",
15680
15967
  "despawn": "lifecycle",
@@ -15822,12 +16109,6 @@ function effectIcon(type, x, y, s, color) {
15822
16109
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: x - s, y1: y, x2: x + s * 0.6, y2: y, stroke: color, strokeWidth: 1.5 }),
15823
16110
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: `${x + s * 0.1},${y - s * 0.5} ${x + s},${y} ${x + s * 0.1},${y + s * 0.5}`, fill: "none", stroke: color, strokeWidth: 1.5, strokeLinejoin: "round" })
15824
16111
  ] });
15825
- case "notify":
15826
- return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
15827
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: `M${x - s * 0.7},${y + s * 0.3} Q${x - s * 0.7},${y - s} ${x},${y - s} Q${x + s * 0.7},${y - s} ${x + s * 0.7},${y + s * 0.3} Z`, fill: "none", stroke: color, strokeWidth: 1.5 }),
15828
- /* @__PURE__ */ jsxRuntime.jsx("line", { x1: x - s * 0.8, y1: y + s * 0.3, x2: x + s * 0.8, y2: y + s * 0.3, stroke: color, strokeWidth: 1.5 }),
15829
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: x, cy: y + s * 0.7, r: s * 0.2, fill: color })
15830
- ] });
15831
16112
  case "call-service":
15832
16113
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
15833
16114
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: x - s, y1: y - s * 0.3, x2: x + s, y2: y - s * 0.3, stroke: color, strokeWidth: 1.5 }),
@@ -21081,9 +21362,6 @@ function getEffectSummary(effects) {
21081
21362
  case "emit":
21082
21363
  summaries.push(`\u2191 ${effect[1] || "event"}`);
21083
21364
  break;
21084
- case "notify":
21085
- summaries.push(`\u{1F4E7} ${effect[1] || ""}`);
21086
- break;
21087
21365
  case "persist":
21088
21366
  summaries.push(`\u{1F4BE} ${effect[1] || "save"}`);
21089
21367
  break;
@@ -21109,7 +21387,7 @@ function extractOutputsFromTransitions(transitions) {
21109
21387
  t.effects.forEach((effect) => {
21110
21388
  if (Array.isArray(effect)) {
21111
21389
  const op = effect[0];
21112
- if (["emit", "notify", "persist", "navigate", "call-service"].includes(op)) {
21390
+ if (["emit", "persist", "navigate", "call-service"].includes(op)) {
21113
21391
  if (isArraySExpr(effect)) {
21114
21392
  const humanText = formatSExprEffectToDomain(effect);
21115
21393
  outputs.add(humanText);
@@ -26493,6 +26771,18 @@ var init_useAuthContext = __esm({
26493
26771
  "hooks/useAuthContext.ts"() {
26494
26772
  }
26495
26773
  });
26774
+ function resolveActiveNavHref(items, currentPath) {
26775
+ let best;
26776
+ for (const item of items) {
26777
+ for (const href of item.children?.length ? [item.href, ...item.children.map((c) => c.href)] : [item.href]) {
26778
+ if (currentPath === href) return href;
26779
+ if (currentPath.startsWith(href + "/") && (!best || href.length > best.length)) {
26780
+ best = href;
26781
+ }
26782
+ }
26783
+ }
26784
+ return best;
26785
+ }
26496
26786
  var DashboardLayout, NavLink, NavLinkTopnav, NavLinkBottom;
26497
26787
  var init_DashboardLayout = __esm({
26498
26788
  "components/core/templates/DashboardLayout.tsx"() {
@@ -26564,6 +26854,7 @@ var init_DashboardLayout = __esm({
26564
26854
  const location = reactRouterDom.useLocation();
26565
26855
  const ctxPagePath = providers.useCurrentPagePath();
26566
26856
  const activePath = (currentPath || void 0) ?? ctxPagePath ?? location.pathname;
26857
+ const activeHref = React89.useMemo(() => resolveActiveNavHref(navItems, activePath), [navItems, activePath]);
26567
26858
  const { signOut: authSignOut } = useAuthContext();
26568
26859
  const user = userProp || (null);
26569
26860
  const { t } = hooks.useTranslate();
@@ -26656,7 +26947,7 @@ var init_DashboardLayout = __esm({
26656
26947
  NavLink,
26657
26948
  {
26658
26949
  item,
26659
- currentPath: activePath,
26950
+ activeHref,
26660
26951
  compact: isRail
26661
26952
  },
26662
26953
  item.href
@@ -26723,7 +27014,7 @@ var init_DashboardLayout = __esm({
26723
27014
  NavLinkTopnav,
26724
27015
  {
26725
27016
  item,
26726
- currentPath: activePath
27017
+ activeHref
26727
27018
  },
26728
27019
  item.href
26729
27020
  ))
@@ -26899,7 +27190,7 @@ var init_DashboardLayout = __esm({
26899
27190
  NavLinkBottom,
26900
27191
  {
26901
27192
  item,
26902
- currentPath: activePath
27193
+ activeHref
26903
27194
  },
26904
27195
  item.href
26905
27196
  )) })
@@ -26913,15 +27204,71 @@ var init_DashboardLayout = __esm({
26913
27204
  DashboardLayout.displayName = "DashboardLayout";
26914
27205
  NavLink = ({
26915
27206
  item,
26916
- currentPath,
27207
+ activeHref,
26917
27208
  compact = false
26918
27209
  }) => {
26919
- const isActive = currentPath === item.href || currentPath.startsWith(item.href + "/");
27210
+ const hasChildren = !!item.children?.length;
27211
+ const childActive = hasChildren && item.children.some((child) => child.href === activeHref);
27212
+ const isActive = item.href === activeHref || childActive;
27213
+ const [open, setOpen] = React89.useState(childActive);
26920
27214
  const iconClassName = cn(
26921
27215
  "h-5 w-5",
26922
27216
  isActive ? "text-primary-foreground" : "text-muted-foreground"
26923
27217
  );
26924
27218
  if (compact) {
27219
+ if (hasChildren) {
27220
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", children: [
27221
+ /* @__PURE__ */ jsxRuntime.jsx(
27222
+ Button,
27223
+ {
27224
+ variant: "ghost",
27225
+ title: item.label,
27226
+ "aria-label": item.label,
27227
+ "aria-expanded": open,
27228
+ className: cn(
27229
+ "flex items-center justify-center w-full px-2 py-2 rounded-lg transition-colors",
27230
+ isActive ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"
27231
+ ),
27232
+ onClick: () => setOpen(!open),
27233
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { as: "span", className: "relative inline-flex", children: [
27234
+ item.icon ? typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, className: iconClassName }) : /* @__PURE__ */ jsxRuntime.jsx(item.icon, { className: iconClassName }) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "font-semibold", as: "span", children: item.label.charAt(0).toUpperCase() }),
27235
+ item.badge && /* @__PURE__ */ jsxRuntime.jsx(
27236
+ Badge,
27237
+ {
27238
+ variant: isActive ? "primary" : "default",
27239
+ size: "sm",
27240
+ className: "absolute -top-2 -right-2 px-1 py-0 text-[10px] leading-4",
27241
+ children: item.badge
27242
+ }
27243
+ )
27244
+ ] })
27245
+ }
27246
+ ),
27247
+ open && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
27248
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "fixed inset-0 z-20", onClick: () => setOpen(false) }),
27249
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "absolute left-full top-0 ml-2 w-48 bg-card dark:bg-card rounded-lg shadow-lg border border-border dark:border-border py-1 z-30", children: item.children.map((child) => {
27250
+ const childIsActive = child.href === activeHref;
27251
+ return /* @__PURE__ */ jsxRuntime.jsxs(
27252
+ reactRouterDom.Link,
27253
+ {
27254
+ to: child.href,
27255
+ onClick: () => setOpen(false),
27256
+ className: cn(
27257
+ "flex items-center gap-2 px-3 py-2 text-sm transition-colors",
27258
+ childIsActive ? "bg-muted text-foreground font-medium" : "text-muted-foreground hover:bg-muted hover:text-foreground"
27259
+ ),
27260
+ children: [
27261
+ child.icon && (typeof child.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: child.icon, className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(child.icon, { className: "h-4 w-4" })),
27262
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "flex-1", as: "span", children: child.label }),
27263
+ child.badge && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: childIsActive ? "primary" : "default", size: "sm", children: child.badge })
27264
+ ]
27265
+ },
27266
+ child.href
27267
+ );
27268
+ }) })
27269
+ ] })
27270
+ ] });
27271
+ }
26925
27272
  return /* @__PURE__ */ jsxRuntime.jsx(
26926
27273
  reactRouterDom.Link,
26927
27274
  {
@@ -26947,6 +27294,78 @@ var init_DashboardLayout = __esm({
26947
27294
  }
26948
27295
  );
26949
27296
  }
27297
+ if (hasChildren) {
27298
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { children: [
27299
+ /* @__PURE__ */ jsxRuntime.jsxs(
27300
+ Button,
27301
+ {
27302
+ variant: "ghost",
27303
+ "aria-expanded": open,
27304
+ className: cn(
27305
+ "flex items-center gap-3 w-full px-3 py-2 rounded-lg text-sm font-medium transition-colors",
27306
+ isActive ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"
27307
+ ),
27308
+ onClick: () => setOpen(!open),
27309
+ children: [
27310
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, className: iconClassName }) : /* @__PURE__ */ jsxRuntime.jsx(item.icon, { className: iconClassName })),
27311
+ /* @__PURE__ */ jsxRuntime.jsx(
27312
+ Typography,
27313
+ {
27314
+ variant: "small",
27315
+ color: isActive ? "inherit" : "primary",
27316
+ className: "flex-1 text-left",
27317
+ as: "span",
27318
+ children: item.label
27319
+ }
27320
+ ),
27321
+ item.badge && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: isActive ? "primary" : "default", size: "sm", children: item.badge }),
27322
+ /* @__PURE__ */ jsxRuntime.jsx(
27323
+ Icon,
27324
+ {
27325
+ name: "chevron-down",
27326
+ className: cn("h-4 w-4 shrink-0 transition-transform", open && "rotate-180")
27327
+ }
27328
+ )
27329
+ ]
27330
+ }
27331
+ ),
27332
+ open && /* @__PURE__ */ jsxRuntime.jsx(
27333
+ VStack,
27334
+ {
27335
+ gap: "none",
27336
+ className: "mt-1 ml-4 pl-4 border-l border-border dark:border-border space-y-1",
27337
+ children: item.children.map((child) => {
27338
+ const childIsActive = child.href === activeHref;
27339
+ return /* @__PURE__ */ jsxRuntime.jsxs(
27340
+ reactRouterDom.Link,
27341
+ {
27342
+ to: child.href,
27343
+ className: cn(
27344
+ "flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm transition-colors",
27345
+ childIsActive ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"
27346
+ ),
27347
+ children: [
27348
+ child.icon && (typeof child.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: child.icon, className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(child.icon, { className: "h-4 w-4" })),
27349
+ /* @__PURE__ */ jsxRuntime.jsx(
27350
+ Typography,
27351
+ {
27352
+ variant: "small",
27353
+ color: childIsActive ? "inherit" : "primary",
27354
+ className: "flex-1",
27355
+ as: "span",
27356
+ children: child.label
27357
+ }
27358
+ ),
27359
+ child.badge && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: childIsActive ? "primary" : "default", size: "sm", children: child.badge })
27360
+ ]
27361
+ },
27362
+ child.href
27363
+ );
27364
+ })
27365
+ }
27366
+ )
27367
+ ] });
27368
+ }
26950
27369
  return /* @__PURE__ */ jsxRuntime.jsxs(
26951
27370
  reactRouterDom.Link,
26952
27371
  {
@@ -26975,9 +27394,63 @@ var init_DashboardLayout = __esm({
26975
27394
  NavLink.displayName = "NavLink";
26976
27395
  NavLinkTopnav = ({
26977
27396
  item,
26978
- currentPath
27397
+ activeHref
26979
27398
  }) => {
26980
- const isActive = currentPath === item.href || currentPath.startsWith(item.href + "/");
27399
+ const hasChildren = !!item.children?.length;
27400
+ const childActive = hasChildren && item.children.some((child) => child.href === activeHref);
27401
+ const isActive = item.href === activeHref || childActive;
27402
+ const [open, setOpen] = React89.useState(false);
27403
+ if (hasChildren) {
27404
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", children: [
27405
+ /* @__PURE__ */ jsxRuntime.jsxs(
27406
+ Button,
27407
+ {
27408
+ variant: "ghost",
27409
+ "aria-expanded": open,
27410
+ className: cn(
27411
+ "flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-colors whitespace-nowrap",
27412
+ isActive ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:bg-muted hover:text-foreground"
27413
+ ),
27414
+ onClick: () => setOpen(!open),
27415
+ children: [
27416
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(item.icon, { className: "h-4 w-4" })),
27417
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "inherit", className: "flex-1", as: "span", children: item.label }),
27418
+ item.badge && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: isActive ? "primary" : "default", size: "sm", children: item.badge }),
27419
+ /* @__PURE__ */ jsxRuntime.jsx(
27420
+ Icon,
27421
+ {
27422
+ name: "chevron-down",
27423
+ className: cn("h-3.5 w-3.5 shrink-0 transition-transform", open && "rotate-180")
27424
+ }
27425
+ )
27426
+ ]
27427
+ }
27428
+ ),
27429
+ open && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
27430
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "fixed inset-0 z-20", onClick: () => setOpen(false) }),
27431
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "absolute left-0 top-full mt-1 w-48 bg-card dark:bg-card rounded-lg shadow-lg border border-border dark:border-border py-1 z-30", children: item.children.map((child) => {
27432
+ const childIsActive = child.href === activeHref;
27433
+ return /* @__PURE__ */ jsxRuntime.jsxs(
27434
+ reactRouterDom.Link,
27435
+ {
27436
+ to: child.href,
27437
+ onClick: () => setOpen(false),
27438
+ className: cn(
27439
+ "flex items-center gap-2 px-3 py-2 text-sm transition-colors",
27440
+ childIsActive ? "bg-muted text-foreground font-medium" : "text-muted-foreground hover:bg-muted hover:text-foreground"
27441
+ ),
27442
+ children: [
27443
+ child.icon && (typeof child.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: child.icon, className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(child.icon, { className: "h-4 w-4" })),
27444
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "flex-1", as: "span", children: child.label }),
27445
+ child.badge && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: childIsActive ? "primary" : "default", size: "sm", children: child.badge })
27446
+ ]
27447
+ },
27448
+ child.href
27449
+ );
27450
+ }) })
27451
+ ] })
27452
+ ] });
27453
+ }
26981
27454
  return /* @__PURE__ */ jsxRuntime.jsxs(
26982
27455
  reactRouterDom.Link,
26983
27456
  {
@@ -26997,9 +27470,9 @@ var init_DashboardLayout = __esm({
26997
27470
  NavLinkTopnav.displayName = "NavLinkTopnav";
26998
27471
  NavLinkBottom = ({
26999
27472
  item,
27000
- currentPath
27473
+ activeHref
27001
27474
  }) => {
27002
- const isActive = currentPath === item.href || currentPath.startsWith(item.href + "/");
27475
+ const isActive = item.href === activeHref;
27003
27476
  const iconClassName = cn(
27004
27477
  "h-5 w-5",
27005
27478
  isActive ? "text-primary" : "text-muted-foreground"
@@ -27938,7 +28411,9 @@ function DataGrid({
27938
28411
  const cardClickAction = actionDefs.find((a) => a.variant !== "danger");
27939
28412
  const handleCardClick = cardClickAction ? (itemData) => () => fireAction(cardClickAction, itemData) : void 0;
27940
28413
  const stopCardClick = handleCardClick ? (e) => e.stopPropagation() : void 0;
27941
- const hasRenderProp = typeof children === "function";
28414
+ const renderItemFn = typeof schemaRenderItem === "function" ? schemaRenderItem : void 0;
28415
+ const itemRenderer = typeof children === "function" ? children : renderItemFn;
28416
+ const hasRenderProp = typeof itemRenderer === "function";
27942
28417
  React89.useEffect(() => {
27943
28418
  if (data.length > 0 && !hasRenderProp && fieldDefs.length === 0) {
27944
28419
  const schemaArr = Array.isArray(schemaRenderItem) ? schemaRenderItem : null;
@@ -28012,7 +28487,7 @@ function DataGrid({
28012
28487
  onClick: handleCardClick?.(itemData),
28013
28488
  className: cn("relative group/rowactions", handleCardClick && "cursor-pointer", isSelected && "ring-2 ring-primary rounded-lg"),
28014
28489
  children: [
28015
- children(itemData, index),
28490
+ itemRenderer(itemData, index),
28016
28491
  actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { onClick: stopCardClick, className: "absolute top-2 right-2 z-10 opacity-0 group-hover/rowactions:opacity-100 focus-within:opacity-100 [@media(pointer:coarse)]:opacity-100 transition-opacity duration-fast", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: [
28017
28492
  inlineCardActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
28018
28493
  Button,
@@ -28345,7 +28820,9 @@ function DataList({
28345
28820
  );
28346
28821
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
28347
28822
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
28348
- const hasRenderProp = typeof children === "function";
28823
+ const renderItemFn = typeof schemaRenderItem === "function" ? schemaRenderItem : void 0;
28824
+ const itemRenderer = typeof children === "function" ? children : renderItemFn;
28825
+ const hasRenderProp = typeof itemRenderer === "function";
28349
28826
  React89__namespace.default.useEffect(() => {
28350
28827
  const renderItemTypeOf = typeof schemaRenderItem;
28351
28828
  const childrenTypeOf = typeof children;
@@ -28563,7 +29040,7 @@ function DataList({
28563
29040
  const actions = renderItemActions(itemData);
28564
29041
  return wrapDnd(
28565
29042
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn("relative group/rowactions", rowClickEvent && "cursor-pointer"), children: [
28566
- children(itemData, index),
29043
+ itemRenderer(itemData, index),
28567
29044
  actions && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "absolute top-2 right-2 z-10 opacity-0 group-hover/rowactions:opacity-100 focus-within:opacity-100 [@media(pointer:coarse)]:opacity-100 transition-opacity duration-fast", children: [
28568
29045
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5 [@media(pointer:coarse)]:hidden", children: actions }),
28569
29046
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "hidden [@media(pointer:coarse)]:block rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -35107,7 +35584,7 @@ function TableView({
35107
35584
  columns,
35108
35585
  fields,
35109
35586
  itemActions,
35110
- maxInlineActions: _maxInlineActions,
35587
+ maxInlineActions,
35111
35588
  itemClickEvent = "",
35112
35589
  selectable = false,
35113
35590
  selectEvent,
@@ -35140,6 +35617,12 @@ function TableView({
35140
35617
  const [localSelected, setLocalSelected] = React89__namespace.default.useState(/* @__PURE__ */ new Set());
35141
35618
  const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
35142
35619
  const actionDefs = Array.isArray(itemActions) ? itemActions : [];
35620
+ const inlineActions = maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : [];
35621
+ const overflowActions = maxInlineActions != null ? actionDefs.slice(maxInlineActions) : actionDefs;
35622
+ const fireAction = (action, row) => eventBus.emit(`UI:${action.event}`, {
35623
+ id: row.id,
35624
+ row
35625
+ });
35143
35626
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
35144
35627
  const dnd = useDataDnd({
35145
35628
  items: allDataRaw,
@@ -35315,7 +35798,7 @@ function TableView({
35315
35798
  }
35316
35799
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format) }) }, col.key);
35317
35800
  }),
35318
- hasActions && /* @__PURE__ */ jsxRuntime.jsx(
35801
+ hasActions && /* @__PURE__ */ jsxRuntime.jsxs(
35319
35802
  HStack,
35320
35803
  {
35321
35804
  gap: "xs",
@@ -35329,23 +35812,38 @@ function TableView({
35329
35812
  "border-l border-[var(--color-border)]",
35330
35813
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
35331
35814
  ),
35332
- children: /* @__PURE__ */ jsxRuntime.jsx(
35333
- Menu,
35334
- {
35335
- position: "bottom-end",
35336
- trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
35337
- items: actionDefs.map((action) => ({
35338
- label: action.label,
35339
- icon: action.icon,
35340
- event: action.event,
35341
- variant: action.variant === "danger" ? "danger" : "default",
35342
- onClick: () => eventBus.emit(`UI:${action.event}`, {
35343
- id: row.id,
35344
- row
35345
- })
35346
- }))
35347
- }
35348
- )
35815
+ children: [
35816
+ inlineActions.map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
35817
+ Button,
35818
+ {
35819
+ variant: action.variant ?? "ghost",
35820
+ size: "sm",
35821
+ onClick: () => fireAction(action, row),
35822
+ "data-testid": `action-${action.event}`,
35823
+ "data-row-id": String(row.id),
35824
+ className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
35825
+ children: [
35826
+ action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
35827
+ action.label
35828
+ ]
35829
+ },
35830
+ action.event
35831
+ )),
35832
+ overflowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
35833
+ Menu,
35834
+ {
35835
+ position: "bottom-end",
35836
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
35837
+ items: overflowActions.map((action) => ({
35838
+ label: action.label,
35839
+ icon: action.icon,
35840
+ event: action.event,
35841
+ variant: action.variant === "danger" ? "danger" : "default",
35842
+ onClick: () => fireAction(action, row)
35843
+ }))
35844
+ }
35845
+ )
35846
+ ]
35349
35847
  }
35350
35848
  )
35351
35849
  ]
@@ -51177,6 +51675,7 @@ var init_component_registry_generated = __esm({
51177
51675
  init_DrawMesh();
51178
51676
  init_DrawShape();
51179
51677
  init_DrawShapeLayer();
51678
+ init_DrawSkinnedMesh();
51180
51679
  init_DrawSprite();
51181
51680
  init_DrawSpriteLayer();
51182
51681
  init_DrawText();
@@ -51455,6 +51954,7 @@ var init_component_registry_generated = __esm({
51455
51954
  "DrawMesh": DrawMesh,
51456
51955
  "DrawShape": DrawShape,
51457
51956
  "DrawShapeLayer": DrawShapeLayer,
51957
+ "DrawSkinnedMesh": DrawSkinnedMesh,
51458
51958
  "DrawSprite": DrawSprite,
51459
51959
  "DrawSpriteLayer": DrawSpriteLayer,
51460
51960
  "DrawText": DrawText,
@@ -51783,7 +52283,7 @@ function renderContainedPortal(t, slot, content, onDismiss) {
51783
52283
  const slotId = `slot-${slot}`;
51784
52284
  switch (slot) {
51785
52285
  case "modal":
51786
- if (SELF_OVERLAY_PATTERNS.has(content.pattern)) {
52286
+ if (patterns.SELF_OVERLAY_PATTERN_TYPES.has(content.pattern)) {
51787
52287
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { id: slotId, className: "contents", children: slotContent });
51788
52288
  }
51789
52289
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -52126,7 +52626,7 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
52126
52626
  children
52127
52627
  }
52128
52628
  );
52129
- wrapper = pattern !== void 0 && SELF_OVERLAY_PATTERNS.has(pattern) ? innerContent : /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, size: "lg", children: innerContent });
52629
+ wrapper = pattern !== void 0 && patterns.SELF_OVERLAY_PATTERN_TYPES.has(pattern) ? innerContent : /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, size: "lg", children: innerContent });
52130
52630
  break;
52131
52631
  }
52132
52632
  case "drawer":
@@ -52186,7 +52686,7 @@ function SlotPortal({
52186
52686
  let wrapper;
52187
52687
  switch (slot) {
52188
52688
  case "modal":
52189
- wrapper = SELF_OVERLAY_PATTERNS.has(content.pattern) ? /* @__PURE__ */ jsxRuntime.jsx(Box, { id: slotId, children: slotContent }) : /* @__PURE__ */ jsxRuntime.jsx(
52689
+ wrapper = patterns.SELF_OVERLAY_PATTERN_TYPES.has(content.pattern) ? /* @__PURE__ */ jsxRuntime.jsx(Box, { id: slotId, children: slotContent }) : /* @__PURE__ */ jsxRuntime.jsx(
52190
52690
  Modal,
52191
52691
  {
52192
52692
  isOpen: true,
@@ -52693,7 +53193,7 @@ function UISlotRenderer({
52693
53193
  }
52694
53194
  return wrapped;
52695
53195
  }
52696
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
53196
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
52697
53197
  var init_UISlotRenderer = __esm({
52698
53198
  "components/core/organisms/UISlotRenderer.tsx"() {
52699
53199
  "use client";
@@ -52724,7 +53224,6 @@ var init_UISlotRenderer = __esm({
52724
53224
  modal: "form",
52725
53225
  drawer: "form"
52726
53226
  };
52727
- SELF_OVERLAY_PATTERNS = /* @__PURE__ */ new Set(["modal", "confirm-dialog"]);
52728
53227
  CONTENT_NODE_SLOTS = /* @__PURE__ */ new Set([
52729
53228
  "logo",
52730
53229
  "master",
@@ -54145,9 +54644,6 @@ function ServerBridgeProvider({
54145
54644
  });
54146
54645
  } else if (effectType === "navigate-back") {
54147
54646
  effects.push({ type: "navigate-back", traitName });
54148
- } else if (effectType === "notify") {
54149
- const message = effect[1];
54150
- effects.push({ type: "notify", message: typeof message === "string" ? message : void 0, traitName });
54151
54647
  }
54152
54648
  }
54153
54649
  if (result.emittedEvents) {