@dschz/solid-flow 1.0.0-next.7 → 1.0.0-next.8
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.
- package/dist/index/index.d.ts +30 -5
- package/dist/index/index.js +321 -220
- package/dist/index/index.jsx +265 -169
- package/dist/styles/index.css +16 -4
- package/package.json +1 -1
package/dist/index/index.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, 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 as getBezierEdgeCenter$1, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter as getEdgeCenter$1, 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, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
|
|
1
|
+
import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, 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, errorMessages, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter as getBezierEdgeCenter$1, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter as getEdgeCenter$1, 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, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
|
|
2
2
|
import { For, Show, createContext, createEffect, createMemo, createProjection, createSignal, createStore, flush, mapArray, merge, omit, onCleanup, onSettled, snapshot, untrack, useContext } from "solid-js";
|
|
3
3
|
import { createMediaQuery } from "@solid-primitives/media";
|
|
4
4
|
import { Dynamic, Portal, isServer } from "@solidjs/web";
|
|
@@ -65,7 +65,9 @@ function propDefaults(props, defaults) {
|
|
|
65
65
|
const getEdgeId = (connection) => {
|
|
66
66
|
let { source, sourceHandle, target, targetHandle } = connection;
|
|
67
67
|
return `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
|
|
68
|
-
}, isEdgeSelectable = (edge, store) => edge.selectable ?? store.defaultEdgeOptions.selectable ?? store.elementsSelectable,
|
|
68
|
+
}, isEdgeSelectable = (edge, store) => edge.selectable ?? store.defaultEdgeOptions.selectable ?? store.elementsSelectable, emitFlowError = (onError, id, message) => {
|
|
69
|
+
onError && onError(id, message);
|
|
70
|
+
}, EdgeLabelRenderer = (props) => {
|
|
69
71
|
let { store } = useInternalSolidFlow(), labelNode = () => store.domNode?.querySelector(".solid-flow__edge-labels");
|
|
70
72
|
return <Show when={labelNode()}>{(root) => <Portal mount={root()}>{props.children}</Portal>}</Show>;
|
|
71
73
|
}, EdgeLabel = (props) => {
|
|
@@ -75,7 +77,7 @@ const getEdgeId = (connection) => {
|
|
|
75
77
|
selectEdgeOnClick: !1,
|
|
76
78
|
transparent: !1,
|
|
77
79
|
style: {}
|
|
78
|
-
}), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.
|
|
80
|
+
}), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.getLayoutedEdge(id())?.zIndex;
|
|
79
81
|
return <EdgeLabelRenderer>
|
|
80
82
|
<div role="button" tabindex={-1} class={[
|
|
81
83
|
"solid-flow__edge-label",
|
|
@@ -320,6 +322,30 @@ const armConnectionGestureLookup = (options) => {
|
|
|
320
322
|
doc.removeEventListener("mousemove", update, !0), doc.removeEventListener("touchmove", update, !0), doc.removeEventListener("mouseup", dispose, !0), doc.removeEventListener("touchend", dispose, !0), lookup.disarm();
|
|
321
323
|
};
|
|
322
324
|
return doc.addEventListener("mousemove", update, !0), doc.addEventListener("touchmove", update, !0), doc.addEventListener("mouseup", dispose, !0), doc.addEventListener("touchend", dispose, !0), lookup;
|
|
325
|
+
}, buildConnectionGestureParams = (options) => {
|
|
326
|
+
let { event, store, actions, gestureLookup } = options;
|
|
327
|
+
return {
|
|
328
|
+
lib: store.lib,
|
|
329
|
+
flowId: store.id,
|
|
330
|
+
domNode: store.domNode,
|
|
331
|
+
autoPanOnConnect: store.autoPanOnConnect,
|
|
332
|
+
autoPanSpeed: store.autoPanSpeed,
|
|
333
|
+
connectionMode: store.connectionMode,
|
|
334
|
+
connectionRadius: store.connectionRadius,
|
|
335
|
+
nodeLookup: gestureLookup,
|
|
336
|
+
cancelConnection: actions.cancelConnection,
|
|
337
|
+
panBy: actions.panBy,
|
|
338
|
+
updateConnection: ((connection) => {
|
|
339
|
+
actions.setConnection(connection), flush();
|
|
340
|
+
}),
|
|
341
|
+
isValidConnection: store.isValidConnection,
|
|
342
|
+
onConnectStart: store.onConnectStart,
|
|
343
|
+
onConnectEnd: store.onConnectEnd,
|
|
344
|
+
getTransform: () => store.transform,
|
|
345
|
+
getFromHandle: () => store.connection.fromHandle,
|
|
346
|
+
dragThreshold: store.connectionDragThreshold,
|
|
347
|
+
handleDomNode: event.currentTarget
|
|
348
|
+
};
|
|
323
349
|
}, EdgeReconnectAnchor = (props) => {
|
|
324
350
|
let _props = propDefaults(props, {
|
|
325
351
|
size: 25,
|
|
@@ -348,25 +374,16 @@ const armConnectionGestureLookup = (options) => {
|
|
|
348
374
|
connectionRadius: store.connectionRadius
|
|
349
375
|
});
|
|
350
376
|
XYHandle.onPointerDown(event, {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
377
|
+
...buildConnectionGestureParams({
|
|
378
|
+
event,
|
|
379
|
+
store,
|
|
380
|
+
actions,
|
|
381
|
+
gestureLookup
|
|
382
|
+
}),
|
|
354
383
|
nodeId: opposite.nodeId,
|
|
355
384
|
handleId: opposite.handleId,
|
|
356
|
-
autoPanOnConnect: store.autoPanOnConnect,
|
|
357
|
-
connectionMode: store.connectionMode,
|
|
358
|
-
connectionRadius: store.connectionRadius,
|
|
359
|
-
nodeLookup: gestureLookup,
|
|
360
385
|
isTarget: opposite.type === "target",
|
|
361
386
|
edgeUpdaterType: opposite.type,
|
|
362
|
-
cancelConnection: actions.cancelConnection,
|
|
363
|
-
panBy: actions.panBy,
|
|
364
|
-
updateConnection: (connection) => {
|
|
365
|
-
actions.setConnection(connection), flush();
|
|
366
|
-
},
|
|
367
|
-
isValidConnection: store.isValidConnection,
|
|
368
|
-
onConnectStart: store.onConnectStart,
|
|
369
|
-
onConnectEnd: store.onConnectEnd,
|
|
370
387
|
onConnect: (connection) => {
|
|
371
388
|
let newEdge = {
|
|
372
389
|
...edge(),
|
|
@@ -376,12 +393,7 @@ const armConnectionGestureLookup = (options) => {
|
|
|
376
393
|
},
|
|
377
394
|
onReconnectEnd: (event, connectionState) => {
|
|
378
395
|
setReconnectingState(!1), store.onReconnectEnd?.(event, edge(), opposite.type, connectionState);
|
|
379
|
-
}
|
|
380
|
-
getTransform: () => store.transform,
|
|
381
|
-
getFromHandle: () => store.connection.fromHandle,
|
|
382
|
-
autoPanSpeed: store.autoPanSpeed,
|
|
383
|
-
dragThreshold: store.connectionDragThreshold,
|
|
384
|
-
handleDomNode: event.currentTarget
|
|
396
|
+
}
|
|
385
397
|
});
|
|
386
398
|
};
|
|
387
399
|
return <EdgeLabel x={_props.position?.x} y={_props.position?.y} style={_props.style} {...rest}>
|
|
@@ -450,14 +462,22 @@ const armConnectionGestureLookup = (options) => {
|
|
|
450
462
|
addSelectedEdges,
|
|
451
463
|
handleNodeSelection: (id, unselect, nodeRef) => {
|
|
452
464
|
let node = store.nodes.find((n) => n.id === id);
|
|
453
|
-
|
|
465
|
+
if (!node) {
|
|
466
|
+
emitFlowError(store.onError, "012", errorMessages.error012(id));
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
|
|
454
470
|
nodes: [node],
|
|
455
471
|
edges: []
|
|
456
|
-
}), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id])
|
|
472
|
+
}), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]);
|
|
457
473
|
},
|
|
458
474
|
handleEdgeSelection: (id) => {
|
|
459
475
|
let edge = edgeLookup[id];
|
|
460
|
-
|
|
476
|
+
if (!edge) {
|
|
477
|
+
emitFlowError(store.onError, "012", errorMessages.error012(id));
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
isEdgeSelectable(edge, store) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
|
|
461
481
|
nodes: [],
|
|
462
482
|
edges: [edge]
|
|
463
483
|
}) : addSelectedEdges([id]));
|
|
@@ -674,7 +694,20 @@ const createMeasurementIngest = ({ setMeasurementsStore, setNodesStore, nodes })
|
|
|
674
694
|
let out = {};
|
|
675
695
|
for (let edge of source.edges) out[edge.id] = edge;
|
|
676
696
|
return out;
|
|
677
|
-
}, {}, { key: "id" })
|
|
697
|
+
}, {}, { key: "id" }), createRowRecordProjection = (rowStores) => {
|
|
698
|
+
let assigned = /* @__PURE__ */ new Map();
|
|
699
|
+
return createProjection((draft) => {
|
|
700
|
+
let seen = /* @__PURE__ */ new Set();
|
|
701
|
+
for (let { id, store } of rowStores()) {
|
|
702
|
+
let row = store.row;
|
|
703
|
+
row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
|
|
704
|
+
}
|
|
705
|
+
for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
|
|
706
|
+
}, {}, {
|
|
707
|
+
key: null,
|
|
708
|
+
shallow: !0
|
|
709
|
+
});
|
|
710
|
+
};
|
|
678
711
|
function isManualZIndexMode(zIndexMode) {
|
|
679
712
|
return zIndexMode === "manual";
|
|
680
713
|
}
|
|
@@ -718,7 +751,7 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
|
|
|
718
751
|
x,
|
|
719
752
|
y
|
|
720
753
|
}, row.internals.z = z;
|
|
721
|
-
} else source.nodes.length;
|
|
754
|
+
} else source.nodes.length, emitFlowError(source.onError, "parent-missing", `Parent node ${userNode.parentId} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);
|
|
722
755
|
}
|
|
723
756
|
return { row };
|
|
724
757
|
}, {}, { key: "id" }), entry = {
|
|
@@ -731,19 +764,8 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
|
|
|
731
764
|
id,
|
|
732
765
|
store
|
|
733
766
|
};
|
|
734
|
-
}, { keyed: (userNode) => userNode.id })
|
|
735
|
-
return
|
|
736
|
-
let seen = /* @__PURE__ */ new Set();
|
|
737
|
-
for (let { id, store } of rowStores()) {
|
|
738
|
-
seen.add(id);
|
|
739
|
-
let row = store.row;
|
|
740
|
-
assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row);
|
|
741
|
-
}
|
|
742
|
-
for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
|
|
743
|
-
}, {}, {
|
|
744
|
-
key: null,
|
|
745
|
-
shallow: !0
|
|
746
|
-
});
|
|
767
|
+
}, { keyed: (userNode) => userNode.id });
|
|
768
|
+
return createRowRecordProjection(rowStores);
|
|
747
769
|
};
|
|
748
770
|
function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode) {
|
|
749
771
|
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({
|
|
@@ -791,18 +813,8 @@ const createLayoutedEdges = (source) => {
|
|
|
791
813
|
let edge = edgeAccessor();
|
|
792
814
|
return { row: buildRow(source, edge) };
|
|
793
815
|
}, { row: null }, { key: "id" })
|
|
794
|
-
}), { keyed: (edge) => edge.id })
|
|
795
|
-
return
|
|
796
|
-
let seen = /* @__PURE__ */ new Set();
|
|
797
|
-
for (let { id, store } of rowStores()) {
|
|
798
|
-
let row = store.row;
|
|
799
|
-
row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
|
|
800
|
-
}
|
|
801
|
-
for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
|
|
802
|
-
}, {}, {
|
|
803
|
-
key: null,
|
|
804
|
-
shallow: !0
|
|
805
|
-
});
|
|
816
|
+
}), { keyed: (edge) => edge.id });
|
|
817
|
+
return createRowRecordProjection(rowStores);
|
|
806
818
|
}, buildRow = (source, edge) => {
|
|
807
819
|
let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
|
|
808
820
|
if (!sourceNode || !targetNode) return null;
|
|
@@ -890,6 +902,9 @@ const createLayoutedEdges = (source) => {
|
|
|
890
902
|
},
|
|
891
903
|
get zIndexMode() {
|
|
892
904
|
return config().zIndexMode;
|
|
905
|
+
},
|
|
906
|
+
get onError() {
|
|
907
|
+
return config().onFlowError;
|
|
893
908
|
}
|
|
894
909
|
}), nodeLookup = new RecordMapFacade(internalNodes), initialViewport = getInitialViewport(_props.fitView, _props.initialViewport, _props.width ?? 0, _props.height ?? 0, nodeLookup), [viewportStore, setViewportStore] = createStore(_props.viewport ?? initialViewport);
|
|
895
910
|
createEffect(() => config().viewport, (next) => {
|
|
@@ -917,6 +932,10 @@ const createLayoutedEdges = (source) => {
|
|
|
917
932
|
let state = connection(), toHandle = state.inProgress ? state.toHandle : null, key = toHandle ? connectionKey(toHandle.nodeId, toHandle.type, toHandle.id ?? null) : null;
|
|
918
933
|
for (let existing of Object.keys(draft)) existing !== key && delete draft[existing];
|
|
919
934
|
key && (draft[key] = state.isValid ? "valid" : "invalid");
|
|
935
|
+
}, {}, { key: null }), connectionOriginByHandle = createProjection((draft) => {
|
|
936
|
+
let fromHandle = connection().fromHandle ?? clickConnectStartHandle(), fromKey = fromHandle ? connectionKey(fromHandle.nodeId, fromHandle.type, fromHandle.id ?? null) : null, siblingKey = fromHandle ? connectionKey(fromHandle.nodeId, fromHandle.type === "source" ? "target" : "source", fromHandle.id ?? null) : null;
|
|
937
|
+
for (let existing of Object.keys(draft)) existing !== fromKey && existing !== siblingKey && delete draft[existing];
|
|
938
|
+
fromKey && (draft[fromKey] = "from"), siblingKey && (draft[siblingKey] = "excluded");
|
|
920
939
|
}, {}, { key: null }), mergedNodeTypes = createMemo(() => ({
|
|
921
940
|
...initialNodeTypes,
|
|
922
941
|
...config().nodeTypes
|
|
@@ -948,6 +967,9 @@ const createLayoutedEdges = (source) => {
|
|
|
948
967
|
get connectionTargetByHandle() {
|
|
949
968
|
return connectionTargetByHandle;
|
|
950
969
|
},
|
|
970
|
+
get connectionOriginByHandle() {
|
|
971
|
+
return connectionOriginByHandle;
|
|
972
|
+
},
|
|
951
973
|
get domNode() {
|
|
952
974
|
return domNode();
|
|
953
975
|
},
|
|
@@ -1086,7 +1108,7 @@ const createLayoutedEdges = (source) => {
|
|
|
1086
1108
|
return store.onError;
|
|
1087
1109
|
},
|
|
1088
1110
|
nodeLookup
|
|
1089
|
-
}), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)),
|
|
1111
|
+
}), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)), getLayoutedEdge = (id) => layoutedEdges[id], fitView = async (options) => store.panZoom ? await fitViewport({
|
|
1090
1112
|
nodes: nodeLookup,
|
|
1091
1113
|
width: store.width,
|
|
1092
1114
|
height: store.height,
|
|
@@ -1433,7 +1455,7 @@ const createLayoutedEdges = (source) => {
|
|
|
1433
1455
|
parentIds,
|
|
1434
1456
|
connections,
|
|
1435
1457
|
actions: {
|
|
1436
|
-
|
|
1458
|
+
getLayoutedEdge,
|
|
1437
1459
|
applyInitialFitView,
|
|
1438
1460
|
applyMeasurementWrites,
|
|
1439
1461
|
applyNodeChanges,
|
|
@@ -1485,7 +1507,14 @@ const createLayoutedEdges = (source) => {
|
|
|
1485
1507
|
let [store, setStore] = typeof nodes == "function" ? createStore(nodes, []) : createStore(nodes);
|
|
1486
1508
|
return [store, setStore];
|
|
1487
1509
|
}, EdgeWrapper = (props) => {
|
|
1488
|
-
let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.
|
|
1510
|
+
let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.getLayoutedEdge(edgeId()), edgeType = () => edge().type ?? "default", selectable = () => isEdgeSelectable(edge(), store), focusable = () => edge().focusable ?? store.edgesFocusable, edgeTypeValid = () => edgeType() in store.edgeTypes, edgeComponent = () => store.edgeTypes[edgeTypeValid() ? edgeType() : "default"];
|
|
1511
|
+
createEffect(() => ({
|
|
1512
|
+
valid: edgeTypeValid(),
|
|
1513
|
+
edgeType: edgeType()
|
|
1514
|
+
}), ({ valid, edgeType }) => {
|
|
1515
|
+
valid || emitFlowError(store.onError, "011", errorMessages.error011(edgeType));
|
|
1516
|
+
});
|
|
1517
|
+
let markerStartUrl = () => edge().markerStart ? `url('#${getMarkerId(edge().markerStart, store.id)}')` : void 0, markerEndUrl = () => edge().markerEnd ? `url('#${getMarkerId(edge().markerEnd, store.id)}')` : void 0, onClick = (event) => {
|
|
1489
1518
|
selectable() && actions.handleEdgeSelection(edgeId()), props.onEdgeClick?.({
|
|
1490
1519
|
edge: edge(),
|
|
1491
1520
|
event
|
|
@@ -1642,10 +1671,7 @@ const Handle = (props) => {
|
|
|
1642
1671
|
position: "top",
|
|
1643
1672
|
isConnectableStart: !0,
|
|
1644
1673
|
isConnectableEnd: !0
|
|
1645
|
-
}), { 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,
|
|
1646
|
-
let fromHandle = store.connectionFromHandle;
|
|
1647
|
-
return fromHandle && fromHandle.nodeId === nodeId() && fromHandle.type === _props.type && fromHandle.id === handleId();
|
|
1648
|
-
}, targetState = () => store.connectionTargetByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingTo = () => targetState() !== void 0, isPossibleTargetHandle = () => store.connectionMode === "strict" ? store.connectionFromHandle?.type !== _props.type : nodeId() !== store.connectionFromHandle?.nodeId || handleId() !== store.connectionFromHandle?.id, valid = () => targetState() === "valid", prevConnections = null;
|
|
1674
|
+
}), { 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, originState = () => store.connectionOriginByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingFrom = () => originState() === "from", targetState = () => store.connectionTargetByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingTo = () => targetState() !== void 0, valid = () => targetState() === "valid", prevConnections = null;
|
|
1649
1675
|
createEffect(() => {
|
|
1650
1676
|
if (!_props.onConnect && !_props.onDisconnect) return null;
|
|
1651
1677
|
let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
|
|
@@ -1671,36 +1697,17 @@ const Handle = (props) => {
|
|
|
1671
1697
|
connectionRadius: store.connectionRadius
|
|
1672
1698
|
});
|
|
1673
1699
|
XYHandle.onPointerDown(event, {
|
|
1700
|
+
...buildConnectionGestureParams({
|
|
1701
|
+
event,
|
|
1702
|
+
store,
|
|
1703
|
+
actions,
|
|
1704
|
+
gestureLookup
|
|
1705
|
+
}),
|
|
1674
1706
|
handleId: handleId(),
|
|
1675
1707
|
nodeId: nodeId(),
|
|
1676
1708
|
isTarget: isTarget(),
|
|
1677
|
-
connectionRadius: store.connectionRadius,
|
|
1678
|
-
domNode: store.domNode,
|
|
1679
|
-
nodeLookup: gestureLookup,
|
|
1680
|
-
connectionMode: store.connectionMode,
|
|
1681
|
-
lib: store.lib,
|
|
1682
|
-
autoPanOnConnect: store.autoPanOnConnect,
|
|
1683
|
-
flowId: store.id,
|
|
1684
1709
|
isValidConnection: _props.isValidConnection ?? store.isValidConnection,
|
|
1685
|
-
|
|
1686
|
-
actions.setConnection(connection), flush();
|
|
1687
|
-
}),
|
|
1688
|
-
cancelConnection: actions.cancelConnection,
|
|
1689
|
-
panBy: actions.panBy,
|
|
1690
|
-
onConnect: onConnectExtended,
|
|
1691
|
-
onConnectStart: (event, startParams) => {
|
|
1692
|
-
store.onConnectStart?.(event, {
|
|
1693
|
-
nodeId: startParams.nodeId,
|
|
1694
|
-
handleId: startParams.handleId,
|
|
1695
|
-
handleType: startParams.handleType
|
|
1696
|
-
});
|
|
1697
|
-
},
|
|
1698
|
-
onConnectEnd: store.onConnectEnd,
|
|
1699
|
-
getTransform: () => store.transform,
|
|
1700
|
-
getFromHandle: () => store.connection.fromHandle,
|
|
1701
|
-
autoPanSpeed: store.autoPanSpeed,
|
|
1702
|
-
dragThreshold: store.connectionDragThreshold,
|
|
1703
|
-
handleDomNode: event.currentTarget
|
|
1710
|
+
onConnect: onConnectExtended
|
|
1704
1711
|
});
|
|
1705
1712
|
}, onClick = (event) => {
|
|
1706
1713
|
if (!nodeId() || !store.clickConnectStartHandle && !_props.isConnectableStart) return;
|
|
@@ -1735,7 +1742,7 @@ const Handle = (props) => {
|
|
|
1735
1742
|
isValid && connection && onConnectExtended(connection);
|
|
1736
1743
|
let connectionClone = structuredClone(snapshot(store.connection));
|
|
1737
1744
|
delete connectionClone.inProgress, connectionClone.toPosition = connectionClone.toHandle ? connectionClone.toHandle.position : null, store.onClickConnectEnd?.(event, connectionClone), actions.setClickConnectStartHandle(void 0);
|
|
1738
|
-
}
|
|
1745
|
+
};
|
|
1739
1746
|
return <div {...rest} role="button" aria-label={store.ariaLabelConfig["handle.ariaLabel"]} tabindex={-1} data-handleid={handleId()} data-nodeid={nodeId()} data-handlepos={_props.position} data-id={`${store.id}-${nodeId()}-${_props.id || null}-${_props.type}`} onClick={store.clickConnect ? onClick : void 0} onPointerDown={onPointerDown} style={_props.style} class={[
|
|
1740
1747
|
"solid-flow__handle",
|
|
1741
1748
|
`solid-flow__handle-${_props.position}`,
|
|
@@ -1751,7 +1758,7 @@ const Handle = (props) => {
|
|
|
1751
1758
|
connectablestart: _props.isConnectableStart,
|
|
1752
1759
|
connectableend: _props.isConnectableEnd,
|
|
1753
1760
|
connectable: !!connectable(),
|
|
1754
|
-
|
|
1761
|
+
excluded: !!originState()
|
|
1755
1762
|
}
|
|
1756
1763
|
]}>
|
|
1757
1764
|
{_props.children}
|
|
@@ -1850,7 +1857,7 @@ const NodeWrapper = (props) => {
|
|
|
1850
1857
|
let el = nodeRef();
|
|
1851
1858
|
el && props.resizeObserver?.unobserve(el);
|
|
1852
1859
|
});
|
|
1853
|
-
let 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 = () => {
|
|
1860
|
+
let 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[nodeTypeValid() ? nodeType() : "default"], isParentNode = () => !!parentIds[node().id], transform = () => {
|
|
1854
1861
|
let { x, y } = node().internals.positionAbsolute;
|
|
1855
1862
|
return `translate(${x}px, ${y}px)`;
|
|
1856
1863
|
}, sizeStyle = () => {
|
|
@@ -1870,7 +1877,9 @@ const NodeWrapper = (props) => {
|
|
|
1870
1877
|
createEffect(() => ({
|
|
1871
1878
|
valid: nodeTypeValid(),
|
|
1872
1879
|
nodeType: nodeType()
|
|
1873
|
-
}), ({ valid, nodeType }) => {
|
|
1880
|
+
}), ({ valid, nodeType }) => {
|
|
1881
|
+
valid || emitFlowError(store.onError, "003", errorMessages.error003(nodeType));
|
|
1882
|
+
}), createEffect(() => ({
|
|
1874
1883
|
id: node().id,
|
|
1875
1884
|
nodeElement: nodeRef(),
|
|
1876
1885
|
nodeType: nodeType(),
|
|
@@ -2146,29 +2155,31 @@ function useInternalSolidFlow() {
|
|
|
2146
2155
|
//#region src/components/connection/ConnectionLine.tsx
|
|
2147
2156
|
/** Internal component rendering the in-progress connection line. */
|
|
2148
2157
|
const ConnectionLine = (props) => {
|
|
2149
|
-
let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid)
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2158
|
+
let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid), inProgress = createMemo(() => {
|
|
2159
|
+
let state = store.connection;
|
|
2160
|
+
return state.inProgress ? state : null;
|
|
2161
|
+
});
|
|
2162
|
+
return <Show when={inProgress()}>
|
|
2163
|
+
{(connection) => <svg class="solid-flow__container solid-flow__connectionline" width={store.width} height={store.height} style={props.containerStyle}>
|
|
2164
|
+
<g class={["solid-flow__connection", connectionStatus()]}>
|
|
2165
|
+
<Show when={props.component} fallback={<InternalConnectionLine style={props.style} connection={connection()} />}>
|
|
2166
|
+
{(CustomComponent) => {
|
|
2155
2167
|
let UserConnectionLine = CustomComponent();
|
|
2156
|
-
return <UserConnectionLine connectionLineType={store.connectionLineType} connectionLineStyle={props.style} fromNode={
|
|
2168
|
+
return <UserConnectionLine connectionLineType={store.connectionLineType} connectionLineStyle={props.style} fromNode={connection().fromNode} fromHandle={connection().fromHandle} fromX={connection().from.x} fromY={connection().from.y} toX={connection().to.x} toY={connection().to.y} fromPosition={connection().fromPosition} toPosition={connection().toPosition} connectionStatus={connectionStatus()} toNode={connection().toNode} toHandle={connection().toHandle} />;
|
|
2157
2169
|
}}
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2170
|
+
</Show>
|
|
2171
|
+
</g>
|
|
2172
|
+
</svg>}
|
|
2161
2173
|
</Show>;
|
|
2162
2174
|
}, InternalConnectionLine = (props) => {
|
|
2163
2175
|
let { store } = useInternalSolidFlow(), path = () => {
|
|
2164
|
-
if (!store.connection.inProgress) return;
|
|
2165
2176
|
let pathParams = {
|
|
2166
|
-
sourceX:
|
|
2167
|
-
sourceY:
|
|
2168
|
-
sourcePosition:
|
|
2169
|
-
targetX:
|
|
2170
|
-
targetY:
|
|
2171
|
-
targetPosition:
|
|
2177
|
+
sourceX: props.connection.from.x,
|
|
2178
|
+
sourceY: props.connection.from.y,
|
|
2179
|
+
sourcePosition: props.connection.fromPosition,
|
|
2180
|
+
targetX: props.connection.to.x,
|
|
2181
|
+
targetY: props.connection.to.y,
|
|
2182
|
+
targetPosition: props.connection.toPosition
|
|
2172
2183
|
};
|
|
2173
2184
|
switch (store.connectionLineType) {
|
|
2174
2185
|
case "default": {
|
|
@@ -2217,19 +2228,26 @@ const ConnectionLine = (props) => {
|
|
|
2217
2228
|
</defs>
|
|
2218
2229
|
</svg>
|
|
2219
2230
|
</Show>;
|
|
2220
|
-
},
|
|
2221
|
-
let
|
|
2222
|
-
|
|
2223
|
-
|
|
2231
|
+
}, createFocusedIdTracker = () => {
|
|
2232
|
+
let [focusedId, setFocusedId] = createSignal(null);
|
|
2233
|
+
return {
|
|
2234
|
+
focusedId,
|
|
2235
|
+
onFocusIn: (event) => {
|
|
2236
|
+
let element = event.target.closest("[data-id]");
|
|
2237
|
+
setFocusedId(element?.getAttribute("data-id") ?? null);
|
|
2238
|
+
},
|
|
2239
|
+
onFocusOut: () => setFocusedId(null)
|
|
2224
2240
|
};
|
|
2225
|
-
|
|
2241
|
+
}, EdgeRenderer = (props) => {
|
|
2242
|
+
let { store, actions } = useInternalSolidFlow(), { focusedId: focusedEdgeId, onFocusIn, onFocusOut } = createFocusedIdTracker();
|
|
2243
|
+
return <div class="solid-flow__edges" onFocusIn={onFocusIn} onFocusOut={onFocusOut}>
|
|
2226
2244
|
<MarkerDefinition />
|
|
2227
2245
|
|
|
2228
2246
|
<For each={store.visibleEdgeIds}>
|
|
2229
2247
|
{(edgeId) => {
|
|
2230
2248
|
let unmounted = createMemo(() => {
|
|
2231
2249
|
if (!store.onlyRenderVisibleElements || focusedEdgeId() === edgeId) return !1;
|
|
2232
|
-
let edge = actions.
|
|
2250
|
+
let edge = actions.getLayoutedEdge(edgeId);
|
|
2233
2251
|
return !!edge && isEdgeCulled(edge, store.cullingViewport);
|
|
2234
2252
|
});
|
|
2235
2253
|
return <Show when={!unmounted()}>
|
|
@@ -2252,11 +2270,8 @@ const ConnectionLine = (props) => {
|
|
|
2252
2270
|
onCleanup(() => {
|
|
2253
2271
|
resizeObserver?.disconnect();
|
|
2254
2272
|
});
|
|
2255
|
-
let
|
|
2256
|
-
|
|
2257
|
-
setFocusedNodeId(nodeElement?.getAttribute("data-id") ?? null);
|
|
2258
|
-
};
|
|
2259
|
-
return <div class="solid-flow__container solid-flow__nodes" onFocusIn={onFocusIn} onFocusOut={() => setFocusedNodeId(null)}>
|
|
2273
|
+
let { focusedId: focusedNodeId, onFocusIn, onFocusOut } = createFocusedIdTracker();
|
|
2274
|
+
return <div class="solid-flow__container solid-flow__nodes" onFocusIn={onFocusIn} onFocusOut={onFocusOut}>
|
|
2260
2275
|
<For each={store.visibleNodeIds}>
|
|
2261
2276
|
{(nodeId) => {
|
|
2262
2277
|
let unmounted = createMemo(() => {
|
|
@@ -2278,7 +2293,7 @@ const ConnectionLine = (props) => {
|
|
|
2278
2293
|
let { store, nodeLookup, edgeLookup, connections, actions } = useInternalSolidFlow(), [containerRef, setContainerRef] = createSignal(), container, containerBounds = null, connectionEndedOnPane = !1, selectionInProgress = !1, selectionSpatialLookup = new GestureSpatialLookup(nodeLookup, 400), selectedNodeIds = /* @__PURE__ */ new Set(), selectedEdgeIds = /* @__PURE__ */ new Set(), autoPanId = 0, position = {
|
|
2279
2294
|
x: 0,
|
|
2280
2295
|
y: 0
|
|
2281
|
-
}, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ??
|
|
2296
|
+
}, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ?? 0, _panOnDrag = () => store.panActivationKeyPressed || props.panOnDrag, isSelecting = () => store.selectionKeyPressed || !!store.selectionRect || props.selectionOnDrag && _panOnDrag() !== !0, isSelectionEnabled = () => store.elementsSelectable && (isSelecting() || store.selectionRectMode === "user"), onClick = (event) => {
|
|
2282
2297
|
if (event.target === container) {
|
|
2283
2298
|
if (selectionInProgress || store.connection.inProgress || connectionEndedOnPane) {
|
|
2284
2299
|
selectionInProgress = !1, connectionEndedOnPane = !1;
|
|
@@ -2575,29 +2590,13 @@ const ConnectionLine = (props) => {
|
|
|
2575
2590
|
Solid Flow
|
|
2576
2591
|
</a>
|
|
2577
2592
|
</Panel>
|
|
2578
|
-
</Show
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
* `flow` and `commands` are stable identities, so destructuring them is safe:
|
|
2586
|
-
* `const { flow, commands } = useSolidFlow()`.
|
|
2587
|
-
*
|
|
2588
|
-
* @public
|
|
2589
|
-
* @returns the flow's read struct and write surface
|
|
2590
|
-
*/
|
|
2591
|
-
function useSolidFlow() {
|
|
2592
|
-
let { flow, commands } = useInternalSolidFlow();
|
|
2593
|
-
return {
|
|
2594
|
-
...commands,
|
|
2595
|
-
flow,
|
|
2596
|
-
commands
|
|
2597
|
-
};
|
|
2598
|
-
}
|
|
2599
|
-
//#endregion
|
|
2600
|
-
//#region src/components/utility/KeyHandler.ts
|
|
2593
|
+
</Show>, MODIFIER_FLAG = {
|
|
2594
|
+
alt: "altKey",
|
|
2595
|
+
control: "ctrlKey",
|
|
2596
|
+
ctrl: "ctrlKey",
|
|
2597
|
+
meta: "metaKey",
|
|
2598
|
+
shift: "shiftKey"
|
|
2599
|
+
};
|
|
2601
2600
|
function isKeyObject(key) {
|
|
2602
2601
|
return typeof key == "object" && !!key;
|
|
2603
2602
|
}
|
|
@@ -2629,18 +2628,13 @@ function matchesKey(event, keyDef) {
|
|
|
2629
2628
|
function matchesKeyArray(event, keyDefs) {
|
|
2630
2629
|
return keyDefs ? (Array.isArray(keyDefs) ? keyDefs : [keyDefs]).some((keyDef) => matchesKey(event, keyDef)) : !1;
|
|
2631
2630
|
}
|
|
2632
|
-
const MODIFIER_FLAG = {
|
|
2633
|
-
alt: "altKey",
|
|
2634
|
-
control: "ctrlKey",
|
|
2635
|
-
ctrl: "ctrlKey",
|
|
2636
|
-
meta: "metaKey",
|
|
2637
|
-
shift: "shiftKey"
|
|
2638
|
-
};
|
|
2639
2631
|
/**
|
|
2640
2632
|
* Whether an event's modifier flags PROVE this key definition cannot be held
|
|
2641
2633
|
* right now: the key itself is a modifier whose flag is off, or one of its
|
|
2642
2634
|
* required modifiers is off. Definitions built on non-modifier keys are never
|
|
2643
|
-
* contradicted (their state isn't derivable from flags).
|
|
2635
|
+
* contradicted (their state isn't derivable from flags). This is the
|
|
2636
|
+
* self-heal for OS overlays that swallow keyups without blurring the window
|
|
2637
|
+
* (upstream xyflow#5679).
|
|
2644
2638
|
*/
|
|
2645
2639
|
function isContradicted(flags, keyDef) {
|
|
2646
2640
|
let keyFlag = MODIFIER_FLAG[getKeyString(keyDef).toLowerCase()];
|
|
@@ -2657,6 +2651,28 @@ function allContradicted(flags, keyDefs) {
|
|
|
2657
2651
|
let keys = Array.isArray(keyDefs) ? keyDefs : [keyDefs];
|
|
2658
2652
|
return keys.length > 0 && keys.every((keyDef) => isContradicted(flags, keyDef));
|
|
2659
2653
|
}
|
|
2654
|
+
//#endregion
|
|
2655
|
+
//#region src/hooks/useSolidFlow.ts
|
|
2656
|
+
/**
|
|
2657
|
+
* Hook for accessing the flow instance: `{ flow, commands }` plus the
|
|
2658
|
+
* commands spread at the top level for upstream familiarity.
|
|
2659
|
+
*
|
|
2660
|
+
* `flow` and `commands` are stable identities, so destructuring them is safe:
|
|
2661
|
+
* `const { flow, commands } = useSolidFlow()`.
|
|
2662
|
+
*
|
|
2663
|
+
* @public
|
|
2664
|
+
* @returns the flow's read struct and write surface
|
|
2665
|
+
*/
|
|
2666
|
+
function useSolidFlow() {
|
|
2667
|
+
let { flow, commands } = useInternalSolidFlow();
|
|
2668
|
+
return {
|
|
2669
|
+
...commands,
|
|
2670
|
+
flow,
|
|
2671
|
+
commands
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
//#endregion
|
|
2675
|
+
//#region src/components/utility/KeyHandler.ts
|
|
2660
2676
|
const KeyHandler = (props) => {
|
|
2661
2677
|
let { store, actions } = useInternalSolidFlow(), { deleteElements } = useSolidFlow(), _props = {
|
|
2662
2678
|
get selectionKey() {
|
|
@@ -2757,7 +2773,13 @@ const KeyHandler = (props) => {
|
|
|
2757
2773
|
"solid-flow",
|
|
2758
2774
|
"solid-flow__container",
|
|
2759
2775
|
_props.class,
|
|
2760
|
-
store.colorMode
|
|
2776
|
+
store.colorMode,
|
|
2777
|
+
{
|
|
2778
|
+
connecting: !!store.connectionFromHandle || !!store.clickConnectStartHandle,
|
|
2779
|
+
"connecting-from-source": (store.connectionFromHandle ?? store.clickConnectStartHandle)?.type === "source",
|
|
2780
|
+
"connecting-from-target": (store.connectionFromHandle ?? store.clickConnectStartHandle)?.type === "target",
|
|
2781
|
+
"connection-strict": store.connectionMode === "strict"
|
|
2782
|
+
}
|
|
2761
2783
|
]} style={rootStyle()} onScroll={(e) => {
|
|
2762
2784
|
e.currentTarget.scrollTo({
|
|
2763
2785
|
top: 0,
|
|
@@ -2830,8 +2852,8 @@ function useConnection() {
|
|
|
2830
2852
|
* @returns store with an array of nodes
|
|
2831
2853
|
*/
|
|
2832
2854
|
function useNodes() {
|
|
2833
|
-
let {
|
|
2834
|
-
return () =>
|
|
2855
|
+
let { flow } = useInternalSolidFlow();
|
|
2856
|
+
return () => flow.nodes;
|
|
2835
2857
|
}
|
|
2836
2858
|
/**
|
|
2837
2859
|
* Hook for getting the current edges from the store.
|
|
@@ -2840,8 +2862,8 @@ function useNodes() {
|
|
|
2840
2862
|
* @returns store with an array of edges
|
|
2841
2863
|
*/
|
|
2842
2864
|
function useEdges() {
|
|
2843
|
-
let {
|
|
2844
|
-
return () =>
|
|
2865
|
+
let { flow } = useInternalSolidFlow();
|
|
2866
|
+
return () => flow.edges;
|
|
2845
2867
|
}
|
|
2846
2868
|
/**
|
|
2847
2869
|
* Hook for getting the current viewport from the store.
|
|
@@ -2899,6 +2921,52 @@ function useInternalNode(id) {
|
|
|
2899
2921
|
return () => flow.internalNodes[id()];
|
|
2900
2922
|
}
|
|
2901
2923
|
//#endregion
|
|
2924
|
+
//#region src/hooks/useKeyPress.ts
|
|
2925
|
+
/**
|
|
2926
|
+
* Reactive "is this key (combo) held right now?" — the Solid Flow
|
|
2927
|
+
* counterpart of React Flow's `useKeyPress`, usable anywhere (no flow
|
|
2928
|
+
* context required).
|
|
2929
|
+
*
|
|
2930
|
+
* The definition is an Accessor per house convention — `useKeyPress(() =>
|
|
2931
|
+
* "a")`, `useKeyPress(() => ["a", "d"])`, or `useKeyPress(() => ({ key:
|
|
2932
|
+
* "s", modifier: ["meta"] }))`; swapping the definition resets the state.
|
|
2933
|
+
*
|
|
2934
|
+
* Hardened beyond upstream:
|
|
2935
|
+
* - Combos re-activate when the base key is re-pressed while the modifier
|
|
2936
|
+
* stays held (upstream's oldest open key bug, xyflow#2248).
|
|
2937
|
+
* - Stuck modifiers self-heal from the flags later keyboard/pointer/wheel
|
|
2938
|
+
* events carry (OS overlays swallow keyups without blurring — the macOS
|
|
2939
|
+
* screenshot HUD; xyflow#5679), and window blur resets.
|
|
2940
|
+
*/
|
|
2941
|
+
function useKeyPress(keys) {
|
|
2942
|
+
let [pressed, setPressed] = createSignal(!1);
|
|
2943
|
+
if (createEffect(() => keys(), () => {
|
|
2944
|
+
setPressed(!1);
|
|
2945
|
+
}, { defer: !0 }), !isServer) {
|
|
2946
|
+
let reconcile = (event) => {
|
|
2947
|
+
pressed() && allContradicted(event, keys()) && (setPressed(!1), flush());
|
|
2948
|
+
};
|
|
2949
|
+
createEventListenerMap(window, {
|
|
2950
|
+
keydown: (event) => {
|
|
2951
|
+
reconcile(event), matchesKeyArray(event, keys()) && (setPressed(!0), flush());
|
|
2952
|
+
},
|
|
2953
|
+
keyup: (event) => {
|
|
2954
|
+
reconcile(event), matchesKeyArray(event, keys()) && (setPressed(!1), flush());
|
|
2955
|
+
},
|
|
2956
|
+
blur: () => {
|
|
2957
|
+
setPressed(!1), flush();
|
|
2958
|
+
}
|
|
2959
|
+
}), createEventListenerMap(window, {
|
|
2960
|
+
pointerdown: reconcile,
|
|
2961
|
+
wheel: reconcile
|
|
2962
|
+
}, {
|
|
2963
|
+
capture: !0,
|
|
2964
|
+
passive: !0
|
|
2965
|
+
});
|
|
2966
|
+
}
|
|
2967
|
+
return pressed;
|
|
2968
|
+
}
|
|
2969
|
+
//#endregion
|
|
2902
2970
|
//#region src/hooks/useNodeConnections.ts
|
|
2903
2971
|
/**
|
|
2904
2972
|
* Hook to retrieve all edges connected to a node. Can be filtered by handle type and id.
|
|
@@ -3084,7 +3152,7 @@ const DotPattern = (props) => {
|
|
|
3084
3152
|
{ selected: !!_props.selected },
|
|
3085
3153
|
_props.class
|
|
3086
3154
|
]} x={_props.x} y={_props.y} rx={_props.borderRadius} ry={_props.borderRadius} width={_props.width} height={_props.height} shape-rendering={_props.shapeRendering} style={style()} onClick={_props.onClick ? (event) => _props.onClick(event, _props.id) : void 0} />;
|
|
3087
|
-
}, getAttrFunction = (
|
|
3155
|
+
}, getAttrFunction = (value) => value instanceof Function ? value : () => value, MiniMap = (props) => {
|
|
3088
3156
|
let { store, nodeLookup } = useInternalSolidFlow(), _props = propDefaults(props, {
|
|
3089
3157
|
position: "bottom-right",
|
|
3090
3158
|
nodeClass: "",
|
|
@@ -3094,19 +3162,41 @@ const DotPattern = (props) => {
|
|
|
3094
3162
|
width: 200,
|
|
3095
3163
|
height: 150,
|
|
3096
3164
|
nodeBorderRadius: 5,
|
|
3165
|
+
offsetScale: 5,
|
|
3097
3166
|
nodeStrokeWidth: 2,
|
|
3098
3167
|
style: {}
|
|
3099
|
-
}), paneProps = omit(_props, "class", "style", "position", "nodeClass", "nodeStrokeColor", "nodeColor", "pannable", "zoomable", "inversePan", "zoomStep", "bgColor", "width", "height", "maskColor", "maskStrokeColor", "maskStrokeWidth", "nodeBorderRadius", "nodeStrokeWidth", "nodeComponent", "onClick", "onNodeClick"), nodeColorFunc = () => _props.nodeColor === void 0 ? void 0 : getAttrFunction(_props.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(_props.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(_props.nodeClass), shapeRendering = typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision", labelledBy = createMemo(() => `solid-flow__minimap-desc-${store.id}`), viewBB = createMemo(() => ({
|
|
3168
|
+
}), paneProps = omit(_props, "class", "style", "position", "nodeClass", "nodeStrokeColor", "nodeColor", "pannable", "zoomable", "inversePan", "zoomStep", "offsetScale", "bgColor", "width", "height", "maskColor", "maskStrokeColor", "maskStrokeWidth", "nodeBorderRadius", "nodeStrokeWidth", "nodeComponent", "onClick", "onNodeClick"), nodeColorFunc = () => _props.nodeColor === void 0 ? void 0 : getAttrFunction(_props.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(_props.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(_props.nodeClass), shapeRendering = typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision", labelledBy = createMemo(() => `solid-flow__minimap-desc-${store.id}`), viewBB = createMemo(() => ({
|
|
3100
3169
|
x: -store.viewport.x / store.viewport.zoom,
|
|
3101
3170
|
y: -store.viewport.y / store.viewport.zoom,
|
|
3102
3171
|
width: store.width / store.viewport.zoom,
|
|
3103
3172
|
height: store.height / store.viewport.zoom
|
|
3104
|
-
})),
|
|
3105
|
-
|
|
3106
|
-
if (nodeLookup.size === 0) return view;
|
|
3173
|
+
})), rectsEqual = (a, b) => a === b || !!a && !!b && a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height, sampleBounds = () => untrack(() => {
|
|
3174
|
+
if (nodeLookup.size === 0) return null;
|
|
3107
3175
|
let bounds = getInternalNodesBounds(nodeLookup);
|
|
3108
|
-
return
|
|
3109
|
-
}),
|
|
3176
|
+
return Number.isFinite(bounds.x) && Number.isFinite(bounds.width) ? bounds : null;
|
|
3177
|
+
}), [graphBounds, setGraphBounds] = createSignal(sampleBounds(), { equals: rectsEqual });
|
|
3178
|
+
createEffect(() => store.dragging, (dragging) => {
|
|
3179
|
+
if (!dragging) {
|
|
3180
|
+
setGraphBounds(sampleBounds());
|
|
3181
|
+
return;
|
|
3182
|
+
}
|
|
3183
|
+
let raf = requestAnimationFrame(function tick() {
|
|
3184
|
+
setGraphBounds(sampleBounds()), raf = requestAnimationFrame(tick);
|
|
3185
|
+
});
|
|
3186
|
+
return () => cancelAnimationFrame(raf);
|
|
3187
|
+
}), createEffect(() => ({
|
|
3188
|
+
count: store.nodes.length,
|
|
3189
|
+
initialized: store.nodesInitialized
|
|
3190
|
+
}), () => {
|
|
3191
|
+
setGraphBounds(sampleBounds());
|
|
3192
|
+
}), createEffect(() => null, () => {
|
|
3193
|
+
let interval = setInterval(() => setGraphBounds(sampleBounds()), 500);
|
|
3194
|
+
return () => clearInterval(interval);
|
|
3195
|
+
});
|
|
3196
|
+
let boundingRect = createMemo(() => {
|
|
3197
|
+
let view = viewBB(), bounds = graphBounds();
|
|
3198
|
+
return bounds ? getBoundsOfRects(bounds, view) : view;
|
|
3199
|
+
}), viewScale = createMemo(() => Math.max(boundingRect().width / _props.width, boundingRect().height / _props.height)), getViewWidth = () => viewScale() * _props.width, getViewHeight = () => viewScale() * _props.height, getOffset = () => _props.offsetScale * viewScale(), getX = () => {
|
|
3110
3200
|
let rect = boundingRect();
|
|
3111
3201
|
return rect.x - (getViewWidth() - rect.width) / 2 - getOffset();
|
|
3112
3202
|
}, getY = () => {
|
|
@@ -3167,9 +3257,15 @@ const DotPattern = (props) => {
|
|
|
3167
3257
|
<title id={labelledBy()}>{store.ariaLabelConfig["minimap.ariaLabel"]}</title>
|
|
3168
3258
|
<For keyed={!1} each={nodeIds()}>
|
|
3169
3259
|
{(nodeId) => {
|
|
3170
|
-
let
|
|
3171
|
-
|
|
3172
|
-
|
|
3260
|
+
let visibleNode = createMemo(() => {
|
|
3261
|
+
let row = nodeLookup.get(nodeId());
|
|
3262
|
+
return row && nodeHasDimensions(row) && !row.hidden ? row : null;
|
|
3263
|
+
});
|
|
3264
|
+
return <Show when={visibleNode()}>
|
|
3265
|
+
{(node) => {
|
|
3266
|
+
let dimensions = () => getNodeDimensions(node()), userNode = () => node().internals.userNode;
|
|
3267
|
+
return <Dynamic component={_props.nodeComponent ?? MiniMapNode} id={nodeId()} x={node().internals.positionAbsolute.x} y={node().internals.positionAbsolute.y} borderRadius={_props.nodeBorderRadius} strokeWidth={_props.nodeStrokeWidth} shapeRendering={shapeRendering} width={dimensions().width} height={dimensions().height} selected={node().selected} color={nodeColorFunc()?.call(null, userNode())} strokeColor={nodeStrokeColorFunc().call(null, userNode())} class={nodeClassFunc().call(null, userNode())} style={node().style} onClick={_props.onNodeClick ? onSvgNodeClick : void 0} />;
|
|
3268
|
+
}}
|
|
3173
3269
|
</Show>;
|
|
3174
3270
|
}}
|
|
3175
3271
|
</For>
|
|
@@ -3286,7 +3382,7 @@ const DotPattern = (props) => {
|
|
|
3286
3382
|
</EdgeLabel>
|
|
3287
3383
|
</Show>;
|
|
3288
3384
|
}, NodeToolbar = (props) => {
|
|
3289
|
-
let { store
|
|
3385
|
+
let { store, flow, commands } = useInternalSolidFlow(), _props = propDefaults(props, {
|
|
3290
3386
|
offset: 10,
|
|
3291
3387
|
position: "top",
|
|
3292
3388
|
align: "center",
|
|
@@ -3298,7 +3394,7 @@ const DotPattern = (props) => {
|
|
|
3298
3394
|
let node = flow.internalNodes[nodeId];
|
|
3299
3395
|
return node && res.push(node), res;
|
|
3300
3396
|
}, []), transform = () => {
|
|
3301
|
-
let nodeRect = getNodesBounds(toolbarNodes());
|
|
3397
|
+
let nodeRect = commands.getNodesBounds(toolbarNodes());
|
|
3302
3398
|
return nodeRect ? getNodeToolbarTransform(nodeRect, store.viewport, _props.position, _props.offset, _props.align) : "";
|
|
3303
3399
|
}, zIndex = () => {
|
|
3304
3400
|
let nodes = toolbarNodes();
|
|
@@ -3321,4 +3417,4 @@ const DotPattern = (props) => {
|
|
|
3321
3417
|
</Show>;
|
|
3322
3418
|
}, SelectionMode = SelectionMode$1, getEdgeCenter = getEdgeCenter$1, getBezierEdgeCenter = getBezierEdgeCenter$1;
|
|
3323
3419
|
//#endregion
|
|
3324
|
-
export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, MiniMapNode, 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, useEdgeId, useEdges, useInternalNode, useNodeConnections, useNodeId, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };
|
|
3420
|
+
export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, MiniMapNode, 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, useEdgeId, useEdges, useInternalNode, useKeyPress, useNodeConnections, useNodeId, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };
|