@jalez/react-flow-automated-layout
Version:
A React library for automated layout of nested node graphs with parent-child relationships using React Flow
1,479 lines (1,478 loc) • 43.2 kB
JavaScript
import Pe, { createContext as De, useContext as Me, useState as C, useEffect as ee, useRef as ue, useCallback as te } from "react";
import { Position as I, useReactFlow as Be, useNodes as Ie, useEdges as We, useOnSelectionChange as Fe, ControlButton as P, Controls as ze } from "@xyflow/react";
import he from "@dagrejs/dagre";
var se = { exports: {} }, Q = {};
/**
* @license React
* react-jsx-runtime.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var fe;
function He() {
if (fe) return Q;
fe = 1;
var n = Symbol.for("react.transitional.element"), o = Symbol.for("react.fragment");
function r(c, s, a) {
var d = null;
if (a !== void 0 && (d = "" + a), s.key !== void 0 && (d = "" + s.key), "key" in s) {
a = {};
for (var l in s)
l !== "key" && (a[l] = s[l]);
} else a = s;
return s = a.ref, {
$$typeof: n,
type: c,
key: d,
ref: s !== void 0 ? s : null,
props: a
};
}
return Q.Fragment = o, Q.jsx = r, Q.jsxs = r, Q;
}
var K = {};
/**
* @license React
* react-jsx-runtime.development.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var pe;
function Ue() {
return pe || (pe = 1, process.env.NODE_ENV !== "production" && function() {
function n(t) {
if (t == null) return null;
if (typeof t == "function")
return t.$$typeof === N ? null : t.displayName || t.name || null;
if (typeof t == "string") return t;
switch (t) {
case v:
return "Fragment";
case j:
return "Profiler";
case f:
return "StrictMode";
case y:
return "Suspense";
case R:
return "SuspenseList";
case G:
return "Activity";
}
if (typeof t == "object")
switch (typeof t.tag == "number" && console.error(
"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
), t.$$typeof) {
case E:
return "Portal";
case g:
return (t.displayName || "Context") + ".Provider";
case b:
return (t._context.displayName || "Context") + ".Consumer";
case x:
var w = t.render;
return t = t.displayName, t || (t = w.displayName || w.name || "", t = t !== "" ? "ForwardRef(" + t + ")" : "ForwardRef"), t;
case L:
return w = t.displayName || null, w !== null ? w : n(t.type) || "Memo";
case B:
w = t._payload, t = t._init;
try {
return n(t(w));
} catch {
}
}
return null;
}
function o(t) {
return "" + t;
}
function r(t) {
try {
o(t);
var w = !1;
} catch {
w = !0;
}
if (w) {
w = console;
var k = w.error, O = typeof Symbol == "function" && Symbol.toStringTag && t[Symbol.toStringTag] || t.constructor.name || "Object";
return k.call(
w,
"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
O
), o(t);
}
}
function c(t) {
if (t === v) return "<>";
if (typeof t == "object" && t !== null && t.$$typeof === B)
return "<...>";
try {
var w = n(t);
return w ? "<" + w + ">" : "<...>";
} catch {
return "<...>";
}
}
function s() {
var t = _.A;
return t === null ? null : t.getOwner();
}
function a() {
return Error("react-stack-top-frame");
}
function d(t) {
if (D.call(t, "key")) {
var w = Object.getOwnPropertyDescriptor(t, "key").get;
if (w && w.isReactWarning) return !1;
}
return t.key !== void 0;
}
function l(t, w) {
function k() {
$ || ($ = !0, console.error(
"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
w
));
}
k.isReactWarning = !0, Object.defineProperty(t, "key", {
get: k,
configurable: !0
});
}
function u() {
var t = n(this.type);
return V[t] || (V[t] = !0, console.error(
"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
)), t = this.props.ref, t !== void 0 ? t : null;
}
function h(t, w, k, O, M, A, X, Z) {
return k = A.ref, t = {
$$typeof: T,
type: t,
key: w,
props: A,
_owner: M
}, (k !== void 0 ? k : null) !== null ? Object.defineProperty(t, "ref", {
enumerable: !1,
get: u
}) : Object.defineProperty(t, "ref", { enumerable: !1, value: null }), t._store = {}, Object.defineProperty(t._store, "validated", {
configurable: !1,
enumerable: !1,
writable: !0,
value: 0
}), Object.defineProperty(t, "_debugInfo", {
configurable: !1,
enumerable: !1,
writable: !0,
value: null
}), Object.defineProperty(t, "_debugStack", {
configurable: !1,
enumerable: !1,
writable: !0,
value: X
}), Object.defineProperty(t, "_debugTask", {
configurable: !1,
enumerable: !1,
writable: !0,
value: Z
}), Object.freeze && (Object.freeze(t.props), Object.freeze(t)), t;
}
function i(t, w, k, O, M, A, X, Z) {
var S = w.children;
if (S !== void 0)
if (O)
if (Y(S)) {
for (O = 0; O < S.length; O++)
m(S[O]);
Object.freeze && Object.freeze(S);
} else
console.error(
"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
);
else m(S);
if (D.call(w, "key")) {
S = n(t);
var W = Object.keys(w).filter(function(ne) {
return ne !== "key";
});
O = 0 < W.length ? "{key: someKey, " + W.join(": ..., ") + ": ...}" : "{key: someKey}", H[S + O] || (W = 0 < W.length ? "{" + W.join(": ..., ") + ": ...}" : "{}", console.error(
`A props object containing a "key" prop is being spread into JSX:
let props = %s;
<%s {...props} />
React keys must be passed directly to JSX without using spread:
let props = %s;
<%s key={someKey} {...props} />`,
O,
S,
W,
S
), H[S + O] = !0);
}
if (S = null, k !== void 0 && (r(k), S = "" + k), d(w) && (r(w.key), S = "" + w.key), "key" in w) {
k = {};
for (var U in w)
U !== "key" && (k[U] = w[U]);
} else k = w;
return S && l(
k,
typeof t == "function" ? t.displayName || t.name || "Unknown" : t
), h(
t,
S,
A,
M,
s(),
k,
X,
Z
);
}
function m(t) {
typeof t == "object" && t !== null && t.$$typeof === T && t._store && (t._store.validated = 1);
}
var p = Pe, T = Symbol.for("react.transitional.element"), E = Symbol.for("react.portal"), v = Symbol.for("react.fragment"), f = Symbol.for("react.strict_mode"), j = Symbol.for("react.profiler"), b = Symbol.for("react.consumer"), g = Symbol.for("react.context"), x = Symbol.for("react.forward_ref"), y = Symbol.for("react.suspense"), R = Symbol.for("react.suspense_list"), L = Symbol.for("react.memo"), B = Symbol.for("react.lazy"), G = Symbol.for("react.activity"), N = Symbol.for("react.client.reference"), _ = p.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, D = Object.prototype.hasOwnProperty, Y = Array.isArray, F = console.createTask ? console.createTask : function() {
return null;
};
p = {
"react-stack-bottom-frame": function(t) {
return t();
}
};
var $, V = {}, J = p["react-stack-bottom-frame"].bind(
p,
a
)(), q = F(c(a)), H = {};
K.Fragment = v, K.jsx = function(t, w, k, O, M) {
var A = 1e4 > _.recentlyCreatedOwnerStacks++;
return i(
t,
w,
k,
!1,
O,
M,
A ? Error("react-stack-top-frame") : J,
A ? F(c(t)) : q
);
}, K.jsxs = function(t, w, k, O, M) {
var A = 1e4 > _.recentlyCreatedOwnerStacks++;
return i(
t,
w,
k,
!0,
O,
M,
A ? Error("react-stack-top-frame") : J,
A ? F(c(t)) : q
);
};
}()), K;
}
var ge;
function Ge() {
return ge || (ge = 1, process.env.NODE_ENV === "production" ? se.exports = He() : se.exports = Ue()), se.exports;
}
var e = Ge();
const Ee = De(void 0);
function re() {
const n = Me(Ee);
if (n === void 0)
throw new Error("useLayoutContext must be used within a LayoutProvider");
return n;
}
const Ye = (n) => {
switch (n) {
case "DOWN":
return "TB";
case "RIGHT":
return "LR";
case "UP":
return "BT";
case "LEFT":
return "RL";
default:
return "TB";
}
}, xe = (n) => {
switch (n) {
case "TB":
return "DOWN";
case "LR":
return "RIGHT";
case "BT":
return "UP";
case "RL":
return "LEFT";
default:
return "DOWN";
}
}, $e = {
enabled: !0,
padding: {
horizontal: 80,
vertical: 48
},
respectHeaderHeight: !0,
minWidth: 200,
minHeight: 100
}, Ve = (n) => {
switch (n) {
case "DOWN":
return I.Bottom;
case "RIGHT":
return I.Right;
case "UP":
return I.Top;
case "LEFT":
return I.Left;
default:
return I.Bottom;
}
}, Je = (n) => {
switch (n) {
case "DOWN":
return I.Top;
case "RIGHT":
return I.Left;
case "UP":
return I.Bottom;
case "LEFT":
return I.Right;
default:
return I.Top;
}
};
function qe(n, o, r) {
if (r)
return { nodes: n, edges: o };
const c = n.filter((d) => !d.hidden), s = new Set(c.map((d) => d.id)), a = o.filter(
(d) => s.has(d.source) && s.has(d.target)
);
return { nodes: c, edges: a };
}
const Xe = 172, Ze = 36, oe = async (n, o, r, c = 0, s = 50, a = 50, d = Xe, l = Ze, u = !1) => {
const h = new he.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
h.setGraph({
rankdir: r,
marginx: c,
marginy: c,
nodesep: s,
ranksep: a,
edgesep: Math.max(20, s / 4),
//When we have siblings, we want their top edges to be aligned
ranker: "tight-tree"
});
const i = u ? n : n.filter((f) => !f.hidden);
if (i.length === 0)
return { nodes: [], edges: [], width: 0, height: 0 };
i.forEach((f) => {
var g, x;
const j = Number((g = f.style) == null ? void 0 : g.width) || d, b = Number((x = f.style) == null ? void 0 : x.height) || l;
h.setNode(f.id, { width: j, height: b });
}), o.forEach((f) => {
const j = f.sourceHandle, b = f.targetHandle;
let g = {};
j === "right" && b === "left" ? g = { constraint: !1, minlen: 1 } : j === "bottom" && b === "top" ? g = { constraint: !0, minlen: 1 } : g = { constraint: !0, minlen: 2 }, h.setEdge(f.source, f.target, g);
}), he.layout(h);
const m = h.graph().width || 0, p = h.graph().height || 0, T = Ve(xe(r)), E = Je(xe(r));
return {
nodes: i.map((f) => {
var L;
const j = h.node(f.id), { width: b, height: g } = j, x = {
...f,
sourcePosition: T,
targetPosition: E,
selected: !1
}, y = j.x, R = j.y;
switch ((L = f.data) == null ? void 0 : L.positionType) {
case "center":
x.position = { x: y, y: R };
break;
case "topRight":
x.position = { x: y + b / 2, y: R - g / 2 };
break;
case "bottomLeft":
x.position = { x: y - b / 2, y: R + g / 2 };
break;
case "bottomRight":
x.position = { x: y + b / 2, y: R + g / 2 };
break;
case "topLeft":
default:
x.position = { x: y - b / 2, y: R - g / 2 };
}
return x;
}),
edges: o,
width: m,
height: p
};
}, Qe = {
calculate: async (n, o, r) => {
const c = r.nodes || n, s = r.edges || o, d = r.dagreDirection || typeof r.direction == "string" && (r.direction === "RIGHT" || r.direction === "LEFT" ? "LR" : "TB") || "TB", l = r.margin ?? (typeof r.padding == "number" ? r.padding : 0), u = r.nodeSpacing ?? 50, h = r.layerSpacing ?? 50, i = r.nodeWidth ?? 172, m = r.nodeHeight ?? 36, p = r.layoutHidden ?? !1;
return oe(
c,
s,
d,
l,
u,
h,
i,
m,
p
);
}
}, Ke = {
dagre: Qe
};
function et({
initialDirection: n = "DOWN",
initialAlgorithm: o = "layered",
initialAutoLayout: r = !0,
initialPadding: c = 50,
initialSpacing: s = { node: 50, layer: 50 },
initialNodeDimensions: a = { width: 172, height: 36 },
initialParentResizingOptions: d,
includeHidden: l = !1,
layoutEngines: u
}) {
const [h, i] = C(n), [m, p] = C(o), [T, E] = C(r), [v, f] = C(!1), [j, b] = C(l), [g, x] = C({
...Ke,
...u
}), [y, R] = C({}), [L, B] = C(c), [G, N] = C(s.node || 150), [_, D] = C(s.layer || 180), [Y, F] = C(a.width || 100), [$, V] = C(a.height || 100), [J, q] = C({
...$e,
...d,
enabled: r
}), [H, t] = C([]);
return {
// State
direction: h,
algorithm: m,
autoLayout: T,
layoutInProgress: v,
layoutHidden: j,
layoutEngines: g,
layoutEngineOptions: y,
padding: L,
nodeSpacing: G,
layerSpacing: _,
nodeWidth: Y,
nodeHeight: $,
parentResizingOptions: J,
selectedNodes: H,
// Setters
setDirection: i,
setAlgorithm: p,
setAutoLayout: E,
setLayoutInProgress: f,
setLayoutHidden: b,
setLayoutEngines: x,
setLayoutEngineOptions: R,
setPadding: B,
setNodeSpacing: N,
setLayerSpacing: D,
setNodeWidth: F,
setNodeHeight: V,
setParentResizingOptionsState: q,
setSelectedNodes: t
};
}
function tt({
nodes: n,
externalNodeIdWithNode: o,
externalNodeParentIdMapWithChildIdSet: r,
noParentKey: c = "no-parent"
}) {
const [s, a] = C(/* @__PURE__ */ new Map()), [d, l] = C(/* @__PURE__ */ new Map()), [u, h] = C({}), [i, m] = C(n.length), [p, T] = C(!1), E = o || s, v = r || d, f = E.size;
return ee(() => {
if (!o || !r) {
const j = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map();
n.forEach((g) => {
var y;
j.set(g.id, g);
const x = g.parentId || c;
b.has(x) || b.set(x, /* @__PURE__ */ new Set()), (y = b.get(x)) == null || y.add(g.id);
}), o || a(j), r || l(b);
}
}, [n, o, r, c]), ee(() => {
n.length !== i && m(n.length);
}, [n]), ee(() => {
E.size > 0 && v.size > 0 && !p && T(!0);
}, [E, v, p]), ee(() => {
const j = {};
v.forEach((g, x) => {
j[x] = g.size;
});
let b = !1;
for (const g in j)
if (!u.hasOwnProperty(g) || j[g] !== u[g]) {
b = !0;
break;
}
b && h(j);
}, [v]), {
nodeIdWithNode: E,
nodeParentIdMapWithChildIdSet: v,
numberOfNodes: f,
nodesLength: i,
childrenInitialized: p,
parentChildStructure: u
};
}
function rt({
nodes: n,
edges: o,
selectedNodes: r,
layoutHidden: c,
calculateLayout: s,
updateNodes: a,
updateEdges: d,
setLayoutInProgress: l,
setNodeSpacing: u,
setLayerSpacing: h
}) {
const i = Be(), m = ue(null), p = ue(null);
return {
applyLayout: te(async (E = [], v = []) => {
m.current && m.current.abort();
const f = new AbortController();
m.current = f;
const j = E.length > 0 ? E : n, b = v.length > 0 ? v : o;
if (j.length === 0)
return { nodes: j, edges: b };
try {
if (l(!0), f.signal.aborted)
return { nodes: j, edges: b };
const { nodes: g, edges: x } = qe(j, b, c), y = await s(g, x, r, f.signal);
return f.signal.aborted ? { nodes: j, edges: b } : (m.current === f && (a ? a(y.nodes) : i != null && i.setNodes && i.setNodes(y.nodes), d ? d(y.edges) : i != null && i.setEdges && i.setEdges(y.edges), p.current && (p.current.node !== void 0 && u(p.current.node), p.current.layer !== void 0 && h(p.current.layer), p.current = null)), y);
} catch (g) {
return f.signal.aborted || console.error("Error applying layout:", g), { nodes: j, edges: b };
} finally {
m.current === f && (l(!1), m.current = null);
}
}, [
n,
o,
r,
s,
a,
d,
i,
c,
l,
u,
h
]),
pendingSpacingUpdateRef: p
};
}
const nt = (n, o, r = "no-parent") => {
const c = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Map();
n.forEach((l, u) => {
const h = o.get(u);
h && s.set(u, {
id: u,
node: h,
children: [],
depth: 0
});
});
const a = (l, u) => {
if (c.has(l) || !n.has(l) || !o.get(l)) return null;
c.add(l);
const i = s.get(l);
i.depth = u;
const m = n.get(l) || /* @__PURE__ */ new Set();
for (const p of m)
if (n.has(p) && o.get(p)) {
const E = a(p, u + 1);
E && i.children.push(E);
}
return i;
}, d = [];
return n.forEach((l, u) => {
const h = o.get(u);
if (h) {
const i = h.parentId;
if (!i || i === r) {
const m = a(u, 0);
m && d.push(m);
}
}
}), d;
};
function ye(n, o, r = "no-parent") {
const c = [];
let s = n;
const a = /* @__PURE__ */ new Set();
for (; s && s !== r; ) {
if (a.has(s)) {
console.warn(`Cycle detected in ancestor path for node ${n}`);
break;
}
a.add(s), c.push(s);
const d = o.get(s);
if (!d || !d.parentId) {
s = r;
break;
}
s = d.parentId;
}
return s === r && c.push(r), c;
}
function st(n, o, r, c = "no-parent") {
const s = ye(n, r, c), a = ye(o, r, c), d = new Set(a);
let l = null, u = -1;
for (let p = 0; p < s.length; p++)
if (d.has(s[p])) {
l = s[p], u = p;
break;
}
if (!l)
return { lca: null, sourceChild: null, targetChild: null };
const h = a.indexOf(l), i = u > 0 ? s[u - 1] : n, m = h > 0 ? a[h - 1] : o;
return { lca: l, sourceChild: i, targetChild: m };
}
function ve(n, o, r = "no-parent") {
const c = /* @__PURE__ */ new Map();
for (const s of n) {
const { lca: a, sourceChild: d, targetChild: l } = st(
s.source,
s.target,
o,
r
);
if (a && d && l && d !== l) {
const u = JSON.parse(JSON.stringify(s));
u.source = d, u.target = l, u.id = `temp_${u.id}_${a}`, u.data = {
...u.data,
isTemporary: !0,
originalSource: s.source,
originalTarget: s.target
}, c.has(a) || c.set(a, []), c.get(a).push(u);
}
}
return c;
}
const ce = 10, Te = async (n, o, r, c, s, a = ce, d = 50, l = 50, u = 172, h = 36, i = oe, m = !1, p = "no-parent") => {
const T = ve(s, c, p), { updatedNodes: E } = await ae(
n,
o,
r,
c,
s,
a,
d,
l,
u,
h,
i,
m,
T
), v = c.get(n);
if (!v)
return { updatedNodes: E, updatedEdges: s };
const { updatedNodes: f } = await Te(
v.parentId || p,
o,
r,
c,
s,
a,
d,
l,
u,
h,
i,
m,
p
);
return {
updatedNodes: [...f, ...E],
updatedEdges: s
// Always return original edges unchanged
};
}, ae = async (n, o, r, c, s, a = ce, d = 50, l = 50, u = 172, h = 36, i = oe, m = !1, p = /* @__PURE__ */ new Map()) => {
const T = r.get(n);
if (!T || T.size === 0)
return { updatedNodes: [] };
const E = [];
if (T.forEach((R) => {
const L = c.get(R);
L && E.push(L);
}), E.length === 0)
return { updatedNodes: [] };
let v = o;
const f = c.get(n);
f && f.data.layoutDirection && (v = f.data.layoutDirection);
const j = p.get(n) || [], { nodes: b, edges: g, width: x, height: y } = await i(
E,
j,
// Only use temporary edges for layout
v,
a,
d,
l,
u,
h,
m
);
return f && x && y && ot(f, x, y), {
updatedNodes: [...b],
udpatedParentNode: f || void 0
};
}, ot = (n, o, r) => (n.style || (n.style = {}), n.width = o, n.height = r, n.measured = {
width: o,
height: r
}, n.style.width = o, n.style.height = r, n), it = async (n, o, r, c, s, a = ce, d = 50, l = 50, u = 172, h = 36, i = oe, m = !1, p = "no-parent") => {
let T = [];
const E = ve(s, c, p), v = /* @__PURE__ */ new Map();
let f = 0;
const j = (g, x) => {
x > f && (f = x);
for (const y of g)
v.has(x) || v.set(x, []), v.get(x).push(y.id), y.children.length > 0 && j(y.children, x + 1);
};
j(n, 0);
for (let g = f; g >= 0; g--) {
const x = v.get(g) || [], y = await Promise.all(x.map(
(R) => ae(
R,
o,
r,
c,
s,
// Pass original edges (only used for returning)
a,
d,
l,
u,
h,
i,
m,
E
// Pass the global temporary edges map
)
));
for (const { updatedNodes: R } of y)
T = [...R, ...T];
}
const { updatedNodes: b } = await ae(
p,
o,
r,
c,
s,
// Pass original edges (only used for returning)
a,
d,
l,
u,
h,
i,
m,
E
// Process root-level temporary edges
);
return T = [...b, ...T], {
updatedNodes: T,
updatedEdges: s
// Always return original edges unchanged
};
}, at = (n, o, r, c = "no-parent") => {
const s = n.map((h) => h.id), a = n.map((h) => {
var i;
return ((i = r.get(h.id)) == null ? void 0 : i.parentId) || h.parentId;
}).filter((h) => !!h), l = Array.from(
/* @__PURE__ */ new Set([...s, ...a])
).filter((h) => o.has(h)), u = l.filter((h) => {
const i = r.get(h);
return i ? !i.parentId || !l.includes(i.parentId) : !0;
});
return u.length === 0 ? [c] : u;
}, ct = async (n, o, r) => {
const {
dagreDirection: c,
nodeParentIdMapWithChildIdSet: s,
nodeIdWithNode: a,
nodes: d,
edges: l,
margin: u,
nodeSpacing: h,
layerSpacing: i,
nodeWidth: m,
nodeHeight: p,
layoutHidden: T = !1,
noParentKey: E = "no-parent"
} = o, v = at(
n,
s,
a,
E
);
if (v.length === 0)
return { nodes: d, edges: l };
const f = /* @__PURE__ */ new Map(), j = /* @__PURE__ */ new Map();
if (r != null && r.aborted)
return { nodes: d, edges: l };
(await Promise.all(
v.map(async (y) => r != null && r.aborted ? { updatedNodes: [], updatedEdges: [] } : Te(
y,
c,
s,
a,
l,
u,
h,
i,
m,
p,
void 0,
T
))
)).forEach(({ updatedNodes: y, updatedEdges: R }) => {
y.forEach((L) => {
f.set(L.id, L);
}), R.forEach((L) => {
j.set(L.id, L);
});
});
const g = d.map(
(y) => f.has(y.id) ? f.get(y.id) : y
), x = l.map(
(y) => j.has(y.id) ? j.get(y.id) : y
);
return { nodes: g, edges: x };
}, lt = (n, o, r, c, s, a, d, l, u = 172, h = 36, i = !1, m = "no-parent") => ({ calculateLayout: te(async (T, E, v, f) => {
if (!(n[r] || n.dagre))
return console.error(`Layout engine "${r}" not found`), { nodes: T, edges: E };
const b = i ? T : T.filter((N) => !N.hidden), g = new Set(b.map((N) => N.id)), x = i ? E : E.filter(
(N) => g.has(N.source) && g.has(N.target)
), y = Ye(o), R = c.padding.horizontal;
let L = [], B = [];
if (v && v.length > 0) {
const N = i ? v : v.filter((D) => !D.hidden), _ = await ct(
N,
{
dagreDirection: y,
nodeParentIdMapWithChildIdSet: s,
nodeIdWithNode: a,
nodes: b,
edges: x,
margin: R,
nodeSpacing: d,
layerSpacing: l,
nodeWidth: u,
nodeHeight: h,
layoutHidden: i,
noParentKey: m
},
f
);
L = _.nodes, B = _.edges;
} else {
if (f != null && f.aborted)
return { nodes: T, edges: E };
const N = nt(s, a, m), _ = await it(
N,
y,
s,
a,
x,
R,
d,
l,
u,
h,
void 0,
i,
m
);
L = _.updatedNodes, B = _.updatedEdges;
}
return {
nodes: T.map((N) => !i && N.hidden ? N : L.find((D) => D.id === N.id) || N),
edges: B
};
}, [
r,
o,
n,
c.padding.horizontal,
s,
a,
d,
l,
u,
h,
i,
m
]) });
function ft({
children: n,
initialDirection: o = "DOWN",
initialAlgorithm: r = "layered",
initialAutoLayout: c = !0,
initialPadding: s = 50,
initialSpacing: a = { node: 50, layer: 50 },
initialNodeDimensions: d = { width: 172, height: 36 },
initialParentResizingOptions: l,
includeHidden: u = !1,
layoutEngines: h,
updateNodes: i,
updateEdges: m,
nodeParentIdMapWithChildIdSet: p,
nodeIdWithNode: T,
noParentKey: E = "no-parent",
disableAutoLayoutEffect: v = !1
}) {
const f = Ie(), j = We(), {
direction: b,
algorithm: g,
autoLayout: x,
layoutInProgress: y,
layoutHidden: R,
layoutEngines: L,
layoutEngineOptions: B,
padding: G,
nodeSpacing: N,
layerSpacing: _,
nodeWidth: D,
nodeHeight: Y,
parentResizingOptions: F,
selectedNodes: $,
setDirection: V,
setAlgorithm: J,
setAutoLayout: q,
setLayoutInProgress: H,
setLayoutHidden: t,
setLayoutEngines: w,
setLayoutEngineOptions: k,
setPadding: O,
setNodeSpacing: M,
setLayerSpacing: A,
setNodeWidth: X,
setNodeHeight: Z,
setParentResizingOptionsState: S,
setSelectedNodes: W
} = et({
initialDirection: o,
initialAlgorithm: r,
initialAutoLayout: c,
initialPadding: s,
initialSpacing: a,
initialNodeDimensions: d,
initialParentResizingOptions: l,
includeHidden: u,
layoutEngines: h
}), {
nodeIdWithNode: U,
nodeParentIdMapWithChildIdSet: ne,
numberOfNodes: ke,
nodesLength: Re,
childrenInitialized: le,
parentChildStructure: Ne
} = tt({
nodes: f,
externalNodeIdWithNode: T,
externalNodeParentIdMapWithChildIdSet: p,
noParentKey: E
}), Le = te(({ nodes: z }) => {
W(z);
}, [W]);
Fe({
onChange: Le
});
const { calculateLayout: Ce } = lt(
L,
b,
g,
F,
ne,
U,
N,
_,
D,
Y,
R,
E
), { applyLayout: de } = rt({
nodes: f,
edges: j,
selectedNodes: $,
layoutHidden: R,
calculateLayout: Ce,
updateNodes: i,
updateEdges: m,
setLayoutInProgress: H,
setNodeSpacing: M,
setLayerSpacing: A
}), Se = te((z, ie) => {
w((Ae) => ({ ...Ae, [z]: ie }));
}, [w]), Oe = te((z) => {
S((ie) => ({
...ie,
...z,
enabled: x
}));
}, [x, S]);
ee(() => {
var z;
v || U.has((z = f[f.length - 1]) == null ? void 0 : z.id) && le && x && de();
}, [le, x, b, ke, N, _, Ne, Re]);
const _e = {
direction: b,
algorithm: g,
autoLayout: x,
layoutInProgress: y,
padding: G,
nodeSpacing: N,
layerSpacing: _,
nodeWidth: D,
nodeHeight: Y,
layoutHidden: R,
parentResizingOptions: F,
layoutEngines: L,
layoutEngineOptions: B,
nodeParentIdMapWithChildIdSet: ne,
nodeIdWithNode: U,
noParentKey: E,
updateNodes: i,
updateEdges: m,
setDirection: V,
setAlgorithm: J,
setAutoLayout: q,
setLayoutInProgress: H,
setPadding: O,
setNodeSpacing: M,
setLayerSpacing: A,
setNodeWidth: X,
setNodeHeight: Z,
setLayoutHidden: t,
setParentResizingOptions: Oe,
setLayoutEngineOptions: k,
applyLayout: de,
clearLayoutCache: () => {
},
registerLayoutEngine: Se
};
return /* @__PURE__ */ e.jsx(Ee.Provider, { value: _e, children: n });
}
const me = ({
compact: n = !1
}) => {
const {
direction: o,
setDirection: r,
clearLayoutCache: c
} = re(), s = (a) => {
r(a), c && c();
};
return n ? /* @__PURE__ */ e.jsx(
P,
{
onClick: () => s(o === "DOWN" ? "RIGHT" : "DOWN"),
title: `Switch to ${o === "DOWN" ? "horizontal" : "vertical"} layout`,
children: /* @__PURE__ */ e.jsx("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: o === "DOWN" ? (
// Horizontal layout icon
/* @__PURE__ */ e.jsx("path", { d: "M4 12h16M16 6l6 6-6 6" })
) : (
// Vertical layout icon
/* @__PURE__ */ e.jsx("path", { d: "M12 4v16M6 16l6 6 6-6" })
) })
}
) : /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
/* @__PURE__ */ e.jsx(
P,
{
onClick: () => s("DOWN"),
className: o === "DOWN" ? "selected" : "",
title: "Top to Bottom",
children: /* @__PURE__ */ e.jsx("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: /* @__PURE__ */ e.jsx("path", { d: "M12 4v16M6 16l6 6 6-6" }) })
}
),
/* @__PURE__ */ e.jsx(
P,
{
onClick: () => s("RIGHT"),
className: o === "RIGHT" ? "selected" : "",
title: "Left to Right",
children: /* @__PURE__ */ e.jsx("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: /* @__PURE__ */ e.jsx("path", { d: "M4 12h16M16 6l6 6-6 6" }) })
}
),
/* @__PURE__ */ e.jsx(
P,
{
onClick: () => s("LEFT"),
className: o === "LEFT" ? "selected" : "",
title: "Right to Left",
children: /* @__PURE__ */ e.jsx("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: /* @__PURE__ */ e.jsx("path", { d: "M20 12H4M8 6L2 12l6 6" }) })
}
),
/* @__PURE__ */ e.jsx(
P,
{
onClick: () => s("UP"),
className: o === "UP" ? "selected" : "",
title: "Bottom to Top",
children: /* @__PURE__ */ e.jsx("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: /* @__PURE__ */ e.jsx("path", { d: "M12 20V4M6 8l6-6 6 6" }) })
}
)
] });
}, we = ({
compact: n = !1
}) => {
const {
nodeSpacing: o,
layerSpacing: r,
setNodeSpacing: c,
setLayerSpacing: s,
clearLayoutCache: a
} = re(), [d, l] = C(!1), u = (i) => {
c(i), a && a();
}, h = (i) => {
s(i), a && a();
};
return n ? /* @__PURE__ */ e.jsxs("div", { style: { position: "relative" }, children: [
/* @__PURE__ */ e.jsx(
P,
{
onClick: () => l(!d),
title: "Adjust node and layer spacing",
children: /* @__PURE__ */ e.jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [
/* @__PURE__ */ e.jsx("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("path", { d: "M7 10v4M17 10v4M10 7h4M10 17h4" })
] })
}
),
d && /* @__PURE__ */ e.jsxs(
"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__ */ e.jsxs("div", { style: { marginBottom: "12px" }, children: [
/* @__PURE__ */ e.jsxs("div", { style: { fontWeight: "bold", marginBottom: "4px" }, children: [
"Node Spacing: ",
o,
"px"
] }),
/* @__PURE__ */ e.jsx("div", { style: { display: "flex", gap: "4px" }, children: [50, 100, 150, 200].map((i) => /* @__PURE__ */ e.jsx(
"button",
{
onClick: () => u(i),
style: {
background: o === i ? "#0041d0" : "#f5f5f5",
color: o === i ? "white" : "inherit",
border: "1px solid #ddd",
borderRadius: "4px",
padding: "4px 8px",
cursor: "pointer"
},
children: i
},
i
)) })
] }),
/* @__PURE__ */ e.jsxs("div", { children: [
/* @__PURE__ */ e.jsxs("div", { style: { fontWeight: "bold", marginBottom: "4px" }, children: [
"Layer Spacing: ",
r,
"px"
] }),
/* @__PURE__ */ e.jsx("div", { style: { display: "flex", gap: "4px" }, children: [50, 100, 150, 200].map((i) => /* @__PURE__ */ e.jsx(
"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__ */ e.jsx("div", { style: { marginTop: "12px", textAlign: "right" }, children: /* @__PURE__ */ e.jsx(
"button",
{
onClick: () => l(!1),
style: {
background: "#f5f5f5",
border: "1px solid #ddd",
borderRadius: "4px",
padding: "4px 8px",
cursor: "pointer"
},
children: "Close"
}
) })
]
}
)
] }) : /* @__PURE__ */ e.jsxs("div", { className: "spacing-controls", children: [
/* @__PURE__ */ e.jsxs(
P,
{
onClick: () => u(Math.max(50, o - 25)),
title: "Decrease node spacing",
children: [
/* @__PURE__ */ e.jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [
/* @__PURE__ */ e.jsx("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("line", { x1: "7", y1: "10", x2: "7", y2: "14" }),
/* @__PURE__ */ e.jsx("line", { x1: "17", y1: "10", x2: "17", y2: "14" }),
/* @__PURE__ */ e.jsx("line", { x1: "10", y1: "7", x2: "14", y2: "7" }),
/* @__PURE__ */ e.jsx("line", { x1: "10", y1: "17", x2: "14", y2: "17" })
] }),
/* @__PURE__ */ e.jsx("span", { style: { marginLeft: "4px" }, children: "-" })
]
}
),
/* @__PURE__ */ e.jsxs("div", { style: {
display: "inline-flex",
alignItems: "center",
padding: "5px 10px",
fontSize: "12px",
background: "#f8f8f8",
borderRadius: "4px",
margin: "0 4px",
border: "1px solid #ddd"
}, children: [
o,
"px"
] }),
/* @__PURE__ */ e.jsxs(
P,
{
onClick: () => u(Math.min(300, o + 25)),
title: "Increase node spacing",
children: [
/* @__PURE__ */ e.jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [
/* @__PURE__ */ e.jsx("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }),
/* @__PURE__ */ e.jsx("line", { x1: "7", y1: "10", x2: "7", y2: "14" }),
/* @__PURE__ */ e.jsx("line", { x1: "17", y1: "10", x2: "17", y2: "14" }),
/* @__PURE__ */ e.jsx("line", { x1: "10", y1: "7", x2: "14", y2: "7" }),
/* @__PURE__ */ e.jsx("line", { x1: "10", y1: "17", x2: "14", y2: "17" })
] }),
/* @__PURE__ */ e.jsx("span", { style: { marginLeft: "4px" }, children: "+" })
]
}
),
/* @__PURE__ */ e.jsx("div", { style: { display: "inline-block", width: "1px", height: "24px", background: "#ddd", margin: "0 10px" } }),
/* @__PURE__ */ e.jsxs(
P,
{
onClick: () => h(Math.max(50, r - 25)),
title: "Decrease layer spacing",
children: [
/* @__PURE__ */ e.jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [
/* @__PURE__ */ e.jsx("line", { x1: "4", y1: "6", x2: "20", y2: "6" }),
/* @__PURE__ */ e.jsx("line", { x1: "4", y1: "12", x2: "20", y2: "12" }),
/* @__PURE__ */ e.jsx("line", { x1: "4", y1: "18", x2: "20", y2: "18" })
] }),
/* @__PURE__ */ e.jsx("span", { style: { marginLeft: "4px" }, children: "-" })
]
}
),
/* @__PURE__ */ e.jsxs("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__ */ e.jsxs(
P,
{
onClick: () => h(Math.min(300, r + 25)),
title: "Increase layer spacing",
children: [
/* @__PURE__ */ e.jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "2", fill: "none", children: [
/* @__PURE__ */ e.jsx("line", { x1: "4", y1: "6", x2: "20", y2: "6" }),
/* @__PURE__ */ e.jsx("line", { x1: "4", y1: "12", x2: "20", y2: "12" }),
/* @__PURE__ */ e.jsx("line", { x1: "4", y1: "18", x2: "20", y2: "18" })
] }),
/* @__PURE__ */ e.jsx("span", { style: { marginLeft: "4px" }, children: "+" })
]
}
)
] });
}, je = ({
compact: n = !1
}) => {
const {
autoLayout: o,
setAutoLayout: r
} = re(), c = () => {
r(!o);
};
return /* @__PURE__ */ e.jsx(
P,
{
onClick: c,
className: o ? "selected" : "",
title: o ? "Disable automatic layout" : "Enable automatic layout",
style: { color: o ? "green" : "inherit" },
children: n ? /* @__PURE__ */ e.jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "1.5", fill: "none", children: [
/* @__PURE__ */ e.jsx("rect", { x: "4", y: "4", width: "4", height: "4", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "4", y: "16", width: "4", height: "4", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "16", y: "10", width: "4", height: "4", rx: "1" }),
/* @__PURE__ */ e.jsxs(e.Fragment, { children: [
/* @__PURE__ */ e.jsx("path", { d: "M8 6c6 0 3 8 8 6" }),
/* @__PURE__ */ e.jsx("path", { d: "M8 18c3-3 2-8 6-6" })
] })
] }) : /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
"Auto-Layout ",
o ? "ON" : "OFF"
] })
}
);
}, be = ({
compact: n = !1
}) => {
const {
layoutInProgress: o,
setLayoutInProgress: r,
applyLayout: c
} = re(), s = async () => {
if (!o)
try {
r(!0), await c();
} catch (a) {
console.error("Error applying layout:", a);
}
};
return /* @__PURE__ */ e.jsxs(
P,
{
onClick: s,
title: "Apply layout",
disabled: o,
style: { color: o ? "#999" : "#000" },
children: [
/* @__PURE__ */ e.jsxs("svg", { viewBox: "0 0 24 24", width: "16", height: "16", stroke: "currentColor", strokeWidth: "1.5", fill: "none", children: [
/* @__PURE__ */ e.jsx("rect", { x: "3", y: "3", width: "5", height: "5", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "16", y: "3", width: "5", height: "5", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "3", y: "16", width: "5", height: "5", rx: "1" }),
/* @__PURE__ */ e.jsx("rect", { x: "16", y: "16", width: "5", height: "5", rx: "1" }),
/* @__PURE__ */ e.jsx("path", { d: "M8 5.5h8M5.5 8v8M18.5 8v8M8 18.5h8" }),
/* @__PURE__ */ e.jsx("circle", { cx: "12", cy: "12", r: "3" }),
/* @__PURE__ */ e.jsx("path", { d: "M11 10.5v3l2-1.5z", fill: "currentColor" })
] }),
!n && /* @__PURE__ */ e.jsx("span", { style: { marginLeft: "4px" }, children: "Apply Layout" })
]
}
);
}, pt = ({
showDirectionControls: n = !0,
showSpacingControls: o = !0,
showAutoLayoutToggle: r = !0,
showApplyLayoutButton: c = !0,
// Enable by default
standalone: s = !1,
position: a = "top-right"
}) => {
const d = re(), {
autoLayout: l
} = d;
return s ? /* @__PURE__ */ e.jsxs(ze, { position: a, showZoom: !1, showFitView: !1, showInteractive: !1, children: [
c && !l && /* @__PURE__ */ e.jsx(
be,
{
compact: !0
}
),
n && /* @__PURE__ */ e.jsx(
me,
{
compact: !0
}
),
o && /* @__PURE__ */ e.jsx(
we,
{
compact: !0
}
),
r && /* @__PURE__ */ e.jsx(
je,
{
compact: !0
}
)
] }) : /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
c && !l && /* @__PURE__ */ e.jsx(
be,
{
compact: !0
}
),
n && /* @__PURE__ */ e.jsx(
me,
{
compact: !0
}
),
o && /* @__PURE__ */ e.jsx(
we,
{
compact: !0
}
),
r && /* @__PURE__ */ e.jsx(
je,
{
compact: !0
}
)
] });
};
export {
je as AutoLayoutToggle,
Qe as DagreEngine,
me as DirectionControls,
pt as LayoutControls,
ft as LayoutProvider,
we as SpacingControls,
Ke as engines,
re as useLayoutContext
};