@dschz/solid-flow 0.3.0-next.0 → 0.3.0-next.1

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,8 +1,7 @@
1
1
  import { Dynamic, Portal, addEvent, claimElement, className, createComponent, delegateEvents, effect, insert, isServer, memo, mergeProps, ref, setAttribute, setStyleProperty, spread, style, template } from "@solidjs/web";
2
- import { For, Show, createContext, createEffect, createMemo, createRenderEffect, createSignal, createStore, flush, mapArray, merge, omit, onCleanup, onSettled, snapshot, untrack, useContext } from "solid-js";
3
- import { ReactiveMap } from "@solid-primitives/map";
2
+ import { For, Show, createContext, createEffect, createMemo, createProjection, createSignal, createStore, flush, mapArray, merge, omit, onCleanup, onSettled, snapshot, untrack, useContext } from "solid-js";
4
3
  import { createMediaQuery } from "@solid-primitives/media";
5
- import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, SelectionMode, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getEdgeCenter, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition, updateAbsolutePositions, updateNodeInternals } from "@xyflow/system";
4
+ import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, SelectionMode, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
6
5
  import { createEventListener, createEventListenerMap } from "@solid-primitives/event-listener";
7
6
  //#region src/components/contexts/edgeId.tsx
8
7
  const EdgeIdContext = createContext(null);
@@ -280,7 +279,7 @@ const EdgeReconnectAnchor = (props) => {
280
279
  style: {}
281
280
  }), rest = omit(_props, "type", "class", "style", "position", "size", "reconnecting", "children"), { store, nodeLookup, edgeLookup, actions } = useInternalSolidFlow(), edgeId = useEdgeId(), [reconnecting, setReconnecting] = createSignal(!1);
282
281
  if (!edgeId()) throw Error("[solid-flow]: EdgeReconnectAnchor must be used within an Edge component");
283
- let edge = () => edgeLookup.get(edgeId()), onPointerDown = (event) => {
282
+ let edge = () => edgeLookup[edgeId()], onPointerDown = (event) => {
284
283
  if (event.button !== 0) return;
285
284
  setReconnecting(!0), store.onReconnectStart?.(event, edge(), _props.type);
286
285
  let opposite = _props.type === "target" ? {
@@ -825,689 +824,335 @@ const EdgeWrapper = (props) => {
825
824
  return props.style;
826
825
  }
827
826
  });
828
- }, getEdgeId = (connection) => {
829
- let { source, sourceHandle, target, targetHandle } = connection;
830
- return `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
831
- }, NodeConnectableContext = createContext(null);
832
- function useNodeConnectable() {
833
- let ctx = useContext(NodeConnectableContext);
834
- if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useNodeConnectable");
835
- return ctx;
836
- }
827
+ }, getDefaultFlowStateProps = () => ({
828
+ id: "1",
829
+ nodes: [],
830
+ edges: [],
831
+ nodeOrigin: [0, 0],
832
+ nodeExtent: infiniteExtent,
833
+ defaultEdgeOptions: {},
834
+ colorMode: "system",
835
+ colorModeSSR: "light",
836
+ connectionMode: "strict",
837
+ connectionLineType: "default",
838
+ connectionRadius: 20,
839
+ nodeDragThreshold: 1,
840
+ minZoom: .5,
841
+ maxZoom: 2,
842
+ selectionMode: "partial",
843
+ fitView: !1,
844
+ noPanClass: "nopan",
845
+ noDragClass: "nodrag",
846
+ noWheelClass: "nowheel",
847
+ autoPanOnNodeDrag: !0,
848
+ autoPanOnConnect: !0,
849
+ autoPanOnNodeFocus: !0,
850
+ autoPanOnSelection: !0,
851
+ autoPanSpeed: 15,
852
+ elevateEdgesOnSelect: !0,
853
+ nodesDraggable: !0,
854
+ nodesConnectable: !0,
855
+ nodesFocusable: !0,
856
+ edgesFocusable: !0,
857
+ elementsSelectable: !0,
858
+ selectNodesOnDrag: !0,
859
+ elevateNodesOnSelect: !0,
860
+ zIndexMode: "basic",
861
+ onlyRenderVisibleElements: !1,
862
+ disableKeyboardA11y: !1,
863
+ defaultMarkerColor: "#b1b1b7",
864
+ ariaLiveMessage: "",
865
+ style: {},
866
+ isValidConnection: (() => !0),
867
+ onFlowError: createDevWarn("Solid Flow", "https://solidflow.dev/")
868
+ });
837
869
  //#endregion
838
- //#region src/components/graph/handle/Handle.tsx
839
- var _tmpl$$29 = /* @__PURE__ */ template("<div>");
840
- const Handle = (props) => {
841
- let _props = propDefaults(props, {
842
- type: "source",
843
- position: "top",
844
- isConnectableStart: !0,
845
- isConnectableEnd: !0
846
- }), { store, nodeLookup, connectionLookup, actions } = useInternalSolidFlow(), rest = omit(_props, "id", "type", "position", "isConnectable", "isConnectableStart", "isConnectableEnd", "isValidConnection", "onConnect", "onDisconnect", "children", "class", "style"), nodeId = useNodeId(), nodeConnectable = useNodeConnectable(), connectable = () => _props.isConnectable ?? nodeConnectable(), isTarget = () => _props.type === "target", handleId = () => _props.id ?? null, connectionInProcess = () => !!store.connection.fromHandle, connectingFrom = () => store.connection.fromHandle && store.connection.fromHandle.nodeId === nodeId() && store.connection.fromHandle.type === _props.type && store.connection.fromHandle.id === handleId(), connectingTo = () => store.connection.toHandle && store.connection.toHandle.nodeId === nodeId() && store.connection.toHandle.type === _props.type && store.connection.toHandle.id === handleId(), isPossibleTargetHandle = () => store.connectionMode === "strict" ? store.connection.fromHandle?.type !== _props.type : nodeId() !== store.connection.fromHandle?.nodeId || handleId() !== store.connection.fromHandle?.id, valid = () => !!(connectingTo() && store.connection.isValid), prevConnections = null;
847
- createEffect(() => {
848
- if (!_props.onConnect && !_props.onDisconnect) return null;
849
- let connectionKey = `${nodeId()}-${_props.type}${_props.id ? `-${_props.id}` : ""}`;
850
- return { connections: connectionLookup.get(connectionKey) };
851
- }, (current) => {
852
- if (!current) return;
853
- let { connections } = current;
854
- if (prevConnections && !areConnectionMapsEqual(connections, prevConnections)) {
855
- let _connections = connections ?? /* @__PURE__ */ new Map();
856
- handleConnectionChange(prevConnections, _connections, props.onDisconnect), handleConnectionChange(_connections, prevConnections, props.onConnect);
870
+ //#region src/core/facades.ts
871
+ /**
872
+ * A read-only `Map` view over an id-keyed record projection, for
873
+ * @xyflow/system interop: system helpers take `Map`s, our reactive lookups
874
+ * are records. Every read passes through to the record, so reads inside
875
+ * tracked scopes subscribe normally — `get`/`has` check with `in` first,
876
+ * which also subscribes while the key is still absent (the projection
877
+ * absent-key footgun), and `size`/iteration read the key set structurally.
878
+ *
879
+ * The mutating `Map` methods throw: writes belong to the roots the
880
+ * projection derives from.
881
+ */
882
+ var RecordMapFacade = class {
883
+ #record;
884
+ constructor(record) {
885
+ this.#record = record;
886
+ }
887
+ get(key) {
888
+ return key in this.#record ? this.#record[key] : void 0;
889
+ }
890
+ has(key) {
891
+ return key in this.#record;
892
+ }
893
+ get size() {
894
+ return Object.keys(this.#record).length;
895
+ }
896
+ *keys() {
897
+ yield* Object.keys(this.#record);
898
+ }
899
+ *values() {
900
+ for (let key of Object.keys(this.#record)) yield this.#record[key];
901
+ }
902
+ *entries() {
903
+ for (let key of Object.keys(this.#record)) yield [key, this.#record[key]];
904
+ }
905
+ [Symbol.iterator]() {
906
+ return this.entries();
907
+ }
908
+ forEach(callback, thisArg) {
909
+ for (let [key, value] of this.entries()) callback.call(thisArg, value, key, this);
910
+ }
911
+ [Symbol.toStringTag] = "RecordMapFacade";
912
+ set() {
913
+ throw Error("RecordMapFacade is read-only; write to the projection's source roots");
914
+ }
915
+ getOrInsert() {
916
+ throw Error("RecordMapFacade is read-only; write to the projection's source roots");
917
+ }
918
+ getOrInsertComputed() {
919
+ throw Error("RecordMapFacade is read-only; write to the projection's source roots");
920
+ }
921
+ delete() {
922
+ throw Error("RecordMapFacade is read-only; write to the projection's source roots");
923
+ }
924
+ clear() {
925
+ throw Error("RecordMapFacade is read-only; write to the projection's source roots");
926
+ }
927
+ };
928
+ //#endregion
929
+ //#region src/core/projections/connections.ts
930
+ /**
931
+ * Lookup keys for the connection index. Each edge is registered under six
932
+ * keys — for both of its endpoints: the node, the node+handle-type, and (when
933
+ * a handle id is present) the node+type+handle:
934
+ * `${nodeId}` · `${nodeId}-${type}` · `${nodeId}-${type}-${handleId}`
935
+ */
936
+ const connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ? `-${type}-${handleId}` : `-${type}` : ""}`, pairKey = (aNode, aHandle, bNode, bHandle) => `${aNode}-${aHandle}--${bNode}-${bHandle}`, createConnections = (source) => createProjection(() => {
937
+ let out = {}, add = (key, entry, connection) => {
938
+ (out[key] ??= {})[entry] = connection;
939
+ };
940
+ for (let edge of source.edges) {
941
+ let sourceHandle = edge.sourceHandle ?? null, targetHandle = edge.targetHandle ?? null, connection = {
942
+ edgeId: edge.id,
943
+ source: edge.source,
944
+ target: edge.target,
945
+ sourceHandle,
946
+ targetHandle
947
+ }, sourceKey = pairKey(edge.source, sourceHandle, edge.target, targetHandle), targetKey = pairKey(edge.target, targetHandle, edge.source, sourceHandle);
948
+ add(edge.source, targetKey, connection), add(connectionKey(edge.source, "source"), targetKey, connection), sourceHandle && add(connectionKey(edge.source, "source", sourceHandle), targetKey, connection), add(edge.target, sourceKey, connection), add(connectionKey(edge.target, "target"), sourceKey, connection), targetHandle && add(connectionKey(edge.target, "target", targetHandle), sourceKey, connection);
949
+ }
950
+ return out;
951
+ }, {}, { key: "id" }), createEdgeLookup = (source) => createProjection(() => {
952
+ let out = {};
953
+ for (let edge of source.edges) out[edge.id] = edge;
954
+ return out;
955
+ }, {}, { key: "id" });
956
+ function isManualZIndexMode(zIndexMode) {
957
+ return zIndexMode === "manual";
958
+ }
959
+ function calculateZ(node, selectedNodeZ, zIndexMode) {
960
+ let zIndex = isNumeric(node.zIndex) ? node.zIndex : 0;
961
+ return isManualZIndexMode(zIndexMode) ? zIndex : zIndex + (node.selected ? selectedNodeZ : 0);
962
+ }
963
+ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (source) => {
964
+ let autoIndex = createMemo(() => {
965
+ if (source.zIndexMode !== "auto") return EMPTY_AUTO_INDEX;
966
+ let index = /* @__PURE__ */ new Map(), rootIds = /* @__PURE__ */ new Set();
967
+ for (let node of source.nodes) node.parentId ? rootIds.has(node.parentId) && !index.has(node.parentId) && index.set(node.parentId, index.size + 1) : rootIds.add(node.id);
968
+ return index;
969
+ }), entryById = /* @__PURE__ */ new Map(), rowStores = mapArray(() => source.nodes, (userNodeAccessor, index) => {
970
+ let id = userNodeAccessor().id, store = createProjection(() => {
971
+ let userNode = userNodeAccessor(), { nodeOrigin, nodeExtent, zIndexMode } = source, selectedNodeZ = source.elevateNodesOnSelect && !isManualZIndexMode(zIndexMode) ? 1e3 : 0, measurement = userNode.id in source.measurements ? source.measurements[userNode.id] : void 0, measured = {
972
+ width: userNode.measured?.width ?? measurement?.measured.width,
973
+ height: userNode.measured?.height ?? measurement?.measured.height
974
+ }, dimensions = getNodeDimensions({
975
+ measured,
976
+ width: userNode.width,
977
+ height: userNode.height,
978
+ initialWidth: userNode.initialWidth,
979
+ initialHeight: userNode.initialHeight
980
+ }), rootParentIndex = autoIndex().get(userNode.id), row = {
981
+ ...userNode,
982
+ measured,
983
+ internals: {
984
+ positionAbsolute: clampPosition(getNodePositionWithOrigin(userNode, nodeOrigin), isCoordinateExtent(userNode.extent) ? userNode.extent : nodeExtent, dimensions),
985
+ handleBounds: measurement?.handleBounds,
986
+ z: calculateZ(userNode, selectedNodeZ, zIndexMode) + (rootParentIndex === void 0 ? 0 : rootParentIndex * 10),
987
+ ...rootParentIndex === void 0 ? {} : { rootParentIndex },
988
+ userNode
989
+ }
990
+ };
991
+ if (userNode.parentId) {
992
+ let parentEntry = entryById.get(userNode.parentId);
993
+ if (parentEntry && parentEntry.index() < index()) {
994
+ let { x, y, z } = calculateChildXYZ(row, parentEntry.store.row, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode);
995
+ row.internals.positionAbsolute = {
996
+ x,
997
+ y
998
+ }, row.internals.z = z;
999
+ } else source.nodes.length;
1000
+ }
1001
+ if (userNode.parentId) {
1002
+ let parent = entryById.get(userNode.parentId);
1003
+ parent?.store.row.internals.positionAbsolute.x, parent?.store.row.internals.z;
1004
+ }
1005
+ return { row };
1006
+ }, {}, { key: "id" }), entry = {
1007
+ store,
1008
+ index
1009
+ };
1010
+ return entryById.set(id, entry), onCleanup(() => {
1011
+ entryById.get(id) === entry && entryById.delete(id);
1012
+ }), {
1013
+ id,
1014
+ store
1015
+ };
1016
+ }, { keyed: (userNode) => userNode.id }), assigned = /* @__PURE__ */ new Map();
1017
+ return createProjection((draft) => {
1018
+ let seen = /* @__PURE__ */ new Set();
1019
+ for (let { id, store } of rowStores()) {
1020
+ seen.add(id);
1021
+ let row = store.row;
1022
+ assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row);
857
1023
  }
858
- prevConnections = connections ?? /* @__PURE__ */ new Map();
1024
+ for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
1025
+ }, {}, {
1026
+ key: null,
1027
+ shallow: !0
859
1028
  });
860
- let onConnectExtended = (connection) => {
861
- let handleConnection = {
862
- ...connection,
863
- id: getEdgeId(connection)
864
- }, edge = store.onBeforeConnect?.(handleConnection) ?? handleConnection;
865
- actions.addEdge(edge), store.onConnect?.(handleConnection);
866
- }, onPointerDown = (event) => {
867
- XYHandle.onPointerDown(event, {
868
- handleId: handleId(),
869
- nodeId: nodeId(),
870
- isTarget: isTarget(),
871
- connectionRadius: store.connectionRadius,
872
- domNode: store.domNode,
873
- nodeLookup,
874
- connectionMode: store.connectionMode,
875
- lib: store.lib,
876
- autoPanOnConnect: store.autoPanOnConnect,
877
- flowId: store.id,
878
- isValidConnection: _props.isValidConnection ?? store.isValidConnection,
879
- updateConnection: ((connection) => {
880
- actions.setConnection(connection), flush();
881
- }),
882
- cancelConnection: actions.cancelConnection,
883
- panBy: actions.panBy,
884
- onConnect: onConnectExtended,
885
- onConnectStart: (event, startParams) => {
886
- store.onConnectStart?.(event, {
887
- nodeId: startParams.nodeId,
888
- handleId: startParams.handleId,
889
- handleType: startParams.handleType
890
- });
891
- },
892
- onConnectEnd: store.onConnectEnd,
893
- getTransform: () => store.transform,
894
- getFromHandle: () => store.connection.fromHandle,
895
- autoPanSpeed: store.autoPanSpeed,
896
- dragThreshold: store.connectionDragThreshold,
897
- handleDomNode: event.currentTarget
898
- });
899
- }, onClick = (event) => {
900
- if (!nodeId() || !store.clickConnectStartHandle && !_props.isConnectableStart) return;
901
- if (!store.clickConnectStartHandle) {
902
- store.onClickConnectStart?.(event, {
903
- nodeId: nodeId(),
904
- handleId: handleId(),
905
- handleType: _props.type
906
- }), actions.setClickConnectStartHandle({
907
- nodeId: nodeId(),
908
- type: _props.type,
909
- id: handleId()
910
- });
911
- return;
1029
+ };
1030
+ function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode) {
1031
+ let { x: parentX, y: parentY } = parentNode.internals.positionAbsolute, childDimensions = getNodeDimensions(childNode), positionWithOrigin = getNodePositionWithOrigin(childNode, nodeOrigin), clampedPosition = isCoordinateExtent(childNode.extent) ? clampPosition(positionWithOrigin, childNode.extent, childDimensions) : positionWithOrigin, absolutePosition = clampPosition({
1032
+ x: parentX + clampedPosition.x,
1033
+ y: parentY + clampedPosition.y
1034
+ }, nodeExtent, childDimensions);
1035
+ childNode.extent === "parent" && (absolutePosition = clampPositionToParent(absolutePosition, childDimensions, parentNode));
1036
+ let childZ = calculateZ(childNode, selectedNodeZ, zIndexMode), parentZ = parentNode.internals.z ?? 0;
1037
+ return {
1038
+ x: absolutePosition.x,
1039
+ y: absolutePosition.y,
1040
+ z: parentZ >= childZ ? parentZ + 1 : childZ
1041
+ };
1042
+ }
1043
+ //#endregion
1044
+ //#region src/core/projections/layoutedEdges.ts
1045
+ /**
1046
+ * Edge layout join: user edges × internal nodes → screen-space edge geometry,
1047
+ * decomposed into SUB-STORES (spike 13): each edge is its own keyed
1048
+ * projection holding `{ row }` — the layouted row, or null while the edge
1049
+ * produces none (missing/unready endpoints, culled) — and the public record
1050
+ * is a SHALLOW projection holding the PRESENT rows' proxies by reference.
1051
+ *
1052
+ * Reads chain: `record[id].sourceX` goes through the shallow slot into the
1053
+ * edge's own store, so every materialized leaf signal hangs off its EDGE's
1054
+ * computed (defeating rc.1's per-update companion walk — see
1055
+ * internalNodes.ts). The edge projection tracks exactly what the join reads —
1056
+ * the edge's props and its endpoints' geometry leaves through nodeLookup
1057
+ * (which chains into the node row stores) — so one node move re-runs only
1058
+ * the adjacent edges' projections; the record computed re-runs only when
1059
+ * membership or presence changes.
1060
+ *
1061
+ * The viewport participates only while onlyRenderVisibleElements is active —
1062
+ * panning must not touch edge rows otherwise.
1063
+ *
1064
+ * Rows whose endpoints are missing or unmeasured simply drop out of the
1065
+ * record — the same "no entry" contract the ReactiveMap pipeline had.
1066
+ */
1067
+ const createLayoutedEdges = (source) => {
1068
+ let rowStores = mapArray(() => source.edges, (edgeAccessor) => ({
1069
+ id: edgeAccessor().id,
1070
+ store: createProjection(() => {
1071
+ let edge = edgeAccessor(), row = buildRow(source, edge);
1072
+ return source.nodeLookup.get(edge.source)?.internals.handleBounds, source.nodeLookup.get(edge.target)?.internals.handleBounds, { row };
1073
+ }, { row: null }, { key: "id" })
1074
+ }), { keyed: (edge) => edge.id }), assigned = /* @__PURE__ */ new Map();
1075
+ return createProjection((draft) => {
1076
+ let seen = /* @__PURE__ */ new Set();
1077
+ for (let { id, store } of rowStores()) {
1078
+ let row = store.row;
1079
+ row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
912
1080
  }
913
- let doc = getHostForElement(event.target), isValidConnectionHandler = _props.isValidConnection ?? store.isValidConnection, { connection, isValid } = XYHandle.isValid(event, {
914
- handle: {
915
- nodeId: nodeId(),
916
- id: handleId(),
917
- type: _props.type
918
- },
919
- connectionMode: store.connectionMode,
920
- fromNodeId: store.clickConnectStartHandle.nodeId,
921
- fromHandleId: store.clickConnectStartHandle.id ?? null,
922
- fromType: store.clickConnectStartHandle.type,
923
- isValidConnection: isValidConnectionHandler,
924
- flowId: store.id,
925
- doc,
926
- lib: store.lib,
927
- nodeLookup
928
- });
929
- isValid && connection && onConnectExtended(connection);
930
- let connectionClone = structuredClone(snapshot(store.connection));
931
- delete connectionClone.inProgress, connectionClone.toPosition = connectionClone.toHandle ? connectionClone.toHandle.position : null, store.onClickConnectEnd?.(event, connectionClone), actions.setClickConnectStartHandle(void 0);
932
- }, connectionIndicator = () => connectable() && (!connectionInProcess() || isPossibleTargetHandle()) && (connectionInProcess() || store.clickConnectStartHandle ? _props.isConnectableEnd : _props.isConnectableStart);
933
- var _el$ = _tmpl$$29();
934
- return spread(_el$, mergeProps(rest, {
935
- role: "button",
936
- get "aria-label"() {
937
- return store.ariaLabelConfig["handle.ariaLabel"];
938
- },
939
- tabindex: -1,
940
- get "data-handleid"() {
941
- return handleId();
942
- },
943
- get "data-nodeid"() {
944
- return nodeId();
1081
+ for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
1082
+ }, {}, {
1083
+ key: null,
1084
+ shallow: !0
1085
+ });
1086
+ }, buildRow = (source, edge) => {
1087
+ let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
1088
+ if (!sourceNode || !targetNode) return source.nodeLookup.size, null;
1089
+ if (source.onlyRenderVisibleElements && !isEdgeVisible({
1090
+ sourceNode,
1091
+ targetNode,
1092
+ width: source.width ?? 0,
1093
+ height: source.height ?? 0,
1094
+ transform: source.transform
1095
+ })) return null;
1096
+ let edgePosition = getEdgePosition({
1097
+ id: edge.id,
1098
+ sourceNode,
1099
+ targetNode,
1100
+ sourceHandle: edge.sourceHandle || null,
1101
+ targetHandle: edge.targetHandle || null,
1102
+ connectionMode: source.connectionMode,
1103
+ onError: source.onError
1104
+ });
1105
+ return edgePosition ? {
1106
+ ...source.defaultEdgeOptions,
1107
+ ...edge,
1108
+ ...edgePosition,
1109
+ zIndex: getElevatedEdgeZIndex({
1110
+ selected: edge.selected,
1111
+ zIndex: edge.zIndex ?? source.defaultEdgeOptions.zIndex,
1112
+ sourceNode,
1113
+ targetNode,
1114
+ elevateOnSelect: source.elevateEdgesOnSelect,
1115
+ zIndexMode: source.zIndexMode
1116
+ }),
1117
+ sourceNode,
1118
+ targetNode,
1119
+ edge
1120
+ } : null;
1121
+ }, createParentIds = (source) => createProjection(() => {
1122
+ let out = {};
1123
+ for (let node of source.nodes) node.parentId && (out[node.parentId] = !0);
1124
+ return out;
1125
+ }, {}, { key: "id" }), getInitialViewport = (fitView, initialViewport, width, height, nodeLookup) => {
1126
+ if (fitView && !initialViewport && width && height) {
1127
+ let bounds = getInternalNodesBounds(nodeLookup, { filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)) });
1128
+ return getViewportForBounds$1(bounds, width, height, .5, 2, .1);
1129
+ }
1130
+ return initialViewport ?? {
1131
+ x: 0,
1132
+ y: 0,
1133
+ zoom: 1
1134
+ };
1135
+ }, createFlowState = (props, injections = {}) => {
1136
+ let _props = merge(getDefaultFlowStateProps(), props), initialNodeTypes = injections.initialNodeTypes ?? {}, initialEdgeTypes = injections.initialEdgeTypes ?? {}, prefersDark = injections.prefersDark ?? (() => _props.colorModeSSR === "dark"), [config, setConfig] = createSignal(_props), [ariaLabelConfig, setAriaLabelConfig] = createSignal(() => mergeAriaLabelConfig(config().ariaLabelConfig)), [ariaLiveMessage, setAriaLiveMessage] = createSignal(() => config().ariaLiveMessage), [clickConnectStartHandle, setClickConnectStartHandle] = createSignal(void 0), [connection, setConnection] = createSignal(initialConnection), [domNode, setDomNode] = createSignal(null), [dragging, setDragging] = createSignal(!1), [elementsSelectable, setElementsSelectable] = createSignal(() => config().elementsSelectable), [height, setHeight] = createSignal(() => config().height), [minZoom, _setMinZoom] = createSignal(() => config().minZoom), [maxZoom, _setMaxZoom] = createSignal(() => config().maxZoom), [nodesConnectable, setNodesConnectable] = createSignal(() => config().nodesDraggable), [nodesDraggable, setNodesDraggable] = createSignal(() => config().nodesDraggable), [panZoom, setPanZoom] = createSignal(null), [selectionRect, setSelectionRect] = createSignal(), [selectionRectMode, setSelectionRectMode] = createSignal(), [snapGrid, setSnapGrid] = createSignal(() => config().snapGrid), [translateExtent, _setTranslateExtent] = createSignal(() => config().translateExtent ?? infiniteExtent), [width, setWidth] = createSignal(() => config().width), [selectionKeyPressed, setSelectionKeyPressed] = createSignal(!1), [multiselectionKeyPressed, setMultiselectionKeyPressed] = createSignal(!1), [deleteKeyPressed, setDeleteKeyPressed] = createSignal(!1), [panActivationKeyPressed, setPanActivationKeyPressed] = createSignal(!1), [zoomActivationKeyPressed, setZoomActivationKeyPressed] = createSignal(!1), [nodesStore, setNodesStore] = createStore(_props.nodes), [edgesStore, setEdgesStore] = createStore(_props.edges), [measurementsStore, setMeasurementsStore] = createStore({}), internalNodes = createInternalNodes({
1137
+ get nodes() {
1138
+ return nodesStore;
945
1139
  },
946
- get "data-handlepos"() {
947
- return _props.position;
1140
+ get measurements() {
1141
+ return measurementsStore;
948
1142
  },
949
- get "data-id"() {
950
- return `${store.id}-${nodeId()}-${_props.id || null}-${_props.type}`;
1143
+ get nodeOrigin() {
1144
+ return config().nodeOrigin;
951
1145
  },
952
- get onClick() {
953
- return store.clickConnect ? onClick : void 0;
1146
+ get nodeExtent() {
1147
+ return config().nodeExtent;
954
1148
  },
955
- onPointerDown,
956
- get style() {
957
- return _props.style;
1149
+ get elevateNodesOnSelect() {
1150
+ return config().elevateNodesOnSelect;
958
1151
  },
959
- get class() {
960
- return [
961
- "solid-flow__handle",
962
- `solid-flow__handle-${_props.position}`,
963
- store.noDragClass,
964
- store.noPanClass,
965
- _props.class,
966
- {
967
- valid: valid(),
968
- connectingto: !!connectingTo(),
969
- connectingfrom: !!connectingFrom(),
970
- source: !isTarget(),
971
- target: isTarget(),
972
- connectablestart: _props.isConnectableStart,
973
- connectableend: _props.isConnectableEnd,
974
- connectable: !!connectable(),
975
- connectionindicator: connectionIndicator()
976
- }
977
- ];
1152
+ get zIndexMode() {
1153
+ return config().zIndexMode;
978
1154
  }
979
- }), !0), insert(_el$, () => _props.children), _el$;
980
- }, DefaultNode = (props) => {
981
- let _props = propDefaults(props, {
982
- targetPosition: Position$1.Top,
983
- sourcePosition: Position$1.Bottom
984
- });
985
- return [
986
- createComponent(Handle, {
987
- type: "target",
988
- get position() {
989
- return _props.targetPosition;
990
- },
991
- get isConnectable() {
992
- return _props.isConnectable;
993
- }
994
- }),
995
- memo(() => props.data.label),
996
- createComponent(Handle, {
997
- type: "source",
998
- get position() {
999
- return _props.sourcePosition;
1000
- },
1001
- get isConnectable() {
1002
- return _props.isConnectable;
1003
- }
1004
- })
1005
- ];
1006
- };
1007
- //#endregion
1008
- //#region src/components/graph/node/GroupNode.tsx
1009
- var _tmpl$$28 = /* @__PURE__ */ template("<div style=position:absolute;left:0;top:0>");
1010
- const GroupNode = (props) => (() => {
1011
- var _el$ = _tmpl$$28();
1012
- return effect(() => ({
1013
- e: toPxString(props.width),
1014
- t: toPxString(props.height)
1015
- }), ({ e, t }, _p$) => {
1016
- e !== _p$?.e && setStyleProperty(_el$, "width", e), t !== _p$?.t && setStyleProperty(_el$, "height", t);
1017
- }), _el$;
1018
- })(), InputNode = (props) => {
1019
- let _props = propDefaults(props, { sourcePosition: Position$1.Bottom });
1020
- return [memo(() => props.data?.label), createComponent(Handle, {
1021
- type: "source",
1022
- get position() {
1023
- return _props.sourcePosition;
1024
- },
1025
- get isConnectable() {
1026
- return _props.isConnectable;
1027
- }
1028
- })];
1029
- }, createDraggable = (elem, params) => {
1030
- let { store, nodeLookup, actions } = useInternalSolidFlow(), [dragging, setDragging] = createSignal(!1);
1031
- return createEffect(() => ({
1032
- el: elem(),
1033
- current: params()
1034
- }), ({ el, current }) => {
1035
- if (!el || current.disabled) return;
1036
- let { onDrag, onDragStart, onDragStop, onNodeMouseDown } = current, dragInstance = XYDrag({
1037
- onDrag,
1038
- onDragStart: (event, dragItems, node, nodes) => {
1039
- setDragging(!0), onDragStart?.(event, dragItems, node, nodes);
1040
- },
1041
- onDragStop: (event, dragItems, node, nodes) => {
1042
- setDragging(!1), onDragStop?.(event, dragItems, node, nodes);
1043
- },
1044
- onNodeMouseDown,
1045
- getStoreItems: () => ({
1046
- nodes: store.nodes,
1047
- nodeLookup,
1048
- edges: store.edges,
1049
- nodeExtent: store.nodeExtent,
1050
- snapGrid: store.snapGrid ?? [0, 0],
1051
- snapToGrid: !!store.snapGrid,
1052
- autoPanSpeed: store.autoPanSpeed,
1053
- nodeOrigin: store.nodeOrigin,
1054
- multiSelectionActive: store.multiselectionKeyPressed,
1055
- domNode: store.domNode,
1056
- transform: store.transform,
1057
- autoPanOnNodeDrag: store.autoPanOnNodeDrag,
1058
- nodesDraggable: store.nodesDraggable,
1059
- selectNodesOnDrag: store.selectNodesOnDrag,
1060
- nodeDragThreshold: store.nodeDragThreshold,
1061
- unselectNodesAndEdges: actions.unselectNodesAndEdges,
1062
- updateNodePositions: actions.updateNodePositions,
1063
- panBy: actions.panBy
1064
- })
1065
- });
1066
- return dragInstance.update({
1067
- domNode: el,
1068
- nodeId: current.nodeId,
1069
- noDragClassName: current.noDragClass,
1070
- handleSelector: current.handleSelector,
1071
- isSelectable: current.isSelectable,
1072
- nodeClickDistance: current.nodeClickDistance
1073
- }), () => {
1074
- dragInstance.destroy();
1075
- };
1076
- }), dragging;
1077
- }, NodeIdContext = createContext(null);
1078
- function useNodeId() {
1079
- let ctx = useContext(NodeIdContext);
1080
- if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useNodeId");
1081
- return ctx;
1082
- }
1083
- //#endregion
1084
- //#region src/components/graph/node/NodeWrapper.tsx
1085
- var _tmpl$$27 = /* @__PURE__ */ template("<div>");
1086
- const NodeWrapper = (props) => {
1087
- let { store, nodeLookup, parentLookup, actions } = useInternalSolidFlow(), [nodeRef, setNodeRef] = createSignal(), node = () => nodeLookup.get(props.nodeId), nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeType()], isParentNode = () => parentLookup.has(node().id), transform = () => {
1088
- let { x, y } = node().internals.positionAbsolute;
1089
- return `translate(${x}px, ${y}px)`;
1090
- }, sizeStyle = () => {
1091
- let w = node().width ?? node().initialWidth, h = node().height ?? node().initialHeight;
1092
- return {
1093
- ...node().style,
1094
- ...w ? { width: toPxString(w) } : {},
1095
- ...h ? { height: toPxString(h) } : {}
1096
- };
1097
- }, style = () => ({
1098
- "z-index": node().internals.z,
1099
- transform: transform(),
1100
- visibility: nodeHasDimensions(node()) ? "visible" : "hidden",
1101
- ...sizeStyle(),
1102
- ...node().style ?? {}
1103
- });
1104
- createEffect(() => ({
1105
- valid: nodeTypeValid(),
1106
- nodeType: nodeType()
1107
- }), ({ valid, nodeType }) => {}), createEffect(() => ({
1108
- id: node().id,
1109
- nodeElement: nodeRef(),
1110
- nodeType: nodeType(),
1111
- sourcePosition: node().sourcePosition,
1112
- targetPosition: node().targetPosition
1113
- }), (current, prev) => {
1114
- current.nodeElement && (prev && prev.nodeElement === current.nodeElement && prev.sourcePosition === current.sourcePosition && prev.targetPosition === current.targetPosition && prev.nodeType === current.nodeType || actions.requestUpdateNodeInternals([[current.id, {
1115
- id: current.id,
1116
- nodeElement: current.nodeElement,
1117
- force: !0
1118
- }]]));
1119
- }), createEffect(() => ({
1120
- nodeElement: nodeRef(),
1121
- hasDimensions: nodeHasDimensions(node()),
1122
- resizeObserver: props.resizeObserver
1123
- }), (current, prev) => {
1124
- current.nodeElement === prev?.nodeElement && current.resizeObserver === prev?.resizeObserver && current.hasDimensions || (prev?.nodeElement && prev.resizeObserver?.unobserve(prev.nodeElement), current.nodeElement && current.resizeObserver?.observe(current.nodeElement));
1125
- });
1126
- let onSelectNodeHandler = (event) => {
1127
- selectable() && (!store.selectNodesOnDrag || !draggable() || store.nodeDragThreshold > 0) && actions.handleNodeSelection(node().id), props.onNodeClick?.({
1128
- node: userNode(),
1129
- event
1130
- });
1131
- }, onKeyDown = (event) => {
1132
- if (isInputDOMNode(event) || store.disableKeyboardA11y) return;
1133
- if (elementSelectionKeys.includes(event.key) && selectable()) {
1134
- actions.handleNodeSelection(node().id, event.key === "Escape", nodeRef());
1135
- return;
1136
- }
1137
- let arrowKeyDiff = ARROW_KEY_DIFFS[event.key];
1138
- draggable() && node().selected && arrowKeyDiff && (event.preventDefault(), actions.setAriaLiveMessage(store.ariaLabelConfig["node.a11yDescription.ariaLiveMessage"]({
1139
- direction: event.key.replace("Arrow", "").toLowerCase(),
1140
- x: ~~node().internals.positionAbsolute.x,
1141
- y: ~~node().internals.positionAbsolute.y
1142
- })), actions.moveSelectedNodes(arrowKeyDiff, event.shiftKey ? 4 : 1));
1143
- }, onFocus = () => {
1144
- if (store.disableKeyboardA11y || !store.autoPanOnNodeFocus || !nodeRef()?.matches(":focus-visible")) return;
1145
- let { width, height, viewport } = store;
1146
- getNodesInside(/* @__PURE__ */ new Map([[node().id, node()]]), {
1147
- x: 0,
1148
- y: 0,
1149
- width,
1150
- height
1151
- }, [
1152
- viewport.x,
1153
- viewport.y,
1154
- viewport.zoom
1155
- ], !0).length > 0 || actions.setCenter(node().position.x + (node().measured.width ?? 0) / 2, node().position.y + (node().measured.height ?? 0) / 2, { zoom: viewport.zoom });
1156
- }, dragging = createDraggable(nodeRef, () => ({
1157
- nodeId: node().id,
1158
- isSelectable: selectable(),
1159
- disabled: !draggable(),
1160
- handleSelector: node().dragHandle,
1161
- noDragClass: store.noDragClass,
1162
- nodeClickDistance: props.nodeClickDistance,
1163
- onNodeMouseDown: actions.handleNodeSelection,
1164
- onDrag: (event, _, targetNode, nodes) => {
1165
- props.onNodeDrag?.({
1166
- event,
1167
- targetNode,
1168
- nodes
1169
- });
1170
- },
1171
- onDragStart: (event, _, targetNode, nodes) => {
1172
- props.onNodeDragStart?.({
1173
- event,
1174
- targetNode,
1175
- nodes
1176
- });
1177
- },
1178
- onDragStop: (event, _, targetNode, nodes) => {
1179
- props.onNodeDragStop?.({
1180
- event,
1181
- targetNode,
1182
- nodes
1183
- });
1184
- }
1185
- }));
1186
- return createComponent(Show, {
1187
- get when() {
1188
- return !node().hidden;
1189
- },
1190
- get children() {
1191
- var _el$ = _tmpl$$27();
1192
- return ref(() => setNodeRef, _el$), spread(_el$, mergeProps({
1193
- get "data-id"() {
1194
- return node().id;
1195
- },
1196
- get class() {
1197
- return [
1198
- "solid-flow__node",
1199
- `solid-flow__node-${nodeType()}`,
1200
- {
1201
- connectable: !!connectable(),
1202
- draggable: !!draggable(),
1203
- dragging: dragging(),
1204
- nopan: !!draggable(),
1205
- parent: isParentNode(),
1206
- selectable: !!selectable(),
1207
- selected: !!node().selected
1208
- },
1209
- node().class
1210
- ];
1211
- },
1212
- get style() {
1213
- return style();
1214
- },
1215
- onClick: onSelectNodeHandler,
1216
- onPointerEnter: (event) => props.onNodePointerEnter?.({
1217
- node: userNode(),
1218
- event
1219
- }),
1220
- onPointerLeave: (event) => props.onNodePointerLeave?.({
1221
- node: userNode(),
1222
- event
1223
- }),
1224
- onPointerMove: (event) => props.onNodePointerMove?.({
1225
- node: userNode(),
1226
- event
1227
- }),
1228
- onContextMenu: (event) => props.onNodeContextMenu?.({
1229
- node: userNode(),
1230
- event
1231
- }),
1232
- onKeyDown: (e) => focusable() && onKeyDown(e),
1233
- onFocus: () => focusable() && onFocus(),
1234
- get tabindex() {
1235
- return focusable() ? 0 : void 0;
1236
- },
1237
- get role() {
1238
- return node().ariaRole ?? (focusable() ? "group" : void 0);
1239
- },
1240
- "aria-roledescription": "node",
1241
- get "aria-describedby"() {
1242
- return store.disableKeyboardA11y ? void 0 : `${ARIA_NODE_DESC_KEY}-${store.id}`;
1243
- }
1244
- }, () => node().domAttributes), !0), insert(_el$, createComponent(NodeIdContext, {
1245
- value: nodeId,
1246
- get children() {
1247
- return createComponent(NodeConnectableContext, {
1248
- value: connectable,
1249
- get children() {
1250
- return createComponent(Dynamic, {
1251
- get component() {
1252
- return nodeComponent();
1253
- },
1254
- get data() {
1255
- return node().data;
1256
- },
1257
- get id() {
1258
- return node().id;
1259
- },
1260
- get selected() {
1261
- return !!node().selected;
1262
- },
1263
- get selectable() {
1264
- return selectable();
1265
- },
1266
- get deletable() {
1267
- return deletable();
1268
- },
1269
- get sourcePosition() {
1270
- return node().sourcePosition;
1271
- },
1272
- get targetPosition() {
1273
- return node().targetPosition;
1274
- },
1275
- get zIndex() {
1276
- return node().internals.z;
1277
- },
1278
- get dragging() {
1279
- return dragging();
1280
- },
1281
- get draggable() {
1282
- return draggable();
1283
- },
1284
- get dragHandle() {
1285
- return node().dragHandle;
1286
- },
1287
- get parentId() {
1288
- return node().parentId;
1289
- },
1290
- get type() {
1291
- return nodeType();
1292
- },
1293
- get isConnectable() {
1294
- return connectable();
1295
- },
1296
- get positionAbsoluteX() {
1297
- return node().internals.positionAbsolute.x;
1298
- },
1299
- get positionAbsoluteY() {
1300
- return node().internals.positionAbsolute.y;
1301
- },
1302
- get width() {
1303
- return node().width;
1304
- },
1305
- get height() {
1306
- return node().height;
1307
- }
1308
- });
1309
- }
1310
- });
1311
- }
1312
- })), _el$;
1313
- }
1314
- });
1315
- }, OutputNode = (props) => {
1316
- let _props = propDefaults(props, { targetPosition: Position$1.Top });
1317
- return [createComponent(Handle, {
1318
- type: "target",
1319
- get position() {
1320
- return _props.targetPosition;
1321
- },
1322
- get isConnectable() {
1323
- return _props.isConnectable;
1324
- }
1325
- }), memo(() => props.data?.label)];
1326
- }, getDefaultFlowStateProps = () => ({
1327
- id: "1",
1328
- nodes: [],
1329
- edges: [],
1330
- nodeOrigin: [0, 0],
1331
- nodeExtent: infiniteExtent,
1332
- defaultEdgeOptions: {},
1333
- colorMode: "system",
1334
- colorModeSSR: "light",
1335
- connectionMode: "strict",
1336
- connectionLineType: "default",
1337
- connectionRadius: 20,
1338
- nodeDragThreshold: 1,
1339
- minZoom: .5,
1340
- maxZoom: 2,
1341
- selectionMode: "partial",
1342
- fitView: !1,
1343
- noPanClass: "nopan",
1344
- noDragClass: "nodrag",
1345
- noWheelClass: "nowheel",
1346
- autoPanOnNodeDrag: !0,
1347
- autoPanOnConnect: !0,
1348
- autoPanOnNodeFocus: !0,
1349
- autoPanOnSelection: !0,
1350
- autoPanSpeed: 15,
1351
- elevateEdgesOnSelect: !0,
1352
- nodesDraggable: !0,
1353
- nodesConnectable: !0,
1354
- nodesFocusable: !0,
1355
- edgesFocusable: !0,
1356
- elementsSelectable: !0,
1357
- selectNodesOnDrag: !0,
1358
- elevateNodesOnSelect: !0,
1359
- zIndexMode: "basic",
1360
- onlyRenderVisibleElements: !1,
1361
- disableKeyboardA11y: !1,
1362
- defaultMarkerColor: "#b1b1b7",
1363
- ariaLiveMessage: "",
1364
- style: {},
1365
- isValidConnection: (() => !0),
1366
- onFlowError: createDevWarn("Solid Flow", "https://solidflow.dev/")
1367
- }), SELECTED_NODE_Z = 1e3, defaultOptions = {
1368
- nodeOrigin: [0, 0],
1369
- nodeExtent: infiniteExtent,
1370
- elevateNodesOnSelect: !0,
1371
- defaults: {},
1372
- zIndexMode: "basic"
1373
- };
1374
- function isManualZIndexMode(zIndexMode) {
1375
- return zIndexMode === "manual";
1376
- }
1377
- const adoptUserNodesDefaultOptions = {
1378
- ...defaultOptions,
1379
- checkEquality: !0
1380
- };
1381
- function mergeObjects(base, incoming) {
1382
- let result = { ...base };
1383
- for (let key in incoming) incoming[key] !== void 0 && (result[key] = incoming[key]);
1384
- return result;
1385
- }
1386
- function adoptUserNodes(nodes, nodeLookup, parentLookup, options) {
1387
- let _options = mergeObjects(adoptUserNodesDefaultOptions, options), nodesInitialized = nodes.length > 0, rootParentIndex = { i: 0 }, tmpLookup = new Map(nodeLookup), selectedNodeZ = _options?.elevateNodesOnSelect && !isManualZIndexMode(_options.zIndexMode) ? SELECTED_NODE_Z : 0;
1388
- nodeLookup.clear(), parentLookup.clear();
1389
- for (let userNode of nodes) {
1390
- let internalNode = tmpLookup.get(userNode.id);
1391
- if (_options.checkEquality && userNode === internalNode?.internals.userNode) nodeLookup.set(userNode.id, internalNode);
1392
- else {
1393
- let positionWithOrigin = getNodePositionWithOrigin(userNode, _options.nodeOrigin), extent = isCoordinateExtent(userNode.extent) ? userNode.extent : _options.nodeExtent, clampedPosition = clampPosition(positionWithOrigin, extent, getNodeDimensions(userNode));
1394
- internalNode = {
1395
- ..._options.defaults,
1396
- ...userNode,
1397
- measured: {
1398
- width: userNode.measured?.width,
1399
- height: userNode.measured?.height
1400
- },
1401
- internals: {
1402
- positionAbsolute: clampedPosition,
1403
- handleBounds: userNode.measured ? internalNode?.internals.handleBounds : void 0,
1404
- z: calculateZ(userNode, selectedNodeZ, _options.zIndexMode),
1405
- userNode
1406
- }
1407
- }, nodeLookup.set(userNode.id, internalNode);
1408
- }
1409
- (internalNode.measured === void 0 || internalNode.measured.width === void 0 || internalNode.measured.height === void 0) && !internalNode.hidden && (nodesInitialized = !1), userNode.parentId && updateChildNode(internalNode, nodeLookup, parentLookup, options, rootParentIndex);
1410
- }
1411
- return nodesInitialized;
1412
- }
1413
- function updateParentLookup(node, parentLookup) {
1414
- if (!node.parentId) return;
1415
- let childNodes = parentLookup.get(node.parentId);
1416
- childNodes ? childNodes.set(node.id, node) : parentLookup.set(node.parentId, /* @__PURE__ */ new Map([[node.id, node]]));
1417
- }
1418
- /**
1419
- * Updates positionAbsolute and zIndex of a child node and the parentLookup.
1420
- */
1421
- function updateChildNode(node, nodeLookup, parentLookup, options, rootParentIndex) {
1422
- let { elevateNodesOnSelect, nodeOrigin, nodeExtent, zIndexMode } = mergeObjects(defaultOptions, options), parentId = node.parentId, parentNode = nodeLookup.get(parentId);
1423
- if (!parentNode) return;
1424
- updateParentLookup(node, parentLookup), rootParentIndex && !parentNode.parentId && parentNode.internals.rootParentIndex === void 0 && zIndexMode === "auto" && (parentNode.internals.rootParentIndex = ++rootParentIndex.i, parentNode.internals.z = parentNode.internals.z + rootParentIndex.i * 10), rootParentIndex && parentNode.internals.rootParentIndex !== void 0 && (rootParentIndex.i = parentNode.internals.rootParentIndex);
1425
- let { x, y, z } = calculateChildXYZ(node, parentNode, nodeOrigin, nodeExtent, elevateNodesOnSelect && !isManualZIndexMode(zIndexMode) ? SELECTED_NODE_Z : 0, zIndexMode), { positionAbsolute } = node.internals, positionChanged = x !== positionAbsolute.x || y !== positionAbsolute.y;
1426
- (positionChanged || z !== node.internals.z) && nodeLookup.set(node.id, {
1427
- ...node,
1428
- internals: {
1429
- ...node.internals,
1430
- positionAbsolute: positionChanged ? {
1431
- x,
1432
- y
1433
- } : positionAbsolute,
1434
- z
1435
- }
1436
- });
1437
- }
1438
- function calculateZ(node, selectedNodeZ, zIndexMode) {
1439
- let zIndex = isNumeric(node.zIndex) ? node.zIndex : 0;
1440
- return isManualZIndexMode(zIndexMode) ? zIndex : zIndex + (node.selected ? selectedNodeZ : 0);
1441
- }
1442
- function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode) {
1443
- let { x: parentX, y: parentY } = parentNode.internals.positionAbsolute, childDimensions = getNodeDimensions(childNode), positionWithOrigin = getNodePositionWithOrigin(childNode, nodeOrigin), clampedPosition = isCoordinateExtent(childNode.extent) ? clampPosition(positionWithOrigin, childNode.extent, childDimensions) : positionWithOrigin, absolutePosition = clampPosition({
1444
- x: parentX + clampedPosition.x,
1445
- y: parentY + clampedPosition.y
1446
- }, nodeExtent, childDimensions);
1447
- childNode.extent === "parent" && (absolutePosition = clampPositionToParent(absolutePosition, childDimensions, parentNode));
1448
- let childZ = calculateZ(childNode, selectedNodeZ, zIndexMode), parentZ = parentNode.internals.z ?? 0;
1449
- return {
1450
- x: absolutePosition.x,
1451
- y: absolutePosition.y,
1452
- z: parentZ >= childZ ? parentZ + 1 : childZ
1453
- };
1454
- }
1455
- /**
1456
- * this function adds the connection to the connectionLookup
1457
- * at the following keys: nodeId-type-handleId, nodeId-type and nodeId
1458
- * @param type type of the connection
1459
- * @param connection connection that should be added to the lookup
1460
- * @param connectionKey at which key the connection should be added
1461
- * @param connectionLookup reference to the connection lookup
1462
- * @param nodeId nodeId of the connection
1463
- * @param handleId handleId of the conneciton
1464
- */
1465
- function addConnectionToLookup(type, connection, connectionKey, connectionLookup, nodeId, handleId) {
1466
- let add = (key) => {
1467
- let next = new Map(untrack(() => connectionLookup.get(key)));
1468
- next.set(connectionKey, connection), connectionLookup.set(key, next);
1469
- };
1470
- add(nodeId), add(`${nodeId}-${type}`), handleId && add(`${nodeId}-${type}-${handleId}`);
1471
- }
1472
- function removeConnectionFromLookup(type, connectionKey, connectionLookup, nodeId, handleId) {
1473
- let remove = (key) => {
1474
- let current = untrack(() => connectionLookup.get(key));
1475
- if (!current) return;
1476
- let next = new Map(current);
1477
- next.delete(connectionKey), next.size === 0 ? connectionLookup.delete(key) : connectionLookup.set(key, next);
1478
- };
1479
- remove(nodeId), remove(`${nodeId}-${type}`), handleId && remove(`${nodeId}-${type}-${handleId}`);
1480
- }
1481
- //#endregion
1482
- //#region src/data/createSolidFlow.tsx
1483
- const InitialNodeTypesMap = {
1484
- input: InputNode,
1485
- output: OutputNode,
1486
- default: DefaultNode,
1487
- group: GroupNode
1488
- }, InitialEdgeTypesMap = {
1489
- straight: StraightEdgeInternal,
1490
- smoothstep: SmoothStepEdgeInternal,
1491
- default: BezierEdgeInternal,
1492
- step: StepEdgeInternal
1493
- }, getInitialViewport = (_nodesInitialized, fitView, initialViewport, width, height, nodeLookup) => {
1494
- if (fitView && !initialViewport && width && height) {
1495
- let bounds = getInternalNodesBounds(nodeLookup, { filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)) });
1496
- return getViewportForBounds$1(bounds, width, height, .5, 2, .1);
1497
- }
1498
- return initialViewport ?? {
1499
- x: 0,
1500
- y: 0,
1501
- zoom: 1
1502
- };
1503
- }, createSolidFlow = (props) => {
1504
- let _props = merge(getDefaultFlowStateProps(), props), nodeLookup = new ReactiveMap(), parentLookup = new ReactiveMap(), edgeLookup = new ReactiveMap(), connectionLookup = new ReactiveMap(), layoutedEdgesMap = new ReactiveMap(), startNodesInitialized = untrack(() => adoptUserNodes(_props.nodes, nodeLookup, parentLookup, {
1505
- nodeExtent: _props.nodeExtent,
1506
- nodeOrigin: _props.nodeOrigin,
1507
- elevateNodesOnSelect: _props.elevateNodesOnSelect,
1508
- zIndexMode: _props.zIndexMode,
1509
- checkEquality: !0
1510
- })), initialViewport = getInitialViewport(startNodesInitialized, _props.fitView, _props.initialViewport, _props.width ?? 0, _props.height ?? 0, nodeLookup), mediaPrefersDark = createMediaQuery("(prefers-color-scheme: dark)", _props.colorModeSSR === "dark"), [config, setConfig] = createSignal(_props), [ariaLabelConfig, setAriaLabelConfig] = createSignal(() => mergeAriaLabelConfig(config().ariaLabelConfig)), [ariaLiveMessage, setAriaLiveMessage] = createSignal(() => config().ariaLiveMessage), [clickConnectStartHandle, setClickConnectStartHandle] = createSignal(void 0), [connection, setConnection] = createSignal(initialConnection), [domNode, setDomNode] = createSignal(null), [dragging, setDragging] = createSignal(!1), [elementsSelectable, setElementsSelectable] = createSignal(() => config().elementsSelectable), [height, setHeight] = createSignal(() => config().height), [minZoom, _setMinZoom] = createSignal(() => config().minZoom), [maxZoom, _setMaxZoom] = createSignal(() => config().maxZoom), [nodesConnectable, setNodesConnectable] = createSignal(() => config().nodesDraggable), [nodesDraggable, setNodesDraggable] = createSignal(() => config().nodesDraggable), [panZoom, setPanZoom] = createSignal(null), [selectionRect, setSelectionRect] = createSignal(), [selectionRectMode, setSelectionRectMode] = createSignal(), [snapGrid, setSnapGrid] = createSignal(() => config().snapGrid), [translateExtent, _setTranslateExtent] = createSignal(() => config().translateExtent ?? infiniteExtent), [width, setWidth] = createSignal(() => config().width), [selectionKeyPressed, setSelectionKeyPressed] = createSignal(!1), [multiselectionKeyPressed, setMultiselectionKeyPressed] = createSignal(!1), [deleteKeyPressed, setDeleteKeyPressed] = createSignal(!1), [panActivationKeyPressed, setPanActivationKeyPressed] = createSignal(!1), [zoomActivationKeyPressed, setZoomActivationKeyPressed] = createSignal(!1), [nodesStore, setNodesStore] = createStore(_props.nodes), [edgesStore, setEdgesStore] = createStore(_props.edges), [viewportStore, setViewportStore] = createStore(_props.viewport ?? initialViewport);
1155
+ }), nodeLookup = new RecordMapFacade(internalNodes), initialViewport = getInitialViewport(_props.fitView, _props.initialViewport, _props.width ?? 0, _props.height ?? 0, nodeLookup), [viewportStore, setViewportStore] = createStore(_props.viewport ?? initialViewport);
1511
1156
  createEffect(() => config().nodes, (next) => {
1512
1157
  setNodesStore(() => next);
1513
1158
  }, { defer: !0 }), createEffect(() => config().edges, (next) => {
@@ -1553,7 +1198,7 @@ const InitialNodeTypesMap = {
1553
1198
  return clickConnectStartHandle();
1554
1199
  },
1555
1200
  get colorMode() {
1556
- return this._colorMode === "system" ? mediaPrefersDark() ? "dark" : "light" : this._colorMode;
1201
+ return this._colorMode === "system" ? prefersDark() ? "dark" : "light" : this._colorMode;
1557
1202
  },
1558
1203
  get connection() {
1559
1204
  let state = connection();
@@ -1570,7 +1215,7 @@ const InitialNodeTypesMap = {
1570
1215
  },
1571
1216
  get edgeTypes() {
1572
1217
  return {
1573
- ...InitialEdgeTypesMap,
1218
+ ...initialEdgeTypes,
1574
1219
  ...this._edgeTypes
1575
1220
  };
1576
1221
  },
@@ -1595,382 +1240,1213 @@ const InitialNodeTypesMap = {
1595
1240
  get edges() {
1596
1241
  return edgesStore;
1597
1242
  },
1598
- get nodes() {
1599
- return nodesStore;
1243
+ get nodes() {
1244
+ return nodesStore;
1245
+ },
1246
+ get nodesConnectable() {
1247
+ return nodesConnectable();
1248
+ },
1249
+ get nodesDraggable() {
1250
+ return nodesDraggable();
1251
+ },
1252
+ get nodeTypes() {
1253
+ return {
1254
+ ...initialNodeTypes,
1255
+ ...this._nodeTypes
1256
+ };
1257
+ },
1258
+ get panZoom() {
1259
+ return panZoom();
1260
+ },
1261
+ get selectedNodes() {
1262
+ return nodesStore.filter((node) => node.selected);
1263
+ },
1264
+ get selectedEdges() {
1265
+ return edgesStore.filter((edge) => edge.selected);
1266
+ },
1267
+ get selectionRect() {
1268
+ return selectionRect();
1269
+ },
1270
+ get selectionRectMode() {
1271
+ return selectionRectMode();
1272
+ },
1273
+ get snapGrid() {
1274
+ return snapGrid();
1275
+ },
1276
+ get viewport() {
1277
+ return viewportStore;
1278
+ },
1279
+ get viewportInitialized() {
1280
+ return panZoom() !== null;
1281
+ },
1282
+ get nodesInitialized() {
1283
+ return nodesInitialized();
1284
+ },
1285
+ get visibleEdgeIds() {
1286
+ return visibleEdgeIds();
1287
+ },
1288
+ get visibleNodeIds() {
1289
+ return visibleNodeIds();
1290
+ },
1291
+ get visibleNodesMap() {
1292
+ return visibleNodesMap();
1293
+ },
1294
+ get transform() {
1295
+ return transform();
1296
+ },
1297
+ get translateExtent() {
1298
+ return translateExtent();
1299
+ },
1300
+ get width() {
1301
+ return width();
1302
+ },
1303
+ get selectionKeyPressed() {
1304
+ return selectionKeyPressed();
1305
+ },
1306
+ get multiselectionKeyPressed() {
1307
+ return multiselectionKeyPressed();
1308
+ },
1309
+ get deleteKeyPressed() {
1310
+ return deleteKeyPressed();
1311
+ },
1312
+ get panActivationKeyPressed() {
1313
+ return panActivationKeyPressed();
1314
+ },
1315
+ get zoomActivationKeyPressed() {
1316
+ return zoomActivationKeyPressed();
1317
+ }
1318
+ }), visibleNodesMap = createMemo(() => nodeLookup), visibleNodeIds = createMemo(() => Object.keys(internalNodes)), parentIds = createParentIds({ get nodes() {
1319
+ return store.nodes;
1320
+ } }), edgeLookup = createEdgeLookup({ get edges() {
1321
+ return store.edges;
1322
+ } }), connections = createConnections({ get edges() {
1323
+ return store.edges;
1324
+ } }), layoutedEdges = createLayoutedEdges({
1325
+ get edges() {
1326
+ return store.edges;
1327
+ },
1328
+ get connectionMode() {
1329
+ return store.connectionMode;
1330
+ },
1331
+ get defaultEdgeOptions() {
1332
+ return store.defaultEdgeOptions;
1333
+ },
1334
+ get elevateEdgesOnSelect() {
1335
+ return store.elevateEdgesOnSelect;
1336
+ },
1337
+ get zIndexMode() {
1338
+ return store.zIndexMode;
1339
+ },
1340
+ get onlyRenderVisibleElements() {
1341
+ return store.onlyRenderVisibleElements;
1342
+ },
1343
+ get width() {
1344
+ return store.width;
1345
+ },
1346
+ get height() {
1347
+ return store.height;
1348
+ },
1349
+ get transform() {
1350
+ return store.transform;
1351
+ },
1352
+ get onError() {
1353
+ return store.onError;
1354
+ },
1355
+ nodeLookup
1356
+ }), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)), getEdge = (id) => layoutedEdges[id], fitView = async (options) => store.panZoom ? await fitViewport({
1357
+ nodes: nodeLookup,
1358
+ width: store.width,
1359
+ height: store.height,
1360
+ panZoom: store.panZoom,
1361
+ minZoom: store.minZoom,
1362
+ maxZoom: store.maxZoom
1363
+ }, options ?? config().fitViewOptions) : !1, resetStoreValues = () => {
1364
+ setDragging(!1), setSelectionRect(void 0), setSelectionRectMode(void 0), setSelectionKeyPressed(!1), setMultiselectionKeyPressed(!1), setDeleteKeyPressed(!1), setPanActivationKeyPressed(!1), setZoomActivationKeyPressed(!1), setConnection({ ...initialConnection }), setClickConnectStartHandle(void 0), setViewportStore(() => config().initialViewport ?? {
1365
+ x: 0,
1366
+ y: 0,
1367
+ zoom: 1
1368
+ }), setAriaLiveMessage(""), setSnapGrid(void 0);
1369
+ }, addEdge = (edgeParams) => {
1370
+ setEdgesStore((edges) => {
1371
+ let next = addEdge$1(edgeParams, edges);
1372
+ next !== edges && edges.push(next[next.length - 1]);
1373
+ });
1374
+ }, initialFitViewApplied = !1, initialNodesMeasured = !1, applyInitialFitView = (initialFitView) => {
1375
+ initialFitViewApplied = !initialFitView;
1376
+ }, tryInitialFitView = () => {
1377
+ initialFitViewApplied || !initialNodesMeasured || untrack(() => store.panZoom && store.width && store.height) && (initialFitViewApplied = !0, untrack(() => fitView()));
1378
+ }, updateNodePositions = (nodeDragItems, dragging = !1) => {
1379
+ setNodesStore((nodes) => {
1380
+ for (let node of nodes) nodeDragItems.has(node.id) && (node.dragging = dragging, node.position = nodeDragItems.get(node.id).position);
1381
+ });
1382
+ }, applyMeasurementWrites = (writes) => {
1383
+ setMeasurementsStore((draft) => {
1384
+ for (let write of writes) if (write.hidden) {
1385
+ let entry = draft[write.id];
1386
+ entry && (entry.handleBounds = void 0);
1387
+ } else draft[write.id] = {
1388
+ measured: write.measured,
1389
+ handleBounds: write.handleBounds
1390
+ };
1391
+ });
1392
+ }, applyNodeChanges = (changes) => {
1393
+ changes.length !== 0 && setNodesStore((nodes) => {
1394
+ let nodeById = new Map(nodes.map((node) => [node.id, node]));
1395
+ for (let change of changes) {
1396
+ let node = nodeById.get(change.id);
1397
+ if (node) switch (change.type) {
1398
+ case "dimensions":
1399
+ change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
1400
+ ...node.measured,
1401
+ ...change.dimensions
1402
+ };
1403
+ break;
1404
+ case "position": node.position = change.position ?? node.position;
1405
+ }
1406
+ }
1407
+ });
1408
+ }, markInitialNodesMeasured = () => {
1409
+ initialNodesMeasured = !0, tryInitialFitView();
1410
+ }, requestMeasure = () => {}, setMeasureRequester = (fn) => {
1411
+ requestMeasure = fn;
1412
+ }, zoomBy = async (factor, options) => store.panZoom ? store.panZoom.scaleBy(factor, options) : !1, zoomIn = (options) => zoomBy(1.2, options), zoomOut = (options) => zoomBy(1 / 1.2, options), setCenter = async (x, y, options) => {
1413
+ let nextZoom = options?.zoom === void 0 ? store.maxZoom : options.zoom, currentPanZoom = store.panZoom;
1414
+ return currentPanZoom ? (await currentPanZoom.setViewport({
1415
+ x: store.width / 2 - x * nextZoom,
1416
+ y: store.height / 2 - y * nextZoom,
1417
+ zoom: nextZoom
1418
+ }, {
1419
+ duration: options?.duration,
1420
+ ease: options?.ease,
1421
+ interpolate: options?.interpolate
1422
+ }), Promise.resolve(!0)) : Promise.resolve(!1);
1423
+ }, setPaneClickDistance = (distance) => {
1424
+ store.panZoom?.setClickDistance(distance);
1425
+ }, unselectNodesAndEdges = ({ nodes: _nodes, edges } = {}) => {
1426
+ let nodesToUnselect = new Set((_nodes || store.nodes).map(({ id }) => id));
1427
+ nodesToUnselect.size && setNodesStore((nodes) => {
1428
+ for (let node of nodes) nodesToUnselect.has(node.id) && (node.selected = !1);
1429
+ });
1430
+ let edgesToUnselect = new Set((edges ?? store.edges).map(({ id }) => id));
1431
+ edgesToUnselect.size && setEdgesStore((edges) => {
1432
+ for (let edge of edges) edgesToUnselect.has(edge.id) && (edge.selected = !1);
1433
+ }), flush();
1434
+ }, addSelectedNodes = (ids) => {
1435
+ let isMultiSelection = store.multiselectionKeyPressed;
1436
+ setNodesStore((nodes) => {
1437
+ for (let node of nodes) {
1438
+ let nodeWillBeSelected = ids.includes(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
1439
+ node.selected !== selected && (node.selected = selected);
1440
+ }
1441
+ }), isMultiSelection || unselectNodesAndEdges({ nodes: [] }), flush();
1442
+ }, addSelectedEdges = (ids) => {
1443
+ let isMultiSelection = store.multiselectionKeyPressed;
1444
+ setEdgesStore((edges) => {
1445
+ for (let edge of edges) {
1446
+ let edgeWillBeSelected = ids.includes(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
1447
+ edge.selected !== selected && (edge.selected = selected);
1448
+ }
1449
+ }), isMultiSelection || unselectNodesAndEdges({ edges: [] }), flush();
1450
+ }, handleNodeSelection = (id, unselect, nodeRef) => {
1451
+ let node = store.nodes.find((n) => n.id === id);
1452
+ node && (setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
1453
+ nodes: [node],
1454
+ edges: []
1455
+ }), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
1456
+ }, handleEdgeSelection = (id) => {
1457
+ let edge = edgeLookup[id];
1458
+ edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
1459
+ nodes: [],
1460
+ edges: [edge]
1461
+ }) : addSelectedEdges([id]));
1462
+ }, moveSelectedNodes = (direction, factor) => {
1463
+ let nodeUpdates = /* @__PURE__ */ new Map(), xVelo = store.snapGrid?.[0] ?? 5, yVelo = store.snapGrid?.[1] ?? 5, xDiff = direction.x * xVelo * factor, yDiff = direction.y * yVelo * factor;
1464
+ for (let node of nodeLookup.values()) {
1465
+ if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
1466
+ let nextPosition = {
1467
+ x: node.internals.positionAbsolute.x + xDiff,
1468
+ y: node.internals.positionAbsolute.y + yDiff
1469
+ };
1470
+ store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
1471
+ let { position } = calculateNodePosition({
1472
+ nodeId: node.id,
1473
+ nextPosition,
1474
+ nodeLookup,
1475
+ nodeExtent: store.nodeExtent,
1476
+ nodeOrigin: store.nodeOrigin,
1477
+ onError: store.onError
1478
+ });
1479
+ nodeUpdates.set(node.id, { position });
1480
+ }
1481
+ updateNodePositions(nodeUpdates);
1482
+ }, panBy$1 = (delta) => panBy({
1483
+ delta,
1484
+ panZoom: store.panZoom,
1485
+ transform: store.transform,
1486
+ translateExtent: store.translateExtent,
1487
+ width: store.width,
1488
+ height: store.height
1489
+ }), cancelConnection = () => {
1490
+ setConnection({ ...initialConnection });
1491
+ }, reset = () => {
1492
+ resetStoreValues(), unselectNodesAndEdges();
1493
+ }, flow = {
1494
+ get nodes() {
1495
+ return store.nodes;
1496
+ },
1497
+ get edges() {
1498
+ return store.edges;
1499
+ },
1500
+ get internalNodes() {
1501
+ return internalNodes;
1502
+ },
1503
+ get layoutedEdges() {
1504
+ return layoutedEdges;
1505
+ },
1506
+ get connections() {
1507
+ return connections;
1508
+ },
1509
+ selection: {
1510
+ get nodes() {
1511
+ return store.selectedNodes;
1512
+ },
1513
+ get edges() {
1514
+ return store.selectedEdges;
1515
+ }
1516
+ },
1517
+ get nodesInitialized() {
1518
+ return store.nodesInitialized;
1519
+ },
1520
+ get viewportInitialized() {
1521
+ return store.viewportInitialized;
1522
+ },
1523
+ get viewport() {
1524
+ return store.viewport;
1525
+ },
1526
+ get width() {
1527
+ return store.width;
1528
+ },
1529
+ get height() {
1530
+ return store.height;
1531
+ },
1532
+ get colorMode() {
1533
+ return store.colorMode;
1534
+ },
1535
+ get connection() {
1536
+ return store.connection;
1537
+ },
1538
+ get dragging() {
1539
+ return store.dragging;
1540
+ },
1541
+ get minZoom() {
1542
+ return store.minZoom;
1543
+ },
1544
+ get maxZoom() {
1545
+ return store.maxZoom;
1546
+ },
1547
+ get nodesDraggable() {
1548
+ return store.nodesDraggable;
1549
+ },
1550
+ get nodesConnectable() {
1551
+ return store.nodesConnectable;
1552
+ },
1553
+ get elementsSelectable() {
1554
+ return store.elementsSelectable;
1555
+ },
1556
+ get snapGrid() {
1557
+ return store.snapGrid;
1558
+ }
1559
+ }, getNodeRect = (node) => {
1560
+ let nodeToUse = isNode(node) ? node : nodeLookup.get(node.id), position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, store.nodeOrigin) : nodeToUse.position, nodeWithPosition = {
1561
+ ...nodeToUse,
1562
+ position,
1563
+ width: nodeToUse.measured?.width ?? nodeToUse.width,
1564
+ height: nodeToUse.measured?.height ?? nodeToUse.height
1565
+ };
1566
+ return nodeToRect(nodeWithPosition);
1567
+ }, updateNode = (id, nodeUpdate, options = { replace: !1 }) => {
1568
+ setNodesStore((nodes) => {
1569
+ let index = nodes.findIndex((node) => node.id === id);
1570
+ if (index === -1) return;
1571
+ let node = nodes[index], nextNode = typeof nodeUpdate == "function" ? nodeUpdate(node) : nodeUpdate;
1572
+ nodes[index] = options?.replace && isNode(nextNode) ? nextNode : {
1573
+ ...node,
1574
+ ...nextNode
1575
+ };
1576
+ });
1577
+ }, commands = {
1578
+ fitView,
1579
+ fitBounds: async (bounds, options) => {
1580
+ if (!store.panZoom) return !1;
1581
+ let viewport = getViewportForBounds$1(bounds, store.width, store.height, store.minZoom, store.maxZoom, options?.padding ?? .1);
1582
+ return await store.panZoom.setViewport(viewport, {
1583
+ duration: options?.duration,
1584
+ ease: options?.ease,
1585
+ interpolate: options?.interpolate
1586
+ }), !0;
1587
+ },
1588
+ zoomIn,
1589
+ zoomOut,
1590
+ setZoom: (zoomLevel, options) => {
1591
+ let currentPanZoom = store.panZoom;
1592
+ return currentPanZoom ? currentPanZoom.scaleTo(zoomLevel, { duration: options?.duration }) : Promise.resolve(!1);
1600
1593
  },
1601
- get nodesConnectable() {
1602
- return nodesConnectable();
1594
+ setCenter,
1595
+ setViewport: async (nextViewport, options) => {
1596
+ let currentViewport = store.viewport;
1597
+ return store.panZoom ? (await store.panZoom.setViewport({
1598
+ x: nextViewport.x ?? currentViewport.x,
1599
+ y: nextViewport.y ?? currentViewport.y,
1600
+ zoom: nextViewport.zoom ?? currentViewport.zoom
1601
+ }, options), !0) : !1;
1603
1602
  },
1604
- get nodesDraggable() {
1605
- return nodesDraggable();
1603
+ panBy: panBy$1,
1604
+ screenToFlowPosition: (position, options = { snapToGrid: !0 }) => {
1605
+ if (!store.domNode) return position;
1606
+ let _snapGrid = options.snapToGrid ? store.snapGrid : !1, { x, y, zoom } = store.viewport, { x: domX, y: domY } = store.domNode.getBoundingClientRect(), correctedPosition = {
1607
+ x: position.x - domX,
1608
+ y: position.y - domY
1609
+ };
1610
+ return pointToRendererPoint(correctedPosition, [
1611
+ x,
1612
+ y,
1613
+ zoom
1614
+ ], _snapGrid !== null, _snapGrid || [1, 1]);
1606
1615
  },
1607
- get nodeTypes() {
1616
+ flowToScreenPosition: (position) => {
1617
+ if (!store.domNode) return position;
1618
+ let { x, y, zoom } = store.viewport, { x: domX, y: domY } = store.domNode.getBoundingClientRect(), rendererPosition = rendererPointToPoint(position, [
1619
+ x,
1620
+ y,
1621
+ zoom
1622
+ ]);
1608
1623
  return {
1609
- ...InitialNodeTypesMap,
1610
- ...this._nodeTypes
1624
+ x: rendererPosition.x + domX,
1625
+ y: rendererPosition.y + domY
1611
1626
  };
1612
1627
  },
1613
- get panZoom() {
1614
- return panZoom();
1628
+ addNodes: (payload) => {
1629
+ let newNodes = Array.isArray(payload) ? payload : [payload];
1630
+ setNodesStore((nodes) => [...nodes, ...newNodes]);
1615
1631
  },
1616
- get selectedNodes() {
1617
- return nodesStore.filter((node) => node.selected);
1632
+ addEdges: (payload) => {
1633
+ let newEdges = Array.isArray(payload) ? payload : [payload];
1634
+ setEdgesStore((edges) => [...edges, ...newEdges]);
1618
1635
  },
1619
- get selectedEdges() {
1620
- return edgesStore.filter((edge) => edge.selected);
1636
+ setNodes: setNodesStore,
1637
+ setEdges: setEdgesStore,
1638
+ updateNode,
1639
+ updateNodeData: (id, dataUpdate, options) => {
1640
+ let node = nodeLookup.get(id)?.internals.userNode;
1641
+ if (!node) return;
1642
+ let nextData = typeof dataUpdate == "function" ? dataUpdate(node) : dataUpdate;
1643
+ updateNode(id, (current) => ({
1644
+ ...current,
1645
+ data: options?.replace ? nextData : {
1646
+ ...current.data,
1647
+ ...nextData
1648
+ }
1649
+ }));
1621
1650
  },
1622
- get selectionRect() {
1623
- return selectionRect();
1651
+ updateEdge: (id, edgeUpdate, options = { replace: !1 }) => {
1652
+ setEdgesStore((edges) => {
1653
+ let index = edges.findIndex((edge) => edge.id === id);
1654
+ if (index === -1) return;
1655
+ let edge = edges[index], nextEdge = typeof edgeUpdate == "function" ? edgeUpdate(edge) : edgeUpdate;
1656
+ edges[index] = options.replace && isEdge(nextEdge) ? nextEdge : {
1657
+ ...edge,
1658
+ ...nextEdge
1659
+ };
1660
+ });
1624
1661
  },
1625
- get selectionRectMode() {
1626
- return selectionRectMode();
1662
+ deleteElements: async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
1663
+ let { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
1664
+ nodesToRemove,
1665
+ edgesToRemove,
1666
+ nodes: store.nodes,
1667
+ edges: store.edges,
1668
+ onBeforeDelete: store.onBeforeDelete
1669
+ });
1670
+ if (matchingEdges) {
1671
+ let remainingEdges = store.edges.filter((edge) => !matchingEdges.some(({ id }) => id === edge.id));
1672
+ store.onEdgesDelete?.(matchingEdges), setEdgesStore(() => remainingEdges);
1673
+ }
1674
+ if (matchingNodes) {
1675
+ let remainingNodes = store.nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id));
1676
+ store.onNodesDelete?.(matchingNodes), setNodesStore(() => remainingNodes);
1677
+ }
1678
+ return {
1679
+ deletedNodes: matchingNodes,
1680
+ deletedEdges: matchingEdges
1681
+ };
1627
1682
  },
1628
- get snapGrid() {
1629
- return snapGrid();
1683
+ getIntersectingNodes: (nodeOrRect, partially = !0, nodesToIntersect) => {
1684
+ let isRect = isRectObject(nodeOrRect), nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
1685
+ return nodeRect ? (nodesToIntersect || store.nodes).filter((n) => {
1686
+ let internalNode = nodeLookup.get(n.id);
1687
+ if (!internalNode || !isRect && n.id === nodeOrRect.id) return !1;
1688
+ let currNodeRect = nodeToRect(internalNode), overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
1689
+ return partially && overlappingArea > 0 || overlappingArea >= nodeRect.width * nodeRect.height;
1690
+ }) : [];
1630
1691
  },
1631
- get viewport() {
1632
- return viewportStore;
1692
+ isNodeIntersecting: (nodeOrRect, area, partially = !0) => {
1693
+ let nodeRect = isRectObject(nodeOrRect) ? nodeOrRect : getNodeRect(nodeOrRect);
1694
+ if (!nodeRect) return !1;
1695
+ let overlappingArea = getOverlappingArea(nodeRect, area);
1696
+ return partially && overlappingArea > 0 || overlappingArea >= nodeRect.width * nodeRect.height;
1633
1697
  },
1634
- get viewportInitialized() {
1635
- return panZoom() !== null;
1698
+ getNodesBounds: (nodesToMeasure) => getNodesBounds$1(nodesToMeasure, {
1699
+ nodeLookup,
1700
+ nodeOrigin: store.nodeOrigin
1701
+ }),
1702
+ updateNodeInternals: (id) => {
1703
+ let updateIds = Array.isArray(id) ? id : [id], updates = [];
1704
+ for (let updateId of updateIds) {
1705
+ let nodeElement = store.domNode?.querySelector(`.solid-flow__node[data-id="${updateId}"]`);
1706
+ nodeElement && updates.push([updateId, {
1707
+ id: updateId,
1708
+ nodeElement,
1709
+ force: !0
1710
+ }]);
1711
+ }
1712
+ requestMeasure(updates);
1636
1713
  },
1637
- get nodesInitialized() {
1638
- return nodesInitialized();
1714
+ toObject: () => structuredClone({
1715
+ nodes: [...snapshot(store.nodes)],
1716
+ edges: [...snapshot(store.edges)],
1717
+ viewport: { ...snapshot(store.viewport) }
1718
+ })
1719
+ };
1720
+ return createEffect(() => !!(width() && height() && panZoom()), (ready) => {
1721
+ ready && tryInitialFitView();
1722
+ }), createEffect(() => ({
1723
+ panZoom: store.panZoom,
1724
+ viewport: {
1725
+ x: store.viewport.x,
1726
+ y: store.viewport.y,
1727
+ zoom: store.viewport.zoom
1728
+ }
1729
+ }), ({ panZoom, viewport }) => {
1730
+ panZoom?.syncViewport(viewport);
1731
+ }), createEffect(() => ({
1732
+ panZoom: panZoom(),
1733
+ extent: [store.minZoom, store.maxZoom]
1734
+ }), ({ panZoom, extent }) => {
1735
+ panZoom?.setScaleExtent(extent);
1736
+ }), createEffect(() => ({
1737
+ panZoom: panZoom(),
1738
+ extent: store.translateExtent
1739
+ }), ({ panZoom, extent }) => {
1740
+ panZoom?.setTranslateExtent(extent);
1741
+ }), createEffect(() => new Set(store.nodes.map((n) => n.id)), (currentIds) => {
1742
+ setMeasurementsStore((draft) => {
1743
+ for (let id of Object.keys(draft)) currentIds.has(id) || delete draft[id];
1744
+ });
1745
+ }), {
1746
+ store,
1747
+ flow,
1748
+ commands,
1749
+ internalNodes,
1750
+ layoutedEdges,
1751
+ nodeLookup,
1752
+ edgeLookup,
1753
+ parentIds,
1754
+ connections,
1755
+ actions: {
1756
+ getEdge,
1757
+ applyInitialFitView,
1758
+ applyMeasurementWrites,
1759
+ applyNodeChanges,
1760
+ markInitialNodesMeasured,
1761
+ setMeasureRequester,
1762
+ resetStoreValues,
1763
+ setAriaLabelConfig,
1764
+ setAriaLiveMessage,
1765
+ setClickConnectStartHandle,
1766
+ setConfig,
1767
+ setConnection,
1768
+ setDeleteKeyPressed,
1769
+ setDomNode,
1770
+ setDragging,
1771
+ get setEdges() {
1772
+ return setEdgesStore;
1773
+ },
1774
+ setElementsSelectable,
1775
+ setHeight,
1776
+ setMultiselectionKeyPressed,
1777
+ get setNodes() {
1778
+ return setNodesStore;
1779
+ },
1780
+ setNodesConnectable,
1781
+ setNodesDraggable,
1782
+ setPanActivationKeyPressed,
1783
+ setPanZoom,
1784
+ setSelectionKeyPressed,
1785
+ setSelectionRect,
1786
+ setSelectionRectMode,
1787
+ get setViewport() {
1788
+ return (viewport) => setViewportStore(() => viewport);
1789
+ },
1790
+ setWidth,
1791
+ setZoomActivationKeyPressed,
1792
+ addEdge,
1793
+ updateNodePositions,
1794
+ zoomIn,
1795
+ zoomOut,
1796
+ fitView,
1797
+ setCenter,
1798
+ setPaneClickDistance,
1799
+ unselectNodesAndEdges,
1800
+ addSelectedNodes,
1801
+ addSelectedEdges,
1802
+ handleNodeSelection,
1803
+ handleEdgeSelection,
1804
+ moveSelectedNodes,
1805
+ panBy: panBy$1,
1806
+ cancelConnection,
1807
+ reset
1808
+ }
1809
+ };
1810
+ }, getEdgeId = (connection) => {
1811
+ let { source, sourceHandle, target, targetHandle } = connection;
1812
+ return `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
1813
+ }, NodeConnectableContext = createContext(null);
1814
+ function useNodeConnectable() {
1815
+ let ctx = useContext(NodeConnectableContext);
1816
+ if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useNodeConnectable");
1817
+ return ctx;
1818
+ }
1819
+ //#endregion
1820
+ //#region src/components/graph/handle/Handle.tsx
1821
+ var _tmpl$$29 = /* @__PURE__ */ template("<div>");
1822
+ const Handle = (props) => {
1823
+ let _props = propDefaults(props, {
1824
+ type: "source",
1825
+ position: "top",
1826
+ isConnectableStart: !0,
1827
+ isConnectableEnd: !0
1828
+ }), { store, nodeLookup, connections, actions } = useInternalSolidFlow(), rest = omit(_props, "id", "type", "position", "isConnectable", "isConnectableStart", "isConnectableEnd", "isValidConnection", "onConnect", "onDisconnect", "children", "class", "style"), nodeId = useNodeId(), nodeConnectable = useNodeConnectable(), connectable = () => _props.isConnectable ?? nodeConnectable(), isTarget = () => _props.type === "target", handleId = () => _props.id ?? null, connectionInProcess = () => !!store.connection.fromHandle, connectingFrom = () => store.connection.fromHandle && store.connection.fromHandle.nodeId === nodeId() && store.connection.fromHandle.type === _props.type && store.connection.fromHandle.id === handleId(), connectingTo = () => store.connection.toHandle && store.connection.toHandle.nodeId === nodeId() && store.connection.toHandle.type === _props.type && store.connection.toHandle.id === handleId(), isPossibleTargetHandle = () => store.connectionMode === "strict" ? store.connection.fromHandle?.type !== _props.type : nodeId() !== store.connection.fromHandle?.nodeId || handleId() !== store.connection.fromHandle?.id, valid = () => !!(connectingTo() && store.connection.isValid), prevConnections = null;
1829
+ createEffect(() => {
1830
+ if (!_props.onConnect && !_props.onDisconnect) return null;
1831
+ let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
1832
+ for (let key of Object.keys(rec ?? {})) map.set(key, { ...rec[key] });
1833
+ return { connections: map };
1834
+ }, (current) => {
1835
+ if (!current) return;
1836
+ let { connections: next } = current;
1837
+ prevConnections && !areConnectionMapsEqual(next, prevConnections) && (handleConnectionChange(prevConnections, next, props.onDisconnect), handleConnectionChange(next, prevConnections, props.onConnect)), prevConnections = next;
1838
+ });
1839
+ let onConnectExtended = (connection) => {
1840
+ let handleConnection = {
1841
+ ...connection,
1842
+ id: getEdgeId(connection)
1843
+ }, edge = store.onBeforeConnect?.(handleConnection) ?? handleConnection;
1844
+ actions.addEdge(edge), store.onConnect?.(handleConnection);
1845
+ }, onPointerDown = (event) => {
1846
+ XYHandle.onPointerDown(event, {
1847
+ handleId: handleId(),
1848
+ nodeId: nodeId(),
1849
+ isTarget: isTarget(),
1850
+ connectionRadius: store.connectionRadius,
1851
+ domNode: store.domNode,
1852
+ nodeLookup,
1853
+ connectionMode: store.connectionMode,
1854
+ lib: store.lib,
1855
+ autoPanOnConnect: store.autoPanOnConnect,
1856
+ flowId: store.id,
1857
+ isValidConnection: _props.isValidConnection ?? store.isValidConnection,
1858
+ updateConnection: ((connection) => {
1859
+ actions.setConnection(connection), flush();
1860
+ }),
1861
+ cancelConnection: actions.cancelConnection,
1862
+ panBy: actions.panBy,
1863
+ onConnect: onConnectExtended,
1864
+ onConnectStart: (event, startParams) => {
1865
+ store.onConnectStart?.(event, {
1866
+ nodeId: startParams.nodeId,
1867
+ handleId: startParams.handleId,
1868
+ handleType: startParams.handleType
1869
+ });
1870
+ },
1871
+ onConnectEnd: store.onConnectEnd,
1872
+ getTransform: () => store.transform,
1873
+ getFromHandle: () => store.connection.fromHandle,
1874
+ autoPanSpeed: store.autoPanSpeed,
1875
+ dragThreshold: store.connectionDragThreshold,
1876
+ handleDomNode: event.currentTarget
1877
+ });
1878
+ }, onClick = (event) => {
1879
+ if (!nodeId() || !store.clickConnectStartHandle && !_props.isConnectableStart) return;
1880
+ if (!store.clickConnectStartHandle) {
1881
+ store.onClickConnectStart?.(event, {
1882
+ nodeId: nodeId(),
1883
+ handleId: handleId(),
1884
+ handleType: _props.type
1885
+ }), actions.setClickConnectStartHandle({
1886
+ nodeId: nodeId(),
1887
+ type: _props.type,
1888
+ id: handleId()
1889
+ });
1890
+ return;
1891
+ }
1892
+ let doc = getHostForElement(event.target), isValidConnectionHandler = _props.isValidConnection ?? store.isValidConnection, { connection, isValid } = XYHandle.isValid(event, {
1893
+ handle: {
1894
+ nodeId: nodeId(),
1895
+ id: handleId(),
1896
+ type: _props.type
1897
+ },
1898
+ connectionMode: store.connectionMode,
1899
+ fromNodeId: store.clickConnectStartHandle.nodeId,
1900
+ fromHandleId: store.clickConnectStartHandle.id ?? null,
1901
+ fromType: store.clickConnectStartHandle.type,
1902
+ isValidConnection: isValidConnectionHandler,
1903
+ flowId: store.id,
1904
+ doc,
1905
+ lib: store.lib,
1906
+ nodeLookup
1907
+ });
1908
+ isValid && connection && onConnectExtended(connection);
1909
+ let connectionClone = structuredClone(snapshot(store.connection));
1910
+ delete connectionClone.inProgress, connectionClone.toPosition = connectionClone.toHandle ? connectionClone.toHandle.position : null, store.onClickConnectEnd?.(event, connectionClone), actions.setClickConnectStartHandle(void 0);
1911
+ }, connectionIndicator = () => connectable() && (!connectionInProcess() || isPossibleTargetHandle()) && (connectionInProcess() || store.clickConnectStartHandle ? _props.isConnectableEnd : _props.isConnectableStart);
1912
+ var _el$ = _tmpl$$29();
1913
+ return spread(_el$, mergeProps(rest, {
1914
+ role: "button",
1915
+ get "aria-label"() {
1916
+ return store.ariaLabelConfig["handle.ariaLabel"];
1639
1917
  },
1640
- get visibleEdgeIds() {
1641
- return visibleEdgeIds();
1918
+ tabindex: -1,
1919
+ get "data-handleid"() {
1920
+ return handleId();
1642
1921
  },
1643
- get visibleNodeIds() {
1644
- return visibleNodeIds();
1922
+ get "data-nodeid"() {
1923
+ return nodeId();
1645
1924
  },
1646
- get visibleNodesMap() {
1647
- return visibleNodesMap();
1925
+ get "data-handlepos"() {
1926
+ return _props.position;
1648
1927
  },
1649
- get transform() {
1650
- return transform();
1928
+ get "data-id"() {
1929
+ return `${store.id}-${nodeId()}-${_props.id || null}-${_props.type}`;
1651
1930
  },
1652
- get translateExtent() {
1653
- return translateExtent();
1931
+ get onClick() {
1932
+ return store.clickConnect ? onClick : void 0;
1654
1933
  },
1655
- get width() {
1656
- return width();
1934
+ onPointerDown,
1935
+ get style() {
1936
+ return _props.style;
1657
1937
  },
1658
- get selectionKeyPressed() {
1659
- return selectionKeyPressed();
1938
+ get class() {
1939
+ return [
1940
+ "solid-flow__handle",
1941
+ `solid-flow__handle-${_props.position}`,
1942
+ store.noDragClass,
1943
+ store.noPanClass,
1944
+ _props.class,
1945
+ {
1946
+ valid: valid(),
1947
+ connectingto: !!connectingTo(),
1948
+ connectingfrom: !!connectingFrom(),
1949
+ source: !isTarget(),
1950
+ target: isTarget(),
1951
+ connectablestart: _props.isConnectableStart,
1952
+ connectableend: _props.isConnectableEnd,
1953
+ connectable: !!connectable(),
1954
+ connectionindicator: connectionIndicator()
1955
+ }
1956
+ ];
1957
+ }
1958
+ }), !0), insert(_el$, () => _props.children), _el$;
1959
+ }, DefaultNode = (props) => {
1960
+ let _props = propDefaults(props, {
1961
+ targetPosition: Position$1.Top,
1962
+ sourcePosition: Position$1.Bottom
1963
+ });
1964
+ return [
1965
+ createComponent(Handle, {
1966
+ type: "target",
1967
+ get position() {
1968
+ return _props.targetPosition;
1969
+ },
1970
+ get isConnectable() {
1971
+ return _props.isConnectable;
1972
+ }
1973
+ }),
1974
+ memo(() => props.data.label),
1975
+ createComponent(Handle, {
1976
+ type: "source",
1977
+ get position() {
1978
+ return _props.sourcePosition;
1979
+ },
1980
+ get isConnectable() {
1981
+ return _props.isConnectable;
1982
+ }
1983
+ })
1984
+ ];
1985
+ };
1986
+ //#endregion
1987
+ //#region src/components/graph/node/GroupNode.tsx
1988
+ var _tmpl$$28 = /* @__PURE__ */ template("<div style=position:absolute;left:0;top:0>");
1989
+ const GroupNode = (props) => (() => {
1990
+ var _el$ = _tmpl$$28();
1991
+ return effect(() => ({
1992
+ e: toPxString(props.width),
1993
+ t: toPxString(props.height)
1994
+ }), ({ e, t }, _p$) => {
1995
+ e !== _p$?.e && setStyleProperty(_el$, "width", e), t !== _p$?.t && setStyleProperty(_el$, "height", t);
1996
+ }), _el$;
1997
+ })(), InputNode = (props) => {
1998
+ let _props = propDefaults(props, { sourcePosition: Position$1.Bottom });
1999
+ return [memo(() => props.data?.label), createComponent(Handle, {
2000
+ type: "source",
2001
+ get position() {
2002
+ return _props.sourcePosition;
1660
2003
  },
1661
- get multiselectionKeyPressed() {
1662
- return multiselectionKeyPressed();
2004
+ get isConnectable() {
2005
+ return _props.isConnectable;
2006
+ }
2007
+ })];
2008
+ }, createDraggable = (elem, params) => {
2009
+ let { store, nodeLookup, actions } = useInternalSolidFlow(), [dragging, setDragging] = createSignal(!1);
2010
+ return createEffect(() => ({
2011
+ el: elem(),
2012
+ current: params()
2013
+ }), ({ el, current }) => {
2014
+ if (!el || current.disabled) return;
2015
+ let { onDrag, onDragStart, onDragStop, onNodeMouseDown } = current, dragInstance = XYDrag({
2016
+ onDrag,
2017
+ onDragStart: (event, dragItems, node, nodes) => {
2018
+ setDragging(!0), onDragStart?.(event, dragItems, node, nodes);
2019
+ },
2020
+ onDragStop: (event, dragItems, node, nodes) => {
2021
+ setDragging(!1), onDragStop?.(event, dragItems, node, nodes);
2022
+ },
2023
+ onNodeMouseDown,
2024
+ getStoreItems: () => ({
2025
+ nodes: store.nodes,
2026
+ nodeLookup,
2027
+ edges: store.edges,
2028
+ nodeExtent: store.nodeExtent,
2029
+ snapGrid: store.snapGrid ?? [0, 0],
2030
+ snapToGrid: !!store.snapGrid,
2031
+ autoPanSpeed: store.autoPanSpeed,
2032
+ nodeOrigin: store.nodeOrigin,
2033
+ multiSelectionActive: store.multiselectionKeyPressed,
2034
+ domNode: store.domNode,
2035
+ transform: store.transform,
2036
+ autoPanOnNodeDrag: store.autoPanOnNodeDrag,
2037
+ nodesDraggable: store.nodesDraggable,
2038
+ selectNodesOnDrag: store.selectNodesOnDrag,
2039
+ nodeDragThreshold: store.nodeDragThreshold,
2040
+ unselectNodesAndEdges: actions.unselectNodesAndEdges,
2041
+ updateNodePositions: actions.updateNodePositions,
2042
+ panBy: actions.panBy
2043
+ })
2044
+ });
2045
+ return dragInstance.update({
2046
+ domNode: el,
2047
+ nodeId: current.nodeId,
2048
+ noDragClassName: current.noDragClass,
2049
+ handleSelector: current.handleSelector,
2050
+ isSelectable: current.isSelectable,
2051
+ nodeClickDistance: current.nodeClickDistance
2052
+ }), () => {
2053
+ dragInstance.destroy();
2054
+ };
2055
+ }), dragging;
2056
+ }, NodeIdContext = createContext(null);
2057
+ function useNodeId() {
2058
+ let ctx = useContext(NodeIdContext);
2059
+ if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useNodeId");
2060
+ return ctx;
2061
+ }
2062
+ //#endregion
2063
+ //#region src/components/graph/node/NodeWrapper.tsx
2064
+ var _tmpl$$27 = /* @__PURE__ */ template("<div>");
2065
+ const NodeWrapper = (props) => {
2066
+ let { store, nodeLookup, parentIds, actions } = useInternalSolidFlow(), [nodeRef, setNodeRef] = createSignal(), node = () => nodeLookup.get(props.nodeId), nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeType()], isParentNode = () => !!parentIds[node().id], transform = () => {
2067
+ let { x, y } = node().internals.positionAbsolute;
2068
+ return `translate(${x}px, ${y}px)`;
2069
+ }, sizeStyle = () => {
2070
+ let w = node().width ?? node().initialWidth, h = node().height ?? node().initialHeight;
2071
+ return {
2072
+ ...node().style,
2073
+ ...w ? { width: toPxString(w) } : {},
2074
+ ...h ? { height: toPxString(h) } : {}
2075
+ };
2076
+ }, style = () => ({
2077
+ "z-index": node().internals.z,
2078
+ transform: transform(),
2079
+ visibility: nodeHasDimensions(node()) ? "visible" : "hidden",
2080
+ ...sizeStyle(),
2081
+ ...node().style ?? {}
2082
+ });
2083
+ createEffect(() => ({
2084
+ valid: nodeTypeValid(),
2085
+ nodeType: nodeType()
2086
+ }), ({ valid, nodeType }) => {}), createEffect(() => ({
2087
+ id: node().id,
2088
+ nodeElement: nodeRef(),
2089
+ nodeType: nodeType(),
2090
+ sourcePosition: node().sourcePosition,
2091
+ targetPosition: node().targetPosition
2092
+ }), (current, prev) => {
2093
+ current.nodeElement && (prev && prev.nodeElement === current.nodeElement && prev.sourcePosition === current.sourcePosition && prev.targetPosition === current.targetPosition && prev.nodeType === current.nodeType || actions.requestUpdateNodeInternals([[current.id, {
2094
+ id: current.id,
2095
+ nodeElement: current.nodeElement,
2096
+ force: !0
2097
+ }]]));
2098
+ }), createEffect(() => ({
2099
+ nodeElement: nodeRef(),
2100
+ hasDimensions: nodeHasDimensions(node()),
2101
+ resizeObserver: props.resizeObserver
2102
+ }), (current, prev) => {
2103
+ current.nodeElement === prev?.nodeElement && current.resizeObserver === prev?.resizeObserver && current.hasDimensions || (prev?.nodeElement && prev.resizeObserver?.unobserve(prev.nodeElement), current.nodeElement && current.resizeObserver?.observe(current.nodeElement));
2104
+ });
2105
+ let onSelectNodeHandler = (event) => {
2106
+ selectable() && (!store.selectNodesOnDrag || !draggable() || store.nodeDragThreshold > 0) && actions.handleNodeSelection(node().id), props.onNodeClick?.({
2107
+ node: userNode(),
2108
+ event
2109
+ });
2110
+ }, onKeyDown = (event) => {
2111
+ if (isInputDOMNode(event) || store.disableKeyboardA11y) return;
2112
+ if (elementSelectionKeys.includes(event.key) && selectable()) {
2113
+ actions.handleNodeSelection(node().id, event.key === "Escape", nodeRef());
2114
+ return;
2115
+ }
2116
+ let arrowKeyDiff = ARROW_KEY_DIFFS[event.key];
2117
+ draggable() && node().selected && arrowKeyDiff && (event.preventDefault(), actions.setAriaLiveMessage(store.ariaLabelConfig["node.a11yDescription.ariaLiveMessage"]({
2118
+ direction: event.key.replace("Arrow", "").toLowerCase(),
2119
+ x: ~~node().internals.positionAbsolute.x,
2120
+ y: ~~node().internals.positionAbsolute.y
2121
+ })), actions.moveSelectedNodes(arrowKeyDiff, event.shiftKey ? 4 : 1));
2122
+ }, onFocus = () => {
2123
+ if (store.disableKeyboardA11y || !store.autoPanOnNodeFocus || !nodeRef()?.matches(":focus-visible")) return;
2124
+ let { width, height, viewport } = store;
2125
+ getNodesInside(/* @__PURE__ */ new Map([[node().id, node()]]), {
2126
+ x: 0,
2127
+ y: 0,
2128
+ width,
2129
+ height
2130
+ }, [
2131
+ viewport.x,
2132
+ viewport.y,
2133
+ viewport.zoom
2134
+ ], !0).length > 0 || actions.setCenter(node().position.x + (node().measured.width ?? 0) / 2, node().position.y + (node().measured.height ?? 0) / 2, { zoom: viewport.zoom });
2135
+ }, dragging = createDraggable(nodeRef, () => ({
2136
+ nodeId: node().id,
2137
+ isSelectable: selectable(),
2138
+ disabled: !draggable(),
2139
+ handleSelector: node().dragHandle,
2140
+ noDragClass: store.noDragClass,
2141
+ nodeClickDistance: props.nodeClickDistance,
2142
+ onNodeMouseDown: actions.handleNodeSelection,
2143
+ onDrag: (event, _, targetNode, nodes) => {
2144
+ props.onNodeDrag?.({
2145
+ event,
2146
+ targetNode,
2147
+ nodes
2148
+ });
1663
2149
  },
1664
- get deleteKeyPressed() {
1665
- return deleteKeyPressed();
2150
+ onDragStart: (event, _, targetNode, nodes) => {
2151
+ props.onNodeDragStart?.({
2152
+ event,
2153
+ targetNode,
2154
+ nodes
2155
+ });
1666
2156
  },
1667
- get panActivationKeyPressed() {
1668
- return panActivationKeyPressed();
2157
+ onDragStop: (event, _, targetNode, nodes) => {
2158
+ props.onNodeDragStop?.({
2159
+ event,
2160
+ targetNode,
2161
+ nodes
2162
+ });
2163
+ }
2164
+ }));
2165
+ return createComponent(Show, {
2166
+ get when() {
2167
+ return !node().hidden;
1669
2168
  },
1670
- get zoomActivationKeyPressed() {
1671
- return zoomActivationKeyPressed();
2169
+ get children() {
2170
+ var _el$ = _tmpl$$27();
2171
+ return ref(() => setNodeRef, _el$), spread(_el$, mergeProps({
2172
+ get "data-id"() {
2173
+ return node().id;
2174
+ },
2175
+ get class() {
2176
+ return [
2177
+ "solid-flow__node",
2178
+ `solid-flow__node-${nodeType()}`,
2179
+ {
2180
+ connectable: !!connectable(),
2181
+ draggable: !!draggable(),
2182
+ dragging: dragging(),
2183
+ nopan: !!draggable(),
2184
+ parent: isParentNode(),
2185
+ selectable: !!selectable(),
2186
+ selected: !!node().selected
2187
+ },
2188
+ node().class
2189
+ ];
2190
+ },
2191
+ get style() {
2192
+ return style();
2193
+ },
2194
+ onClick: onSelectNodeHandler,
2195
+ onPointerEnter: (event) => props.onNodePointerEnter?.({
2196
+ node: userNode(),
2197
+ event
2198
+ }),
2199
+ onPointerLeave: (event) => props.onNodePointerLeave?.({
2200
+ node: userNode(),
2201
+ event
2202
+ }),
2203
+ onPointerMove: (event) => props.onNodePointerMove?.({
2204
+ node: userNode(),
2205
+ event
2206
+ }),
2207
+ onContextMenu: (event) => props.onNodeContextMenu?.({
2208
+ node: userNode(),
2209
+ event
2210
+ }),
2211
+ onKeyDown: (e) => focusable() && onKeyDown(e),
2212
+ onFocus: () => focusable() && onFocus(),
2213
+ get tabindex() {
2214
+ return focusable() ? 0 : void 0;
2215
+ },
2216
+ get role() {
2217
+ return node().ariaRole ?? (focusable() ? "group" : void 0);
2218
+ },
2219
+ "aria-roledescription": "node",
2220
+ get "aria-describedby"() {
2221
+ return store.disableKeyboardA11y ? void 0 : `${ARIA_NODE_DESC_KEY}-${store.id}`;
2222
+ }
2223
+ }, () => node().domAttributes), !0), insert(_el$, createComponent(NodeIdContext, {
2224
+ value: nodeId,
2225
+ get children() {
2226
+ return createComponent(NodeConnectableContext, {
2227
+ value: connectable,
2228
+ get children() {
2229
+ return createComponent(Dynamic, {
2230
+ get component() {
2231
+ return nodeComponent();
2232
+ },
2233
+ get data() {
2234
+ return node().data;
2235
+ },
2236
+ get id() {
2237
+ return node().id;
2238
+ },
2239
+ get selected() {
2240
+ return !!node().selected;
2241
+ },
2242
+ get selectable() {
2243
+ return selectable();
2244
+ },
2245
+ get deletable() {
2246
+ return deletable();
2247
+ },
2248
+ get sourcePosition() {
2249
+ return node().sourcePosition;
2250
+ },
2251
+ get targetPosition() {
2252
+ return node().targetPosition;
2253
+ },
2254
+ get zIndex() {
2255
+ return node().internals.z;
2256
+ },
2257
+ get dragging() {
2258
+ return dragging();
2259
+ },
2260
+ get draggable() {
2261
+ return draggable();
2262
+ },
2263
+ get dragHandle() {
2264
+ return node().dragHandle;
2265
+ },
2266
+ get parentId() {
2267
+ return node().parentId;
2268
+ },
2269
+ get type() {
2270
+ return nodeType();
2271
+ },
2272
+ get isConnectable() {
2273
+ return connectable();
2274
+ },
2275
+ get positionAbsoluteX() {
2276
+ return node().internals.positionAbsolute.x;
2277
+ },
2278
+ get positionAbsoluteY() {
2279
+ return node().internals.positionAbsolute.y;
2280
+ },
2281
+ get width() {
2282
+ return node().width;
2283
+ },
2284
+ get height() {
2285
+ return node().height;
2286
+ }
2287
+ });
2288
+ }
2289
+ });
2290
+ }
2291
+ })), _el$;
1672
2292
  }
1673
- }), visibleNodesMap = createMemo(() => nodeLookup), visibleNodeIds = createMemo(() => Array.from(visibleNodesMap().values()).map((edge) => edge.id)), visibleEdgeIds = createMemo(() => Array.from(layoutedEdgesMap.values()).map((edge) => edge.id)), getEdge = (id) => layoutedEdgesMap.get(id), fitView = async (options) => store.panZoom ? await fitViewport({
1674
- nodes: nodeLookup,
1675
- width: store.width,
1676
- height: store.height,
1677
- panZoom: store.panZoom,
1678
- minZoom: store.minZoom,
1679
- maxZoom: store.maxZoom
1680
- }, options ?? config().fitViewOptions) : !1, resetStoreValues = () => {
1681
- setDragging(!1), setSelectionRect(void 0), setSelectionRectMode(void 0), setSelectionKeyPressed(!1), setMultiselectionKeyPressed(!1), setDeleteKeyPressed(!1), setPanActivationKeyPressed(!1), setZoomActivationKeyPressed(!1), setConnection({ ...initialConnection }), setClickConnectStartHandle(void 0), setViewportStore(() => config().initialViewport ?? {
1682
- x: 0,
1683
- y: 0,
1684
- zoom: 1
1685
- }), setAriaLiveMessage(""), setSnapGrid(void 0);
1686
- }, addEdge = (edgeParams) => {
1687
- setEdgesStore((edges) => {
1688
- let next = addEdge$1(edgeParams, edges);
1689
- next !== edges && edges.push(next[next.length - 1]);
1690
- });
1691
- }, initialFitViewApplied = !1, initialNodesMeasured = !1, applyInitialFitView = (initialFitView) => {
1692
- initialFitViewApplied = !initialFitView;
1693
- }, tryInitialFitView = () => {
1694
- initialFitViewApplied || !initialNodesMeasured || untrack(() => store.panZoom && store.width && store.height) && (initialFitViewApplied = !0, untrack(() => fitView()));
1695
- }, updateNodePositions = (nodeDragItems, dragging = !1) => {
1696
- setNodesStore((nodes) => {
1697
- for (let node of nodes) nodeDragItems.has(node.id) && (node.dragging = dragging, node.position = nodeDragItems.get(node.id).position);
1698
- });
1699
- }, pendingEntries, requestUpdateNodeInternals = (updateEntries) => {
1700
- if (pendingEntries) {
1701
- pendingEntries.push(...updateEntries);
1702
- return;
2293
+ });
2294
+ }, OutputNode = (props) => {
2295
+ let _props = propDefaults(props, { targetPosition: Position$1.Top });
2296
+ return [createComponent(Handle, {
2297
+ type: "target",
2298
+ get position() {
2299
+ return _props.targetPosition;
2300
+ },
2301
+ get isConnectable() {
2302
+ return _props.isConnectable;
1703
2303
  }
1704
- pendingEntries = updateEntries, scheduleIdleCallback(() => {
1705
- {
1706
- let updates = new Map(pendingEntries);
1707
- pendingEntries = void 0;
1708
- let { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, store.domNode, store.nodeOrigin);
1709
- if (!updatedInternals) return;
1710
- updateAbsolutePositions(nodeLookup, parentLookup, {
1711
- nodeOrigin: store.nodeOrigin,
1712
- nodeExtent: store.nodeExtent,
1713
- zIndexMode: store.zIndexMode
1714
- });
1715
- let nodeToChange = changes.reduce((acc, change) => {
1716
- let node = nodeLookup.get(change.id)?.internals.userNode;
1717
- return node && acc.set(node.id, change), acc;
1718
- }, /* @__PURE__ */ new Map());
1719
- setNodesStore((nodes) => {
1720
- for (let node of nodes) {
1721
- let change = nodeToChange.get(node.id);
1722
- if (change) switch (change.type) {
1723
- case "dimensions":
1724
- change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
1725
- ...node.measured,
1726
- ...change.dimensions
1727
- };
1728
- break;
1729
- case "position": node.position = change.position ?? node.position;
1730
- }
1731
- }
1732
- }), flush(), initialNodesMeasured = !0, tryInitialFitView();
1733
- }
1734
- });
1735
- }, zoomBy = async (factor, options) => store.panZoom ? store.panZoom.scaleBy(factor, options) : !1, zoomIn = (options) => zoomBy(1.2, options), zoomOut = (options) => zoomBy(1 / 1.2, options), setCenter = async (x, y, options) => {
1736
- let nextZoom = options?.zoom === void 0 ? store.maxZoom : options.zoom, currentPanZoom = store.panZoom;
1737
- return currentPanZoom ? (await currentPanZoom.setViewport({
1738
- x: store.width / 2 - x * nextZoom,
1739
- y: store.height / 2 - y * nextZoom,
1740
- zoom: nextZoom
1741
- }, {
1742
- duration: options?.duration,
1743
- ease: options?.ease,
1744
- interpolate: options?.interpolate
1745
- }), Promise.resolve(!0)) : Promise.resolve(!1);
1746
- }, setPaneClickDistance = (distance) => {
1747
- store.panZoom?.setClickDistance(distance);
1748
- }, unselectNodesAndEdges = ({ nodes: _nodes, edges } = {}) => {
1749
- let nodesToUnselect = new Set((_nodes || store.nodes).map(({ id }) => id));
1750
- nodesToUnselect.size && setNodesStore((nodes) => {
1751
- for (let node of nodes) nodesToUnselect.has(node.id) && (node.selected = !1);
1752
- });
1753
- let edgesToUnselect = new Set((edges ?? store.edges).map(({ id }) => id));
1754
- edgesToUnselect.size && setEdgesStore((edges) => {
1755
- for (let edge of edges) edgesToUnselect.has(edge.id) && (edge.selected = !1);
1756
- });
1757
- }, addSelectedNodes = (ids) => {
1758
- let isMultiSelection = store.multiselectionKeyPressed, selectState = /* @__PURE__ */ new Map();
1759
- setNodesStore((nodes) => {
1760
- for (let node of nodes) {
1761
- let nodeWillBeSelected = ids.includes(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
1762
- if (selectState.set(node.id, selected), node.selected === selected) continue;
1763
- let internalNode = nodeLookup.get(node.id);
1764
- internalNode && (internalNode.selected = selected), node.selected = selected;
1765
- }
1766
- }), isMultiSelection || unselectNodesAndEdges({ nodes: [] });
1767
- }, addSelectedEdges = (ids) => {
1768
- let isMultiSelection = store.multiselectionKeyPressed, edgeSelectState = /* @__PURE__ */ new Map();
1769
- setEdgesStore((edges) => {
1770
- for (let edge of edges) {
1771
- let edgeWillBeSelected = ids.includes(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
1772
- edgeSelectState.set(edge.id, selected), edge.selected !== selected && (edge.selected = selected);
1773
- }
1774
- }), isMultiSelection || unselectNodesAndEdges({ edges: [] });
1775
- };
1776
- return createEffect(() => !!(width() && height() && panZoom()), (ready) => {
1777
- ready && tryInitialFitView();
1778
- }), createEffect(() => ({
1779
- panZoom: store.panZoom,
1780
- viewport: {
1781
- x: store.viewport.x,
1782
- y: store.viewport.y,
1783
- zoom: store.viewport.zoom
2304
+ }), memo(() => props.data?.label)];
2305
+ };
2306
+ //#endregion
2307
+ //#region src/data/xyflow.ts
2308
+ /**
2309
+ * The DOM side of the measurement pipeline (fork of @xyflow/system's
2310
+ * updateNodeInternals): reads each updated node element's dimensions and
2311
+ * handle bounds from the DOM and reports them as data — measurement writes
2312
+ * for the measurements root plus user-facing dimension/position changes —
2313
+ * instead of writing into a node lookup. The internalNodes projection turns
2314
+ * the measurement writes back into internal-node state.
2315
+ *
2316
+ * `parentExpandChildren` must be turned into changes via
2317
+ * {@link handleExpandParent} only AFTER the measurement writes have been
2318
+ * flushed, so parent geometry reflects this measuring pass.
2319
+ */
2320
+ function measureNodeInternals(updates, nodeLookup, domNode, nodeExtent) {
2321
+ let measurementWrites = [], changes = [], parentExpandChildren = [], updatedInternals = !1, viewportNode = domNode?.querySelector(".xyflow__viewport");
2322
+ if (!viewportNode) return {
2323
+ updatedInternals,
2324
+ measurementWrites,
2325
+ changes,
2326
+ parentExpandChildren
2327
+ };
2328
+ let style = window.getComputedStyle(viewportNode), { m22: zoom } = new window.DOMMatrixReadOnly(style.transform);
2329
+ for (let update of updates.values()) {
2330
+ let node = nodeLookup.get(update.id);
2331
+ if (!node) continue;
2332
+ if (node.hidden) {
2333
+ measurementWrites.push({
2334
+ id: node.id,
2335
+ hidden: !0
2336
+ }), updatedInternals = !0;
2337
+ continue;
1784
2338
  }
1785
- }), ({ panZoom, viewport }) => {
1786
- panZoom?.syncViewport(viewport);
1787
- }), createEffect(() => ({
1788
- panZoom: panZoom(),
1789
- extent: [store.minZoom, store.maxZoom]
1790
- }), ({ panZoom, extent }) => {
1791
- panZoom?.setScaleExtent(extent);
1792
- }), createEffect(() => ({
1793
- panZoom: panZoom(),
1794
- extent: store.translateExtent
1795
- }), ({ panZoom, extent }) => {
1796
- panZoom?.setTranslateExtent(extent);
1797
- }), createRenderEffect(mapArray(() => store.nodes, (userNode) => {
1798
- createRenderEffect(() => {
1799
- let internalNode = untrack(() => nodeLookup.get(userNode.id)), selectedNodeZ = store.elevateNodesOnSelect && store.zIndexMode !== "manual" ? 1e3 : 0, clampedPosition = clampPosition(getNodePositionWithOrigin(userNode, store.nodeOrigin), isCoordinateExtent(userNode.extent) ? userNode.extent : store.nodeExtent, getNodeDimensions(userNode)), preservedMeasured = {
1800
- width: userNode.measured?.width ?? internalNode?.measured?.width,
1801
- height: userNode.measured?.height ?? internalNode?.measured?.height
1802
- }, updatedNodeInternals = {
1803
- ...userNode,
1804
- measured: preservedMeasured,
1805
- internals: {
1806
- positionAbsolute: clampedPosition,
1807
- handleBounds: !userNode.measured && !internalNode?.measured ? void 0 : internalNode?.internals.handleBounds,
1808
- z: calculateZ(userNode, selectedNodeZ, store.zIndexMode),
1809
- userNode
2339
+ let dimensions = getDimensions(update.nodeElement), dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
2340
+ if (dimensions.width && dimensions.height && (dimensionChanged || !node.internals.handleBounds || update.force)) {
2341
+ let nodeBounds = update.nodeElement.getBoundingClientRect(), extent = isCoordinateExtent(node.extent) ? node.extent : nodeExtent, { positionAbsolute } = node.internals;
2342
+ node.parentId && node.extent === "parent" ? positionAbsolute = clampPositionToParent(positionAbsolute, dimensions, nodeLookup.get(node.parentId)) : extent && (positionAbsolute = clampPosition(positionAbsolute, extent, dimensions)), measurementWrites.push({
2343
+ id: node.id,
2344
+ measured: dimensions,
2345
+ handleBounds: {
2346
+ source: getHandleBounds("source", update.nodeElement, nodeBounds, zoom, node.id),
2347
+ target: getHandleBounds("target", update.nodeElement, nodeBounds, zoom, node.id)
2348
+ }
2349
+ }), updatedInternals = !0, dimensionChanged && (changes.push({
2350
+ id: node.id,
2351
+ type: "dimensions",
2352
+ dimensions
2353
+ }), node.expandParent && node.parentId && parentExpandChildren.push({
2354
+ id: node.id,
2355
+ parentId: node.parentId,
2356
+ rect: nodeToRect({
2357
+ ...node,
2358
+ measured: dimensions,
2359
+ internals: {
2360
+ ...node.internals,
2361
+ positionAbsolute
2362
+ }
2363
+ })
2364
+ }));
2365
+ }
2366
+ }
2367
+ return {
2368
+ updatedInternals,
2369
+ measurementWrites,
2370
+ changes,
2371
+ parentExpandChildren
2372
+ };
2373
+ }
2374
+ function handleExpandParent(children, nodeLookup, getChildNodes, nodeOrigin = [0, 0]) {
2375
+ let changes = [], parentExpansions = /* @__PURE__ */ new Map();
2376
+ for (let child of children) {
2377
+ let parent = nodeLookup.get(child.parentId);
2378
+ if (!parent) continue;
2379
+ let parentRect = parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent), expandedRect = getBoundsOfRects(parentRect, child.rect);
2380
+ parentExpansions.set(child.parentId, {
2381
+ expandedRect,
2382
+ parent
2383
+ });
2384
+ }
2385
+ return parentExpansions.size > 0 && parentExpansions.forEach(({ expandedRect, parent }, parentId) => {
2386
+ let positionAbsolute = parent.internals.positionAbsolute, dimensions = getNodeDimensions(parent), origin = parent.origin ?? nodeOrigin, xChange = expandedRect.x < positionAbsolute.x ? Math.round(Math.abs(positionAbsolute.x - expandedRect.x)) : 0, yChange = expandedRect.y < positionAbsolute.y ? Math.round(Math.abs(positionAbsolute.y - expandedRect.y)) : 0, newWidth = Math.max(dimensions.width, Math.round(expandedRect.width)), newHeight = Math.max(dimensions.height, Math.round(expandedRect.height)), widthChange = (newWidth - dimensions.width) * origin[0], heightChange = (newHeight - dimensions.height) * origin[1];
2387
+ if (xChange > 0 || yChange > 0 || widthChange || heightChange) {
2388
+ changes.push({
2389
+ id: parentId,
2390
+ type: "position",
2391
+ position: {
2392
+ x: parent.position.x - xChange + widthChange,
2393
+ y: parent.position.y - yChange + heightChange
1810
2394
  }
1811
- };
1812
- nodeLookup.set(userNode.id, updatedNodeInternals), userNode.parentId && updateChildNode(updatedNodeInternals, nodeLookup, parentLookup, {
1813
- nodeOrigin: store.nodeOrigin,
1814
- nodeExtent: store.nodeExtent,
1815
- elevateNodesOnSelect: store.elevateNodesOnSelect,
1816
- zIndexMode: store.zIndexMode,
1817
- checkEquality: !0
1818
- });
1819
- }, () => {}), onCleanup(() => {});
1820
- }), () => {}), createEffect(() => new Set(store.nodes.map((n) => n.id)), (currentIds) => {
1821
- for (let id of untrack(() => Array.from(nodeLookup.keys()))) currentIds.has(id) || nodeLookup.delete(id);
1822
- }), createRenderEffect(mapArray(() => store.edges, (edge) => {
1823
- let { source: sourceNodeId, target: targetNodeId, sourceHandle = null, targetHandle = null } = edge, connection = {
1824
- edgeId: edge.id,
1825
- source: sourceNodeId,
1826
- target: targetNodeId,
1827
- sourceHandle,
1828
- targetHandle
1829
- }, sourceKey = `${sourceNodeId}-${sourceHandle}--${targetNodeId}-${targetHandle}`, targetKey = `${targetNodeId}-${targetHandle}--${sourceNodeId}-${sourceHandle}`;
1830
- createRenderEffect(() => {
1831
- addConnectionToLookup("source", connection, targetKey, connectionLookup, sourceNodeId, sourceHandle), addConnectionToLookup("target", connection, sourceKey, connectionLookup, targetNodeId, targetHandle), edgeLookup.set(edge.id, edge);
1832
- }, () => {}), createRenderEffect(() => {
1833
- let sourceNode = nodeLookup.get(edge.source), targetNode = nodeLookup.get(edge.target);
1834
- if (!sourceNode || !targetNode) return;
1835
- if (store.onlyRenderVisibleElements) {
1836
- if (!isEdgeVisible({
1837
- sourceNode,
1838
- targetNode,
1839
- width: store.width ?? 0,
1840
- height: store.height ?? 0,
1841
- transform: store.transform
1842
- })) return;
1843
- store.visibleNodesMap.set(sourceNode.id, sourceNode), store.visibleNodesMap.set(targetNode.id, targetNode);
1844
- }
1845
- let edgePosition = getEdgePosition({
1846
- id: edge.id,
1847
- sourceNode,
1848
- targetNode,
1849
- sourceHandle: edge.sourceHandle || null,
1850
- targetHandle: edge.targetHandle || null,
1851
- connectionMode: store.connectionMode,
1852
- onError: store.onError
1853
2395
  });
1854
- edgePosition && layoutedEdgesMap.set(edge.id, {
1855
- ...store.defaultEdgeOptions,
1856
- ...edge,
1857
- ...edgePosition,
1858
- zIndex: getElevatedEdgeZIndex({
1859
- selected: edge.selected,
1860
- zIndex: edge.zIndex ?? store.defaultEdgeOptions.zIndex,
1861
- sourceNode,
1862
- targetNode,
1863
- elevateOnSelect: store.elevateEdgesOnSelect,
1864
- zIndexMode: store.zIndexMode
1865
- }),
1866
- sourceNode,
1867
- targetNode,
1868
- edge
2396
+ for (let childNode of getChildNodes(parentId)) children.some((child) => child.id === childNode.id) || changes.push({
2397
+ id: childNode.id,
2398
+ type: "position",
2399
+ position: {
2400
+ x: childNode.position.x + xChange,
2401
+ y: childNode.position.y + yChange
2402
+ }
1869
2403
  });
1870
- }, () => {}), onCleanup(() => {
1871
- edgeLookup.delete(edge.id), layoutedEdgesMap.delete(edge.id), removeConnectionFromLookup("source", targetKey, connectionLookup, sourceNodeId, sourceHandle), removeConnectionFromLookup("target", sourceKey, connectionLookup, targetNodeId, targetHandle);
2404
+ }
2405
+ (dimensions.width < expandedRect.width || dimensions.height < expandedRect.height || xChange || yChange) && changes.push({
2406
+ id: parentId,
2407
+ type: "dimensions",
2408
+ setAttributes: !0,
2409
+ dimensions: {
2410
+ width: newWidth + (xChange ? origin[0] * xChange - widthChange : 0),
2411
+ height: newHeight + (yChange ? origin[1] * yChange - heightChange : 0)
2412
+ }
1872
2413
  });
1873
- }), () => {}), createEffect(() => new Set(store.edges.map((e) => e.id)), (currentIds) => {
1874
- for (let id of untrack(() => Array.from(edgeLookup.keys()))) currentIds.has(id) || (edgeLookup.delete(id), connectionLookup.delete(id), layoutedEdgesMap.delete(id));
1875
- }), {
1876
- store,
1877
- nodeLookup,
1878
- edgeLookup,
1879
- parentLookup,
1880
- connectionLookup,
2414
+ }), changes;
2415
+ }
2416
+ //#endregion
2417
+ //#region src/data/createSolidFlow.tsx
2418
+ const InitialNodeTypesMap = {
2419
+ input: InputNode,
2420
+ output: OutputNode,
2421
+ default: DefaultNode,
2422
+ group: GroupNode
2423
+ }, InitialEdgeTypesMap = {
2424
+ straight: StraightEdgeInternal,
2425
+ smoothstep: SmoothStepEdgeInternal,
2426
+ default: BezierEdgeInternal,
2427
+ step: StepEdgeInternal
2428
+ }, createSolidFlow = (props) => {
2429
+ let state = createFlowState(props, {
2430
+ prefersDark: createMediaQuery("(prefers-color-scheme: dark)", props.colorModeSSR === "dark"),
2431
+ initialNodeTypes: InitialNodeTypesMap,
2432
+ initialEdgeTypes: InitialEdgeTypesMap
2433
+ }), { store, nodeLookup, actions } = state, pendingEntries, requestUpdateNodeInternals = (updateEntries) => {
2434
+ if (pendingEntries) {
2435
+ pendingEntries.push(...updateEntries);
2436
+ return;
2437
+ }
2438
+ pendingEntries = updateEntries, scheduleIdleCallback(() => {
2439
+ let updates = new Map(pendingEntries);
2440
+ pendingEntries = void 0;
2441
+ let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode);
2442
+ updatedInternals && (actions.applyMeasurementWrites(measurementWrites), flush(), parentExpandChildren.length > 0 && changes.push(...handleExpandParent(parentExpandChildren, nodeLookup, (parentId) => store.nodes.filter((node) => node.parentId === parentId), store.nodeOrigin)), actions.applyNodeChanges(changes), flush(), actions.markInitialNodesMeasured());
2443
+ });
2444
+ };
2445
+ return actions.setMeasureRequester(requestUpdateNodeInternals), {
2446
+ ...state,
1881
2447
  actions: {
1882
- getEdge,
1883
- applyInitialFitView,
1884
- resetStoreValues,
1885
- requestUpdateNodeInternals,
1886
- setAriaLabelConfig,
1887
- setAriaLiveMessage,
1888
- setClickConnectStartHandle,
1889
- setConfig,
1890
- setConnection,
1891
- setDeleteKeyPressed,
1892
- setDomNode,
1893
- setDragging,
1894
- get setEdges() {
1895
- return setEdgesStore;
1896
- },
1897
- setElementsSelectable,
1898
- setHeight,
1899
- setMultiselectionKeyPressed,
1900
- get setNodes() {
1901
- return setNodesStore;
1902
- },
1903
- setNodesConnectable,
1904
- setNodesDraggable,
1905
- setPanActivationKeyPressed,
1906
- setPanZoom,
1907
- setSelectionKeyPressed,
1908
- setSelectionRect,
1909
- setSelectionRectMode,
1910
- get setViewport() {
1911
- return (viewport) => setViewportStore(() => viewport);
1912
- },
1913
- setWidth,
1914
- setZoomActivationKeyPressed,
1915
- addEdge,
1916
- updateNodePositions,
1917
- zoomIn,
1918
- zoomOut,
1919
- fitView,
1920
- setCenter,
1921
- setPaneClickDistance,
1922
- unselectNodesAndEdges,
1923
- addSelectedNodes,
1924
- addSelectedEdges,
1925
- handleNodeSelection: (id, unselect, nodeRef) => {
1926
- let node = store.nodes.find((n) => n.id === id);
1927
- node && (setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
1928
- nodes: [node],
1929
- edges: []
1930
- }), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
1931
- },
1932
- handleEdgeSelection: (id) => {
1933
- let edge = edgeLookup.get(id);
1934
- edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
1935
- nodes: [],
1936
- edges: [edge]
1937
- }) : addSelectedEdges([id]));
1938
- },
1939
- moveSelectedNodes: (direction, factor) => {
1940
- let nodeUpdates = /* @__PURE__ */ new Map(), xVelo = store.snapGrid?.[0] ?? 5, yVelo = store.snapGrid?.[1] ?? 5, xDiff = direction.x * xVelo * factor, yDiff = direction.y * yVelo * factor;
1941
- for (let node of nodeLookup.values()) {
1942
- if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
1943
- let nextPosition = {
1944
- x: node.internals.positionAbsolute.x + xDiff,
1945
- y: node.internals.positionAbsolute.y + yDiff
1946
- };
1947
- store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
1948
- let { position, positionAbsolute } = calculateNodePosition({
1949
- nodeId: node.id,
1950
- nextPosition,
1951
- nodeLookup,
1952
- nodeExtent: store.nodeExtent,
1953
- nodeOrigin: store.nodeOrigin,
1954
- onError: store.onError
1955
- });
1956
- node.position = position, node.internals.positionAbsolute = positionAbsolute, nodeUpdates.set(node.id, node);
1957
- }
1958
- updateNodePositions(nodeUpdates);
1959
- },
1960
- panBy: (delta) => panBy({
1961
- delta,
1962
- panZoom: store.panZoom,
1963
- transform: store.transform,
1964
- translateExtent: store.translateExtent,
1965
- width: store.width,
1966
- height: store.height
1967
- }),
1968
- cancelConnection: () => {
1969
- setConnection({ ...initialConnection });
1970
- },
1971
- reset: () => {
1972
- resetStoreValues(), unselectNodesAndEdges();
1973
- }
2448
+ ...actions,
2449
+ requestUpdateNodeInternals
1974
2450
  }
1975
2451
  };
1976
2452
  }, SolidFlowContext = createContext(null);
@@ -2139,7 +2615,7 @@ const isSetEqual = (a, b) => {
2139
2615
  for (let item of a) if (!b.has(item)) return !1;
2140
2616
  return !0;
2141
2617
  }, Pane = (props) => {
2142
- let { store, nodeLookup, edgeLookup, connectionLookup, actions } = useInternalSolidFlow(), [containerRef, setContainerRef] = createSignal(), container, containerBounds = null, connectionEndedOnPane = !1, selectionInProgress = !1, selectedNodeIds = /* @__PURE__ */ new Set(), selectedEdgeIds = /* @__PURE__ */ new Set(), autoPanId = 0, position = {
2618
+ let { store, nodeLookup, edgeLookup, connections, actions } = useInternalSolidFlow(), [containerRef, setContainerRef] = createSignal(), container, containerBounds = null, connectionEndedOnPane = !1, selectionInProgress = !1, selectedNodeIds = /* @__PURE__ */ new Set(), selectedEdgeIds = /* @__PURE__ */ new Set(), autoPanId = 0, position = {
2143
2619
  x: 0,
2144
2620
  y: 0
2145
2621
  }, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ?? 1, _panOnDrag = () => store.panActivationKeyPressed || props.panOnDrag, isSelecting = () => store.selectionKeyPressed || !!store.selectionRect || props.selectionOnDrag && _panOnDrag() !== !0, isSelectionEnabled = () => store.elementsSelectable && (isSelecting() || store.selectionRectMode === "user"), onClick = (event) => {
@@ -2185,9 +2661,9 @@ const isSetEqual = (a, b) => {
2185
2661
  let edgesSelectable = store.defaultEdgeOptions.selectable ?? !0;
2186
2662
  selectedEdgeIds = /* @__PURE__ */ new Set();
2187
2663
  for (let nodeId of selectedNodeIds) {
2188
- let connections = connectionLookup.get(nodeId);
2189
- if (connections) for (let { edgeId } of connections.values()) {
2190
- let edge = edgeLookup.get(edgeId);
2664
+ let nodeConnections = connections[nodeId];
2665
+ if (nodeConnections) for (let { edgeId } of Object.values(nodeConnections)) {
2666
+ let edge = edgeLookup[edgeId];
2191
2667
  edge && (edge.selectable ?? edgesSelectable) && selectedEdgeIds.add(edgeId);
2192
2668
  }
2193
2669
  }
@@ -2793,7 +3269,7 @@ var _tmpl$$8 = /* @__PURE__ */ template("<div>");
2793
3269
  * The toolbar does not scale with the viewport so that its content is always legible.
2794
3270
  */
2795
3271
  const EdgeToolbar = (props) => {
2796
- let rest = omit(props, "x", "y", "alignX", "alignY", "isVisible", "selectEdgeOnClick", "class", "children"), { store, edgeLookup } = useInternalSolidFlow(), edgeId = useEdgeId(), isActive = () => typeof props.isVisible == "boolean" ? props.isVisible : !!edgeLookup.get(edgeId())?.selected, transform = () => getEdgeToolbarTransform(props.x, props.y, store.viewport.zoom, props.alignX ?? "center", props.alignY ?? "center");
3272
+ let rest = omit(props, "x", "y", "alignX", "alignY", "isVisible", "selectEdgeOnClick", "class", "children"), { store, edgeLookup } = useInternalSolidFlow(), edgeId = useEdgeId(), isActive = () => typeof props.isVisible == "boolean" ? props.isVisible : !!edgeLookup[edgeId()]?.selected, transform = () => getEdgeToolbarTransform(props.x, props.y, store.viewport.zoom, props.alignX ?? "center", props.alignY ?? "center");
2797
3273
  return createComponent(Show, {
2798
3274
  get when() {
2799
3275
  return isActive();
@@ -3146,8 +3622,8 @@ const ResizeControl = (props) => {
3146
3622
  * @returns an accessor for the current color mode class
3147
3623
  */
3148
3624
  function useColorMode() {
3149
- let { store } = useInternalSolidFlow();
3150
- return () => store.colorMode;
3625
+ let { flow } = useInternalSolidFlow();
3626
+ return () => flow.colorMode;
3151
3627
  }
3152
3628
  //#endregion
3153
3629
  //#region src/hooks/useConnection.tsx
@@ -3158,8 +3634,8 @@ function useColorMode() {
3158
3634
  * @returns current connection as a readable store
3159
3635
  */
3160
3636
  function useConnection() {
3161
- let { store } = useInternalSolidFlow();
3162
- return () => store.connection;
3637
+ let { flow } = useInternalSolidFlow();
3638
+ return () => flow.connection;
3163
3639
  }
3164
3640
  //#endregion
3165
3641
  //#region src/hooks/useGraph.ts
@@ -3190,15 +3666,15 @@ function useEdges() {
3190
3666
  * @returns store with the viewport object
3191
3667
  */
3192
3668
  function useViewport() {
3193
- let { store } = useInternalSolidFlow();
3194
- return () => store.viewport;
3669
+ let { flow } = useInternalSolidFlow();
3670
+ return () => flow.viewport;
3195
3671
  }
3196
3672
  //#endregion
3197
3673
  //#region src/hooks/useHandleEdgeSelect.tsx
3198
3674
  function useHandleEdgeSelect() {
3199
3675
  let { store, edgeLookup, actions } = useInternalSolidFlow();
3200
3676
  return (id) => {
3201
- let edge = edgeLookup.get(id);
3677
+ let edge = edgeLookup[id];
3202
3678
  edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) && (actions.setSelectionRect(void 0), actions.setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && actions.unselectNodesAndEdges({
3203
3679
  nodes: [],
3204
3680
  edges: [edge]
@@ -3217,8 +3693,8 @@ function useHandleEdgeSelect() {
3217
3693
  * @returns an accessor that indicates whether the nodes are initialized
3218
3694
  */
3219
3695
  function useNodesInitialized() {
3220
- let { store } = useInternalSolidFlow();
3221
- return () => store.nodesInitialized;
3696
+ let { flow } = useInternalSolidFlow();
3697
+ return () => flow.nodesInitialized;
3222
3698
  }
3223
3699
  /**
3224
3700
  * Hook for seeing if the viewport is initialized.
@@ -3229,8 +3705,8 @@ function useNodesInitialized() {
3229
3705
  * @returns an accessor that indicates whether the viewport is initialized
3230
3706
  */
3231
3707
  function useViewportInitialized() {
3232
- let { store } = useInternalSolidFlow();
3233
- return () => store.viewportInitialized;
3708
+ let { flow } = useInternalSolidFlow();
3709
+ return () => flow.viewportInitialized;
3234
3710
  }
3235
3711
  //#endregion
3236
3712
  //#region src/hooks/useInternalNode.tsx
@@ -3242,8 +3718,8 @@ function useViewportInitialized() {
3242
3718
  * @returns an accessor with an internal node or undefined
3243
3719
  */
3244
3720
  function useInternalNode(id) {
3245
- let { nodeLookup } = useInternalSolidFlow();
3246
- return () => nodeLookup.get(id());
3721
+ let { flow } = useInternalSolidFlow();
3722
+ return () => flow.internalNodes[id()];
3247
3723
  }
3248
3724
  //#endregion
3249
3725
  //#region src/hooks/useNodeConnections.ts
@@ -3259,24 +3735,28 @@ function useInternalNode(id) {
3259
3735
  * @returns an array with connections
3260
3736
  */
3261
3737
  const useNodeConnections = (params) => {
3262
- let { connectionLookup } = useInternalSolidFlow(), ctxNodeId = () => {
3738
+ let { flow } = useInternalSolidFlow(), ctxNodeId = () => {
3263
3739
  let id = useContext(NodeIdContext);
3264
3740
  return id ? id() : "";
3265
- }, id = () => params().handleId, type = () => params().handleType, nodeId = () => params().id ?? ctxNodeId(), [connections, setConnections] = createSignal([]), lookupKey = () => `${nodeId()}${type() ? id() ? `-${type()}-${id()}` : `-${type()}` : ""}`, prevConnections;
3266
- return createEffect(() => ({ connections: connectionLookup.get(lookupKey()) }), ({ connections: nextConnections }) => {
3267
- areConnectionMapsEqual(nextConnections, prevConnections) || (prevConnections = nextConnections, setConnections(Array.from(nextConnections?.values() ?? [])));
3741
+ }, id = () => params().handleId, type = () => params().handleType, nodeId = () => params().id ?? ctxNodeId(), [connections, setConnections] = createSignal([]), prevConnections;
3742
+ return createEffect(() => {
3743
+ let rec = flow.connections[connectionKey(nodeId(), type(), id())], map = /* @__PURE__ */ new Map();
3744
+ for (let key of Object.keys(rec ?? {})) map.set(key, { ...rec[key] });
3745
+ return { connections: map };
3746
+ }, ({ connections: nextConnections }) => {
3747
+ areConnectionMapsEqual(nextConnections, prevConnections) || (prevConnections = nextConnections, setConnections(Array.from(nextConnections.values())));
3268
3748
  }), connections;
3269
3749
  };
3270
3750
  //#endregion
3271
3751
  //#region src/hooks/useNodesData.ts
3272
3752
  function useNodesData(nodeIds) {
3273
- let { nodeLookup } = useInternalSolidFlow(), prevNodesData = [];
3753
+ let { flow } = useInternalSolidFlow(), prevNodesData = [];
3274
3754
  return createMemo(() => {
3275
3755
  let nodesData = [], idValues = nodeIds();
3276
3756
  if (!idValues) return;
3277
3757
  let ids = Array.isArray(idValues) ? idValues : [idValues];
3278
3758
  for (let nodeId of ids) {
3279
- let node = nodeLookup.get(nodeId)?.internals.userNode;
3759
+ let node = flow.internalNodes[nodeId]?.internals.userNode;
3280
3760
  node && nodesData.push({
3281
3761
  id: node.id,
3282
3762
  type: node.type,
@@ -3289,206 +3769,45 @@ function useNodesData(nodeIds) {
3289
3769
  //#endregion
3290
3770
  //#region src/hooks/useSolidFlow.tsx
3291
3771
  /**
3292
- * Hook for accessing the SvelteFlow instance.
3772
+ * Hook for accessing the flow instance: `{ flow, commands }` plus the
3773
+ * commands spread at the top level for upstream familiarity.
3774
+ *
3775
+ * `flow` and `commands` are stable identities, so destructuring them is safe:
3776
+ * `const { flow, commands } = useSolidFlow()`.
3293
3777
  *
3294
3778
  * @public
3295
- * @returns A set of helper functions
3779
+ * @returns the flow's read struct, write surface, and deprecated aliases
3296
3780
  */
3297
3781
  function useSolidFlow() {
3298
- let { store, actions, nodeLookup, edgeLookup, connectionLookup } = useInternalSolidFlow(), getNodeRect = (node) => {
3299
- let nodeToUse = isNode(node) ? node : nodeLookup.get(node.id), position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, store.nodeOrigin) : nodeToUse.position, nodeWithPosition = {
3300
- ...nodeToUse,
3301
- position,
3302
- width: nodeToUse.measured?.width ?? nodeToUse.width,
3303
- height: nodeToUse.measured?.height ?? nodeToUse.height
3304
- };
3305
- return nodeToRect(nodeWithPosition);
3306
- }, updateNode = (id, nodeUpdate, options = { replace: !1 }) => {
3307
- actions.setNodes((nodes) => {
3308
- let index = nodes.findIndex((node) => node.id === id);
3309
- if (index === -1) return;
3310
- let node = nodes[index], nextNode = typeof nodeUpdate == "function" ? nodeUpdate(node) : nodeUpdate;
3311
- nodes[index] = options?.replace && isNode(nextNode) ? nextNode : {
3312
- ...node,
3313
- ...nextNode
3314
- };
3315
- });
3316
- }, updateEdge = (id, edgeUpdate, options = { replace: !1 }) => {
3317
- actions.setEdges((edges) => {
3318
- let index = edges.findIndex((edge) => edge.id === id);
3319
- if (index === -1) return;
3320
- let edge = edges[index], nextEdge = typeof edgeUpdate == "function" ? edgeUpdate(edge) : edgeUpdate;
3321
- edges[index] = options.replace && isEdge(nextEdge) ? nextEdge : {
3322
- ...edge,
3323
- ...nextEdge
3324
- };
3325
- });
3326
- }, getInternalNode = (id) => nodeLookup.get(id);
3782
+ let { flow, commands, store, edgeLookup } = useInternalSolidFlow(), getInternalNode = (id) => flow.internalNodes[id];
3327
3783
  return {
3328
- zoomIn: actions.zoomIn,
3329
- zoomOut: actions.zoomOut,
3784
+ ...commands,
3785
+ flow,
3786
+ commands,
3330
3787
  getInternalNode,
3331
- setCenter: actions.setCenter,
3332
- fitView: actions.fitView,
3333
3788
  getNode: (id) => getInternalNode(id)?.internals.userNode,
3334
- getNodes: (ids) => ids ? getElements(nodeLookup, ids) : store.nodes,
3335
- getEdge: (id) => edgeLookup.get(id),
3336
- getEdges: (ids) => ids ? getElements(edgeLookup, ids) : store.edges,
3337
- addNodes: (payload) => {
3338
- let newNodes = Array.isArray(payload) ? payload : [payload];
3339
- actions.setNodes((nodes) => [...nodes, ...newNodes]);
3340
- },
3341
- addEdges: (payload) => {
3342
- let newEdges = Array.isArray(payload) ? payload : [payload];
3343
- actions.setEdges((edges) => [...edges, ...newEdges]);
3344
- },
3789
+ getNodes: (ids) => ids ? ids.flatMap((id) => {
3790
+ let userNode = flow.internalNodes[id]?.internals.userNode;
3791
+ return userNode ? [userNode] : [];
3792
+ }) : [...flow.nodes],
3793
+ getEdge: (id) => edgeLookup[id],
3794
+ getEdges: (ids) => ids ? ids.flatMap((id) => edgeLookup[id] ? [edgeLookup[id]] : []) : [...flow.edges],
3345
3795
  getViewport: () => snapshot(store.viewport),
3346
- setViewport: async (nextViewport, options) => {
3347
- let currentViewport = store.viewport;
3348
- return store.panZoom ? (await store.panZoom.setViewport({
3349
- x: nextViewport.x ?? currentViewport.x,
3350
- y: nextViewport.y ?? currentViewport.y,
3351
- zoom: nextViewport.zoom ?? currentViewport.zoom
3352
- }, options), Promise.resolve(!0)) : Promise.resolve(!1);
3353
- },
3354
- getZoom: () => store.viewport.zoom,
3355
- setZoom: (zoomLevel, options) => {
3356
- let panZoom = store.panZoom;
3357
- return panZoom ? panZoom.scaleTo(zoomLevel, { duration: options?.duration }) : Promise.resolve(!1);
3358
- },
3359
- fitBounds: async (bounds, options) => {
3360
- if (!store.panZoom) return Promise.resolve(!1);
3361
- let viewport = getViewportForBounds$1(bounds, store.width, store.height, store.minZoom, store.maxZoom, options?.padding ?? .1);
3362
- return await store.panZoom.setViewport(viewport, {
3363
- duration: options?.duration,
3364
- ease: options?.ease,
3365
- interpolate: options?.interpolate
3366
- }), Promise.resolve(!0);
3367
- },
3368
- getIntersectingNodes: (nodeOrRect, partially = !0, nodesToIntersect) => {
3369
- let isRect = isRectObject(nodeOrRect), nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
3370
- return nodeRect ? (nodesToIntersect || store.nodes).filter((n) => {
3371
- let internalNode = nodeLookup.get(n.id);
3372
- if (!internalNode || !isRect && n.id === nodeOrRect.id) return !1;
3373
- let currNodeRect = nodeToRect(internalNode), overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
3374
- return partially && overlappingArea > 0 || overlappingArea >= nodeRect.width * nodeRect.height;
3375
- }) : [];
3376
- },
3377
- isNodeIntersecting: (nodeOrRect, area, partially = !0) => {
3378
- let nodeRect = isRectObject(nodeOrRect) ? nodeOrRect : getNodeRect(nodeOrRect);
3379
- if (!nodeRect) return !1;
3380
- let overlappingArea = getOverlappingArea(nodeRect, area);
3381
- return partially && overlappingArea > 0 || overlappingArea >= nodeRect.width * nodeRect.height;
3382
- },
3383
- deleteElements: async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
3384
- let { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
3385
- nodesToRemove,
3386
- edgesToRemove,
3387
- nodes: store.nodes,
3388
- edges: store.edges,
3389
- onBeforeDelete: store.onBeforeDelete
3390
- });
3391
- if (matchingEdges) {
3392
- let remmainingEdges = store.edges.filter((edge) => !matchingEdges.some(({ id }) => id === edge.id));
3393
- store.onEdgesDelete?.(matchingEdges), actions.setEdges(() => remmainingEdges);
3394
- }
3395
- if (matchingNodes) {
3396
- let remmainingNodes = store.nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id));
3397
- store.onNodesDelete?.(matchingNodes), actions.setNodes(() => remmainingNodes);
3398
- }
3399
- return {
3400
- deletedNodes: matchingNodes,
3401
- deletedEdges: matchingEdges
3402
- };
3403
- },
3404
- screenToFlowPosition: (position, options = { snapToGrid: !0 }) => {
3405
- if (!store.domNode) return position;
3406
- let _snapGrid = options.snapToGrid ? store.snapGrid : !1, { x, y, zoom } = store.viewport, { x: domX, y: domY } = store.domNode.getBoundingClientRect(), correctedPosition = {
3407
- x: position.x - domX,
3408
- y: position.y - domY
3409
- };
3410
- return pointToRendererPoint(correctedPosition, [
3411
- x,
3412
- y,
3413
- zoom
3414
- ], _snapGrid !== null, _snapGrid || [1, 1]);
3415
- },
3416
- /**
3417
- *
3418
- * @param position
3419
- * @returns
3420
- */
3421
- flowToScreenPosition: (position) => {
3422
- if (!store.domNode) return position;
3423
- let { x, y, zoom } = store.viewport, { x: domX, y: domY } = store.domNode.getBoundingClientRect(), rendererPosition = rendererPointToPoint(position, [
3424
- x,
3425
- y,
3426
- zoom
3427
- ]);
3428
- return {
3429
- x: rendererPosition.x + domX,
3430
- y: rendererPosition.y + domY
3431
- };
3432
- },
3433
- toObject: () => structuredClone({
3434
- nodes: [...snapshot(store.nodes)],
3435
- edges: [...snapshot(store.edges)],
3436
- viewport: { ...snapshot(store.viewport) }
3437
- }),
3438
- updateNode,
3439
- updateNodeData: (id, dataUpdate, options) => {
3440
- let node = nodeLookup.get(id)?.internals.userNode;
3441
- if (!node) return;
3442
- let nextData = typeof dataUpdate == "function" ? dataUpdate(node) : dataUpdate;
3443
- updateNode(id, (node) => ({
3444
- ...node,
3445
- data: options?.replace ? nextData : {
3446
- ...node.data,
3447
- ...nextData
3448
- }
3449
- }));
3450
- },
3451
- updateEdge,
3452
- getNodesBounds: (nodes) => getNodesBounds$1(nodes, {
3453
- nodeLookup,
3454
- nodeOrigin: store.nodeOrigin
3455
- }),
3456
- getHandleConnections: ({ type, id, nodeId }) => Array.from(connectionLookup.get(`${nodeId}-${type}-${id ?? null}`)?.values() ?? [])
3796
+ getZoom: () => flow.viewport.zoom,
3797
+ getHandleConnections: ({ type, id, nodeId }) => Object.values(flow.connections[connectionKey(nodeId, type, id ?? null)] ?? {})
3457
3798
  };
3458
3799
  }
3459
- function getElements(lookup, ids) {
3460
- let result = [];
3461
- for (let id of ids) {
3462
- let item = lookup.get(id);
3463
- if (item) {
3464
- let element = "internals" in item ? item.internals?.userNode : item;
3465
- result.push(element);
3466
- }
3467
- }
3468
- return result;
3469
- }
3470
3800
  //#endregion
3471
3801
  //#region src/hooks/useUpdateNodeInternals.ts
3472
3802
  /**
3473
- * Hook for updating node internals.
3803
+ * Hook for updating node internals. Sugar for `commands.updateNodeInternals`.
3474
3804
  *
3475
3805
  * @public
3476
3806
  * @returns function for updating node internals
3477
3807
  */
3478
3808
  function useUpdateNodeInternals() {
3479
- let { store, actions } = useInternalSolidFlow();
3480
- return (id) => {
3481
- let updateIds = Array.isArray(id) ? id : [id], updates = [];
3482
- for (let updateId of updateIds) {
3483
- let nodeElement = store.domNode?.querySelector(`.solid-flow__node[data-id="${updateId}"]`);
3484
- nodeElement && updates.push([updateId, {
3485
- id: updateId,
3486
- nodeElement,
3487
- force: !0
3488
- }]);
3489
- }
3490
- actions.requestUpdateNodeInternals(updates);
3491
- };
3809
+ let { commands } = useInternalSolidFlow();
3810
+ return commands.updateNodeInternals;
3492
3811
  }
3493
3812
  //#endregion
3494
3813
  //#region src/components/graph/plugins/NodeToolbar.tsx
@@ -4053,4 +4372,4 @@ const SolidFlow = (props) => {
4053
4372
  return [store, setStore];
4054
4373
  };
4055
4374
  //#endregion
4056
- export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdges, useHandleEdgeSelect, useInternalNode, useNodeConnections, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };
4375
+ export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, connectionKey, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdges, useHandleEdgeSelect, useInternalNode, useNodeConnections, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };