@almadar/ui 4.38.1 → 4.39.1

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.
@@ -3779,17 +3779,20 @@ function parseApplicationLevel(schema) {
3779
3779
  }
3780
3780
  }
3781
3781
  }
3782
+ const seenLinks = /* @__PURE__ */ new Set();
3782
3783
  for (const emit of emitMap) {
3783
3784
  for (const listen of listenMap) {
3784
- if (emit.event === listen.event && emit.orbital !== listen.orbital) {
3785
- crossLinks.push({
3786
- emitterOrbital: emit.orbital,
3787
- listenerOrbital: listen.orbital,
3788
- eventName: emit.event,
3789
- emitterTrait: emit.trait,
3790
- listenerTrait: listen.trait
3791
- });
3792
- }
3785
+ if (emit.event !== listen.event || emit.orbital === listen.orbital) continue;
3786
+ const key = `${emit.orbital}\u241F${listen.orbital}\u241F${emit.event}`;
3787
+ if (seenLinks.has(key)) continue;
3788
+ seenLinks.add(key);
3789
+ crossLinks.push({
3790
+ emitterOrbital: emit.orbital,
3791
+ listenerOrbital: listen.orbital,
3792
+ eventName: emit.event,
3793
+ emitterTrait: emit.trait,
3794
+ listenerTrait: listen.trait
3795
+ });
3793
3796
  }
3794
3797
  }
3795
3798
  return { orbitals, crossLinks };
@@ -48232,17 +48235,20 @@ function findCrossLinks(orbitals) {
48232
48235
  }
48233
48236
  }
48234
48237
  }
48238
+ const seen = /* @__PURE__ */ new Set();
48235
48239
  for (const em of emitters) {
48236
48240
  for (const li of listeners6) {
48237
- if (em.event === li.event && em.orbital !== li.orbital) {
48238
- links.push({
48239
- emitterOrbital: em.orbital,
48240
- listenerOrbital: li.orbital,
48241
- event: em.event,
48242
- emitterTrait: em.trait,
48243
- listenerTrait: li.trait
48244
- });
48245
- }
48241
+ if (em.event !== li.event || em.orbital === li.orbital) continue;
48242
+ const key = `${em.orbital}\u241F${li.orbital}\u241F${em.event}`;
48243
+ if (seen.has(key)) continue;
48244
+ seen.add(key);
48245
+ links.push({
48246
+ emitterOrbital: em.orbital,
48247
+ listenerOrbital: li.orbital,
48248
+ event: em.event,
48249
+ emitterTrait: em.trait,
48250
+ listenerTrait: li.trait
48251
+ });
48246
48252
  }
48247
48253
  }
48248
48254
  return links;
@@ -51907,12 +51913,17 @@ function FlowCanvasInner({
51907
51913
  const [edges, setEdges, onEdgesChange] = react.useEdgesState(activeEdges);
51908
51914
  const reactFlow = react.useReactFlow();
51909
51915
  React119.useEffect(() => {
51916
+ setEdges([]);
51910
51917
  setNodes(activeNodes);
51911
51918
  setEdges(activeEdges);
51912
51919
  requestAnimationFrame(() => {
51913
51920
  reactFlow.fitView({ duration: 300, padding: 0.15 });
51914
51921
  });
51915
51922
  }, [activeNodes, activeEdges, setNodes, setEdges, reactFlow]);
51923
+ const visibleEdges = React119.useMemo(() => {
51924
+ const nodeIds = new Set(nodes.map((n) => n.id));
51925
+ return edges.filter((e) => nodeIds.has(e.source) && nodeIds.has(e.target));
51926
+ }, [nodes, edges]);
51916
51927
  const handleNodeDoubleClick = React119.useCallback((_, node) => {
51917
51928
  if (atBehaviorLevel && composeLevel === "behavior") {
51918
51929
  const d = node.data;
@@ -52046,7 +52057,7 @@ function FlowCanvasInner({
52046
52057
  react.ReactFlow,
52047
52058
  {
52048
52059
  nodes,
52049
- edges,
52060
+ edges: visibleEdges,
52050
52061
  nodeTypes: NODE_TYPES,
52051
52062
  edgeTypes: EDGE_TYPES,
52052
52063
  defaultEdgeOptions: DEFAULT_EDGE_OPTIONS,
@@ -52721,7 +52732,10 @@ var EventWireOverlay = ({
52721
52732
  const y1 = fromPos.cy + ny * orbitalR;
52722
52733
  const x2 = toPos.cx - nx * (orbitalR + 6);
52723
52734
  const y2 = toPos.cy - ny * (orbitalR + 6);
52724
- const offset = 25 + wireIdx * 18;
52735
+ const total = links.length;
52736
+ const span = Math.min(90, Math.max(0, total - 1) * 14);
52737
+ const step = total > 1 ? span / (total - 1) : 0;
52738
+ const offset = 25 + (wireIdx - (total - 1) / 2) * step;
52725
52739
  const { cpx, cpy } = curveControlPoint(x1, y1, x2, y2, offset);
52726
52740
  const pathD = `M${x1},${y1} Q${cpx},${cpy} ${x2},${y2}`;
52727
52741
  if (!Number.isFinite(x1) || !Number.isFinite(y1) || !Number.isFinite(x2) || !Number.isFinite(y2) || !Number.isFinite(cpx) || !Number.isFinite(cpy)) {
package/dist/avl/index.js CHANGED
@@ -3733,17 +3733,20 @@ function parseApplicationLevel(schema) {
3733
3733
  }
3734
3734
  }
3735
3735
  }
3736
+ const seenLinks = /* @__PURE__ */ new Set();
3736
3737
  for (const emit of emitMap) {
3737
3738
  for (const listen of listenMap) {
3738
- if (emit.event === listen.event && emit.orbital !== listen.orbital) {
3739
- crossLinks.push({
3740
- emitterOrbital: emit.orbital,
3741
- listenerOrbital: listen.orbital,
3742
- eventName: emit.event,
3743
- emitterTrait: emit.trait,
3744
- listenerTrait: listen.trait
3745
- });
3746
- }
3739
+ if (emit.event !== listen.event || emit.orbital === listen.orbital) continue;
3740
+ const key = `${emit.orbital}\u241F${listen.orbital}\u241F${emit.event}`;
3741
+ if (seenLinks.has(key)) continue;
3742
+ seenLinks.add(key);
3743
+ crossLinks.push({
3744
+ emitterOrbital: emit.orbital,
3745
+ listenerOrbital: listen.orbital,
3746
+ eventName: emit.event,
3747
+ emitterTrait: emit.trait,
3748
+ listenerTrait: listen.trait
3749
+ });
3747
3750
  }
3748
3751
  }
3749
3752
  return { orbitals, crossLinks };
@@ -48186,17 +48189,20 @@ function findCrossLinks(orbitals) {
48186
48189
  }
48187
48190
  }
48188
48191
  }
48192
+ const seen = /* @__PURE__ */ new Set();
48189
48193
  for (const em of emitters) {
48190
48194
  for (const li of listeners6) {
48191
- if (em.event === li.event && em.orbital !== li.orbital) {
48192
- links.push({
48193
- emitterOrbital: em.orbital,
48194
- listenerOrbital: li.orbital,
48195
- event: em.event,
48196
- emitterTrait: em.trait,
48197
- listenerTrait: li.trait
48198
- });
48199
- }
48195
+ if (em.event !== li.event || em.orbital === li.orbital) continue;
48196
+ const key = `${em.orbital}\u241F${li.orbital}\u241F${em.event}`;
48197
+ if (seen.has(key)) continue;
48198
+ seen.add(key);
48199
+ links.push({
48200
+ emitterOrbital: em.orbital,
48201
+ listenerOrbital: li.orbital,
48202
+ event: em.event,
48203
+ emitterTrait: em.trait,
48204
+ listenerTrait: li.trait
48205
+ });
48200
48206
  }
48201
48207
  }
48202
48208
  return links;
@@ -51861,12 +51867,17 @@ function FlowCanvasInner({
51861
51867
  const [edges, setEdges, onEdgesChange] = useEdgesState(activeEdges);
51862
51868
  const reactFlow = useReactFlow();
51863
51869
  useEffect(() => {
51870
+ setEdges([]);
51864
51871
  setNodes(activeNodes);
51865
51872
  setEdges(activeEdges);
51866
51873
  requestAnimationFrame(() => {
51867
51874
  reactFlow.fitView({ duration: 300, padding: 0.15 });
51868
51875
  });
51869
51876
  }, [activeNodes, activeEdges, setNodes, setEdges, reactFlow]);
51877
+ const visibleEdges = useMemo(() => {
51878
+ const nodeIds = new Set(nodes.map((n) => n.id));
51879
+ return edges.filter((e) => nodeIds.has(e.source) && nodeIds.has(e.target));
51880
+ }, [nodes, edges]);
51870
51881
  const handleNodeDoubleClick = useCallback((_, node) => {
51871
51882
  if (atBehaviorLevel && composeLevel === "behavior") {
51872
51883
  const d = node.data;
@@ -52000,7 +52011,7 @@ function FlowCanvasInner({
52000
52011
  ReactFlow,
52001
52012
  {
52002
52013
  nodes,
52003
- edges,
52014
+ edges: visibleEdges,
52004
52015
  nodeTypes: NODE_TYPES,
52005
52016
  edgeTypes: EDGE_TYPES,
52006
52017
  defaultEdgeOptions: DEFAULT_EDGE_OPTIONS,
@@ -52675,7 +52686,10 @@ var EventWireOverlay = ({
52675
52686
  const y1 = fromPos.cy + ny * orbitalR;
52676
52687
  const x2 = toPos.cx - nx * (orbitalR + 6);
52677
52688
  const y2 = toPos.cy - ny * (orbitalR + 6);
52678
- const offset = 25 + wireIdx * 18;
52689
+ const total = links.length;
52690
+ const span = Math.min(90, Math.max(0, total - 1) * 14);
52691
+ const step = total > 1 ? span / (total - 1) : 0;
52692
+ const offset = 25 + (wireIdx - (total - 1) / 2) * step;
52679
52693
  const { cpx, cpy } = curveControlPoint(x1, y1, x2, y2, offset);
52680
52694
  const pathD = `M${x1},${y1} Q${cpx},${cpy} ${x2},${y2}`;
52681
52695
  if (!Number.isFinite(x1) || !Number.isFinite(y1) || !Number.isFinite(x2) || !Number.isFinite(y2) || !Number.isFinite(cpx) || !Number.isFinite(cpy)) {
@@ -26895,6 +26895,16 @@ function nextBlockId(prefix = "blk") {
26895
26895
  const random = Math.random().toString(36).slice(2, 8);
26896
26896
  return `${prefix}-${Date.now().toString(36)}-${_idSeq}-${random}`;
26897
26897
  }
26898
+ function normalizeBlocks(raw) {
26899
+ if (!raw || raw.length === 0) return [createBlock("paragraph")];
26900
+ return raw.map((row) => {
26901
+ const r = row;
26902
+ const rawType = r.type;
26903
+ const type = typeof rawType === "string" && BLOCK_TYPES.has(rawType) ? rawType : "paragraph";
26904
+ const id = typeof r.id === "string" && r.id ? r.id : nextBlockId(type);
26905
+ return { ...r, id, type };
26906
+ });
26907
+ }
26898
26908
  function createBlock(type) {
26899
26909
  switch (type) {
26900
26910
  case "bullet-list":
@@ -27445,7 +27455,7 @@ function BlockRow({
27445
27455
  }
27446
27456
  );
27447
27457
  }
27448
- var TOOLBAR_ENTRIES, BLOCK_TYPE_LABEL, CHANGEABLE_TYPES, _idSeq; exports.RichBlockEditor = void 0;
27458
+ var TOOLBAR_ENTRIES, BLOCK_TYPE_LABEL, CHANGEABLE_TYPES, _idSeq, BLOCK_TYPES; exports.RichBlockEditor = void 0;
27449
27459
  var init_RichBlockEditor = __esm({
27450
27460
  "components/molecules/RichBlockEditor.tsx"() {
27451
27461
  "use client";
@@ -27492,6 +27502,18 @@ var init_RichBlockEditor = __esm({
27492
27502
  "code"
27493
27503
  ];
27494
27504
  _idSeq = 0;
27505
+ BLOCK_TYPES = /* @__PURE__ */ new Set([
27506
+ "paragraph",
27507
+ "heading-1",
27508
+ "heading-2",
27509
+ "heading-3",
27510
+ "bullet-list",
27511
+ "numbered-list",
27512
+ "quote",
27513
+ "code",
27514
+ "divider",
27515
+ "image"
27516
+ ]);
27495
27517
  exports.RichBlockEditor = ({
27496
27518
  initialBlocks,
27497
27519
  onChange,
@@ -27502,7 +27524,7 @@ var init_RichBlockEditor = __esm({
27502
27524
  className
27503
27525
  }) => {
27504
27526
  const [blocks, setBlocks] = React121.useState(
27505
- () => initialBlocks ?? [createBlock("paragraph")]
27527
+ () => normalizeBlocks(initialBlocks)
27506
27528
  );
27507
27529
  const onChangeRef = React121.useRef(onChange);
27508
27530
  React121.useEffect(() => {
@@ -26850,6 +26850,16 @@ function nextBlockId(prefix = "blk") {
26850
26850
  const random = Math.random().toString(36).slice(2, 8);
26851
26851
  return `${prefix}-${Date.now().toString(36)}-${_idSeq}-${random}`;
26852
26852
  }
26853
+ function normalizeBlocks(raw) {
26854
+ if (!raw || raw.length === 0) return [createBlock("paragraph")];
26855
+ return raw.map((row) => {
26856
+ const r = row;
26857
+ const rawType = r.type;
26858
+ const type = typeof rawType === "string" && BLOCK_TYPES.has(rawType) ? rawType : "paragraph";
26859
+ const id = typeof r.id === "string" && r.id ? r.id : nextBlockId(type);
26860
+ return { ...r, id, type };
26861
+ });
26862
+ }
26853
26863
  function createBlock(type) {
26854
26864
  switch (type) {
26855
26865
  case "bullet-list":
@@ -27400,7 +27410,7 @@ function BlockRow({
27400
27410
  }
27401
27411
  );
27402
27412
  }
27403
- var TOOLBAR_ENTRIES, BLOCK_TYPE_LABEL, CHANGEABLE_TYPES, _idSeq, RichBlockEditor;
27413
+ var TOOLBAR_ENTRIES, BLOCK_TYPE_LABEL, CHANGEABLE_TYPES, _idSeq, BLOCK_TYPES, RichBlockEditor;
27404
27414
  var init_RichBlockEditor = __esm({
27405
27415
  "components/molecules/RichBlockEditor.tsx"() {
27406
27416
  "use client";
@@ -27447,6 +27457,18 @@ var init_RichBlockEditor = __esm({
27447
27457
  "code"
27448
27458
  ];
27449
27459
  _idSeq = 0;
27460
+ BLOCK_TYPES = /* @__PURE__ */ new Set([
27461
+ "paragraph",
27462
+ "heading-1",
27463
+ "heading-2",
27464
+ "heading-3",
27465
+ "bullet-list",
27466
+ "numbered-list",
27467
+ "quote",
27468
+ "code",
27469
+ "divider",
27470
+ "image"
27471
+ ]);
27450
27472
  RichBlockEditor = ({
27451
27473
  initialBlocks,
27452
27474
  onChange,
@@ -27457,7 +27479,7 @@ var init_RichBlockEditor = __esm({
27457
27479
  className
27458
27480
  }) => {
27459
27481
  const [blocks, setBlocks] = useState(
27460
- () => initialBlocks ?? [createBlock("paragraph")]
27482
+ () => normalizeBlocks(initialBlocks)
27461
27483
  );
27462
27484
  const onChangeRef = useRef(onChange);
27463
27485
  useEffect(() => {
@@ -8,7 +8,7 @@
8
8
  * scope for the Phase 10 scaffold.
9
9
  */
10
10
  import React from "react";
11
- import type { EventEmit, EventPayloadValue } from '@almadar/core';
11
+ import type { EntityRow, EventEmit, EventPayloadValue } from '@almadar/core';
12
12
  export type BlockType = "paragraph" | "heading-1" | "heading-2" | "heading-3" | "bullet-list" | "numbered-list" | "quote" | "code" | "divider" | "image";
13
13
  export interface RichBlock {
14
14
  id: string;
@@ -19,7 +19,14 @@ export interface RichBlock {
19
19
  [key: string]: EventPayloadValue;
20
20
  }
21
21
  export interface RichBlockEditorProps {
22
- initialBlocks?: RichBlock[];
22
+ /**
23
+ * Initial block payload. Accepts strongly-typed RichBlock[] from native
24
+ * callers and the wider EntityRow[] shape that orb-bound traits emit
25
+ * (orb `[object]` lowers to `Record<string, FieldValue | undefined>[]`,
26
+ * which is structurally EntityRow[]). Items missing id/type are normalized
27
+ * into paragraph blocks at mount.
28
+ */
29
+ initialBlocks?: readonly RichBlock[] | readonly EntityRow[];
23
30
  onChange?: (blocks: RichBlock[]) => void;
24
31
  changeEvent?: EventEmit<{
25
32
  blocks: RichBlock[];
@@ -3571,17 +3571,20 @@ function parseApplicationLevel(schema) {
3571
3571
  }
3572
3572
  }
3573
3573
  }
3574
+ const seenLinks = /* @__PURE__ */ new Set();
3574
3575
  for (const emit of emitMap) {
3575
3576
  for (const listen of listenMap) {
3576
- if (emit.event === listen.event && emit.orbital !== listen.orbital) {
3577
- crossLinks.push({
3578
- emitterOrbital: emit.orbital,
3579
- listenerOrbital: listen.orbital,
3580
- eventName: emit.event,
3581
- emitterTrait: emit.trait,
3582
- listenerTrait: listen.trait
3583
- });
3584
- }
3577
+ if (emit.event !== listen.event || emit.orbital === listen.orbital) continue;
3578
+ const key = `${emit.orbital}\u241F${listen.orbital}\u241F${emit.event}`;
3579
+ if (seenLinks.has(key)) continue;
3580
+ seenLinks.add(key);
3581
+ crossLinks.push({
3582
+ emitterOrbital: emit.orbital,
3583
+ listenerOrbital: listen.orbital,
3584
+ eventName: emit.event,
3585
+ emitterTrait: emit.trait,
3586
+ listenerTrait: listen.trait
3587
+ });
3585
3588
  }
3586
3589
  }
3587
3590
  return { orbitals, crossLinks };
@@ -3547,17 +3547,20 @@ function parseApplicationLevel(schema) {
3547
3547
  }
3548
3548
  }
3549
3549
  }
3550
+ const seenLinks = /* @__PURE__ */ new Set();
3550
3551
  for (const emit of emitMap) {
3551
3552
  for (const listen of listenMap) {
3552
- if (emit.event === listen.event && emit.orbital !== listen.orbital) {
3553
- crossLinks.push({
3554
- emitterOrbital: emit.orbital,
3555
- listenerOrbital: listen.orbital,
3556
- eventName: emit.event,
3557
- emitterTrait: emit.trait,
3558
- listenerTrait: listen.trait
3559
- });
3560
- }
3553
+ if (emit.event !== listen.event || emit.orbital === listen.orbital) continue;
3554
+ const key = `${emit.orbital}\u241F${listen.orbital}\u241F${emit.event}`;
3555
+ if (seenLinks.has(key)) continue;
3556
+ seenLinks.add(key);
3557
+ crossLinks.push({
3558
+ emitterOrbital: emit.orbital,
3559
+ listenerOrbital: listen.orbital,
3560
+ eventName: emit.event,
3561
+ emitterTrait: emit.trait,
3562
+ listenerTrait: listen.trait
3563
+ });
3561
3564
  }
3562
3565
  }
3563
3566
  return { orbitals, crossLinks };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "4.38.1",
3
+ "version": "4.39.1",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [