@floegence/floe-webapp-core 0.86.11 → 0.86.12

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,274 +1,277 @@
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) {
6
- 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;
1
+ import { AvoidLib as J } from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/index.js";
2
+ import Y from "../../node_modules/.pnpm/libavoid-js@0.5.0-beta.5/node_modules/libavoid-js/dist/libavoid.wasm.js";
3
+ let j;
4
+ const V = { NORTH: 1, SOUTH: 2, WEST: 4, EAST: 8 }, b = ["NORTH", "EAST", "SOUTH", "WEST"], E = (t) => t.delete();
5
+ async function I(t, c = {}) {
6
+ const p = c.edgeClearance ?? 4;
7
+ if (!Number.isFinite(p) || p < 0)
8
+ throw new Error("Graph edge clearance must be finite and nonnegative");
9
+ if (!t.nodes.length) return t;
10
+ if (!t.edges.length) return X(t);
11
+ await (j ??= J.load(Y).catch((o) => {
12
+ throw j = void 0, o;
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 s = J.getInstance(), r = new Map(t.nodes.map((o) => [o.id, o])), m = (o) => {
15
+ const e = [];
16
+ for (let i = r.get(o).parentId; i; i = r.get(i).parentId)
17
+ e.push(i);
18
+ return e;
19
+ }, d = /* @__PURE__ */ new Map();
20
+ for (const o of t.edges) {
21
+ const e = /* @__PURE__ */ new Set([...m(o.source), ...m(o.target)]), i = JSON.stringify([...e].sort()), u = d.get(i) ?? { open: e, edges: [] };
22
+ u.edges.push(o), d.set(i, u);
20
23
  }
21
- const T = /* @__PURE__ */ new Map();
22
- for (const { open: y, edges: m } of x.values()) {
24
+ const S = /* @__PURE__ */ new Map();
25
+ for (const { open: o, edges: e } of d.values()) {
23
26
  const i = new s.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
+ i.setRoutingParameter(s.RoutingParameter.shapeBufferDistance, p), 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);
29
+ const u = new Map(
30
+ t.nodes.filter((n) => !o.has(n.id) && m(n.id).every((x) => o.has(x))).map((n) => {
31
+ const x = new s.Point(n.x, n.y), y = new s.Point(n.x + n.width, n.y + n.height), a = new s.Rectangle(x, y), h = new s.ShapeRef(i, a);
32
+ return E(x), E(y), E(a), [n.id, h];
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,
34
+ ), v = /* @__PURE__ */ new Map(), l = t.nodes.filter((n) => u.has(n.id)), G = /* @__PURE__ */ new Map();
35
+ e.forEach((n) => {
36
+ const x = r.get(n.source), y = r.get(n.target), a = z(x, y), h = n.sourcePort ? x.ports.find((T) => T.id === n.sourcePort).side : n.targetPort ? D(y.ports.find((T) => T.id === n.targetPort).side) : a.source, g = n.targetPort ? y.ports.find((T) => T.id === n.targetPort).side : n.sourcePort ? D(x.ports.find((T) => T.id === n.sourcePort).side) : a.target, f = [n.source, n.target].sort().join("\0"), w = G.get(f) ?? 0;
37
+ G.set(f, w + 1);
38
+ const M = w % 2 === 0 ? -6 : 6, R = n.source === n.target ? void 0 : _(
39
+ x,
40
+ y,
41
+ l,
39
42
  a,
40
43
  M,
41
- t.sourcePort ? h : void 0,
42
- t.targetPort ? u : void 0
44
+ n.sourcePort ? h : void 0,
45
+ n.targetPort ? g : void 0
43
46
  );
44
- c.set(t.id, {
47
+ v.set(n.id, {
45
48
  sourceSide: R?.source ?? h,
46
- targetSide: R?.target ?? u,
49
+ targetSide: R?.target ?? g,
47
50
  offset: M
48
51
  });
49
52
  });
50
- let l = N.length + 2;
51
- const A = /* @__PURE__ */ new Map(), C = (t, o) => Math.max(0, Math.min(1, t / o));
52
- 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) => {
53
+ let U = b.length + 2;
54
+ const O = /* @__PURE__ */ new Map(), P = (n, x) => Math.max(0, Math.min(1, n / x));
55
+ for (const n of t.nodes) {
56
+ const x = u.get(n.id);
57
+ if (!x) continue;
58
+ const y = (a, h, g, f, w) => {
56
59
  const M = new s.ShapeConnectionPin(
57
- o,
60
+ x,
58
61
  a,
59
- C(h, t.width),
60
- C(u, t.height),
62
+ P(h, n.width),
63
+ P(g, n.height),
61
64
  !0,
62
65
  0,
63
- d
66
+ f
64
67
  );
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)
68
+ M.setExclusive(w), M.setConnectionCost(
69
+ n.width / 2 + n.height / 2 - Math.abs(h - n.width / 2) - Math.abs(g - n.height / 2)
67
70
  );
68
71
  };
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(
72
+ for (const a of new Set(n.ports?.map((h) => h.side))) {
73
+ const { x: h, y: g } = W(n, a), f = b.indexOf(a) + 2;
74
+ y(f, h - n.x, g - n.y, V[a], !1), O.set(
72
75
  JSON.stringify([
73
- t.id,
74
- C(h - t.x, t.width),
75
- C(u - t.y, t.height),
76
+ n.id,
77
+ P(h - n.x, n.width),
78
+ P(g - n.y, n.height),
76
79
  a
77
80
  ]),
78
- d
81
+ f
79
82
  );
80
83
  }
81
84
  }
82
- const H = (t, o, g, a) => {
83
- const h = r.get(t), u = e.get(t);
84
- if (u && o)
85
+ const C = (n, x, y, a) => {
86
+ const h = r.get(n), g = u.get(n);
87
+ if (g && x)
85
88
  return new s.ConnEnd(
86
- u,
87
- N.indexOf(h.ports.find((R) => R.id === o).side) + 2
89
+ g,
90
+ b.indexOf(h.ports.find((R) => R.id === x).side) + 2
88
91
  );
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,
92
+ if (g) {
93
+ const R = P(y.x - h.x, h.width), T = P(y.y - h.y, h.height), A = JSON.stringify([n, R, T, a]), F = O.get(A);
94
+ if (F !== void 0) return new s.ConnEnd(g, F);
95
+ const B = U++;
96
+ return O.set(A, B), new s.ShapeConnectionPin(
97
+ g,
98
+ B,
96
99
  R,
97
- P,
100
+ T,
98
101
  !0,
99
102
  0,
100
- j[a]
101
- ).setExclusive(!1), new s.ConnEnd(u, k);
103
+ V[a]
104
+ ).setExclusive(!1), new s.ConnEnd(g, B);
102
105
  }
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,
108
- 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,
113
- t.targetPort,
114
- t.source === t.target ? {
115
- x: g.x + g.width,
116
- 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);
106
+ const f = x ? W(h, h.ports.find((R) => R.id === x).side) : y, w = new s.Point(f.x, f.y), M = new s.ConnEnd(w);
107
+ return E(w), M;
108
+ }, N = e.map((n) => {
109
+ const x = r.get(n.source), y = r.get(n.target), a = v.get(n.id), h = C(
110
+ n.source,
111
+ n.sourcePort,
112
+ n.source === n.target ? { x: x.x + x.width, y: x.y + x.height / 3 } : k(x, a.sourceSide, y, a.offset),
113
+ n.source === n.target ? "EAST" : a.sourceSide
114
+ ), g = C(
115
+ n.target,
116
+ n.targetPort,
117
+ n.source === n.target ? {
118
+ x: y.x + y.width,
119
+ y: y.y + y.height * 2 / 3
120
+ } : k(y, a.targetSide, x, a.offset),
121
+ n.source === n.target ? "EAST" : a.targetSide
122
+ ), f = new s.ConnRef(i, h, g);
123
+ if (E(h), E(g), n.source === n.target) {
124
+ const w = r.get(n.source), M = new s.CheckpointVector();
125
+ for (const R of [w.y + w.height / 3, w.y + w.height * 2 / 3]) {
126
+ const T = new s.Point(w.x + w.width + Math.max(24, p + 4), R), A = new s.Checkpoint(T);
127
+ M.push_back(A), E(T), E(A);
125
128
  }
126
- d.setRoutingCheckpoints(M), O(M);
129
+ f.setRoutingCheckpoints(M), E(M);
127
130
  }
128
- return { edge: t, connection: d };
131
+ return { edge: n, connection: f };
129
132
  });
130
133
  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;
134
+ for (const { edge: n, connection: x } of N) {
135
+ const y = x.displayRoute(), a = Array.from({ length: y.size() }, (h, g) => {
136
+ const f = y.at(g), w = { x: f.x, y: f.y };
137
+ return E(f), w;
135
138
  });
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))
137
- throw new Error(`Graph edge cannot be routed: ${t.id}`);
138
- T.set(t.id, a);
139
+ if (E(y), !x.hasValidRoute() || a.length < 2 || a.some((h) => !Number.isFinite(h.x) || !Number.isFinite(h.y)) || a.some((h, g) => g > 0 && h.x !== a[g - 1].x && h.y !== a[g - 1].y))
140
+ throw new Error(`Graph edge cannot be routed: ${n.id}`);
141
+ S.set(n.id, a);
139
142
  }
140
143
  } finally {
141
144
  i.delete();
142
145
  }
143
146
  }
144
- const w = n.edges.map((y) => ({ ...y, sections: [T.get(y.id)] }));
145
- return F({
146
- nodes: n.nodes,
147
- edges: w,
148
- bounds: n.bounds
147
+ const H = t.edges.map((o) => ({ ...o, sections: [S.get(o.id)] }));
148
+ return X({
149
+ nodes: t.nodes,
150
+ edges: H,
151
+ bounds: t.bounds
149
152
  });
150
153
  }
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 }
154
+ function X(t) {
155
+ const c = [
156
+ ...t.nodes.flatMap((r) => [
157
+ { x: r.x, y: r.y },
158
+ { x: r.x + r.width, y: r.y + r.height }
156
159
  ]),
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));
160
+ ...t.edges.flatMap((r) => r.sections.flat())
161
+ ], p = Math.min(...c.map((r) => r.x)), s = Math.min(...c.map((r) => r.y));
159
162
  return {
160
- nodes: n.nodes,
161
- edges: n.edges,
163
+ nodes: t.nodes,
164
+ edges: t.edges,
162
165
  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
166
+ x: p,
167
+ y: s,
168
+ width: Math.max(...c.map((r) => r.x)) - p,
169
+ height: Math.max(...c.map((r) => r.y)) - s
167
170
  }
168
171
  };
169
172
  }
170
- function U(n, s) {
173
+ function W(t, c) {
171
174
  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
175
+ x: c === "WEST" ? t.x : c === "EAST" ? t.x + t.width : t.x + t.width / 2,
176
+ y: c === "NORTH" ? t.y : c === "SOUTH" ? t.y + t.height : t.y + t.height / 2
174
177
  };
175
178
  }
176
- function B(n) {
179
+ function D(t) {
177
180
  return {
178
181
  NORTH: "SOUTH",
179
182
  EAST: "WEST",
180
183
  SOUTH: "NORTH",
181
184
  WEST: "EAST"
182
- }[n];
185
+ }[t];
183
186
  }
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]
187
+ function _(t, c, p, s, r, m, d) {
188
+ let S;
189
+ const H = (o, e, i) => i === "NORTH" ? e.x === o.x && e.y < o.y : i === "SOUTH" ? e.x === o.x && e.y > o.y : i === "WEST" ? e.y === o.y && e.x < o.x : e.y === o.y && e.x > o.x;
190
+ for (const o of m ? [m] : b)
191
+ for (const e of d ? [d] : b) {
192
+ const i = m ? W(t, o) : k(t, o, c, r), u = d ? W(c, e) : k(c, e, t, r), v = i.x === u.x || i.y === u.y ? [[i, u]] : [
193
+ [i, { x: u.x, y: i.y }, u],
194
+ [i, { x: i.x, y: u.y }, u]
192
195
  ];
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
196
+ for (const l of v) {
197
+ if (p.includes(t) && !H(i, l[1], o) || p.includes(c) && !H(u, l.at(-2), e) || l.slice(1).some((O, P) => {
198
+ const C = l[P];
199
+ return p.some(
200
+ (N) => Math.max(C.x, O.x) > N.x && Math.min(C.x, O.x) < N.x + N.width && Math.max(C.y, O.y) > N.y && Math.min(C.y, O.y) < N.y + N.height
198
201
  );
199
202
  }))
200
203
  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),
204
+ const U = l.slice(1).reduce(
205
+ (O, P, C) => O + Math.abs(P.x - l[C].x) + Math.abs(P.y - l[C].y),
203
206
  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 });
207
+ ) + (l.length - 2) * 32 + (o === s.source ? 0 : 16) + (e === s.target ? 0 : 16);
208
+ (!S || U < S.score) && (S = { source: o, target: e, score: U });
206
209
  }
207
210
  }
208
- return y;
211
+ return S;
209
212
  }
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 };
213
+ function z(t, c) {
214
+ const p = (e, i) => i.x >= e.x && i.y >= e.y && i.x + i.width <= e.x + e.width && i.y + i.height <= e.y + e.height, s = p(t, c) ? t : p(c, t) ? c : void 0;
215
+ if (s) {
216
+ const e = s === t ? c : t, i = {
217
+ NORTH: e.y - s.y,
218
+ EAST: s.x + s.width - e.x - e.width,
219
+ SOUTH: s.y + s.height - e.y - e.height,
220
+ WEST: e.x - s.x
221
+ }, u = [...b].sort((v, l) => i[v] - i[l])[0];
222
+ return { source: u, target: u };
220
223
  }
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),
224
+ const r = c.x + c.width / 2 - (t.x + t.width / 2), m = c.y + c.height / 2 - (t.y + t.height / 2), d = Math.max(t.x - (c.x + c.width), c.x - (t.x + t.width), 0), S = Math.max(
225
+ t.y - (c.y + c.height),
226
+ c.y - (t.y + t.height),
224
227
  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) };
228
+ ), o = (S === 0 && d > 0 ? !0 : d === 0 && S > 0 ? !1 : d === 0 && S === 0 ? Math.abs(r) >= Math.abs(m) : d <= S) ? r >= 0 ? "EAST" : "WEST" : m >= 0 ? "SOUTH" : "NORTH";
229
+ return { source: o, target: D(o) };
227
230
  }
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) {
231
+ function k(t, c, p, s = 0) {
232
+ const r = (o) => Math.min(8, o / 4), m = (o, e, i) => Math.max(e + r(i), Math.min(e + i - r(i), o)), d = (o, e, i, u) => {
233
+ const v = Math.max(o, i), l = Math.min(o + e, i + u);
234
+ return v < l ? (v + l) / 2 + s : void 0;
235
+ }, S = p.x + p.width / 2, H = p.y + p.height / 2;
236
+ switch (c) {
234
237
  case "NORTH":
235
238
  return {
236
- x: T(
237
- w(n.x, n.width, r.x, r.width) ?? y + p,
238
- n.x,
239
- n.width
239
+ x: m(
240
+ d(t.x, t.width, p.x, p.width) ?? S + s,
241
+ t.x,
242
+ t.width
240
243
  ),
241
- y: n.y
244
+ y: t.y
242
245
  };
243
246
  case "EAST":
244
247
  return {
245
- x: n.x + n.width,
246
- y: T(
247
- w(n.y, n.height, r.y, r.height) ?? m + p,
248
- n.y,
249
- n.height
248
+ x: t.x + t.width,
249
+ y: m(
250
+ d(t.y, t.height, p.y, p.height) ?? H + s,
251
+ t.y,
252
+ t.height
250
253
  )
251
254
  };
252
255
  case "SOUTH":
253
256
  return {
254
- x: T(
255
- w(n.x, n.width, r.x, r.width) ?? y + p,
256
- n.x,
257
- n.width
257
+ x: m(
258
+ d(t.x, t.width, p.x, p.width) ?? S + s,
259
+ t.x,
260
+ t.width
258
261
  ),
259
- y: n.y + n.height
262
+ y: t.y + t.height
260
263
  };
261
264
  case "WEST":
262
265
  return {
263
- x: n.x,
264
- y: T(
265
- w(n.y, n.height, r.y, r.height) ?? m + p,
266
- n.y,
267
- n.height
266
+ x: t.x,
267
+ y: m(
268
+ d(t.y, t.height, p.y, p.height) ?? H + s,
269
+ t.y,
270
+ t.height
268
271
  )
269
272
  };
270
273
  }
271
274
  }
272
275
  export {
273
- $ as routeGraphGeometry
276
+ I as routeGraphGeometry
274
277
  };
@@ -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.12",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",