footprint-explainable-ui 0.25.1 → 0.25.3

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.
package/dist/index.cjs CHANGED
@@ -3520,6 +3520,16 @@ function createDagreTraceLayout(options = {}) {
3520
3520
  return (graph) => dagreTraceLayout(graph, options);
3521
3521
  }
3522
3522
 
3523
+ // src/components/FlowchartView/_internal/devWarn.ts
3524
+ function isDevModeEnv() {
3525
+ const proc = globalThis.process;
3526
+ return proc?.env?.NODE_ENV !== "production";
3527
+ }
3528
+ function devWarn(messageFn, ...extras) {
3529
+ if (!isDevModeEnv()) return;
3530
+ console.warn(messageFn(), ...extras);
3531
+ }
3532
+
3523
3533
  // src/components/FlowchartView/_internal/snapLinearSuccessors.ts
3524
3534
  function snapLinearSuccessors(graph, options = {}) {
3525
3535
  if (graph.nodes.length === 0) return graph;
@@ -3621,36 +3631,79 @@ function centerForkParents(graph, options = {}) {
3621
3631
  }
3622
3632
  return minX <= maxX ? Math.max(minX, Math.min(maxX, desiredX)) : x0;
3623
3633
  };
3634
+ const evenFanKids = (forkCenter, kids) => {
3635
+ if (kids.length < 2) return;
3636
+ const sorted = [...kids].sort((a, b) => centerX(a) - centerX(b));
3637
+ let gap = 0;
3638
+ for (let i = 0; i < sorted.length - 1; i++) {
3639
+ gap = Math.max(gap, width.get(sorted[i]) / 2 + nodeSep + width.get(sorted[i + 1]) / 2);
3640
+ }
3641
+ const mid = (sorted.length - 1) / 2;
3642
+ for (let i = 0; i < sorted.length; i++) {
3643
+ workingX.set(sorted[i], forkCenter + (i - mid) * gap - width.get(sorted[i]) / 2);
3644
+ }
3645
+ };
3624
3646
  const order = [...graph.nodes].sort(
3625
3647
  (a, b) => b.position.y - a.position.y || a.position.x - b.position.x || a.id.localeCompare(b.id)
3626
3648
  );
3627
3649
  for (const n of order) {
3628
- if ((outDegree.get(n.id) ?? 0) < 2) continue;
3629
- if ((inDegree.get(n.id) ?? 0) > 1) continue;
3630
- const kids = (childrenOf.get(n.id) ?? []).filter(
3650
+ const outD = outDegree.get(n.id) ?? 0;
3651
+ const inD = inDegree.get(n.id) ?? 0;
3652
+ const isFork = outD >= 2 && inD <= 1;
3653
+ const isMerge = inD >= 2 && outD <= 1;
3654
+ if (!isFork && !isMerge) continue;
3655
+ const kin = ((isFork ? childrenOf.get(n.id) : predsOf.get(n.id)) ?? []).filter(
3631
3656
  (k) => byId.get(k)?.parentId === n.parentId
3632
3657
  // same compound only
3633
3658
  );
3634
- if (kids.length < 2) continue;
3635
- const centers = kids.map(centerX);
3659
+ if (kin.length < 2) continue;
3660
+ const centers = kin.map(centerX);
3636
3661
  const wN = width.get(n.id);
3637
3662
  const span = (Math.min(...centers) + Math.max(...centers)) / 2;
3638
3663
  workingX.set(n.id, clampX(n.id, span - wN / 2));
3664
+ if (isFork) {
3665
+ const succSets = kin.map((k) => childrenOf.get(k) ?? []);
3666
+ const isDiamond = kin.length >= 2 && succSets[0].some((s) => succSets.every((ss) => ss.includes(s)));
3667
+ if (isDiamond) evenFanKids(centerX(n.id), kin);
3668
+ }
3669
+ const stepOf = isFork ? predsOf : childrenOf;
3639
3670
  let curId = n.id;
3640
3671
  const walked = /* @__PURE__ */ new Set([curId]);
3641
3672
  for (; ; ) {
3642
- const ps = predsOf.get(curId);
3643
- if (!ps || ps.length !== 1) break;
3644
- const p = ps[0];
3645
- if (walked.has(p)) break;
3646
- if ((outDegree.get(p) ?? 0) !== 1) break;
3647
- if ((inDegree.get(p) ?? 0) > 1) break;
3648
- if (byId.get(p)?.parentId !== byId.get(curId)?.parentId) break;
3649
- workingX.set(p, clampX(p, centerX(curId) - width.get(p) / 2));
3650
- walked.add(p);
3651
- curId = p;
3673
+ const nexts = stepOf.get(curId);
3674
+ if (!nexts || nexts.length !== 1) break;
3675
+ const m = nexts[0];
3676
+ if (walked.has(m)) break;
3677
+ if ((outDegree.get(m) ?? 0) > 1) break;
3678
+ if ((inDegree.get(m) ?? 0) > 1) break;
3679
+ if (byId.get(m)?.parentId !== byId.get(curId)?.parentId) break;
3680
+ workingX.set(m, clampX(m, centerX(curId) - width.get(m) / 2));
3681
+ walked.add(m);
3682
+ curId = m;
3652
3683
  }
3653
3684
  }
3685
+ for (const n of order) {
3686
+ const outD = outDegree.get(n.id) ?? 0;
3687
+ const inD = inDegree.get(n.id) ?? 0;
3688
+ if (!(outD >= 2 && inD <= 1)) continue;
3689
+ const kids = (childrenOf.get(n.id) ?? []).filter(
3690
+ (k) => byId.get(k)?.parentId === n.parentId
3691
+ );
3692
+ if (kids.length < 2) continue;
3693
+ const succSets = kids.map((k) => childrenOf.get(k) ?? []);
3694
+ const isDiamond = succSets[0].some((s) => succSets.every((ss) => ss.includes(s)));
3695
+ if (isDiamond) continue;
3696
+ const ps = predsOf.get(n.id);
3697
+ if (!ps || ps.length !== 1) continue;
3698
+ const pred = ps[0];
3699
+ if ((outDegree.get(pred) ?? 0) !== 1) continue;
3700
+ if (byId.get(pred)?.parentId !== byId.get(n.id)?.parentId) continue;
3701
+ const before = centerX(n.id);
3702
+ workingX.set(n.id, clampX(n.id, centerX(pred) - width.get(n.id) / 2));
3703
+ const delta = centerX(n.id) - before;
3704
+ if (delta === 0) continue;
3705
+ for (const k of kids) workingX.set(k, clampX(k, workingX.get(k) + delta));
3706
+ }
3654
3707
  const nodes = graph.nodes.map(
3655
3708
  (n) => workingX.get(n.id) === n.position.x ? n : { ...n, position: { x: workingX.get(n.id), y: n.position.y } }
3656
3709
  );
@@ -4965,6 +5018,13 @@ function TracedFlow({
4965
5018
  style
4966
5019
  }) {
4967
5020
  const layout = layoutProp ?? dagreTraceLayout;
5021
+ (0, import_react25.useEffect)(() => {
5022
+ if (layoutProp === dagreTraceLayout) {
5023
+ devWarn(
5024
+ () => "[footprint-explainable-ui] <TracedFlow layout={dagreTraceLayout}> bypasses the built-in measure-then-layout pipeline (content-exact sizing, fork/merge centering, straight spines). OMIT the `layout` prop to use it \u2014 passing the raw dagreTraceLayout silently forfeits every layout improvement eui ships."
5025
+ );
5026
+ }
5027
+ }, [layoutProp]);
4968
5028
  const colors = (0, import_react25.useMemo)(
4969
5029
  () => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
4970
5030
  [colorOverrides]