UNPKG

@jalez/react-flow-automated-layout

Version:

A React library for automated layout of nested node graphs with parent-child relationships using React Flow

1,513 lines (1,512 loc) 42.2 kB
import { jsx as d, jsxs as N, Fragment as V } from "react/jsx-runtime"; import { createContext as It, useContext as Gt, useState as k, useEffect as I, useRef as ht, useCallback as G } from "react"; import { Position as R, useReactFlow as _t, useNodes as $t, useEdges as Ft, useOnSelectionChange as Pt, ControlButton as M, Controls as Ut } from "@xyflow/react"; import dt from "@dagrejs/dagre"; const bt = It(void 0); function _() { const t = Gt(bt); if (t === void 0) throw new Error("useLayoutContext must be used within a LayoutProvider"); return t; } const Vt = (t) => { switch (t) { case "DOWN": return "TB"; case "RIGHT": return "LR"; case "UP": return "BT"; case "LEFT": return "RL"; default: return "TB"; } }, ut = (t) => { switch (t) { case "TB": return "DOWN"; case "LR": return "RIGHT"; case "BT": return "UP"; case "RL": return "LEFT"; default: return "DOWN"; } }, Yt = { enabled: !0, padding: { horizontal: 80, vertical: 48 }, respectHeaderHeight: !0, minWidth: 200, minHeight: 100 }, jt = (t) => { switch (t) { case "DOWN": return R.Bottom; case "RIGHT": return R.Right; case "UP": return R.Top; case "LEFT": return R.Left; default: return R.Bottom; } }, Xt = (t) => { switch (t) { case "DOWN": return R.Top; case "RIGHT": return R.Left; case "UP": return R.Bottom; case "LEFT": return R.Right; default: return R.Top; } }; function Jt(t, r, e) { if (e) return { nodes: t, edges: r }; const s = t.filter((l) => !l.hidden), n = new Set(s.map((l) => l.id)), o = r.filter( (l) => n.has(l.source) && n.has(l.target) ); return { nodes: s, edges: o }; } const Wt = 172, Zt = 36, Y = async (t, r, e, s = 0, n = 50, o = 50, l = Wt, a = Zt, h = !1) => { const c = new dt.graphlib.Graph().setDefaultEdgeLabel(() => ({})); c.setGraph({ rankdir: e, marginx: s, marginy: s, nodesep: n, ranksep: o, edgesep: Math.max(20, n / 4), //When we have siblings, we want their top edges to be aligned ranker: "tight-tree" }); const i = h ? t : t.filter((p) => !p.hidden); if (i.length === 0) return { nodes: [], edges: [], width: 0, height: 0 }; i.forEach((p) => { var y, w; const f = Number((y = p.style) == null ? void 0 : y.width) || l, b = Number((w = p.style) == null ? void 0 : w.height) || a; c.setNode(p.id, { width: f, height: b }); }), r.forEach((p) => { var E, C; const f = p.sourceHandle, b = p.targetHandle, y = !!((E = p.data) != null && E.isReciprocal), w = !!((C = p.data) != null && C.isSyntheticBridge); let g = {}; y ? g = { constraint: !1, minlen: 1, weight: 5 } : w ? g = { constraint: !0, minlen: 1, weight: 4 } : f === "right" && b === "left" ? g = { constraint: !1, minlen: 1 } : f === "bottom" && b === "top" ? g = { constraint: !0, minlen: 1 } : g = { constraint: !0, minlen: 2 }, c.setEdge(p.source, p.target, g); }), dt.layout(c); const u = c.graph().width || 0, x = c.graph().height || 0, v = jt(ut(e)), m = Xt(ut(e)); return { nodes: i.map((p) => { var C; const f = c.node(p.id), { width: b, height: y } = f, w = { ...p, sourcePosition: v, targetPosition: m, selected: !1 }, g = f.x, E = f.y; switch ((C = p.data) == null ? void 0 : C.positionType) { case "center": w.position = { x: g, y: E }; break; case "topRight": w.position = { x: g + b / 2, y: E - y / 2 }; break; case "bottomLeft": w.position = { x: g - b / 2, y: E + y / 2 }; break; case "bottomRight": w.position = { x: g + b / 2, y: E + y / 2 }; break; case "topLeft": default: w.position = { x: g - b / 2, y: E - y / 2 }; } return w; }), edges: r, width: u, height: x }; }, qt = { calculate: async (t, r, e) => { const s = e.nodes || t, n = e.edges || r, l = e.dagreDirection || typeof e.direction == "string" && (e.direction === "RIGHT" || e.direction === "LEFT" ? "LR" : "TB") || "TB", a = e.margin ?? (typeof e.padding == "number" ? e.padding : 0), h = e.nodeSpacing ?? 50, c = e.layerSpacing ?? 50, i = e.nodeWidth ?? 172, u = e.nodeHeight ?? 36, x = e.layoutHidden ?? !1; return Y( s, n, l, a, h, c, i, u, x ); } }, Qt = { dagre: qt }; function Kt({ initialDirection: t = "DOWN", initialAlgorithm: r = "layered", initialAutoLayout: e = !0, initialPadding: s = 50, initialSpacing: n = { node: 50, layer: 50 }, initialNodeDimensions: o = { width: 172, height: 36 }, initialParentResizingOptions: l, includeHidden: a = !1, layoutEngines: h }) { const [c, i] = k(t), [u, x] = k(r), [v, m] = k(e), [L, p] = k(!1), [f, b] = k(a), [y, w] = k({ ...Qt, ...h }), [g, E] = k({}), [C, B] = k(s), [$, T] = k(n.node || 150), [S, O] = k(n.layer || 180), [F, P] = k(o.width || 100), [j, X] = k(o.height || 100), [J, W] = k({ ...Yt, ...l, enabled: e }), [U, Z] = k([]); return { // State direction: c, algorithm: u, autoLayout: v, layoutInProgress: L, layoutHidden: f, layoutEngines: y, layoutEngineOptions: g, padding: C, nodeSpacing: $, layerSpacing: S, nodeWidth: F, nodeHeight: j, parentResizingOptions: J, selectedNodes: U, // Setters setDirection: i, setAlgorithm: x, setAutoLayout: m, setLayoutInProgress: p, setLayoutHidden: b, setLayoutEngines: w, setLayoutEngineOptions: E, setPadding: B, setNodeSpacing: T, setLayerSpacing: O, setNodeWidth: P, setNodeHeight: X, setParentResizingOptionsState: W, setSelectedNodes: Z }; } function te({ nodes: t, externalNodeIdWithNode: r, externalNodeParentIdMapWithChildIdSet: e, noParentKey: s = "no-parent" }) { const [n, o] = k(/* @__PURE__ */ new Map()), [l, a] = k(/* @__PURE__ */ new Map()), [h, c] = k({}), [i, u] = k(t.length), [x, v] = k(!1), m = r || n, L = e || l, p = m.size; return I(() => { if (!r || !e) { const f = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map(); t.forEach((y) => { var g; f.set(y.id, y); const w = y.parentId || s; b.has(w) || b.set(w, /* @__PURE__ */ new Set()), (g = b.get(w)) == null || g.add(y.id); }), r || o(f), e || a(b); } }, [t, r, e, s]), I(() => { t.length !== i && u(t.length); }, [t]), I(() => { m.size > 0 && L.size > 0 && !x && v(!0); }, [m, L, x]), I(() => { const f = {}; L.forEach((y, w) => { f[w] = y.size; }); let b = !1; for (const y in f) if (!h.hasOwnProperty(y) || f[y] !== h[y]) { b = !0; break; } b && c(f); }, [L]), { nodeIdWithNode: m, nodeParentIdMapWithChildIdSet: L, numberOfNodes: p, nodesLength: i, childrenInitialized: x, parentChildStructure: h }; } function ee({ nodes: t, edges: r, selectedNodes: e, layoutHidden: s, calculateLayout: n, updateNodes: o, updateEdges: l, setLayoutInProgress: a, setNodeSpacing: h, setLayerSpacing: c }) { const i = _t(), u = ht(null), x = ht(null); return { applyLayout: G(async (m = [], L = []) => { u.current && u.current.abort(); const p = new AbortController(); u.current = p; const f = m.length > 0 ? m : t, b = L.length > 0 ? L : r; if (f.length === 0) return { nodes: f, edges: b }; try { if (a(!0), p.signal.aborted) return { nodes: f, edges: b }; const { nodes: y, edges: w } = Jt(f, b, s), g = await n(y, w, e, p.signal); return p.signal.aborted ? { nodes: f, edges: b } : (u.current === p && (o ? o(g.nodes) : i != null && i.setNodes && i.setNodes(g.nodes), l ? l(g.edges) : i != null && i.setEdges && i.setEdges(g.edges), x.current && (x.current.node !== void 0 && h(x.current.node), x.current.layer !== void 0 && c(x.current.layer), x.current = null)), g); } catch (y) { return p.signal.aborted || console.error("Error applying layout:", y), { nodes: f, edges: b }; } finally { u.current === p && (a(!1), u.current = null); } }, [ t, r, e, n, o, l, i, s, a, h, c ]), pendingSpacingUpdateRef: x }; } const re = (t, r, e = "no-parent") => { const s = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Map(); t.forEach((a, h) => { const c = r.get(h); c && n.set(h, { id: h, node: c, children: [], depth: 0 }); }); const o = (a, h) => { if (s.has(a) || !t.has(a) || !r.get(a)) return null; s.add(a); const i = n.get(a); i.depth = h; const u = t.get(a) || /* @__PURE__ */ new Set(); for (const x of u) if (t.has(x) && r.get(x)) { const m = o(x, h + 1); m && i.children.push(m); } return i; }, l = []; return t.forEach((a, h) => { const c = r.get(h); if (c) { const i = c.parentId; if (!i || i === e) { const u = o(h, 0); u && l.push(u); } } }), l; }; function K(t, r, e = "no-parent") { const s = []; let n = t; const o = /* @__PURE__ */ new Set(); for (; n && n !== e; ) { if (o.has(n)) { console.warn(`Cycle detected in ancestor path for node ${t}`); break; } o.add(n), s.push(n); const l = r.get(n); if (!l || !l.parentId) { n = e; break; } n = l.parentId; } return n === e && s.push(e), s; } function D(t, r, e, s = "no-parent") { if (t === r) return t; const n = K(t, e, s), o = n.indexOf(r); return o === -1 ? null : o === 0 ? t : n[o - 1] || null; } function H(t, r, e, s = "no-parent") { const n = K(t, e, s), o = K(r, e, s), l = new Set(o); let a = null, h = -1; for (let x = 0; x < n.length; x++) if (l.has(n[x])) { a = n[x], h = x; break; } if (!a) return { lca: null, sourceChild: null, targetChild: null }; const c = o.indexOf(a), i = h > 0 ? n[h - 1] : t, u = c > 0 ? o[c - 1] : r; return { lca: a, sourceChild: i, targetChild: u }; } const ne = (t) => JSON.parse(JSON.stringify(t)), Lt = (t, r, e, s, n) => { const o = ne(t); return o.source = r, o.target = e, o.id = s, o.data = { ...o.data, ...n }, o; }, se = (t) => { for (const r of t.values()) { const e = /* @__PURE__ */ new Map(); r.forEach((n) => { const o = `${n.source}->${n.target}`, l = e.get(o) || []; l.push(n), e.set(o, l); }); const s = /* @__PURE__ */ new Set(); r.forEach((n) => { const o = `${n.source}->${n.target}`, l = `${n.target}->${n.source}`; if (s.has(o) || s.has(l)) return; const a = e.get(l); if (!a || a.length === 0) return; [...e.get(o) || [], ...a].forEach((c) => { c.data = { ...c.data, isReciprocal: !0 }; }), s.add(o), s.add(l); }); } }, ie = (t, r, e, s) => { const n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(); t.forEach((a) => { const h = n.get(a.target) || []; h.push(a), n.set(a.target, h); const c = o.get(a.source) || []; c.push(a), o.set(a.source, c); }); const l = /* @__PURE__ */ new Set(); o.forEach((a, h) => { const c = n.get(h) || []; c.length !== 0 && c.forEach((i) => { a.forEach((u) => { if (i.source === u.target) return; const { lca: x, sourceChild: v, targetChild: m } = H( i.source, u.target, r, s ), L = H( i.source, h, r, s ).lca, p = H( h, u.target, r, s ).lca; if (!L || L !== p) return; const f = D( i.source, L, r, s ), b = D( u.target, L, r, s ), y = D( h, L, r, s ); if (!f || !b || !y || f !== b || f === y) return; const w = f, g = D( i.source, w, r, s ), E = D( u.target, w, r, s ); if (!x || !v || !m || !g || !E || g === E) return; const C = `synthetic_bridge_${i.id}_${h}_${u.id}_${w}`; if (l.has(C)) return; const B = Lt( i, g, E, C, { isTemporary: !0, isSyntheticBridge: !0, bridgeNode: h, bridgeBranch: y, anchorBranch: f, originalSource: i.source, originalTarget: u.target } ); e.has(w) || e.set(w, []), e.get(w).push(B), l.add(C); }); }); }); }; function Ct(t, r, e = "no-parent") { const s = /* @__PURE__ */ new Map(); for (const n of t) { const { lca: o, sourceChild: l, targetChild: a } = H( n.source, n.target, r, e ); if (o && l && a && l !== a) { const h = Lt( n, l, a, `temp_${n.id}_${o}`, { isTemporary: !0, originalSource: n.source, originalTarget: n.target } ); s.has(o) || s.set(o, []), s.get(o).push(h); } } return ie(t, r, s, e), se(s), s; } const et = 10, pt = (t, r) => t.find((e) => e.id === r), gt = (t, r, e) => { var a, h; const s = e.get(t); if (!s) return null; let n = s.position.x + (s.width || Number((a = s.style) == null ? void 0 : a.width) || 172) / 2, o = s.position.y + (s.height || Number((h = s.style) == null ? void 0 : h.height) || 36) / 2, l = s.parentId; for (; l && l !== r; ) { const c = e.get(l); if (!c) break; n += c.position.x, o += c.position.y, l = c.parentId; } return { x: n, y: o }; }, z = (t) => { var r, e; return { width: t.width || Number((r = t.style) == null ? void 0 : r.width) || 172, height: t.height || Number((e = t.style) == null ? void 0 : e.height) || 36 }; }, ft = (t) => { const { width: r, height: e } = z(t); return { x: t.position.x + r / 2, y: t.position.y + e / 2 }; }, oe = (t, r) => { if (t.length === 0) return { nodes: t, width: 0, height: 0 }; let e = Number.POSITIVE_INFINITY, s = Number.POSITIVE_INFINITY, n = Number.NEGATIVE_INFINITY, o = Number.NEGATIVE_INFINITY; t.forEach((i) => { const { width: u, height: x } = z(i); e = Math.min(e, i.position.x), s = Math.min(s, i.position.y), n = Math.max(n, i.position.x + u), o = Math.max(o, i.position.y + x); }); const l = r - e, a = r - s; t.forEach((i) => { i.position = { x: i.position.x + l, y: i.position.y + a }; }); const h = n - e + r * 2, c = o - s + r * 2; return { nodes: t, width: h, height: c }; }, ce = (t, r, e, s) => { if (!(t.length < 2 || s.size === 0)) if (r === "TB" || r === "BT") { const n = [...t].sort((o, l) => o.position.x - l.position.x); n.forEach((o, l) => { if (!s.has(o.id)) return; let a = o.position.x + z(o).width; for (let h = l + 1; h < n.length; h++) { const c = n[h], { width: i } = z(c), u = a + e; c.position.x < u && (c.position.x = u), a = c.position.x + i; } }); } else { const n = [...t].sort((o, l) => o.position.y - l.position.y); n.forEach((o, l) => { if (!s.has(o.id)) return; let a = o.position.y + z(o).height; for (let h = l + 1; h < n.length; h++) { const c = n[h], { height: i } = z(c), u = a + e; c.position.y < u && (c.position.y = u), a = c.position.y + i; } }); } }, ae = (t, r, e, s) => { const n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(); r.forEach((a) => { const h = n.get(a.target) || []; h.push(a), n.set(a.target, h); const c = o.get(a.source) || []; c.push(a), o.set(a.source, c); }); const l = /* @__PURE__ */ new Map(); return o.forEach((a, h) => { const c = n.get(h) || []; c.length !== 0 && c.forEach((i) => { a.forEach((u) => { if (i.source === u.target) return; const x = H( i.source, h, e, s ).lca, v = H( h, u.target, e, s ).lca; if (x !== t || v !== t) return; const m = D( i.source, t, e, s ), L = D( u.target, t, e, s ), p = D( h, t, e, s ); if (!m || !L || !p || m !== L || m === p) return; const f = D( i.source, m, e, s ), b = D( u.target, m, e, s ); if (!f || !b || f === b) return; const y = `${m}:${p}:${f}:${b}`; l.set(y, { anchorContainerId: m, bridgeContainerId: p, sourceNodeId: f, targetNodeId: b }); }); }); }), [...l.values()]; }, le = (t, r, e, s, n, o, l) => { const a = ae(r, n, o, l), h = /* @__PURE__ */ new Set(); return a.forEach((c) => { const i = pt(t, c.anchorContainerId), u = pt(t, c.bridgeContainerId); if (!i || !u) return; const x = gt(c.sourceNodeId, r, o), v = gt(c.targetNodeId, r, o); if (!x || !v) return; const { width: m, height: L } = z(u), { width: p, height: f } = z(i), b = ft(i), y = ft(u); if (e === "TB" || e === "BT") { const w = (x.y + v.y) / 2; u.position.y = w - L / 2; const g = y.x >= b.x, E = g ? u.position.x - (i.position.x + p) : i.position.x - (u.position.x + m), C = Math.max(s, E); u.position.x = g ? i.position.x + p + C : i.position.x - m - C; } else { const w = (x.x + v.x) / 2; u.position.x = w - m / 2; const g = y.y >= b.y, E = g ? u.position.y - (i.position.y + f) : i.position.y - (u.position.y + L), C = Math.max(s, E); u.position.y = g ? i.position.y + f + C : i.position.y - L - C; } h.add(u.id); }), h; }, Et = async (t, r, e, s, n, o = et, l = 50, a = 50, h = 172, c = 36, i = Y, u = !1, x = "no-parent") => { const v = Ct(n, s, x), { updatedNodes: m } = await tt( t, r, e, s, n, o, l, a, h, c, i, u, v, x ), L = s.get(t); if (!L) return { updatedNodes: m, updatedEdges: n }; const { updatedNodes: p } = await Et( L.parentId || x, r, e, s, n, o, l, a, h, c, i, u, x ); return { updatedNodes: [...p, ...m], updatedEdges: n // Always return original edges unchanged }; }, tt = async (t, r, e, s, n, o = et, l = 50, a = 50, h = 172, c = 36, i = Y, u = !1, x = /* @__PURE__ */ new Map(), v = "no-parent") => { const m = e.get(t); if (!m || m.size === 0) return { updatedNodes: [] }; const L = []; if (m.forEach((C) => { const B = s.get(C); B && L.push(B); }), L.length === 0) return { updatedNodes: [] }; let p = r; const f = s.get(t); f && f.data.layoutDirection && (p = f.data.layoutDirection); const b = x.get(t) || [], { nodes: y, edges: w } = await i( L, b, // Only use temporary edges for layout p, o, l, a, h, c, u ); y.forEach((C) => { s.set(C.id, C); }); const g = le( y, t, p, l, n, s, v ); ce( y, p, l, g ), y.forEach((C) => { s.set(C.id, C); }); const E = oe(y, o); return E.nodes.forEach((C) => { s.set(C.id, C); }), f && E.width && E.height && he(f, E.width, E.height), { updatedNodes: [...E.nodes], udpatedParentNode: f || void 0 }; }, he = (t, r, e) => (t.style || (t.style = {}), t.width = r, t.height = e, t.measured = { width: r, height: e }, t.style.width = r, t.style.height = e, t), de = async (t, r, e, s, n, o = et, l = 50, a = 50, h = 172, c = 36, i = Y, u = !1, x = "no-parent") => { let v = []; const m = Ct(n, s, x), L = /* @__PURE__ */ new Map(); let p = 0; const f = (y, w) => { w > p && (p = w); for (const g of y) L.has(w) || L.set(w, []), L.get(w).push(g.id), g.children.length > 0 && f(g.children, w + 1); }; f(t, 0); for (let y = p; y >= 0; y--) { const w = L.get(y) || [], g = await Promise.all(w.map( (E) => tt( E, r, e, s, n, // Pass original edges (only used for returning) o, l, a, h, c, i, u, m, // Pass the global temporary edges map x ) )); for (const { updatedNodes: E } of g) v = [...E, ...v]; } const { updatedNodes: b } = await tt( x, r, e, s, n, // Pass original edges (only used for returning) o, l, a, h, c, i, u, m, // Process root-level temporary edges x ); return v = [...b, ...v], { updatedNodes: v, updatedEdges: n // Always return original edges unchanged }; }, ue = (t, r, e, s = "no-parent") => { const n = t.map((c) => c.id), o = t.map((c) => { var i; return ((i = e.get(c.id)) == null ? void 0 : i.parentId) || c.parentId; }).filter((c) => !!c), a = Array.from( /* @__PURE__ */ new Set([...n, ...o]) ).filter((c) => r.has(c)), h = a.filter((c) => { const i = e.get(c); return i ? !i.parentId || !a.includes(i.parentId) : !0; }); return h.length === 0 ? [s] : h; }, pe = async (t, r, e) => { const { dagreDirection: s, nodeParentIdMapWithChildIdSet: n, nodeIdWithNode: o, nodes: l, edges: a, margin: h, nodeSpacing: c, layerSpacing: i, nodeWidth: u, nodeHeight: x, layoutHidden: v = !1, noParentKey: m = "no-parent" } = r, L = ue( t, n, o, m ); if (L.length === 0) return { nodes: l, edges: a }; const p = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(); if (e != null && e.aborted) return { nodes: l, edges: a }; (await Promise.all( L.map(async (g) => e != null && e.aborted ? { updatedNodes: [], updatedEdges: [] } : Et( g, s, n, o, a, h, c, i, u, x, void 0, v )) )).forEach(({ updatedNodes: g, updatedEdges: E }) => { g.forEach((C) => { p.set(C.id, C); }), E.forEach((C) => { f.set(C.id, C); }); }); const y = l.map( (g) => p.has(g.id) ? p.get(g.id) : g ), w = a.map( (g) => f.has(g.id) ? f.get(g.id) : g ); return { nodes: y, edges: w }; }, ge = (t, r, e, s, n, o, l, a, h = 172, c = 36, i = !1, u = "no-parent") => ({ calculateLayout: G(async (v, m, L, p) => { if (!(t[e] || t.dagre)) return console.error(`Layout engine "${e}" not found`), { nodes: v, edges: m }; const b = i ? v : v.filter((T) => !T.hidden), y = new Set(b.map((T) => T.id)), w = i ? m : m.filter( (T) => y.has(T.source) && y.has(T.target) ), g = Vt(r), E = s.padding.horizontal; let C = [], B = []; if (L && L.length > 0) { const T = i ? L : L.filter((O) => !O.hidden), S = await pe( T, { dagreDirection: g, nodeParentIdMapWithChildIdSet: n, nodeIdWithNode: o, nodes: b, edges: w, margin: E, nodeSpacing: l, layerSpacing: a, nodeWidth: h, nodeHeight: c, layoutHidden: i, noParentKey: u }, p ); C = S.nodes, B = S.edges; } else { if (p != null && p.aborted) return { nodes: v, edges: m }; const T = re(n, o, u), S = await de( T, g, n, o, w, E, l, a, h, c, void 0, i, u ); C = S.updatedNodes, B = S.updatedEdges; } return { nodes: v.map((T) => !i && T.hidden ? T : C.find((O) => O.id === T.id) || T), edges: B }; }, [ e, r, t, s.padding.horizontal, n, o, l, a, h, c, i, u ]) }); function me({ children: t, initialDirection: r = "DOWN", initialAlgorithm: e = "layered", initialAutoLayout: s = !0, initialPadding: n = 50, initialSpacing: o = { node: 50, layer: 50 }, initialNodeDimensions: l = { width: 172, height: 36 }, initialParentResizingOptions: a, includeHidden: h = !1, layoutEngines: c, updateNodes: i, updateEdges: u, nodeParentIdMapWithChildIdSet: x, nodeIdWithNode: v, noParentKey: m = "no-parent", disableAutoLayoutEffect: L = !1 }) { const p = $t(), f = Ft(), { direction: b, algorithm: y, autoLayout: w, layoutInProgress: g, layoutHidden: E, layoutEngines: C, layoutEngineOptions: B, padding: $, nodeSpacing: T, layerSpacing: S, nodeWidth: O, nodeHeight: F, parentResizingOptions: P, selectedNodes: j, setDirection: X, setAlgorithm: J, setAutoLayout: W, setLayoutInProgress: U, setLayoutHidden: Z, setLayoutEngines: rt, setLayoutEngineOptions: vt, setPadding: Nt, setNodeSpacing: nt, setLayerSpacing: st, setNodeWidth: Tt, setNodeHeight: kt, setParentResizingOptionsState: it, setSelectedNodes: ot } = Kt({ initialDirection: r, initialAlgorithm: e, initialAutoLayout: s, initialPadding: n, initialSpacing: o, initialNodeDimensions: l, initialParentResizingOptions: a, includeHidden: h, layoutEngines: c }), { nodeIdWithNode: q, nodeParentIdMapWithChildIdSet: ct, numberOfNodes: Bt, nodesLength: St, childrenInitialized: at, parentChildStructure: Mt } = te({ nodes: p, externalNodeIdWithNode: v, externalNodeParentIdMapWithChildIdSet: x, noParentKey: m }), Rt = G(({ nodes: A }) => { ot(A); }, [ot]); Pt({ onChange: Rt }); const { calculateLayout: Dt } = ge( C, b, y, P, ct, q, T, S, O, F, E, m ), { applyLayout: lt } = ee({ nodes: p, edges: f, selectedNodes: j, layoutHidden: E, calculateLayout: Dt, updateNodes: i, updateEdges: u, setLayoutInProgress: U, setNodeSpacing: nt, setLayerSpacing: st }), Ot = G((A, Q) => { rt((Ht) => ({ ...Ht, [A]: Q })); }, [rt]), At = G((A) => { it((Q) => ({ ...Q, ...A, enabled: w })); }, [w, it]); I(() => { var A; L || q.has((A = p[p.length - 1]) == null ? void 0 : A.id) && at && w && lt(); }, [at, w, b, Bt, T, S, Mt, St]); const zt = { direction: b, algorithm: y, autoLayout: w, layoutInProgress: g, padding: $, nodeSpacing: T, layerSpacing: S, nodeWidth: O, nodeHeight: F, layoutHidden: E, parentResizingOptions: P, layoutEngines: C, layoutEngineOptions: B, nodeParentIdMapWithChildIdSet: ct, nodeIdWithNode: q, noParentKey: m, updateNodes: i, updateEdges: u, setDirection: X, setAlgorithm: J, setAutoLayout: W, setLayoutInProgress: U, setPadding: Nt, setNodeSpacing: nt, setLayerSpacing: st, setNodeWidth: Tt, setNodeHeight: kt, setLayoutHidden: Z, setParentResizingOptions: At, setLayoutEngineOptions: vt, applyLayout: lt, clearLayoutCache: () => { }, registerLayoutEngine: Ot }; return /* @__PURE__ */ d(bt.Provider, { value: zt, children: t }); } const yt = ({ compact: t = !1 }) => { const { direction: r, setDirection: e, clearLayoutCache: s } = _(), n = (o) => { e(o), s && s(); }; return t ? /* @__PURE__ */ d( M, { onClick: () => n(r === "DOWN" ? "RIGHT" : "DOWN"), title: `Switch to ${r === "DOWN" ? "horizontal" : "vertical"} layout`, children: /* @__PURE__ */ d("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: r === "DOWN" ? ( // Horizontal layout icon /* @__PURE__ */ d("path", { d: "M4 12h16M16 6l6 6-6 6" }) ) : ( // Vertical layout icon /* @__PURE__ */ d("path", { d: "M12 4v16M6 16l6 6 6-6" }) ) }) } ) : /* @__PURE__ */ N(V, { children: [ /* @__PURE__ */ d( M, { onClick: () => n("DOWN"), className: r === "DOWN" ? "selected" : "", title: "Top to Bottom", children: /* @__PURE__ */ d("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: /* @__PURE__ */ d("path", { d: "M12 4v16M6 16l6 6 6-6" }) }) } ), /* @__PURE__ */ d( M, { onClick: () => n("RIGHT"), className: r === "RIGHT" ? "selected" : "", title: "Left to Right", children: /* @__PURE__ */ d("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: /* @__PURE__ */ d("path", { d: "M4 12h16M16 6l6 6-6 6" }) }) } ), /* @__PURE__ */ d( M, { onClick: () => n("LEFT"), className: r === "LEFT" ? "selected" : "", title: "Right to Left", children: /* @__PURE__ */ d("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: /* @__PURE__ */ d("path", { d: "M20 12H4M8 6L2 12l6 6" }) }) } ), /* @__PURE__ */ d( M, { onClick: () => n("UP"), className: r === "UP" ? "selected" : "", title: "Bottom to Top", children: /* @__PURE__ */ d("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: /* @__PURE__ */ d("path", { d: "M12 20V4M6 8l6-6 6 6" }) }) } ) ] }); }, xt = ({ compact: t = !1 }) => { const { nodeSpacing: r, layerSpacing: e, setNodeSpacing: s, setLayerSpacing: n, clearLayoutCache: o } = _(), [l, a] = k(!1), h = (i) => { s(i), o && o(); }, c = (i) => { n(i), o && o(); }; return t ? /* @__PURE__ */ N("div", { style: { position: "relative" }, children: [ /* @__PURE__ */ d( M, { onClick: () => a(!l), title: "Adjust node and layer spacing", children: /* @__PURE__ */ N("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [ /* @__PURE__ */ d("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("path", { d: "M7 10v4M17 10v4M10 7h4M10 17h4" }) ] }) } ), l && /* @__PURE__ */ N( "div", { className: "react-flow-spacing-dropdown", style: { position: "absolute", right: "0", top: "100%", marginTop: "8px", background: "white", border: "1px solid #ddd", borderRadius: "4px", padding: "8px", boxShadow: "0 2px 10px rgba(0,0,0,0.1)", zIndex: 10, minWidth: "200px" }, children: [ /* @__PURE__ */ N("div", { style: { marginBottom: "12px" }, children: [ /* @__PURE__ */ N("div", { style: { fontWeight: "bold", marginBottom: "4px" }, children: [ "Node Spacing: ", r, "px" ] }), /* @__PURE__ */ d("div", { style: { display: "flex", gap: "4px" }, children: [50, 100, 150, 200].map((i) => /* @__PURE__ */ d( "button", { onClick: () => h(i), style: { background: r === i ? "#0041d0" : "#f5f5f5", color: r === i ? "white" : "inherit", border: "1px solid #ddd", borderRadius: "4px", padding: "4px 8px", cursor: "pointer" }, children: i }, i )) }) ] }), /* @__PURE__ */ N("div", { children: [ /* @__PURE__ */ N("div", { style: { fontWeight: "bold", marginBottom: "4px" }, children: [ "Layer Spacing: ", e, "px" ] }), /* @__PURE__ */ d("div", { style: { display: "flex", gap: "4px" }, children: [50, 100, 150, 200].map((i) => /* @__PURE__ */ d( "button", { onClick: () => c(i), style: { background: e === i ? "#0041d0" : "#f5f5f5", color: e === i ? "white" : "inherit", border: "1px solid #ddd", borderRadius: "4px", padding: "4px 8px", cursor: "pointer" }, children: i }, i )) }) ] }), /* @__PURE__ */ d("div", { style: { marginTop: "12px", textAlign: "right" }, children: /* @__PURE__ */ d( "button", { onClick: () => a(!1), style: { background: "#f5f5f5", border: "1px solid #ddd", borderRadius: "4px", padding: "4px 8px", cursor: "pointer" }, children: "Close" } ) }) ] } ) ] }) : /* @__PURE__ */ N("div", { className: "spacing-controls", children: [ /* @__PURE__ */ N( M, { onClick: () => h(Math.max(50, r - 25)), title: "Decrease node spacing", children: [ /* @__PURE__ */ N("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [ /* @__PURE__ */ d("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("line", { x1: "7", y1: "10", x2: "7", y2: "14" }), /* @__PURE__ */ d("line", { x1: "17", y1: "10", x2: "17", y2: "14" }), /* @__PURE__ */ d("line", { x1: "10", y1: "7", x2: "14", y2: "7" }), /* @__PURE__ */ d("line", { x1: "10", y1: "17", x2: "14", y2: "17" }) ] }), /* @__PURE__ */ d("span", { style: { marginLeft: "4px" }, children: "-" }) ] } ), /* @__PURE__ */ N("div", { style: { display: "inline-flex", alignItems: "center", padding: "5px 10px", fontSize: "12px", background: "#f8f8f8", borderRadius: "4px", margin: "0 4px", border: "1px solid #ddd" }, children: [ r, "px" ] }), /* @__PURE__ */ N( M, { onClick: () => h(Math.min(300, r + 25)), title: "Increase node spacing", children: [ /* @__PURE__ */ N("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [ /* @__PURE__ */ d("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ d("line", { x1: "7", y1: "10", x2: "7", y2: "14" }), /* @__PURE__ */ d("line", { x1: "17", y1: "10", x2: "17", y2: "14" }), /* @__PURE__ */ d("line", { x1: "10", y1: "7", x2: "14", y2: "7" }), /* @__PURE__ */ d("line", { x1: "10", y1: "17", x2: "14", y2: "17" }) ] }), /* @__PURE__ */ d("span", { style: { marginLeft: "4px" }, children: "+" }) ] } ), /* @__PURE__ */ d("div", { style: { display: "inline-block", width: "1px", height: "24px", background: "#ddd", margin: "0 10px" } }), /* @__PURE__ */ N( M, { onClick: () => c(Math.max(50, e - 25)), title: "Decrease layer spacing", children: [ /* @__PURE__ */ N("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [ /* @__PURE__ */ d("line", { x1: "4", y1: "6", x2: "20", y2: "6" }), /* @__PURE__ */ d("line", { x1: "4", y1: "12", x2: "20", y2: "12" }), /* @__PURE__ */ d("line", { x1: "4", y1: "18", x2: "20", y2: "18" }) ] }), /* @__PURE__ */ d("span", { style: { marginLeft: "4px" }, children: "-" }) ] } ), /* @__PURE__ */ N("div", { style: { display: "inline-flex", alignItems: "center", padding: "5px 10px", fontSize: "12px", background: "#f8f8f8", borderRadius: "4px", margin: "0 4px", border: "1px solid #ddd" }, children: [ e, "px" ] }), /* @__PURE__ */ N( M, { onClick: () => c(Math.min(300, e + 25)), title: "Increase layer spacing", children: [ /* @__PURE__ */ N("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [ /* @__PURE__ */ d("line", { x1: "4", y1: "6", x2: "20", y2: "6" }), /* @__PURE__ */ d("line", { x1: "4", y1: "12", x2: "20", y2: "12" }), /* @__PURE__ */ d("line", { x1: "4", y1: "18", x2: "20", y2: "18" }) ] }), /* @__PURE__ */ d("span", { style: { marginLeft: "4px" }, children: "+" }) ] } ) ] }); }, wt = ({ compact: t = !1 }) => { const { autoLayout: r, setAutoLayout: e } = _(); return /* @__PURE__ */ d( M, { onClick: () => { e(!r); }, className: r ? "selected" : "", title: r ? "Disable automatic layout" : "Enable automatic layout", style: { color: r ? "green" : "inherit" }, children: t ? /* @__PURE__ */ N("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "1.5", fill: "none", children: [ /* @__PURE__ */ d("rect", { x: "4", y: "4", width: "4", height: "4", rx: "1" }), /* @__PURE__ */ d("rect", { x: "4", y: "16", width: "4", height: "4", rx: "1" }), /* @__PURE__ */ d("rect", { x: "16", y: "10", width: "4", height: "4", rx: "1" }), /* @__PURE__ */ N(V, { children: [ /* @__PURE__ */ d("path", { d: "M8 6c6 0 3 8 8 6" }), /* @__PURE__ */ d("path", { d: "M8 18c3-3 2-8 6-6" }) ] }) ] }) : /* @__PURE__ */ N(V, { children: [ "Auto-Layout ", r ? "ON" : "OFF" ] }) } ); }, mt = ({ compact: t = !1 }) => { const { layoutInProgress: r, setLayoutInProgress: e, applyLayout: s } = _(); return /* @__PURE__ */ N( M, { onClick: async () => { if (!r) try { e(!0), await s(); } catch (o) { console.error("Error applying layout:", o); } }, title: "Apply layout", disabled: r, style: { color: r ? "#999" : "#000" }, children: [ /* @__PURE__ */ N("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "1.5", fill: "none", children: [ /* @__PURE__ */ d("rect", { x: "3", y: "3", width: "5", height: "5", rx: "1" }), /* @__PURE__ */ d("rect", { x: "16", y: "3", width: "5", height: "5", rx: "1" }), /* @__PURE__ */ d("rect", { x: "3", y: "16", width: "5", height: "5", rx: "1" }), /* @__PURE__ */ d("rect", { x: "16", y: "16", width: "5", height: "5", rx: "1" }), /* @__PURE__ */ d("path", { d: "M8 5.5h8M5.5 8v8M18.5 8v8M8 18.5h8" }), /* @__PURE__ */ d("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ d("path", { d: "M11 10.5v3l2-1.5z", fill: "currentColor" }) ] }), !t && /* @__PURE__ */ d("span", { style: { marginLeft: "4px" }, children: "Apply Layout" }) ] } ); }, be = ({ showDirectionControls: t = !0, showSpacingControls: r = !0, showAutoLayoutToggle: e = !0, showApplyLayoutButton: s = !0, // Enable by default standalone: n = !1, position: o = "top-right" }) => { const l = _(), { autoLayout: a } = l; return n ? /* @__PURE__ */ N(Ut, { position: o, showZoom: !1, showFitView: !1, showInteractive: !1, children: [ s && !a && /* @__PURE__ */ d( mt, { compact: !0 } ), t && /* @__PURE__ */ d( yt, { compact: !0 } ), r && /* @__PURE__ */ d( xt, { compact: !0 } ), e && /* @__PURE__ */ d( wt, { compact: !0 } ) ] }) : /* @__PURE__ */ N(V, { children: [ s && !a && /* @__PURE__ */ d( mt, { compact: !0 } ), t && /* @__PURE__ */ d( yt, { compact: !0 } ), r && /* @__PURE__ */ d( xt, { compact: !0 } ), e && /* @__PURE__ */ d( wt, { compact: !0 } ) ] }); }; export { wt as AutoLayoutToggle, qt as DagreEngine, yt as DirectionControls, be as LayoutControls, me as LayoutProvider, xt as SpacingControls, Qt as engines, _ as useLayoutContext };