@floegence/floe-webapp-core 0.86.11 → 0.86.13

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.
@@ -1,48 +1,49 @@
1
- import { applyGraphPositions as b } from "./positions.js";
1
+ import { applyGraphPositions as G } from "./positions.js";
2
2
  import { computePackedGraphLayout as k } from "./packing.js";
3
- function $(a) {
4
- const o = /* @__PURE__ */ new Set(), c = (t) => {
5
- if (!t || o.has(t)) throw new Error(`Duplicate or empty graph ID: ${t}`);
6
- o.add(t);
7
- }, i = new Map(a.nodes.map((t) => [t.id, t]));
8
- for (const t of a.nodes) {
3
+ function $(d) {
4
+ const r = /* @__PURE__ */ new Set(), c = (t) => {
5
+ if (!t || r.has(t)) throw new Error(`Duplicate or empty graph ID: ${t}`);
6
+ r.add(t);
7
+ }, i = new Map(d.nodes.map((t) => [t.id, t]));
8
+ for (const t of d.nodes) {
9
9
  if (c(t.id), ![t.width, t.height].every((n) => Number.isFinite(n) && n > 0))
10
10
  throw new Error(`Invalid dimensions for graph node: ${t.id}`);
11
11
  for (const n of t.ports ?? []) c(n.id);
12
12
  const s = /* @__PURE__ */ new Set([t.id]);
13
- let r = t.parentId;
14
- for (; r !== void 0; ) {
15
- const n = i.get(r);
13
+ let o = t.parentId;
14
+ for (; o !== void 0; ) {
15
+ const n = i.get(o);
16
16
  if (!n || n.kind !== "group")
17
17
  throw new Error(`Invalid parent for graph node: ${t.id}`);
18
- if (s.has(r)) throw new Error(`Cyclic graph containment: ${t.id}`);
19
- s.add(r), r = n.parentId;
18
+ if (s.has(o)) throw new Error(`Cyclic graph containment: ${t.id}`);
19
+ s.add(o), o = n.parentId;
20
20
  }
21
21
  }
22
- for (const t of a.edges) {
22
+ for (const t of d.edges) {
23
23
  c(t.id);
24
- for (const [s, r] of [
24
+ for (const [s, o] of [
25
25
  [t.source, t.sourcePort],
26
26
  [t.target, t.targetPort]
27
27
  ]) {
28
28
  const n = i.get(s);
29
- if (!n || r !== void 0 && !n.ports?.some((h) => h.id === r))
29
+ if (!n || o !== void 0 && !n.ports?.some((h) => h.id === o))
30
30
  throw new Error(`Invalid endpoint for graph edge: ${t.id}`);
31
31
  }
32
32
  }
33
33
  }
34
- async function P(a, o, c) {
35
- $(a);
36
- const i = O(a, o);
37
- if (o.aspectRatio !== void 0 && (!Number.isFinite(o.aspectRatio) || o.aspectRatio <= 0))
34
+ async function P(d, r, c) {
35
+ if ($(d), r.edgeClearance !== void 0 && (!Number.isFinite(r.edgeClearance) || r.edgeClearance < 0))
36
+ throw new Error("Graph edge clearance must be finite and nonnegative");
37
+ const i = N(d, r);
38
+ if (r.aspectRatio !== void 0 && (!Number.isFinite(r.aspectRatio) || r.aspectRatio <= 0))
38
39
  throw new Error("Graph layout aspect ratio must be finite and positive");
39
- const t = o.groupPadding ?? { top: 64, right: 28, bottom: 28, left: 28 };
40
- if (![...Object.values(t), o.spacing ?? 64].every((e) => Number.isFinite(e) && e >= 0))
40
+ const t = r.groupPadding ?? { top: 64, right: 28, bottom: 28, left: 28 };
41
+ if (![...Object.values(t), r.spacing ?? 64].every((e) => Number.isFinite(e) && e >= 0))
41
42
  throw new Error("Graph layout spacing must be finite and nonnegative");
42
- if (o.layers && (M(a, o.layers), o.positionMode === "fixed" && o.positions?.length))
43
+ if (r.layers && (O(d, r.layers), r.positionMode === "fixed" && r.positions?.length))
43
44
  throw new Error("Fixed positions cannot be combined with graph layers");
44
- if (o.aspectRatio !== void 0 || o.layers)
45
- return k(i, o, c);
45
+ if (r.aspectRatio !== void 0 || r.layers)
46
+ return k(i, r, c);
46
47
  const s = /* @__PURE__ */ new Map();
47
48
  for (const e of i.nodes)
48
49
  s.set(e.id, {
@@ -50,29 +51,29 @@ async function P(a, o, c) {
50
51
  width: e.width,
51
52
  height: e.height,
52
53
  ...e.kind === "group" ? { children: [] } : {},
53
- ports: e.ports?.map((d) => ({
54
- id: d.id,
54
+ ports: e.ports?.map((a) => ({
55
+ id: a.id,
55
56
  width: 1,
56
57
  height: 1,
57
- layoutOptions: { "elk.port.side": d.side }
58
+ layoutOptions: { "elk.port.side": a.side }
58
59
  })),
59
60
  layoutOptions: {
60
61
  "elk.portConstraints": "FIXED_ORDER",
61
62
  "elk.padding": `[top=${t.top},left=${t.left},bottom=${t.bottom},right=${t.right}]`
62
63
  }
63
64
  });
64
- const r = [];
65
+ const o = [];
65
66
  for (const e of i.nodes)
66
- (e.parentId ? s.get(e.parentId).children : r).push(s.get(e.id));
67
+ (e.parentId ? s.get(e.parentId).children : o).push(s.get(e.id));
67
68
  const n = /* @__PURE__ */ new Set([
68
- ...i.nodes.flatMap((e) => [e.id, ...(e.ports ?? []).map((d) => d.id)]),
69
+ ...i.nodes.flatMap((e) => [e.id, ...(e.ports ?? []).map((a) => a.id)]),
69
70
  ...i.edges.map((e) => e.id)
70
71
  ]);
71
72
  let h = "$graph";
72
73
  for (; n.has(h); ) h += "$";
73
74
  const p = await c.layout({
74
75
  id: h,
75
- children: r,
76
+ children: o,
76
77
  edges: i.edges.map((e) => ({
77
78
  id: e.id,
78
79
  sources: [e.sourcePort ?? e.source],
@@ -80,20 +81,20 @@ async function P(a, o, c) {
80
81
  })),
81
82
  layoutOptions: {
82
83
  "elk.algorithm": "layered",
83
- "elk.direction": o.direction ?? "RIGHT",
84
+ "elk.direction": r.direction ?? "RIGHT",
84
85
  "elk.edgeRouting": "ORTHOGONAL",
85
86
  "elk.hierarchyHandling": "INCLUDE_CHILDREN",
86
- "elk.spacing.nodeNode": String(o.spacing ?? 64),
87
- "elk.layered.spacing.nodeNodeBetweenLayers": String(o.spacing ?? 64),
87
+ "elk.spacing.nodeNode": String(r.spacing ?? 64),
88
+ "elk.layered.spacing.nodeNodeBetweenLayers": String(r.spacing ?? 64),
88
89
  "elk.layered.considerModelOrder.strategy": "NODES_AND_EDGES",
89
90
  "elk.randomSeed": "1"
90
91
  }
91
- }), y = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), E = (e) => {
92
- for (const d of e.edges ?? []) {
93
- const g = d.container ?? e.id, f = y.get(g) ?? { x: 0, y: 0 };
94
- x.set(
95
- d.id,
96
- (d.sections ?? []).map(
92
+ }), y = /* @__PURE__ */ new Map(), E = /* @__PURE__ */ new Map(), x = (e) => {
93
+ for (const a of e.edges ?? []) {
94
+ const g = a.container ?? e.id, f = y.get(g) ?? { x: 0, y: 0 };
95
+ E.set(
96
+ a.id,
97
+ (a.sections ?? []).map(
97
98
  (l) => [l.startPoint, ...l.bendPoints ?? [], l.endPoint].map((m) => ({
98
99
  x: m.x + f.x,
99
100
  y: m.y + f.y
@@ -101,55 +102,55 @@ async function P(a, o, c) {
101
102
  )
102
103
  );
103
104
  }
104
- for (const d of e.children ?? []) E(d);
105
- }, v = (e, d, g) => {
106
- const f = d + (e.x ?? 0), l = g + (e.y ?? 0);
105
+ for (const a of e.children ?? []) x(a);
106
+ }, v = (e, a, g) => {
107
+ const f = a + (e.x ?? 0), l = g + (e.y ?? 0);
107
108
  y.set(e.id, { x: f, y: l, width: e.width ?? 0, height: e.height ?? 0 });
108
109
  for (const m of e.children ?? []) v(m, f, l);
109
110
  };
110
111
  for (const e of p.children ?? []) v(e, 0, 0);
111
- E(p);
112
- const w = (!o.positions?.length || o.positionMode === "compact") && o.anchor && y.get(o.anchor.nodeId), u = w ? o.anchor.position.x - w.x : 0, I = w ? o.anchor.position.y - w.y : 0, G = i.nodes.map((e) => {
113
- const d = y.get(e.id);
114
- return { ...e, ...d, x: d.x + u, y: d.y + I };
112
+ x(p);
113
+ const w = (!r.positions?.length || r.positionMode === "compact") && r.anchor && y.get(r.anchor.nodeId), u = w ? r.anchor.position.x - w.x : 0, I = w ? r.anchor.position.y - w.y : 0, b = i.nodes.map((e) => {
114
+ const a = y.get(e.id);
115
+ return { ...e, ...a, x: a.x + u, y: a.y + I };
115
116
  });
116
- return b(
117
+ return G(
117
118
  {
118
- nodes: G,
119
+ nodes: b,
119
120
  edges: i.edges.map((e) => ({
120
121
  ...e,
121
- sections: (x.get(e.id) ?? []).map(
122
- (d) => d.map((g) => ({ x: g.x + u, y: g.y + I }))
122
+ sections: (E.get(e.id) ?? []).map(
123
+ (a) => a.map((g) => ({ x: g.x + u, y: g.y + I }))
123
124
  )
124
125
  })),
125
126
  bounds: { x: u, y: I, width: p.width ?? 0, height: p.height ?? 0 }
126
127
  },
127
- o,
128
+ r,
128
129
  i.nodes
129
130
  );
130
131
  }
131
- function O(a, o) {
132
- if (o.positionMode !== "compact" || !o.positions?.length) return a;
133
- const c = o.direction ?? "RIGHT", i = new Map(
134
- o.positions.map((r) => [
135
- r.nodeId,
136
- c === "RIGHT" || c === "LEFT" ? r.y : r.x
132
+ function N(d, r) {
133
+ if (r.positionMode !== "compact" || !r.positions?.length) return d;
134
+ const c = r.direction ?? "RIGHT", i = new Map(
135
+ r.positions.map((o) => [
136
+ o.nodeId,
137
+ c === "RIGHT" || c === "LEFT" ? o.y : o.x
137
138
  ])
138
- ), t = new Map(a.nodes.map((r, n) => [r.id, n]));
139
- return { nodes: [...a.nodes].sort((r, n) => {
140
- const h = (r.parentId ?? "").localeCompare(n.parentId ?? ""), p = o.layers && !r.parentId && !n.parentId ? 0 : (i.get(r.id) ?? 1 / 0) - (i.get(n.id) ?? 1 / 0);
141
- return h || p || t.get(r.id) - t.get(n.id);
142
- }), edges: a.edges };
139
+ ), t = new Map(d.nodes.map((o, n) => [o.id, n]));
140
+ return { nodes: [...d.nodes].sort((o, n) => {
141
+ const h = (o.parentId ?? "").localeCompare(n.parentId ?? ""), p = r.layers && !o.parentId && !n.parentId ? 0 : (i.get(o.id) ?? 1 / 0) - (i.get(n.id) ?? 1 / 0);
142
+ return h || p || t.get(o.id) - t.get(n.id);
143
+ }), edges: d.edges };
143
144
  }
144
- function M(a, o) {
145
- const c = new Map(a.nodes.map((t) => [t.id, t])), i = /* @__PURE__ */ new Set();
146
- for (const [t, s] of o.entries()) {
145
+ function O(d, r) {
146
+ const c = new Map(d.nodes.map((t) => [t.id, t])), i = /* @__PURE__ */ new Set();
147
+ for (const [t, s] of r.entries()) {
147
148
  if (!s.length) throw new Error(`Graph layer must not be empty: ${t}`);
148
- for (const r of s) {
149
- const n = c.get(r);
150
- if (!n || n.parentId) throw new Error(`Graph layer object must be a root node: ${r}`);
151
- if (i.has(r)) throw new Error(`Graph object appears in multiple layers: ${r}`);
152
- i.add(r);
149
+ for (const o of s) {
150
+ const n = c.get(o);
151
+ if (!n || n.parentId) throw new Error(`Graph layer object must be a root node: ${o}`);
152
+ if (i.has(o)) throw new Error(`Graph object appears in multiple layers: ${o}`);
153
+ i.add(o);
153
154
  }
154
155
  }
155
156
  }
@@ -1,6 +1,6 @@
1
1
  import { applyGraphPositions as $ } from "./positions.js";
2
2
  import { routeGraphGeometry as P } from "./routing.js";
3
- async function j(f, i, S) {
3
+ async function j(f, s, S) {
4
4
  const y = new Map(f.nodes.map((e) => [e.id, { ...e, x: 0, y: 0 }])), O = new Map(f.nodes.map((e, d) => [e.id, d])), m = /* @__PURE__ */ new Map();
5
5
  for (const e of y.values()) {
6
6
  const d = m.get(e.parentId) ?? [];
@@ -12,22 +12,22 @@ async function j(f, i, S) {
12
12
  ]);
13
13
  let T = "$packed";
14
14
  for (; p.has(T); ) T += "$";
15
- const k = i.groupPadding ?? { top: 64, right: 28, bottom: 28, left: 28 }, E = i.direction ?? "RIGHT", w = new Map(
16
- (i.positions ?? []).map((e) => [
15
+ const k = s.groupPadding ?? { top: 64, right: 28, bottom: 28, left: 28 }, E = s.direction ?? "RIGHT", w = new Map(
16
+ (s.positions ?? []).map((e) => [
17
17
  e.nodeId,
18
18
  E === "RIGHT" || E === "LEFT" ? e.y : e.x
19
19
  ])
20
- ), I = (e, d, s) => {
21
- e.x += d, e.y += s;
22
- for (const v of m.get(e.id) ?? []) I(v, d, s);
20
+ ), I = (e, d, i) => {
21
+ e.x += d, e.y += i;
22
+ for (const v of m.get(e.id) ?? []) I(v, d, i);
23
23
  }, x = (e, d) => {
24
- let s = y.get(e);
25
- for (; s && s.parentId !== d; )
26
- s = s.parentId ? y.get(s.parentId) : void 0;
27
- return s;
24
+ let i = y.get(e);
25
+ for (; i && i.parentId !== d; )
26
+ i = i.parentId ? y.get(i.parentId) : void 0;
27
+ return i;
28
28
  }, G = async (e) => {
29
29
  const d = [...m.get(e) ?? []];
30
- (e !== void 0 || !i.layers) && d.sort(
30
+ (e !== void 0 || !s.layers) && d.sort(
31
31
  (o, a) => (w.get(o.id) ?? 1 / 0) - (w.get(a.id) ?? 1 / 0) || O.get(o.id) - O.get(a.id)
32
32
  );
33
33
  for (const o of d) {
@@ -36,28 +36,28 @@ async function j(f, i, S) {
36
36
  o.width = Math.max(o.width, a.width), o.height = Math.max(o.height, a.height);
37
37
  }
38
38
  if (!d.length) return { width: 0, height: 0 };
39
- if (e === void 0 && i.layers)
40
- return z(d, f, i, x, I);
41
- const s = /* @__PURE__ */ new Map();
39
+ if (e === void 0 && s.layers)
40
+ return z(d, f, s, x, I);
41
+ const i = /* @__PURE__ */ new Map();
42
42
  for (const o of f.edges) {
43
43
  const a = x(o.source, e), M = x(o.target, e);
44
44
  if (!a || !M || a.id === M.id) continue;
45
45
  const H = JSON.stringify([a.id, M.id]);
46
- s.has(H) || s.set(H, { id: o.id, sources: [a.id], targets: [M.id] });
46
+ i.has(H) || i.set(H, { id: o.id, sources: [a.id], targets: [M.id] });
47
47
  }
48
48
  const v = await S.layout({
49
49
  id: e ?? T,
50
50
  children: d.map((o) => ({ id: o.id, width: o.width, height: o.height })),
51
- edges: [...s.values()],
51
+ edges: [...i.values()],
52
52
  layoutOptions: {
53
- "elk.algorithm": s.size ? "layered" : "rectpacking",
53
+ "elk.algorithm": i.size ? "layered" : "rectpacking",
54
54
  "elk.direction": E,
55
55
  "elk.edgeRouting": "ORTHOGONAL",
56
56
  "elk.separateConnectedComponents": "true",
57
- ...i.aspectRatio !== void 0 ? { "elk.aspectRatio": String(i.aspectRatio) } : {},
58
- "elk.spacing.componentComponent": String(i.spacing ?? 64),
59
- "elk.spacing.nodeNode": String(i.spacing ?? 64),
60
- "elk.layered.spacing.nodeNodeBetweenLayers": String(i.spacing ?? 64),
57
+ ...s.aspectRatio !== void 0 ? { "elk.aspectRatio": String(s.aspectRatio) } : {},
58
+ "elk.spacing.componentComponent": String(s.spacing ?? 64),
59
+ "elk.spacing.nodeNode": String(s.spacing ?? 64),
60
+ "elk.layered.spacing.nodeNodeBetweenLayers": String(s.spacing ?? 64),
61
61
  "elk.layered.considerModelOrder.strategy": "NODES_AND_EDGES",
62
62
  "elk.padding": e ? `[top=${k.top},left=${k.left},bottom=${k.bottom},right=${k.right}]` : "[top=12,left=12,bottom=12,right=12]",
63
63
  "elk.randomSeed": "1"
@@ -68,23 +68,23 @@ async function j(f, i, S) {
68
68
  I(a, (o.x ?? 0) - a.x, (o.y ?? 0) - a.y);
69
69
  }
70
70
  return { width: v.width ?? 0, height: v.height ?? 0 };
71
- }, u = await G(), R = (!i.positions?.length || i.positionMode === "compact" || i.layers) && i.anchor && y.get(i.anchor.nodeId);
71
+ }, u = await G(), R = (!s.positions?.length || s.positionMode === "compact" || s.layers) && s.anchor && y.get(s.anchor.nodeId);
72
72
  if (R) {
73
- const e = i.anchor.position.x - R.x, d = i.anchor.position.y - R.y;
74
- for (const s of m.get(void 0) ?? []) I(s, e, d);
73
+ const e = s.anchor.position.x - R.x, d = s.anchor.position.y - R.y;
74
+ for (const i of m.get(void 0) ?? []) I(i, e, d);
75
75
  }
76
76
  const C = {
77
77
  nodes: [...y.values()],
78
78
  edges: f.edges.map((e) => ({ ...e, sections: [] })),
79
79
  bounds: { x: 0, y: 0, ...u }
80
80
  };
81
- return i.positions?.length && i.positionMode !== "compact" && !i.layers ? $(C, i, f.nodes) : P(C);
81
+ return s.positions?.length && s.positionMode !== "compact" && !s.layers ? $(C, s, f.nodes) : P(C, s);
82
82
  }
83
- function z(f, i, S, y, O) {
83
+ function z(f, s, S, y, O) {
84
84
  const m = S.direction ?? "RIGHT", p = m === "RIGHT" || m === "LEFT", T = m === "RIGHT" || m === "DOWN", k = new Map(f.map((t, n) => [t.id, n])), E = new Map(
85
85
  (S.positions ?? []).filter((t) => k.has(t.nodeId)).map((t) => [t.nodeId, p ? t.y : t.x])
86
86
  ), w = (t, n) => k.get(t) - k.get(n) || t.localeCompare(n), I = (t, n) => (E.get(t) ?? 1 / 0) - (E.get(n) ?? 1 / 0) || w(t, n), x = new Map(f.map((t) => [t.id, /* @__PURE__ */ new Set()]));
87
- for (const t of i.edges) {
87
+ for (const t of s.edges) {
88
88
  const n = y(t.source, void 0)?.id, r = y(t.target, void 0)?.id;
89
89
  n && r && n !== r && (x.get(n)?.add(r), x.get(r)?.add(n));
90
90
  }
@@ -118,25 +118,25 @@ function z(f, i, S, y, O) {
118
118
  r.has(l) || (r.set(l, r.get(h) + 1), u.set(l, u.get(h)), c.push(l));
119
119
  }
120
120
  }
121
- const d = Math.max(G.length, e), s = Array.from({ length: d }, () => []);
122
- for (const t of f) s[u.get(t.id)].push(t);
123
- for (const t of s) t.sort((n, r) => I(n.id, r.id));
121
+ const d = Math.max(G.length, e), i = Array.from({ length: d }, () => []);
122
+ for (const t of f) i[u.get(t.id)].push(t);
123
+ for (const t of i) t.sort((n, r) => I(n.id, r.id));
124
124
  const v = (t, n) => {
125
- const r = new Map(s[n].map((h, l) => [h.id, l])), c = new Map(s[t].map((h, l) => [h.id, l])), g = (h) => {
125
+ const r = new Map(i[n].map((h, l) => [h.id, l])), c = new Map(i[t].map((h, l) => [h.id, l])), g = (h) => {
126
126
  const l = [...x.get(h) ?? []].flatMap((N) => {
127
127
  const b = r.get(N);
128
128
  return u.get(N) === n && b !== void 0 ? [b] : [];
129
129
  });
130
130
  return l.length ? l.reduce((N, b) => N + b, 0) / l.length : c.get(h);
131
131
  };
132
- s[t].sort((h, l) => g(h.id) - g(l.id) || I(h.id, l.id));
132
+ i[t].sort((h, l) => g(h.id) - g(l.id) || I(h.id, l.id));
133
133
  };
134
- for (let t = 1; t < s.length; t++) v(t, t - 1);
135
- for (let t = s.length - 2; t >= 0; t--) v(t, t + 1);
134
+ for (let t = 1; t < i.length; t++) v(t, t - 1);
135
+ for (let t = i.length - 2; t >= 0; t--) v(t, t + 1);
136
136
  const o = S.spacing ?? 64;
137
137
  let a = 0, M = 0;
138
138
  const H = [], L = [];
139
- for (const t of s) {
139
+ for (const t of i) {
140
140
  let n = 0;
141
141
  const r = Math.max(0, ...t.map((c) => p ? c.width : c.height));
142
142
  H.push(a), L.push(r);
@@ -1,75 +1,76 @@
1
- import { routeGraphGeometry as G } from "./routing.js";
2
- function E(d, p, v) {
3
- if (!p.positions?.length || p.positionMode === "compact") return d;
4
- const f = new Map(d.nodes.map((t) => [t.id, { ...t }])), l = /* @__PURE__ */ new Map();
5
- for (const t of p.positions) {
6
- if (!f.has(t.nodeId) || l.has(t.nodeId) || !Number.isFinite(t.x) || !Number.isFinite(t.y))
1
+ import { routeGraphGeometry as v } from "./routing.js";
2
+ function C(l, x, G) {
3
+ if (!x.positions?.length || x.positionMode === "compact")
4
+ return x.edgeClearance === void 0 ? l : v(l, x);
5
+ const f = new Map(l.nodes.map((t) => [t.id, { ...t }])), M = /* @__PURE__ */ new Map();
6
+ for (const t of x.positions) {
7
+ if (!f.has(t.nodeId) || M.has(t.nodeId) || !Number.isFinite(t.x) || !Number.isFinite(t.y))
7
8
  throw new Error(`Invalid graph position: ${t.nodeId}`);
8
- l.set(t.nodeId, t);
9
+ M.set(t.nodeId, t);
9
10
  }
10
11
  const y = /* @__PURE__ */ new Map();
11
12
  for (const t of f.values())
12
13
  if (t.parentId) {
13
- const m = y.get(t.parentId) ?? [];
14
- m.push(t), y.set(t.parentId, m);
14
+ const c = y.get(t.parentId) ?? [];
15
+ c.push(t), y.set(t.parentId, c);
15
16
  }
16
- const x = p.groupPadding ?? { top: 64, left: 28, right: 28, bottom: 28 }, u = p.positionMode === "preferred", I = new Map(v.map((t) => [t.id, t])), b = (t, m, M) => {
17
- const g = { x: t.x, y: t.y }, c = l.get(t.id);
18
- t.x = c?.x ?? t.x + m, t.y = c?.y ?? t.y + M;
17
+ const m = x.groupPadding ?? { top: 64, left: 28, right: 28, bottom: 28 }, u = x.positionMode === "preferred", I = new Map(G.map((t) => [t.id, t])), b = (t, c, d) => {
18
+ const g = { x: t.x, y: t.y }, p = M.get(t.id);
19
+ t.x = p?.x ?? t.x + c, t.y = p?.y ?? t.y + d;
19
20
  const i = y.get(t.id) ?? [];
20
- for (const a of i) b(a, t.x - g.x, t.y - g.y);
21
+ for (const o of i) b(o, t.x - g.x, t.y - g.y);
21
22
  if (!i.length || u) return;
22
- const r = Math.min(...i.map((a) => a.x)) - x.left, h = Math.min(...i.map((a) => a.y)) - x.top;
23
- if (c && (r < t.x || h < t.y))
23
+ const a = Math.min(...i.map((o) => o.x)) - m.left, h = Math.min(...i.map((o) => o.y)) - m.top;
24
+ if (p && (a < t.x || h < t.y))
24
25
  throw new Error(`Pinned child lies outside group content: ${t.id}`);
25
- const s = Math.max(
26
+ const e = Math.max(
26
27
  t.x + t.width,
27
- ...i.map((a) => a.x + a.width + x.right)
28
+ ...i.map((o) => o.x + o.width + m.right)
28
29
  ), n = Math.max(
29
30
  t.y + t.height,
30
- ...i.map((a) => a.y + a.height + x.bottom)
31
+ ...i.map((o) => o.y + o.height + m.bottom)
31
32
  );
32
- c || (t.x = Math.min(t.x, r), t.y = Math.min(t.y, h)), t.width = s - t.x, t.height = n - t.y;
33
+ p || (t.x = Math.min(t.x, a), t.y = Math.min(t.y, h)), t.width = e - t.x, t.height = n - t.y;
33
34
  };
34
35
  for (const t of f.values()) t.parentId || b(t, 0, 0);
35
36
  if (u) {
36
- const t = Math.max(16, p.spacing ?? 64), m = (i, r, h) => {
37
- i.x += r, i.y += h;
38
- for (const s of y.get(i.id) ?? []) m(s, r, h);
39
- }, M = (i) => {
40
- const r = [];
37
+ const t = Math.max(16, x.spacing ?? 64), c = (i, a, h) => {
38
+ i.x += a, i.y += h;
39
+ for (const e of y.get(i.id) ?? []) c(e, a, h);
40
+ }, d = (i) => {
41
+ const a = [];
41
42
  for (const h of [...i].sort(
42
- (s, n) => s.y - n.y || s.x - n.x || s.id.localeCompare(n.id)
43
+ (e, n) => e.y - n.y || e.x - n.x || e.id.localeCompare(n.id)
43
44
  )) {
44
- const s = { x: h.x, y: h.y };
45
- for (const o of [...r].sort((e, w) => e.x - w.x))
46
- h.y < o.y + o.height + t && h.y + h.height + t > o.y && s.x < o.x + o.width + t && s.x + h.width + t > o.x && (s.x = o.x + o.width + t);
45
+ const e = { x: h.x, y: h.y };
46
+ for (const r of [...a].sort((s, w) => s.x - w.x))
47
+ h.y < r.y + r.height + t && h.y + h.height + t > r.y && e.x < r.x + r.width + t && e.x + h.width + t > r.x && (e.x = r.x + r.width + t);
47
48
  const n = { x: h.x, y: h.y };
48
- for (const o of [...r].sort((e, w) => e.y - w.y))
49
- h.x < o.x + o.width + t && h.x + h.width + t > o.x && n.y < o.y + o.height + t && n.y + h.height + t > o.y && (n.y = o.y + o.height + t);
50
- const a = s.x - h.x < n.y - h.y ? s : n;
51
- m(h, a.x - h.x, a.y - h.y), r.push(h);
49
+ for (const r of [...a].sort((s, w) => s.y - w.y))
50
+ h.x < r.x + r.width + t && h.x + h.width + t > r.x && n.y < r.y + r.height + t && n.y + h.height + t > r.y && (n.y = r.y + r.height + t);
51
+ const o = e.x - h.x < n.y - h.y ? e : n;
52
+ c(h, o.x - h.x, o.y - h.y), a.push(h);
52
53
  }
53
54
  }, g = (i) => {
54
- const r = y.get(i.id) ?? [];
55
- if (!r.length) return;
56
- for (const e of r) g(e);
57
- M(r);
58
- const h = Math.max(12, x.left), s = Math.max(12, x.top), n = Math.max(12, x.right), a = Math.max(12, x.bottom), o = l.get(i.id);
59
- i.x = Math.min(o?.x ?? 1 / 0, Math.min(...r.map((e) => e.x)) - h), i.y = Math.min(o?.y ?? 1 / 0, Math.min(...r.map((e) => e.y)) - s), i.width = Math.max(
55
+ const a = y.get(i.id) ?? [];
56
+ if (!a.length) return;
57
+ for (const s of a) g(s);
58
+ d(a);
59
+ const h = Math.max(12, m.left), e = Math.max(12, m.top), n = Math.max(12, m.right), o = Math.max(12, m.bottom), r = M.get(i.id);
60
+ i.x = Math.min(r?.x ?? 1 / 0, Math.min(...a.map((s) => s.x)) - h), i.y = Math.min(r?.y ?? 1 / 0, Math.min(...a.map((s) => s.y)) - e), i.width = Math.max(
60
61
  I.get(i.id).width,
61
- Math.max(...r.map((e) => e.x + e.width)) + n - i.x
62
+ Math.max(...a.map((s) => s.x + s.width)) + n - i.x
62
63
  ), i.height = Math.max(
63
64
  I.get(i.id).height,
64
- Math.max(...r.map((e) => e.y + e.height)) + a - i.y
65
+ Math.max(...a.map((s) => s.y + s.height)) + o - i.y
65
66
  );
66
- }, c = [...f.values()].filter((i) => !i.parentId);
67
- for (const i of c) g(i);
68
- M(c);
67
+ }, p = [...f.values()].filter((i) => !i.parentId);
68
+ for (const i of p) g(i);
69
+ d(p);
69
70
  }
70
- return G({ ...d, nodes: [...f.values()] });
71
+ return v({ ...l, nodes: [...f.values()] }, x);
71
72
  }
72
73
  export {
73
- E as applyGraphPositions,
74
- G as routeGraphGeometry
74
+ C as applyGraphPositions,
75
+ v as routeGraphGeometry
75
76
  };
@@ -1,3 +1,3 @@
1
- import type { GraphLayout } from './types';
1
+ import type { GraphLayout, GraphLayoutOptions } from './types';
2
2
  /** Joint orthogonal routing through the final rectangular geometry. */
3
- export declare function routeGraphGeometry(layout: GraphLayout): Promise<GraphLayout>;
3
+ export declare function routeGraphGeometry(layout: GraphLayout, options?: Pick<GraphLayoutOptions, 'edgeClearance'>): Promise<GraphLayout>;
@@ -1,240 +1,242 @@
1
- import { AvoidLib as G } from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/index.js";
2
- import V from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/libavoid.wasm.js";
3
- let J;
4
- const j = { NORTH: 1, SOUTH: 2, WEST: 4, EAST: 8 }, N = ["NORTH", "EAST", "SOUTH", "WEST"], O = (n) => n.delete();
5
- async function $(n) {
1
+ import { AvoidLib as Y } from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/index.js";
2
+ import tt from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/libavoid.wasm.js";
3
+ let _;
4
+ const L = { NORTH: 1, SOUTH: 2, WEST: 4, EAST: 8 }, A = ["NORTH", "EAST", "SOUTH", "WEST"], S = (n) => n.delete();
5
+ async function et(n, o = {}) {
6
+ const a = o.edgeClearance ?? 4;
7
+ if (!Number.isFinite(a) || a < 0)
8
+ throw new Error("Graph edge clearance must be finite and nonnegative");
6
9
  if (!n.nodes.length) return n;
7
- if (!n.edges.length) return F(n);
8
- await (J ??= G.load(V).catch((y) => {
9
- throw J = void 0, y;
10
+ if (!n.edges.length) return $(n);
11
+ await (_ ??= Y.load(tt).catch((r) => {
12
+ throw _ = void 0, r;
10
13
  }));
11
- const s = G.getInstance(), r = new Map(n.nodes.map((y) => [y.id, y])), p = (y) => {
12
- const m = [];
13
- for (let i = r.get(y).parentId; i; i = r.get(i).parentId)
14
- m.push(i);
15
- return m;
16
- }, x = /* @__PURE__ */ new Map();
17
- for (const y of n.edges) {
18
- const m = /* @__PURE__ */ new Set([...p(y.source), ...p(y.target)]), i = JSON.stringify([...m].sort()), e = x.get(i) ?? { open: m, edges: [] };
19
- e.edges.push(y), x.set(i, e);
14
+ const i = Y.getInstance(), h = new Map(n.nodes.map((r) => [r.id, r])), l = (r) => {
15
+ const c = [];
16
+ for (let s = h.get(r).parentId; s; s = h.get(s).parentId)
17
+ c.push(s);
18
+ return c;
19
+ }, f = /* @__PURE__ */ new Map();
20
+ for (const r of n.edges) {
21
+ const c = /* @__PURE__ */ new Set([...l(r.source), ...l(r.target)]), s = JSON.stringify([...c].sort()), M = f.get(s) ?? { open: c, edges: [] };
22
+ M.edges.push(r), f.set(s, M);
20
23
  }
21
24
  const T = /* @__PURE__ */ new Map();
22
- for (const { open: y, edges: m } of x.values()) {
23
- const i = new s.Router(2);
25
+ for (const { open: r, edges: c } of f.values()) {
26
+ const s = new i.Router(2);
24
27
  try {
25
- i.setRoutingParameter(s.RoutingParameter.shapeBufferDistance, 4), i.setRoutingParameter(s.RoutingParameter.idealNudgingDistance, 8), i.setRoutingParameter(s.RoutingParameter.crossingPenalty, 80), i.setRoutingParameter(s.RoutingParameter.fixedSharedPathPenalty, 120), i.setRoutingParameter(s.RoutingParameter.portDirectionPenalty, 0), i.setRoutingOption(s.RoutingOption.nudgeOrthogonalSegmentsConnectedToShapes, !1), i.setRoutingOption(s.RoutingOption.nudgeSharedPathsWithCommonEndPoint, !0);
26
- const e = new Map(
27
- n.nodes.filter((t) => !y.has(t.id) && p(t.id).every((o) => y.has(o))).map((t) => {
28
- const o = new s.Point(t.x, t.y), g = new s.Point(t.x + t.width, t.y + t.height), a = new s.Rectangle(o, g), h = new s.ShapeRef(i, a);
29
- return O(o), O(g), O(a), [t.id, h];
28
+ s.setRoutingParameter(i.RoutingParameter.shapeBufferDistance, a), s.setRoutingParameter(i.RoutingParameter.idealNudgingDistance, 8), s.setRoutingParameter(i.RoutingParameter.crossingPenalty, 80), s.setRoutingParameter(i.RoutingParameter.fixedSharedPathPenalty, 120), s.setRoutingParameter(i.RoutingParameter.portDirectionPenalty, 0), s.setRoutingOption(i.RoutingOption.nudgeOrthogonalSegmentsConnectedToShapes, !1), s.setRoutingOption(i.RoutingOption.nudgeSharedPathsWithCommonEndPoint, !0);
29
+ const M = new Map(
30
+ n.nodes.filter((t) => !r.has(t.id) && l(t.id).every((e) => r.has(e))).map((t) => {
31
+ const e = new i.Point(t.x, t.y), g = new i.Point(t.x + t.width, t.y + t.height), p = new i.Rectangle(e, g), x = new i.ShapeRef(s, p);
32
+ return S(e), S(g), S(p), [t.id, x];
30
33
  })
31
- ), c = /* @__PURE__ */ new Map(), S = n.nodes.filter((t) => e.has(t.id)), E = /* @__PURE__ */ new Map();
32
- m.forEach((t) => {
33
- const o = r.get(t.source), g = r.get(t.target), a = Y(o, g), h = t.sourcePort ? o.ports.find((P) => P.id === t.sourcePort).side : t.targetPort ? B(g.ports.find((P) => P.id === t.targetPort).side) : a.source, u = t.targetPort ? g.ports.find((P) => P.id === t.targetPort).side : t.sourcePort ? B(o.ports.find((P) => P.id === t.sourcePort).side) : a.target, d = [t.source, t.target].sort().join("\0"), f = E.get(d) ?? 0;
34
- E.set(d, f + 1);
35
- const M = f % 2 === 0 ? -6 : 6, R = t.source === t.target ? void 0 : X(
36
- o,
37
- g,
38
- S,
39
- a,
40
- M,
41
- t.sourcePort ? h : void 0,
42
- t.targetPort ? u : void 0
43
- );
44
- c.set(t.id, {
45
- sourceSide: R?.source ?? h,
46
- targetSide: R?.target ?? u,
47
- offset: M
48
- });
49
- });
50
- let l = N.length + 2;
51
- const A = /* @__PURE__ */ new Map(), C = (t, o) => Math.max(0, Math.min(1, t / o));
34
+ ), O = /* @__PURE__ */ new Map(), E = /* @__PURE__ */ new Map();
35
+ for (const t of c) {
36
+ const e = [t.source, t.target].sort().join("\0"), g = O.get(e) ?? 0;
37
+ O.set(e, g + 1), E.set(t.id, g % 2 === 0 ? -6 : 6);
38
+ }
39
+ let Q = A.length + 2;
40
+ const B = /* @__PURE__ */ new Map(), b = (t, e) => Math.max(0, Math.min(1, t / e));
52
41
  for (const t of n.nodes) {
53
- const o = e.get(t.id);
54
- if (!o) continue;
55
- const g = (a, h, u, d, f) => {
56
- const M = new s.ShapeConnectionPin(
57
- o,
58
- a,
59
- C(h, t.width),
60
- C(u, t.height),
42
+ const e = M.get(t.id);
43
+ if (!e) continue;
44
+ const g = (p, x, w, y, m) => {
45
+ const N = new i.ShapeConnectionPin(
46
+ e,
47
+ p,
48
+ b(x, t.width),
49
+ b(w, t.height),
61
50
  !0,
62
51
  0,
63
- d
52
+ y
64
53
  );
65
- M.setExclusive(f), M.setConnectionCost(
66
- t.width / 2 + t.height / 2 - Math.abs(h - t.width / 2) - Math.abs(u - t.height / 2)
54
+ N.setExclusive(m), N.setConnectionCost(
55
+ t.width / 2 + t.height / 2 - Math.abs(x - t.width / 2) - Math.abs(w - t.height / 2)
67
56
  );
68
57
  };
69
- for (const a of new Set(t.ports?.map((h) => h.side))) {
70
- const { x: h, y: u } = U(t, a), d = N.indexOf(a) + 2;
71
- g(d, h - t.x, u - t.y, j[a], !1), A.set(
58
+ for (const p of new Set(t.ports?.map((x) => x.side))) {
59
+ const { x, y: w } = q(t, p), y = A.indexOf(p) + 2;
60
+ g(y, x - t.x, w - t.y, L[p], !1), B.set(
72
61
  JSON.stringify([
73
62
  t.id,
74
- C(h - t.x, t.width),
75
- C(u - t.y, t.height),
76
- a
63
+ b(x - t.x, t.width),
64
+ b(w - t.y, t.height),
65
+ p
77
66
  ]),
78
- d
67
+ y
79
68
  );
80
69
  }
81
70
  }
82
- const H = (t, o, g, a) => {
83
- const h = r.get(t), u = e.get(t);
84
- if (u && o)
85
- return new s.ConnEnd(
86
- u,
87
- N.indexOf(h.ports.find((R) => R.id === o).side) + 2
71
+ const F = /* @__PURE__ */ new Map(), Z = n.nodes.filter((t) => M.has(t.id)), J = (t, e, g, p, x, w = !1) => {
72
+ const y = M.get(t.id);
73
+ if (y && g)
74
+ return new i.ConnEnd(
75
+ y,
76
+ A.indexOf(t.ports.find((d) => d.id === g).side) + 2
88
77
  );
89
- if (u) {
90
- const R = C(g.x - h.x, h.width), P = C(g.y - h.y, h.height), b = JSON.stringify([t, R, P, a]), D = A.get(b);
91
- if (D !== void 0) return new s.ConnEnd(u, D);
92
- const k = l++;
93
- return A.set(b, k), new s.ShapeConnectionPin(
94
- u,
95
- k,
96
- R,
97
- P,
98
- !0,
99
- 0,
100
- j[a]
101
- ).setExclusive(!1), new s.ConnEnd(u, k);
78
+ const m = g ? [
79
+ {
80
+ side: t.ports.find((d) => d.id === g).side,
81
+ position: q(t, t.ports.find((d) => d.id === g).side)
82
+ }
83
+ ] : x ? [{ side: "EAST", position: x }] : (w ? [K(t, e).source] : A).flatMap((d) => {
84
+ const P = nt(t, d, e, p);
85
+ if (w) return [{ side: d, position: P }];
86
+ const R = d === "NORTH" || d === "SOUTH", H = R ? t.x : t.y, v = R ? t.width : t.height, C = H + Math.min(8, v / 4), j = H + v - Math.min(8, v / 4);
87
+ return [
88
+ R ? P.x : P.y,
89
+ C,
90
+ j,
91
+ ...Z.flatMap((u) => {
92
+ const k = R ? u.x : u.y, X = k + (R ? u.width : u.height);
93
+ return [k - a, X + a, k - a - 8, X + a + 8];
94
+ }).filter((u) => u >= C && u <= j)
95
+ ].map((u) => ({
96
+ side: d,
97
+ position: R ? { x: u, y: P.y } : { x: P.x, y: u }
98
+ }));
99
+ });
100
+ if (y) {
101
+ const d = (v, C) => JSON.stringify([
102
+ t.id,
103
+ b(C.x - t.x, t.width),
104
+ b(C.y - t.y, t.height),
105
+ v
106
+ ]), P = !!(g || x || w), R = P ? B.get(d(m[0].side, m[0].position)) : F.get(t.id);
107
+ if (P && R !== void 0) return new i.ConnEnd(y, R);
108
+ const H = R ?? Q++;
109
+ P || F.set(t.id, H);
110
+ for (const { side: v, position: C } of m) {
111
+ const j = d(v, C);
112
+ if (B.has(j)) continue;
113
+ B.set(j, H);
114
+ const D = C.x - t.x, u = C.y - t.y, k = new i.ShapeConnectionPin(
115
+ y,
116
+ H,
117
+ b(D, t.width),
118
+ b(u, t.height),
119
+ !0,
120
+ 0,
121
+ L[v]
122
+ );
123
+ k.setExclusive(!1), k.setConnectionCost(
124
+ t.width / 2 + t.height / 2 - Math.abs(D - t.width / 2) - Math.abs(u - t.height / 2)
125
+ );
126
+ }
127
+ return new i.ConnEnd(y, H);
102
128
  }
103
- const d = o ? U(h, h.ports.find((R) => R.id === o).side) : g, f = new s.Point(d.x, d.y), M = new s.ConnEnd(f);
104
- return O(f), M;
105
- }, v = m.map((t) => {
106
- const o = r.get(t.source), g = r.get(t.target), a = c.get(t.id), h = H(
107
- t.source,
129
+ const N = K(t, e).source, G = m.find((d) => d.side === N)?.position ?? m[0].position, W = new i.Point(G.x, G.y), z = new i.ConnEnd(W);
130
+ return S(W), z;
131
+ }, V = (t) => +!!(t.sourcePort || t.targetPort || t.source === t.target || O.get([t.source, t.target].sort().join("\0")) > 1), I = [...c].sort((t, e) => V(e) - V(t)).map((t) => {
132
+ const e = h.get(t.source), g = h.get(t.target), p = t.source === t.target, x = O.get([t.source, t.target].sort().join("\0")) > 1, w = J(
133
+ e,
134
+ g,
108
135
  t.sourcePort,
109
- t.source === t.target ? { x: o.x + o.width, y: o.y + o.height / 3 } : W(o, a.sourceSide, g, a.offset),
110
- t.source === t.target ? "EAST" : a.sourceSide
111
- ), u = H(
112
- t.target,
136
+ E.get(t.id),
137
+ p ? { x: e.x + e.width, y: e.y + e.height / 3 } : void 0,
138
+ x
139
+ ), y = J(
140
+ g,
141
+ e,
113
142
  t.targetPort,
114
- t.source === t.target ? {
143
+ E.get(t.id),
144
+ p ? {
115
145
  x: g.x + g.width,
116
146
  y: g.y + g.height * 2 / 3
117
- } : W(g, a.targetSide, o, a.offset),
118
- t.source === t.target ? "EAST" : a.targetSide
119
- ), d = new s.ConnRef(i, h, u);
120
- if (O(h), O(u), t.source === t.target) {
121
- const f = r.get(t.source), M = new s.CheckpointVector();
122
- for (const R of [f.y + f.height / 3, f.y + f.height * 2 / 3]) {
123
- const P = new s.Point(f.x + f.width + 24, R), b = new s.Checkpoint(P);
124
- M.push_back(b), O(P), O(b);
147
+ } : void 0,
148
+ x
149
+ ), m = new i.ConnRef(s, w, y);
150
+ if (S(w), S(y), p) {
151
+ const N = new i.CheckpointVector();
152
+ for (const G of [
153
+ e.y + e.height / 3,
154
+ e.y + e.height * 2 / 3
155
+ ]) {
156
+ const W = new i.Point(
157
+ e.x + e.width + Math.max(24, a + 4),
158
+ G
159
+ ), z = new i.Checkpoint(W);
160
+ N.push_back(z), S(W), S(z);
125
161
  }
126
- d.setRoutingCheckpoints(M), O(M);
162
+ m.setRoutingCheckpoints(N), S(N);
127
163
  }
128
- return { edge: t, connection: d };
164
+ return { edge: t, connection: m };
129
165
  });
130
- i.processTransaction();
131
- for (const { edge: t, connection: o } of v) {
132
- const g = o.displayRoute(), a = Array.from({ length: g.size() }, (h, u) => {
133
- const d = g.at(u), f = { x: d.x, y: d.y };
134
- return O(d), f;
166
+ s.processTransaction();
167
+ for (const { edge: t, connection: e } of I) {
168
+ const g = e.displayRoute(), p = Array.from({ length: g.size() }, (x, w) => {
169
+ const y = g.at(w), m = { x: y.x, y: y.y };
170
+ return S(y), m;
135
171
  });
136
- if (O(g), !o.hasValidRoute() || a.length < 2 || a.some((h) => !Number.isFinite(h.x) || !Number.isFinite(h.y)) || a.some((h, u) => u > 0 && h.x !== a[u - 1].x && h.y !== a[u - 1].y))
172
+ if (S(g), !e.hasValidRoute() || p.length < 2 || p.some((x) => !Number.isFinite(x.x) || !Number.isFinite(x.y)) || p.some((x, w) => w > 0 && x.x !== p[w - 1].x && x.y !== p[w - 1].y))
137
173
  throw new Error(`Graph edge cannot be routed: ${t.id}`);
138
- T.set(t.id, a);
174
+ T.set(t.id, p);
139
175
  }
140
176
  } finally {
141
- i.delete();
177
+ s.delete();
142
178
  }
143
179
  }
144
- const w = n.edges.map((y) => ({ ...y, sections: [T.get(y.id)] }));
145
- return F({
180
+ const U = n.edges.map((r) => ({ ...r, sections: [T.get(r.id)] }));
181
+ return $({
146
182
  nodes: n.nodes,
147
- edges: w,
183
+ edges: U,
148
184
  bounds: n.bounds
149
185
  });
150
186
  }
151
- function F(n) {
152
- const s = [
153
- ...n.nodes.flatMap((x) => [
154
- { x: x.x, y: x.y },
155
- { x: x.x + x.width, y: x.y + x.height }
187
+ function $(n) {
188
+ const o = [
189
+ ...n.nodes.flatMap((h) => [
190
+ { x: h.x, y: h.y },
191
+ { x: h.x + h.width, y: h.y + h.height }
156
192
  ]),
157
- ...n.edges.flatMap((x) => x.sections.flat())
158
- ], r = Math.min(...s.map((x) => x.x)), p = Math.min(...s.map((x) => x.y));
193
+ ...n.edges.flatMap((h) => h.sections.flat())
194
+ ], a = Math.min(...o.map((h) => h.x)), i = Math.min(...o.map((h) => h.y));
159
195
  return {
160
196
  nodes: n.nodes,
161
197
  edges: n.edges,
162
198
  bounds: {
163
- x: r,
164
- y: p,
165
- width: Math.max(...s.map((x) => x.x)) - r,
166
- height: Math.max(...s.map((x) => x.y)) - p
199
+ x: a,
200
+ y: i,
201
+ width: Math.max(...o.map((h) => h.x)) - a,
202
+ height: Math.max(...o.map((h) => h.y)) - i
167
203
  }
168
204
  };
169
205
  }
170
- function U(n, s) {
206
+ function q(n, o) {
171
207
  return {
172
- x: s === "WEST" ? n.x : s === "EAST" ? n.x + n.width : n.x + n.width / 2,
173
- y: s === "NORTH" ? n.y : s === "SOUTH" ? n.y + n.height : n.y + n.height / 2
208
+ x: o === "WEST" ? n.x : o === "EAST" ? n.x + n.width : n.x + n.width / 2,
209
+ y: o === "NORTH" ? n.y : o === "SOUTH" ? n.y + n.height : n.y + n.height / 2
174
210
  };
175
211
  }
176
- function B(n) {
177
- return {
178
- NORTH: "SOUTH",
179
- EAST: "WEST",
180
- SOUTH: "NORTH",
181
- WEST: "EAST"
182
- }[n];
183
- }
184
- function X(n, s, r, p, x, T, w) {
185
- let y;
186
- const m = (i, e, c) => c === "NORTH" ? e.x === i.x && e.y < i.y : c === "SOUTH" ? e.x === i.x && e.y > i.y : c === "WEST" ? e.y === i.y && e.x < i.x : e.y === i.y && e.x > i.x;
187
- for (const i of T ? [T] : N)
188
- for (const e of w ? [w] : N) {
189
- const c = T ? U(n, i) : W(n, i, s, x), S = w ? U(s, e) : W(s, e, n, x), E = c.x === S.x || c.y === S.y ? [[c, S]] : [
190
- [c, { x: S.x, y: c.y }, S],
191
- [c, { x: c.x, y: S.y }, S]
192
- ];
193
- for (const l of E) {
194
- if (r.includes(n) && !m(c, l[1], i) || r.includes(s) && !m(S, l.at(-2), e) || l.slice(1).some((H, v) => {
195
- const t = l[v];
196
- return r.some(
197
- (o) => Math.max(t.x, H.x) > o.x && Math.min(t.x, H.x) < o.x + o.width && Math.max(t.y, H.y) > o.y && Math.min(t.y, H.y) < o.y + o.height
198
- );
199
- }))
200
- continue;
201
- const C = l.slice(1).reduce(
202
- (H, v, t) => H + Math.abs(v.x - l[t].x) + Math.abs(v.y - l[t].y),
203
- 0
204
- ) + (l.length - 2) * 32 + (i === p.source ? 0 : 16) + (e === p.target ? 0 : 16);
205
- (!y || C < y.score) && (y = { source: i, target: e, score: C });
206
- }
207
- }
208
- return y;
209
- }
210
- function Y(n, s) {
211
- const r = (e, c) => c.x >= e.x && c.y >= e.y && c.x + c.width <= e.x + e.width && c.y + c.height <= e.y + e.height, p = r(n, s) ? n : r(s, n) ? s : void 0;
212
- if (p) {
213
- const e = p === n ? s : n, c = {
214
- NORTH: e.y - p.y,
215
- EAST: p.x + p.width - e.x - e.width,
216
- SOUTH: p.y + p.height - e.y - e.height,
217
- WEST: e.x - p.x
218
- }, S = [...N].sort((E, l) => c[E] - c[l])[0];
219
- return { source: S, target: S };
212
+ function K(n, o) {
213
+ const a = (c, s) => s.x >= c.x && s.y >= c.y && s.x + s.width <= c.x + c.width && s.y + s.height <= c.y + c.height, i = a(n, o) ? n : a(o, n) ? o : void 0;
214
+ if (i) {
215
+ const c = i === n ? o : n, s = {
216
+ NORTH: c.y - i.y,
217
+ EAST: i.x + i.width - c.x - c.width,
218
+ SOUTH: i.y + i.height - c.y - c.height,
219
+ WEST: c.x - i.x
220
+ }, M = [...A].sort((O, E) => s[O] - s[E])[0];
221
+ return { source: M, target: M };
220
222
  }
221
- const x = s.x + s.width / 2 - (n.x + n.width / 2), T = s.y + s.height / 2 - (n.y + n.height / 2), w = Math.max(n.x - (s.x + s.width), s.x - (n.x + n.width), 0), y = Math.max(
222
- n.y - (s.y + s.height),
223
- s.y - (n.y + n.height),
223
+ const h = o.x + o.width / 2 - (n.x + n.width / 2), l = o.y + o.height / 2 - (n.y + n.height / 2), f = Math.max(n.x - (o.x + o.width), o.x - (n.x + n.width), 0), T = Math.max(
224
+ n.y - (o.y + o.height),
225
+ o.y - (n.y + n.height),
224
226
  0
225
- ), i = (y === 0 && w > 0 ? !0 : w === 0 && y > 0 ? !1 : w === 0 && y === 0 ? Math.abs(x) >= Math.abs(T) : w <= y) ? x >= 0 ? "EAST" : "WEST" : T >= 0 ? "SOUTH" : "NORTH";
226
- return { source: i, target: B(i) };
227
+ ), r = (T === 0 && f > 0 ? !0 : f === 0 && T > 0 ? !1 : f === 0 && T === 0 ? Math.abs(h) >= Math.abs(l) : f <= T) ? h >= 0 ? "EAST" : "WEST" : l >= 0 ? "SOUTH" : "NORTH";
228
+ return { source: r, target: A[(A.indexOf(r) + 2) % 4] };
227
229
  }
228
- function W(n, s, r, p = 0) {
229
- const x = (i) => Math.min(8, i / 4), T = (i, e, c) => Math.max(e + x(c), Math.min(e + c - x(c), i)), w = (i, e, c, S) => {
230
- const E = Math.max(i, c), l = Math.min(i + e, c + S);
231
- return E < l ? (E + l) / 2 + p : void 0;
232
- }, y = r.x + r.width / 2, m = r.y + r.height / 2;
233
- switch (s) {
230
+ function nt(n, o, a, i = 0) {
231
+ const h = (r) => Math.min(8, r / 4), l = (r, c, s) => Math.max(c + h(s), Math.min(c + s - h(s), r)), f = (r, c, s, M) => {
232
+ const O = Math.max(r, s), E = Math.min(r + c, s + M);
233
+ return O < E ? (O + E) / 2 + i : void 0;
234
+ }, T = a.x + a.width / 2, U = a.y + a.height / 2;
235
+ switch (o) {
234
236
  case "NORTH":
235
237
  return {
236
- x: T(
237
- w(n.x, n.width, r.x, r.width) ?? y + p,
238
+ x: l(
239
+ f(n.x, n.width, a.x, a.width) ?? T + i,
238
240
  n.x,
239
241
  n.width
240
242
  ),
@@ -243,16 +245,16 @@ function W(n, s, r, p = 0) {
243
245
  case "EAST":
244
246
  return {
245
247
  x: n.x + n.width,
246
- y: T(
247
- w(n.y, n.height, r.y, r.height) ?? m + p,
248
+ y: l(
249
+ f(n.y, n.height, a.y, a.height) ?? U + i,
248
250
  n.y,
249
251
  n.height
250
252
  )
251
253
  };
252
254
  case "SOUTH":
253
255
  return {
254
- x: T(
255
- w(n.x, n.width, r.x, r.width) ?? y + p,
256
+ x: l(
257
+ f(n.x, n.width, a.x, a.width) ?? T + i,
256
258
  n.x,
257
259
  n.width
258
260
  ),
@@ -261,8 +263,8 @@ function W(n, s, r, p = 0) {
261
263
  case "WEST":
262
264
  return {
263
265
  x: n.x,
264
- y: T(
265
- w(n.y, n.height, r.y, r.height) ?? m + p,
266
+ y: l(
267
+ f(n.y, n.height, a.y, a.height) ?? U + i,
266
268
  n.y,
267
269
  n.height
268
270
  )
@@ -270,5 +272,5 @@ function W(n, s, r, p = 0) {
270
272
  }
271
273
  }
272
274
  export {
273
- $ as routeGraphGeometry
275
+ et as routeGraphGeometry
274
276
  };
@@ -46,6 +46,8 @@ export interface GraphLayout {
46
46
  bounds: GraphBounds;
47
47
  }
48
48
  export interface GraphLayoutOptions {
49
+ /** Clearance around routing obstacles in world units. Defaults to 4; never changes node geometry. */
50
+ edgeClearance?: number;
49
51
  /** Desired width/height when packing disconnected objects, including group members. */
50
52
  aspectRatio?: number;
51
53
  /** Absolute world positions. Descendants move with their group. Invalid positions always fail. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floegence/floe-webapp-core",
3
- "version": "0.86.11",
3
+ "version": "0.86.13",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",