@dschz/solid-flow 0.3.0-next.1 → 0.3.0-next.3
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 +577 -399
- package/dist/index/index.js +3263 -3212
- package/dist/index/index.jsx +798 -764
- package/dist/styles/index.css +45 -43
- package/package.json +1 -1
package/dist/index/index.jsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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
2
|
import { For, Show, createContext, createEffect, createMemo, createProjection, createSignal, createStore, flush, mapArray, merge, omit, onCleanup, onSettled, snapshot, untrack, useContext } from "solid-js";
|
|
2
3
|
import { createMediaQuery } from "@solid-primitives/media";
|
|
3
|
-
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";
|
|
4
4
|
import { Dynamic, Portal, isServer } from "@solidjs/web";
|
|
5
5
|
import { createEventListener, createEventListenerMap } from "@solid-primitives/event-listener";
|
|
6
|
-
//#region src/
|
|
6
|
+
//#region src/contexts/edgeId.ts
|
|
7
7
|
const EdgeIdContext = createContext(null);
|
|
8
8
|
function useEdgeId() {
|
|
9
9
|
let ctx = useContext(EdgeIdContext);
|
|
@@ -53,9 +53,10 @@ function propDefaults(props, defaults) {
|
|
|
53
53
|
});
|
|
54
54
|
return out;
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
const getEdgeId = (connection) => {
|
|
57
|
+
let { source, sourceHandle, target, targetHandle } = connection;
|
|
58
|
+
return `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
|
|
59
|
+
}, EdgeLabelRenderer = (props) => {
|
|
59
60
|
let { store } = useInternalSolidFlow(), labelNode = () => store.domNode?.querySelector(".solid-flow__edge-labels");
|
|
60
61
|
return <Show when={labelNode()}>{(root) => <Portal mount={root()}>{props.children}</Portal>}</Show>;
|
|
61
62
|
}, EdgeLabel = (props) => {
|
|
@@ -222,145 +223,40 @@ const EdgeLabelRenderer = (props) => {
|
|
|
222
223
|
</div>
|
|
223
224
|
</Show>
|
|
224
225
|
</>;
|
|
225
|
-
},
|
|
226
|
-
let
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
event
|
|
239
|
-
});
|
|
240
|
-
}, onKeyDown = (event) => {
|
|
241
|
-
store.disableKeyboardA11y || !elementSelectionKeys.includes(event.key) || !selectable() || (event.key === "Escape" ? actions.unselectNodesAndEdges({ edges: [edge()] }) : actions.addSelectedEdges([edge().id]));
|
|
242
|
-
}, ariaLabel = () => edge().ariaLabel ?? `Edge from ${edge().source} to ${edge().target}`;
|
|
243
|
-
return <EdgeIdContext value={edgeId}>
|
|
244
|
-
<Show when={!edge().hidden}>
|
|
245
|
-
<svg class="solid-flow__edge-wrapper" style={{ "z-index": edge().zIndex }}>
|
|
246
|
-
<g ref={edgeRef} data-id={edge().id} tabindex={focusable() ? 0 : void 0} role={edge().ariaRole ?? (focusable() ? "group" : "img")} aria-label={ariaLabel()} aria-roledescription="edge" aria-describedby={focusable() ? `${ARIA_EDGE_DESC_KEY}-${store.id}` : void 0} class={[
|
|
247
|
-
"solid-flow__edge",
|
|
248
|
-
`solid-flow__edge-${edgeType()}`,
|
|
249
|
-
{
|
|
250
|
-
animated: !!edge().animated,
|
|
251
|
-
selected: !!edge().selected,
|
|
252
|
-
selectable: !!selectable()
|
|
253
|
-
},
|
|
254
|
-
edge().class
|
|
255
|
-
]} onClick={onClick} onKeyDown={(e) => focusable() && onKeyDown(e)} onContextMenu={(e) => onPointerEvent(e, "contextmenu")} onPointerEnter={(e) => onPointerEvent(e, "pointerenter")} onPointerLeave={(e) => onPointerEvent(e, "pointerleave")} {...edge().domAttributes}>
|
|
256
|
-
<Dynamic component={edgeComponent()} id={edge().id} source={edge().source} target={edge().target} sourceX={edge().sourceX} sourceY={edge().sourceY} targetX={edge().targetX} targetY={edge().targetY} sourcePosition={edge().sourcePosition} targetPosition={edge().targetPosition} animated={edge().animated} selected={edge().selected} label={edge().label} labelStyle={edge().labelStyle} data={edge().data} style={edge().style} interactionWidth={edge().interactionWidth} selectable={selectable()} deletable={edge().deletable ?? !0} type={edgeType()} sourceHandleId={edge().sourceHandle} targetHandleId={edge().targetHandle} markerStart={markerStartUrl()} markerEnd={markerEndUrl()} />
|
|
257
|
-
</g>
|
|
258
|
-
</svg>
|
|
259
|
-
</Show>
|
|
260
|
-
</EdgeIdContext>;
|
|
261
|
-
}, SmoothStepEdge = (props) => {
|
|
262
|
-
let pathData = createMemo(() => {
|
|
263
|
-
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
264
|
-
sourceX: props.sourceX,
|
|
265
|
-
sourceY: props.sourceY,
|
|
266
|
-
targetX: props.targetX,
|
|
267
|
-
targetY: props.targetY,
|
|
268
|
-
sourcePosition: props.sourcePosition,
|
|
269
|
-
targetPosition: props.targetPosition,
|
|
270
|
-
borderRadius: props.pathOptions?.borderRadius,
|
|
271
|
-
offset: props.pathOptions?.offset
|
|
272
|
-
});
|
|
273
|
-
return {
|
|
274
|
-
path,
|
|
275
|
-
labelX,
|
|
276
|
-
labelY
|
|
277
|
-
};
|
|
278
|
-
});
|
|
279
|
-
return <BaseEdge id={props.id} path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
280
|
-
}, SmoothStepEdgeInternal = (props) => {
|
|
281
|
-
let pathData = () => {
|
|
282
|
-
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
283
|
-
sourceX: props.sourceX,
|
|
284
|
-
sourceY: props.sourceY,
|
|
285
|
-
targetX: props.targetX,
|
|
286
|
-
targetY: props.targetY,
|
|
287
|
-
sourcePosition: props.sourcePosition,
|
|
288
|
-
targetPosition: props.targetPosition
|
|
289
|
-
});
|
|
290
|
-
return {
|
|
291
|
-
path,
|
|
292
|
-
labelX,
|
|
293
|
-
labelY
|
|
294
|
-
};
|
|
295
|
-
};
|
|
296
|
-
return <BaseEdge path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
297
|
-
}, StepEdge = (props) => {
|
|
298
|
-
let pathData = createMemo(() => {
|
|
299
|
-
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
300
|
-
sourceX: props.sourceX,
|
|
301
|
-
sourceY: props.sourceY,
|
|
302
|
-
targetX: props.targetX,
|
|
303
|
-
targetY: props.targetY,
|
|
304
|
-
sourcePosition: props.sourcePosition,
|
|
305
|
-
targetPosition: props.targetPosition,
|
|
306
|
-
borderRadius: 0,
|
|
307
|
-
offset: props.pathOptions?.offset
|
|
308
|
-
});
|
|
309
|
-
return {
|
|
310
|
-
path,
|
|
311
|
-
labelX,
|
|
312
|
-
labelY
|
|
313
|
-
};
|
|
314
|
-
});
|
|
315
|
-
return <BaseEdge id={props.id} path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
316
|
-
}, StepEdgeInternal = (props) => {
|
|
317
|
-
let pathData = () => {
|
|
318
|
-
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
319
|
-
sourceX: props.sourceX,
|
|
320
|
-
sourceY: props.sourceY,
|
|
321
|
-
targetX: props.targetX,
|
|
322
|
-
targetY: props.targetY,
|
|
323
|
-
sourcePosition: props.sourcePosition,
|
|
324
|
-
targetPosition: props.targetPosition,
|
|
325
|
-
borderRadius: 0
|
|
326
|
-
});
|
|
327
|
-
return {
|
|
328
|
-
path,
|
|
329
|
-
labelX,
|
|
330
|
-
labelY
|
|
331
|
-
};
|
|
332
|
-
};
|
|
333
|
-
return <BaseEdge path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
334
|
-
}, StraightEdge = (props) => {
|
|
335
|
-
let pathData = createMemo(() => {
|
|
336
|
-
let [path, labelX, labelY] = getStraightPath$1({
|
|
337
|
-
sourceX: props.sourceX,
|
|
338
|
-
sourceY: props.sourceY,
|
|
339
|
-
targetX: props.targetX,
|
|
340
|
-
targetY: props.targetY
|
|
341
|
-
});
|
|
342
|
-
return {
|
|
343
|
-
path,
|
|
344
|
-
labelX,
|
|
345
|
-
labelY
|
|
346
|
-
};
|
|
347
|
-
});
|
|
348
|
-
return <BaseEdge id={props.id} path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
349
|
-
}, StraightEdgeInternal = (props) => {
|
|
350
|
-
let pathData = () => {
|
|
351
|
-
let [path, labelX, labelY] = getStraightPath$1({
|
|
352
|
-
sourceX: props.sourceX,
|
|
353
|
-
sourceY: props.sourceY,
|
|
354
|
-
targetX: props.targetX,
|
|
355
|
-
targetY: props.targetY
|
|
356
|
-
});
|
|
357
|
-
return {
|
|
358
|
-
path,
|
|
359
|
-
labelX,
|
|
360
|
-
labelY
|
|
361
|
-
};
|
|
226
|
+
}, createEdgeStore = (edges) => {
|
|
227
|
+
let [store, setStore] = createStore(edges);
|
|
228
|
+
return [store, setStore];
|
|
229
|
+
}, STEP = .5 / 2, rectsEqual = (a, b) => a === b || !!a && !!b && a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height, rectsOverlap = (a, b) => a.x <= b.x + b.width && a.x + a.width >= b.x && a.y <= b.y + b.height && a.y + a.height >= b.y, createCullingViewport = (source) => createMemo(() => {
|
|
230
|
+
if (!source.onlyRenderVisibleElements) return null;
|
|
231
|
+
let { width, height } = source;
|
|
232
|
+
if (!width || !height) return null;
|
|
233
|
+
let [tx, ty, zoom] = source.transform, zoomBucket = 2 ** Math.floor(Math.log2(zoom)), bucketWidth = width / zoomBucket, bucketHeight = height / zoomBucket, stepX = bucketWidth * STEP, stepY = bucketHeight * STEP, centerX = (width / 2 - tx) / zoom, centerY = (height / 2 - ty) / zoom, quantizedX = Math.round(centerX / stepX) * stepX, quantizedY = Math.round(centerY / stepY) * stepY, halfWidth = bucketWidth * 1, halfHeight = bucketHeight * 1;
|
|
234
|
+
return {
|
|
235
|
+
x: quantizedX - halfWidth,
|
|
236
|
+
y: quantizedY - halfHeight,
|
|
237
|
+
width: 2 * halfWidth,
|
|
238
|
+
height: 2 * halfHeight
|
|
362
239
|
};
|
|
363
|
-
|
|
240
|
+
}, { equals: rectsEqual }), isNodeCulled = (node, cullingViewport) => {
|
|
241
|
+
if (!cullingViewport || node.selected) return !1;
|
|
242
|
+
let { width, height } = node.measured;
|
|
243
|
+
if (!width || !height) return !1;
|
|
244
|
+
let { x, y } = node.internals.positionAbsolute;
|
|
245
|
+
return !rectsOverlap({
|
|
246
|
+
x,
|
|
247
|
+
y,
|
|
248
|
+
width,
|
|
249
|
+
height
|
|
250
|
+
}, cullingViewport);
|
|
251
|
+
}, isEdgeCulled = (row, cullingViewport) => {
|
|
252
|
+
if (!cullingViewport || row.selected) return !1;
|
|
253
|
+
let x = Math.min(row.sourceX, row.targetX), y = Math.min(row.sourceY, row.targetY);
|
|
254
|
+
return !rectsOverlap({
|
|
255
|
+
x,
|
|
256
|
+
y,
|
|
257
|
+
width: Math.abs(row.sourceX - row.targetX),
|
|
258
|
+
height: Math.abs(row.sourceY - row.targetY)
|
|
259
|
+
}, cullingViewport);
|
|
364
260
|
}, getDefaultFlowStateProps = () => ({
|
|
365
261
|
id: "1",
|
|
366
262
|
nodes: [],
|
|
@@ -395,7 +291,7 @@ const EdgeLabelRenderer = (props) => {
|
|
|
395
291
|
selectNodesOnDrag: !0,
|
|
396
292
|
elevateNodesOnSelect: !0,
|
|
397
293
|
zIndexMode: "basic",
|
|
398
|
-
onlyRenderVisibleElements: !
|
|
294
|
+
onlyRenderVisibleElements: !0,
|
|
399
295
|
disableKeyboardA11y: !1,
|
|
400
296
|
defaultMarkerColor: "#b1b1b7",
|
|
401
297
|
ariaLiveMessage: "",
|
|
@@ -595,8 +491,10 @@ function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, select
|
|
|
595
491
|
* the adjacent edges' projections; the record computed re-runs only when
|
|
596
492
|
* membership or presence changes.
|
|
597
493
|
*
|
|
598
|
-
* The viewport participates
|
|
599
|
-
* panning must not touch
|
|
494
|
+
* The viewport never participates here: #15 culling is CSS-only, applied by
|
|
495
|
+
* EdgeWrapper from the quantized culling viewport — panning must not touch
|
|
496
|
+
* edge rows, and the record's membership must not change as edges cross the
|
|
497
|
+
* viewport (no mount/unmount churn).
|
|
600
498
|
*
|
|
601
499
|
* Rows whose endpoints are missing or unmeasured simply drop out of the
|
|
602
500
|
* record — the same "no entry" contract the ReactiveMap pipeline had.
|
|
@@ -623,13 +521,6 @@ const createLayoutedEdges = (source) => {
|
|
|
623
521
|
}, buildRow = (source, edge) => {
|
|
624
522
|
let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
|
|
625
523
|
if (!sourceNode || !targetNode) return source.nodeLookup.size, null;
|
|
626
|
-
if (source.onlyRenderVisibleElements && !isEdgeVisible({
|
|
627
|
-
sourceNode,
|
|
628
|
-
targetNode,
|
|
629
|
-
width: source.width ?? 0,
|
|
630
|
-
height: source.height ?? 0,
|
|
631
|
-
transform: source.transform
|
|
632
|
-
})) return null;
|
|
633
524
|
let edgePosition = getEdgePosition({
|
|
634
525
|
id: edge.id,
|
|
635
526
|
sourceNode,
|
|
@@ -825,8 +716,8 @@ const createLayoutedEdges = (source) => {
|
|
|
825
716
|
get visibleNodeIds() {
|
|
826
717
|
return visibleNodeIds();
|
|
827
718
|
},
|
|
828
|
-
get
|
|
829
|
-
return
|
|
719
|
+
get cullingViewport() {
|
|
720
|
+
return cullingViewport();
|
|
830
721
|
},
|
|
831
722
|
get transform() {
|
|
832
723
|
return transform();
|
|
@@ -852,7 +743,20 @@ const createLayoutedEdges = (source) => {
|
|
|
852
743
|
get zoomActivationKeyPressed() {
|
|
853
744
|
return zoomActivationKeyPressed();
|
|
854
745
|
}
|
|
855
|
-
}),
|
|
746
|
+
}), cullingViewport = createCullingViewport({
|
|
747
|
+
get onlyRenderVisibleElements() {
|
|
748
|
+
return store.onlyRenderVisibleElements;
|
|
749
|
+
},
|
|
750
|
+
get width() {
|
|
751
|
+
return store.width;
|
|
752
|
+
},
|
|
753
|
+
get height() {
|
|
754
|
+
return store.height;
|
|
755
|
+
},
|
|
756
|
+
get transform() {
|
|
757
|
+
return transform();
|
|
758
|
+
}
|
|
759
|
+
}), visibleNodeIds = createMemo(() => Object.keys(internalNodes)), parentIds = createParentIds({ get nodes() {
|
|
856
760
|
return store.nodes;
|
|
857
761
|
} }), edgeLookup = createEdgeLookup({ get edges() {
|
|
858
762
|
return store.edges;
|
|
@@ -874,18 +778,6 @@ const createLayoutedEdges = (source) => {
|
|
|
874
778
|
get zIndexMode() {
|
|
875
779
|
return store.zIndexMode;
|
|
876
780
|
},
|
|
877
|
-
get onlyRenderVisibleElements() {
|
|
878
|
-
return store.onlyRenderVisibleElements;
|
|
879
|
-
},
|
|
880
|
-
get width() {
|
|
881
|
-
return store.width;
|
|
882
|
-
},
|
|
883
|
-
get height() {
|
|
884
|
-
return store.height;
|
|
885
|
-
},
|
|
886
|
-
get transform() {
|
|
887
|
-
return store.transform;
|
|
888
|
-
},
|
|
889
781
|
get onError() {
|
|
890
782
|
return store.onError;
|
|
891
783
|
},
|
|
@@ -1344,89 +1236,233 @@ const createLayoutedEdges = (source) => {
|
|
|
1344
1236
|
reset
|
|
1345
1237
|
}
|
|
1346
1238
|
};
|
|
1347
|
-
},
|
|
1348
|
-
let
|
|
1349
|
-
return
|
|
1350
|
-
},
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
}
|
|
1356
|
-
//#endregion
|
|
1357
|
-
//#region src/components/graph/handle/Handle.tsx
|
|
1358
|
-
const Handle = (props) => {
|
|
1359
|
-
let _props = propDefaults(props, {
|
|
1360
|
-
type: "source",
|
|
1361
|
-
position: "top",
|
|
1362
|
-
isConnectableStart: !0,
|
|
1363
|
-
isConnectableEnd: !0
|
|
1364
|
-
}), { 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;
|
|
1365
|
-
createEffect(() => {
|
|
1366
|
-
if (!_props.onConnect && !_props.onDisconnect) return null;
|
|
1367
|
-
let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
|
|
1368
|
-
for (let key of Object.keys(rec ?? {})) map.set(key, { ...rec[key] });
|
|
1369
|
-
return { connections: map };
|
|
1370
|
-
}, (current) => {
|
|
1371
|
-
if (!current) return;
|
|
1372
|
-
let { connections: next } = current;
|
|
1373
|
-
prevConnections && !areConnectionMapsEqual(next, prevConnections) && (handleConnectionChange(prevConnections, next, props.onDisconnect), handleConnectionChange(next, prevConnections, props.onConnect)), prevConnections = next;
|
|
1374
|
-
});
|
|
1375
|
-
let onConnectExtended = (connection) => {
|
|
1376
|
-
let handleConnection = {
|
|
1377
|
-
...connection,
|
|
1378
|
-
id: getEdgeId(connection)
|
|
1379
|
-
}, edge = store.onBeforeConnect?.(handleConnection) ?? handleConnection;
|
|
1380
|
-
actions.addEdge(edge), store.onConnect?.(handleConnection);
|
|
1381
|
-
}, onPointerDown = (event) => {
|
|
1382
|
-
XYHandle.onPointerDown(event, {
|
|
1383
|
-
handleId: handleId(),
|
|
1384
|
-
nodeId: nodeId(),
|
|
1385
|
-
isTarget: isTarget(),
|
|
1386
|
-
connectionRadius: store.connectionRadius,
|
|
1387
|
-
domNode: store.domNode,
|
|
1388
|
-
nodeLookup,
|
|
1389
|
-
connectionMode: store.connectionMode,
|
|
1390
|
-
lib: store.lib,
|
|
1391
|
-
autoPanOnConnect: store.autoPanOnConnect,
|
|
1392
|
-
flowId: store.id,
|
|
1393
|
-
isValidConnection: _props.isValidConnection ?? store.isValidConnection,
|
|
1394
|
-
updateConnection: ((connection) => {
|
|
1395
|
-
actions.setConnection(connection), flush();
|
|
1396
|
-
}),
|
|
1397
|
-
cancelConnection: actions.cancelConnection,
|
|
1398
|
-
panBy: actions.panBy,
|
|
1399
|
-
onConnect: onConnectExtended,
|
|
1400
|
-
onConnectStart: (event, startParams) => {
|
|
1401
|
-
store.onConnectStart?.(event, {
|
|
1402
|
-
nodeId: startParams.nodeId,
|
|
1403
|
-
handleId: startParams.handleId,
|
|
1404
|
-
handleType: startParams.handleType
|
|
1405
|
-
});
|
|
1406
|
-
},
|
|
1407
|
-
onConnectEnd: store.onConnectEnd,
|
|
1408
|
-
getTransform: () => store.transform,
|
|
1409
|
-
getFromHandle: () => store.connection.fromHandle,
|
|
1410
|
-
autoPanSpeed: store.autoPanSpeed,
|
|
1411
|
-
dragThreshold: store.connectionDragThreshold,
|
|
1412
|
-
handleDomNode: event.currentTarget
|
|
1239
|
+
}, createNodeStore = (nodes) => {
|
|
1240
|
+
let [store, setStore] = createStore(nodes);
|
|
1241
|
+
return [store, setStore];
|
|
1242
|
+
}, EdgeWrapper = (props) => {
|
|
1243
|
+
let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.getEdge(edgeId()), edgeType = () => edge().type ?? "default", selectable = () => edge().selectable ?? store.elementsSelectable, focusable = () => edge().focusable ?? store.edgesFocusable, edgeComponent = () => store.edgeTypes[edgeType()], markerStartUrl = () => edge().markerStart ? `url('#${getMarkerId(edge().markerStart, store.id)}')` : void 0, markerEndUrl = () => edge().markerEnd ? `url('#${getMarkerId(edge().markerEnd, store.id)}')` : void 0, onClick = (event) => {
|
|
1244
|
+
selectable() && actions.handleEdgeSelection(edgeId()), props.onEdgeClick?.({
|
|
1245
|
+
edge: edge(),
|
|
1246
|
+
event
|
|
1413
1247
|
});
|
|
1414
|
-
},
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1248
|
+
}, onPointerEvent = (event, type) => {
|
|
1249
|
+
({
|
|
1250
|
+
contextmenu: props.onEdgeContextMenu,
|
|
1251
|
+
pointerenter: props.onEdgePointerEnter,
|
|
1252
|
+
pointerleave: props.onEdgePointerLeave
|
|
1253
|
+
})[type]?.({
|
|
1254
|
+
edge: edge(),
|
|
1255
|
+
event
|
|
1256
|
+
});
|
|
1257
|
+
}, onKeyDown = (event) => {
|
|
1258
|
+
store.disableKeyboardA11y || !elementSelectionKeys.includes(event.key) || !selectable() || (event.key === "Escape" ? actions.unselectNodesAndEdges({ edges: [edge()] }) : actions.addSelectedEdges([edge().id]));
|
|
1259
|
+
}, ariaLabel = () => edge().ariaLabel ?? `Edge from ${edge().source} to ${edge().target}`, culled = createMemo(() => isEdgeCulled(edge(), store.cullingViewport));
|
|
1260
|
+
return <EdgeIdContext value={edgeId}>
|
|
1261
|
+
<Show when={!edge().hidden}>
|
|
1262
|
+
<svg class="solid-flow__edge-wrapper" style={{
|
|
1263
|
+
"z-index": edge().zIndex,
|
|
1264
|
+
visibility: culled() ? "hidden" : void 0,
|
|
1265
|
+
"pointer-events": culled() ? "none" : void 0
|
|
1266
|
+
}}>
|
|
1267
|
+
<g ref={edgeRef} data-id={edge().id} tabindex={focusable() ? 0 : void 0} role={edge().ariaRole ?? (focusable() ? "group" : "img")} aria-label={ariaLabel()} aria-roledescription="edge" aria-describedby={focusable() ? `${ARIA_EDGE_DESC_KEY}-${store.id}` : void 0} class={[
|
|
1268
|
+
"solid-flow__edge",
|
|
1269
|
+
`solid-flow__edge-${edgeType()}`,
|
|
1270
|
+
{
|
|
1271
|
+
animated: !!edge().animated,
|
|
1272
|
+
selected: !!edge().selected,
|
|
1273
|
+
selectable: !!selectable()
|
|
1274
|
+
},
|
|
1275
|
+
edge().class
|
|
1276
|
+
]} onClick={onClick} onKeyDown={(e) => focusable() && onKeyDown(e)} onContextMenu={(e) => onPointerEvent(e, "contextmenu")} onPointerEnter={(e) => onPointerEvent(e, "pointerenter")} onPointerLeave={(e) => onPointerEvent(e, "pointerleave")} {...edge().domAttributes}>
|
|
1277
|
+
<Dynamic component={edgeComponent()} id={edge().id} source={edge().source} target={edge().target} sourceX={edge().sourceX} sourceY={edge().sourceY} targetX={edge().targetX} targetY={edge().targetY} sourcePosition={edge().sourcePosition} targetPosition={edge().targetPosition} animated={edge().animated} selected={edge().selected} label={edge().label} labelStyle={edge().labelStyle} data={edge().data} style={edge().style} interactionWidth={edge().interactionWidth} selectable={selectable()} deletable={edge().deletable ?? !0} type={edgeType()} sourceHandleId={edge().sourceHandle} targetHandleId={edge().targetHandle} markerStart={markerStartUrl()} markerEnd={markerEndUrl()} />
|
|
1278
|
+
</g>
|
|
1279
|
+
</svg>
|
|
1280
|
+
</Show>
|
|
1281
|
+
</EdgeIdContext>;
|
|
1282
|
+
}, SmoothStepEdge = (props) => {
|
|
1283
|
+
let pathData = createMemo(() => {
|
|
1284
|
+
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
1285
|
+
sourceX: props.sourceX,
|
|
1286
|
+
sourceY: props.sourceY,
|
|
1287
|
+
targetX: props.targetX,
|
|
1288
|
+
targetY: props.targetY,
|
|
1289
|
+
sourcePosition: props.sourcePosition,
|
|
1290
|
+
targetPosition: props.targetPosition,
|
|
1291
|
+
borderRadius: props.pathOptions?.borderRadius,
|
|
1292
|
+
offset: props.pathOptions?.offset
|
|
1293
|
+
});
|
|
1294
|
+
return {
|
|
1295
|
+
path,
|
|
1296
|
+
labelX,
|
|
1297
|
+
labelY
|
|
1298
|
+
};
|
|
1299
|
+
});
|
|
1300
|
+
return <BaseEdge id={props.id} path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
1301
|
+
}, SmoothStepEdgeInternal = (props) => {
|
|
1302
|
+
let pathData = () => {
|
|
1303
|
+
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
1304
|
+
sourceX: props.sourceX,
|
|
1305
|
+
sourceY: props.sourceY,
|
|
1306
|
+
targetX: props.targetX,
|
|
1307
|
+
targetY: props.targetY,
|
|
1308
|
+
sourcePosition: props.sourcePosition,
|
|
1309
|
+
targetPosition: props.targetPosition
|
|
1310
|
+
});
|
|
1311
|
+
return {
|
|
1312
|
+
path,
|
|
1313
|
+
labelX,
|
|
1314
|
+
labelY
|
|
1315
|
+
};
|
|
1316
|
+
};
|
|
1317
|
+
return <BaseEdge path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
1318
|
+
}, StepEdge = (props) => {
|
|
1319
|
+
let pathData = createMemo(() => {
|
|
1320
|
+
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
1321
|
+
sourceX: props.sourceX,
|
|
1322
|
+
sourceY: props.sourceY,
|
|
1323
|
+
targetX: props.targetX,
|
|
1324
|
+
targetY: props.targetY,
|
|
1325
|
+
sourcePosition: props.sourcePosition,
|
|
1326
|
+
targetPosition: props.targetPosition,
|
|
1327
|
+
borderRadius: 0,
|
|
1328
|
+
offset: props.pathOptions?.offset
|
|
1329
|
+
});
|
|
1330
|
+
return {
|
|
1331
|
+
path,
|
|
1332
|
+
labelX,
|
|
1333
|
+
labelY
|
|
1334
|
+
};
|
|
1335
|
+
});
|
|
1336
|
+
return <BaseEdge id={props.id} path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
1337
|
+
}, StepEdgeInternal = (props) => {
|
|
1338
|
+
let pathData = () => {
|
|
1339
|
+
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
1340
|
+
sourceX: props.sourceX,
|
|
1341
|
+
sourceY: props.sourceY,
|
|
1342
|
+
targetX: props.targetX,
|
|
1343
|
+
targetY: props.targetY,
|
|
1344
|
+
sourcePosition: props.sourcePosition,
|
|
1345
|
+
targetPosition: props.targetPosition,
|
|
1346
|
+
borderRadius: 0
|
|
1347
|
+
});
|
|
1348
|
+
return {
|
|
1349
|
+
path,
|
|
1350
|
+
labelX,
|
|
1351
|
+
labelY
|
|
1352
|
+
};
|
|
1353
|
+
};
|
|
1354
|
+
return <BaseEdge path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
1355
|
+
}, StraightEdge = (props) => {
|
|
1356
|
+
let pathData = createMemo(() => {
|
|
1357
|
+
let [path, labelX, labelY] = getStraightPath$1({
|
|
1358
|
+
sourceX: props.sourceX,
|
|
1359
|
+
sourceY: props.sourceY,
|
|
1360
|
+
targetX: props.targetX,
|
|
1361
|
+
targetY: props.targetY
|
|
1362
|
+
});
|
|
1363
|
+
return {
|
|
1364
|
+
path,
|
|
1365
|
+
labelX,
|
|
1366
|
+
labelY
|
|
1367
|
+
};
|
|
1368
|
+
});
|
|
1369
|
+
return <BaseEdge id={props.id} path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
1370
|
+
}, StraightEdgeInternal = (props) => {
|
|
1371
|
+
let pathData = () => {
|
|
1372
|
+
let [path, labelX, labelY] = getStraightPath$1({
|
|
1373
|
+
sourceX: props.sourceX,
|
|
1374
|
+
sourceY: props.sourceY,
|
|
1375
|
+
targetX: props.targetX,
|
|
1376
|
+
targetY: props.targetY
|
|
1377
|
+
});
|
|
1378
|
+
return {
|
|
1379
|
+
path,
|
|
1380
|
+
labelX,
|
|
1381
|
+
labelY
|
|
1382
|
+
};
|
|
1383
|
+
};
|
|
1384
|
+
return <BaseEdge path={pathData().path} labelX={pathData().labelX} labelY={pathData().labelY} label={props.label} labelStyle={props.labelStyle} markerStart={props.markerStart} markerEnd={props.markerEnd} interactionWidth={props.interactionWidth} style={props.style} />;
|
|
1385
|
+
}, NodeConnectableContext = createContext(null);
|
|
1386
|
+
function useNodeConnectable() {
|
|
1387
|
+
let ctx = useContext(NodeConnectableContext);
|
|
1388
|
+
if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useNodeConnectable");
|
|
1389
|
+
return ctx;
|
|
1390
|
+
}
|
|
1391
|
+
//#endregion
|
|
1392
|
+
//#region src/components/handle/Handle.tsx
|
|
1393
|
+
/** Connection point on a node; place inside custom nodes to make them connectable. */
|
|
1394
|
+
const Handle = (props) => {
|
|
1395
|
+
let _props = propDefaults(props, {
|
|
1396
|
+
type: "source",
|
|
1397
|
+
position: "top",
|
|
1398
|
+
isConnectableStart: !0,
|
|
1399
|
+
isConnectableEnd: !0
|
|
1400
|
+
}), { 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;
|
|
1401
|
+
createEffect(() => {
|
|
1402
|
+
if (!_props.onConnect && !_props.onDisconnect) return null;
|
|
1403
|
+
let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
|
|
1404
|
+
for (let key of Object.keys(rec ?? {})) map.set(key, { ...rec[key] });
|
|
1405
|
+
return { connections: map };
|
|
1406
|
+
}, (current) => {
|
|
1407
|
+
if (!current) return;
|
|
1408
|
+
let { connections: next } = current;
|
|
1409
|
+
prevConnections && !areConnectionMapsEqual(next, prevConnections) && (handleConnectionChange(prevConnections, next, props.onDisconnect), handleConnectionChange(next, prevConnections, props.onConnect)), prevConnections = next;
|
|
1410
|
+
});
|
|
1411
|
+
let onConnectExtended = (connection) => {
|
|
1412
|
+
let handleConnection = {
|
|
1413
|
+
...connection,
|
|
1414
|
+
id: getEdgeId(connection)
|
|
1415
|
+
}, edge = store.onBeforeConnect?.(handleConnection) ?? handleConnection;
|
|
1416
|
+
actions.addEdge(edge), store.onConnect?.(handleConnection);
|
|
1417
|
+
}, onPointerDown = (event) => {
|
|
1418
|
+
XYHandle.onPointerDown(event, {
|
|
1419
|
+
handleId: handleId(),
|
|
1420
|
+
nodeId: nodeId(),
|
|
1421
|
+
isTarget: isTarget(),
|
|
1422
|
+
connectionRadius: store.connectionRadius,
|
|
1423
|
+
domNode: store.domNode,
|
|
1424
|
+
nodeLookup,
|
|
1425
|
+
connectionMode: store.connectionMode,
|
|
1426
|
+
lib: store.lib,
|
|
1427
|
+
autoPanOnConnect: store.autoPanOnConnect,
|
|
1428
|
+
flowId: store.id,
|
|
1429
|
+
isValidConnection: _props.isValidConnection ?? store.isValidConnection,
|
|
1430
|
+
updateConnection: ((connection) => {
|
|
1431
|
+
actions.setConnection(connection), flush();
|
|
1432
|
+
}),
|
|
1433
|
+
cancelConnection: actions.cancelConnection,
|
|
1434
|
+
panBy: actions.panBy,
|
|
1435
|
+
onConnect: onConnectExtended,
|
|
1436
|
+
onConnectStart: (event, startParams) => {
|
|
1437
|
+
store.onConnectStart?.(event, {
|
|
1438
|
+
nodeId: startParams.nodeId,
|
|
1439
|
+
handleId: startParams.handleId,
|
|
1440
|
+
handleType: startParams.handleType
|
|
1441
|
+
});
|
|
1442
|
+
},
|
|
1443
|
+
onConnectEnd: store.onConnectEnd,
|
|
1444
|
+
getTransform: () => store.transform,
|
|
1445
|
+
getFromHandle: () => store.connection.fromHandle,
|
|
1446
|
+
autoPanSpeed: store.autoPanSpeed,
|
|
1447
|
+
dragThreshold: store.connectionDragThreshold,
|
|
1448
|
+
handleDomNode: event.currentTarget
|
|
1449
|
+
});
|
|
1450
|
+
}, onClick = (event) => {
|
|
1451
|
+
if (!nodeId() || !store.clickConnectStartHandle && !_props.isConnectableStart) return;
|
|
1452
|
+
if (!store.clickConnectStartHandle) {
|
|
1453
|
+
store.onClickConnectStart?.(event, {
|
|
1454
|
+
nodeId: nodeId(),
|
|
1455
|
+
handleId: handleId(),
|
|
1456
|
+
handleType: _props.type
|
|
1457
|
+
}), actions.setClickConnectStartHandle({
|
|
1458
|
+
nodeId: nodeId(),
|
|
1459
|
+
type: _props.type,
|
|
1460
|
+
id: handleId()
|
|
1461
|
+
});
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
let doc = getHostForElement(event.target), isValidConnectionHandler = _props.isValidConnection ?? store.isValidConnection, { connection, isValid } = XYHandle.isValid(event, {
|
|
1465
|
+
handle: {
|
|
1430
1466
|
nodeId: nodeId(),
|
|
1431
1467
|
id: handleId(),
|
|
1432
1468
|
type: _props.type
|
|
@@ -1542,7 +1578,8 @@ function useNodeId() {
|
|
|
1542
1578
|
return ctx;
|
|
1543
1579
|
}
|
|
1544
1580
|
//#endregion
|
|
1545
|
-
//#region src/components/
|
|
1581
|
+
//#region src/components/node/NodeWrapper.tsx
|
|
1582
|
+
/** Internal per-node wrapper: dragging, selection, a11y, measurement, viewport culling, and the dynamic node component. */
|
|
1546
1583
|
const NodeWrapper = (props) => {
|
|
1547
1584
|
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 = () => {
|
|
1548
1585
|
let { x, y } = node().internals.positionAbsolute;
|
|
@@ -1554,10 +1591,11 @@ const NodeWrapper = (props) => {
|
|
|
1554
1591
|
...w ? { width: toPxString(w) } : {},
|
|
1555
1592
|
...h ? { height: toPxString(h) } : {}
|
|
1556
1593
|
};
|
|
1557
|
-
}, style = () => ({
|
|
1594
|
+
}, culled = createMemo(() => isNodeCulled(node(), store.cullingViewport)), style = () => ({
|
|
1558
1595
|
"z-index": node().internals.z,
|
|
1559
1596
|
transform: transform(),
|
|
1560
|
-
visibility: nodeHasDimensions(node()) ? "
|
|
1597
|
+
visibility: culled() || !nodeHasDimensions(node()) ? "hidden" : "visible",
|
|
1598
|
+
"pointer-events": culled() ? "none" : void 0,
|
|
1561
1599
|
...sizeStyle(),
|
|
1562
1600
|
...node().style ?? {}
|
|
1563
1601
|
});
|
|
@@ -1685,7 +1723,7 @@ const NodeWrapper = (props) => {
|
|
|
1685
1723
|
</>;
|
|
1686
1724
|
};
|
|
1687
1725
|
//#endregion
|
|
1688
|
-
//#region src/
|
|
1726
|
+
//#region src/browser/measure.ts
|
|
1689
1727
|
/**
|
|
1690
1728
|
* The DOM side of the measurement pipeline (fork of @xyflow/system's
|
|
1691
1729
|
* updateNodeInternals): reads each updated node element's dimensions and
|
|
@@ -1795,7 +1833,7 @@ function handleExpandParent(children, nodeLookup, getChildNodes, nodeOrigin = [0
|
|
|
1795
1833
|
}), changes;
|
|
1796
1834
|
}
|
|
1797
1835
|
//#endregion
|
|
1798
|
-
//#region src/
|
|
1836
|
+
//#region src/browser/createSolidFlow.ts
|
|
1799
1837
|
const InitialNodeTypesMap = {
|
|
1800
1838
|
input: InputNode,
|
|
1801
1839
|
output: OutputNode,
|
|
@@ -1837,8 +1875,54 @@ function useInternalSolidFlow() {
|
|
|
1837
1875
|
return ctx;
|
|
1838
1876
|
}
|
|
1839
1877
|
//#endregion
|
|
1840
|
-
//#region src/components/
|
|
1841
|
-
|
|
1878
|
+
//#region src/components/connection/ConnectionLine.tsx
|
|
1879
|
+
/** Internal component rendering the in-progress connection line. */
|
|
1880
|
+
const ConnectionLine = (props) => {
|
|
1881
|
+
let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid);
|
|
1882
|
+
return <Show when={store.connection.inProgress}>
|
|
1883
|
+
<svg class="solid-flow__container solid-flow__connectionline" width={store.width} height={store.height} style={props.containerStyle}>
|
|
1884
|
+
<g class={["solid-flow__connection", connectionStatus()]}>
|
|
1885
|
+
<Show when={props.component} fallback={<InternalConnectionLine style={props.style} />}>
|
|
1886
|
+
{(CustomComponent) => {
|
|
1887
|
+
let UserConnectionLine = CustomComponent();
|
|
1888
|
+
return <UserConnectionLine connectionLineType={store.connectionLineType} connectionLineStyle={props.style} fromNode={store.connection.fromNode} fromHandle={store.connection.fromHandle} fromX={store.connection.from.x} fromY={store.connection.from.y} toX={store.connection.to.x} toY={store.connection.to.y} fromPosition={store.connection.fromPosition} toPosition={store.connection.toPosition} connectionStatus={connectionStatus()} toNode={store.connection.toNode} toHandle={store.connection.toHandle} />;
|
|
1889
|
+
}}
|
|
1890
|
+
</Show>
|
|
1891
|
+
</g>
|
|
1892
|
+
</svg>
|
|
1893
|
+
</Show>;
|
|
1894
|
+
}, InternalConnectionLine = (props) => {
|
|
1895
|
+
let { store } = useInternalSolidFlow(), path = () => {
|
|
1896
|
+
if (!store.connection.inProgress) return;
|
|
1897
|
+
let pathParams = {
|
|
1898
|
+
sourceX: store.connection.from.x,
|
|
1899
|
+
sourceY: store.connection.from.y,
|
|
1900
|
+
sourcePosition: store.connection.fromPosition,
|
|
1901
|
+
targetX: store.connection.to.x,
|
|
1902
|
+
targetY: store.connection.to.y,
|
|
1903
|
+
targetPosition: store.connection.toPosition
|
|
1904
|
+
};
|
|
1905
|
+
switch (store.connectionLineType) {
|
|
1906
|
+
case "default": {
|
|
1907
|
+
let [path] = getBezierPath$1(pathParams);
|
|
1908
|
+
return path;
|
|
1909
|
+
}
|
|
1910
|
+
case "straight": {
|
|
1911
|
+
let [path] = getStraightPath$1(pathParams);
|
|
1912
|
+
return path;
|
|
1913
|
+
}
|
|
1914
|
+
case "step":
|
|
1915
|
+
case "smoothstep": {
|
|
1916
|
+
let [path] = getSmoothStepPath$1({
|
|
1917
|
+
...pathParams,
|
|
1918
|
+
borderRadius: store.connectionLineType === "step" ? 0 : void 0
|
|
1919
|
+
});
|
|
1920
|
+
return path;
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
};
|
|
1924
|
+
return <path class="solid-flow__connection-path" fill="none" style={props.style} d={path()} />;
|
|
1925
|
+
}, Marker = (props) => {
|
|
1842
1926
|
let _props = propDefaults(props, {
|
|
1843
1927
|
markerUnits: "strokeWidth",
|
|
1844
1928
|
orient: "auto-start-reverse",
|
|
@@ -2117,52 +2201,451 @@ const Marker = (props) => {
|
|
|
2117
2201
|
}), <div ref={setRef} class="solid-flow__container solid-flow__zoom">
|
|
2118
2202
|
{props.children}
|
|
2119
2203
|
</div>;
|
|
2120
|
-
},
|
|
2121
|
-
let {
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
return <UserConnectionLine connectionLineType={store.connectionLineType} connectionLineStyle={props.style} fromNode={store.connection.fromNode} fromHandle={store.connection.fromHandle} fromX={store.connection.from.x} fromY={store.connection.from.y} toX={store.connection.to.x} toY={store.connection.to.y} fromPosition={store.connection.fromPosition} toPosition={store.connection.toPosition} connectionStatus={connectionStatus()} toNode={store.connection.toNode} toHandle={store.connection.toHandle} />;
|
|
2129
|
-
}}
|
|
2130
|
-
</Show>
|
|
2131
|
-
</g>
|
|
2132
|
-
</svg>
|
|
2204
|
+
}, Selection = (props) => {
|
|
2205
|
+
let _props = propDefaults(props, { isVisible: !0 }), styles = () => ({
|
|
2206
|
+
..._props.width != null && { width: typeof _props.width == "string" ? _props.width : toPxString(_props.width) },
|
|
2207
|
+
..._props.height != null && { height: typeof _props.height == "string" ? _props.height : toPxString(_props.height) },
|
|
2208
|
+
..._props.x != null && _props.y != null && { transform: `translate(${props.x}px, ${props.y}px)` }
|
|
2209
|
+
});
|
|
2210
|
+
return <Show when={_props.isVisible}>
|
|
2211
|
+
<div class="solid-flow__selection" style={styles()} />
|
|
2133
2212
|
</Show>;
|
|
2134
|
-
},
|
|
2135
|
-
let { store } = useInternalSolidFlow(),
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2213
|
+
}, NodeSelection = (props) => {
|
|
2214
|
+
let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref, setRef] = createSignal(), bounds = () => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null;
|
|
2215
|
+
createEffect(() => ({
|
|
2216
|
+
el: ref(),
|
|
2217
|
+
focusable: !store.disableKeyboardA11y
|
|
2218
|
+
}), ({ el, focusable }) => {
|
|
2219
|
+
focusable && el?.focus({ preventScroll: !0 });
|
|
2220
|
+
});
|
|
2221
|
+
let onContextMenu = (event) => {
|
|
2222
|
+
let selectedNodes = store.nodes.filter((n) => n.selected);
|
|
2223
|
+
props.onSelectionContextMenu?.({
|
|
2224
|
+
nodes: selectedNodes,
|
|
2225
|
+
event
|
|
2226
|
+
});
|
|
2227
|
+
}, onClick = (event) => {
|
|
2228
|
+
let selectedNodes = store.nodes.filter((n) => n.selected);
|
|
2229
|
+
props.onSelectionClick?.({
|
|
2230
|
+
nodes: selectedNodes,
|
|
2231
|
+
event
|
|
2232
|
+
});
|
|
2233
|
+
};
|
|
2234
|
+
createDraggable(ref, () => ({
|
|
2235
|
+
disabled: !1,
|
|
2236
|
+
onDrag: (event, _, __, nodes) => {
|
|
2237
|
+
props.onNodeDrag?.({
|
|
2238
|
+
event,
|
|
2239
|
+
targetNode: null,
|
|
2240
|
+
nodes
|
|
2241
|
+
});
|
|
2242
|
+
},
|
|
2243
|
+
onDragStart: (event, _, __, nodes) => {
|
|
2244
|
+
props.onNodeDragStart?.({
|
|
2245
|
+
event,
|
|
2246
|
+
targetNode: null,
|
|
2247
|
+
nodes
|
|
2248
|
+
});
|
|
2249
|
+
},
|
|
2250
|
+
onDragStop: (event, _, __, nodes) => {
|
|
2251
|
+
props.onNodeDragStop?.({
|
|
2252
|
+
event,
|
|
2253
|
+
targetNode: null,
|
|
2254
|
+
nodes
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
}));
|
|
2258
|
+
let onKeyDown = (event) => {
|
|
2259
|
+
let diff = ARROW_KEY_DIFFS[event.key];
|
|
2260
|
+
diff && (event.preventDefault(), actions.moveSelectedNodes(diff, event.shiftKey ? 4 : 1));
|
|
2261
|
+
};
|
|
2262
|
+
return <Show when={store.selectionRectMode === "nodes" && bounds() && isNumeric(bounds()?.x) && isNumeric(bounds()?.y)}>
|
|
2263
|
+
<div ref={setRef} class={["solid-flow__selection-wrapper", store.noPanClass]} style={{
|
|
2264
|
+
width: toPxString(bounds()?.width),
|
|
2265
|
+
height: toPxString(bounds()?.height),
|
|
2266
|
+
transform: `translate(${bounds()?.x}px, ${bounds()?.y}px)`
|
|
2267
|
+
}} onClick={onClick} onContextMenu={onContextMenu} role={store.disableKeyboardA11y ? void 0 : "button"} tabindex={store.disableKeyboardA11y ? void 0 : -1} onKeyDown={store.disableKeyboardA11y ? void 0 : onKeyDown}>
|
|
2268
|
+
<Selection width="100%" height="100%" x={0} y={0} />
|
|
2269
|
+
</div>
|
|
2270
|
+
</Show>;
|
|
2271
|
+
}, Attribution = (props) => <Show when={!props.proOptions?.hideAttribution}>
|
|
2272
|
+
<Panel position={props.position ?? "bottom-right"} class="solid-flow__attribution" data-message="Feel free to remove the attribution or check out how you could support us: https://solidflow.dev/support-us">
|
|
2273
|
+
<a href="https://solidflow.dev" target="_blank" rel="noopener noreferrer" aria-label="Solid Flow attribution">
|
|
2274
|
+
Solid Flow
|
|
2275
|
+
</a>
|
|
2276
|
+
</Panel>
|
|
2277
|
+
</Show>;
|
|
2278
|
+
//#endregion
|
|
2279
|
+
//#region src/hooks/useSolidFlow.ts
|
|
2280
|
+
/**
|
|
2281
|
+
* Hook for accessing the flow instance: `{ flow, commands }` plus the
|
|
2282
|
+
* commands spread at the top level for upstream familiarity.
|
|
2283
|
+
*
|
|
2284
|
+
* `flow` and `commands` are stable identities, so destructuring them is safe:
|
|
2285
|
+
* `const { flow, commands } = useSolidFlow()`.
|
|
2286
|
+
*
|
|
2287
|
+
* @public
|
|
2288
|
+
* @returns the flow's read struct, write surface, and deprecated aliases
|
|
2289
|
+
*/
|
|
2290
|
+
function useSolidFlow() {
|
|
2291
|
+
let { flow, commands, store, edgeLookup } = useInternalSolidFlow(), getInternalNode = (id) => flow.internalNodes[id];
|
|
2292
|
+
return {
|
|
2293
|
+
...commands,
|
|
2294
|
+
flow,
|
|
2295
|
+
commands,
|
|
2296
|
+
getInternalNode,
|
|
2297
|
+
getNode: (id) => getInternalNode(id)?.internals.userNode,
|
|
2298
|
+
getNodes: (ids) => ids ? ids.flatMap((id) => {
|
|
2299
|
+
let userNode = flow.internalNodes[id]?.internals.userNode;
|
|
2300
|
+
return userNode ? [userNode] : [];
|
|
2301
|
+
}) : [...flow.nodes],
|
|
2302
|
+
getEdge: (id) => edgeLookup[id],
|
|
2303
|
+
getEdges: (ids) => ids ? ids.flatMap((id) => edgeLookup[id] ? [edgeLookup[id]] : []) : [...flow.edges],
|
|
2304
|
+
getViewport: () => snapshot(store.viewport),
|
|
2305
|
+
getZoom: () => flow.viewport.zoom,
|
|
2306
|
+
getHandleConnections: ({ type, id, nodeId }) => Object.values(flow.connections[connectionKey(nodeId, type, id ?? null)] ?? {})
|
|
2307
|
+
};
|
|
2308
|
+
}
|
|
2309
|
+
//#endregion
|
|
2310
|
+
//#region src/components/utility/KeyHandler.ts
|
|
2311
|
+
function isKeyObject(key) {
|
|
2312
|
+
return typeof key == "object" && !!key;
|
|
2313
|
+
}
|
|
2314
|
+
function getModifier(key) {
|
|
2315
|
+
return isKeyObject(key) && key.modifier || [];
|
|
2316
|
+
}
|
|
2317
|
+
function getKeyString(key) {
|
|
2318
|
+
return key == null ? "" : isKeyObject(key) ? key.key : key;
|
|
2319
|
+
}
|
|
2320
|
+
function matchesKey(event, keyDef) {
|
|
2321
|
+
if (!keyDef) return !1;
|
|
2322
|
+
let keyString = getKeyString(keyDef);
|
|
2323
|
+
if (!keyString) return !1;
|
|
2324
|
+
let modifiers = getModifier(keyDef);
|
|
2325
|
+
if (Array.isArray(modifiers)) {
|
|
2326
|
+
let modifierMatch = modifiers.flatMap((mod) => mod).every((mod) => {
|
|
2327
|
+
switch (mod.toLowerCase()) {
|
|
2328
|
+
case "meta": return event.metaKey;
|
|
2329
|
+
case "ctrl": return event.ctrlKey;
|
|
2330
|
+
case "alt": return event.altKey;
|
|
2331
|
+
case "shift": return event.shiftKey;
|
|
2332
|
+
default: return !1;
|
|
2161
2333
|
}
|
|
2334
|
+
});
|
|
2335
|
+
return event.key === keyString && modifierMatch;
|
|
2336
|
+
}
|
|
2337
|
+
return event.key === keyString;
|
|
2338
|
+
}
|
|
2339
|
+
function matchesKeyArray(event, keyDefs) {
|
|
2340
|
+
return keyDefs ? (Array.isArray(keyDefs) ? keyDefs : [keyDefs]).some((keyDef) => matchesKey(event, keyDef)) : !1;
|
|
2341
|
+
}
|
|
2342
|
+
const KeyHandler = (props) => {
|
|
2343
|
+
let { store, actions } = useInternalSolidFlow(), { deleteElements } = useSolidFlow(), _props = {
|
|
2344
|
+
get selectionKey() {
|
|
2345
|
+
return props.selectionKey ?? "Shift";
|
|
2346
|
+
},
|
|
2347
|
+
get multiSelectionKey() {
|
|
2348
|
+
return props.multiSelectionKey ?? (isMacOs() ? "Meta" : "Control");
|
|
2349
|
+
},
|
|
2350
|
+
get deleteKey() {
|
|
2351
|
+
return props.deleteKey ?? "Backspace";
|
|
2352
|
+
},
|
|
2353
|
+
get panActivationKey() {
|
|
2354
|
+
return props.panActivationKey ?? " ";
|
|
2355
|
+
},
|
|
2356
|
+
get zoomActivationKey() {
|
|
2357
|
+
return props.zoomActivationKey ?? (isMacOs() ? "Meta" : "Control");
|
|
2358
|
+
}
|
|
2359
|
+
}, resetKeysAndSelection = () => {
|
|
2360
|
+
actions.setSelectionRect(void 0), actions.setSelectionKeyPressed(!1), actions.setMultiselectionKeyPressed(!1), actions.setDeleteKeyPressed(!1), actions.setPanActivationKeyPressed(!1), actions.setZoomActivationKeyPressed(!1);
|
|
2361
|
+
}, handleDelete = async () => {
|
|
2362
|
+
let selectedNodes = store.nodes.filter((node) => node.selected), selectedEdges = store.edges.filter((edge) => edge.selected), { deletedNodes, deletedEdges } = await deleteElements({
|
|
2363
|
+
nodes: selectedNodes,
|
|
2364
|
+
edges: selectedEdges
|
|
2365
|
+
});
|
|
2366
|
+
(deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
|
|
2367
|
+
nodes: deletedNodes,
|
|
2368
|
+
edges: deletedEdges
|
|
2369
|
+
});
|
|
2370
|
+
};
|
|
2371
|
+
return isServer || createEventListenerMap(window, {
|
|
2372
|
+
keydown: (event) => {
|
|
2373
|
+
matchesKeyArray(event, _props.selectionKey) && actions.setSelectionKeyPressed(!0), matchesKeyArray(event, _props.multiSelectionKey) && actions.setMultiselectionKeyPressed(!0), matchesKeyArray(event, _props.deleteKey) && !isInputDOMNode(event) && (event.ctrlKey || event.metaKey || event.shiftKey || (actions.setDeleteKeyPressed(!0), handleDelete())), matchesKeyArray(event, _props.panActivationKey) && actions.setPanActivationKeyPressed(!0), matchesKeyArray(event, _props.zoomActivationKey) && actions.setZoomActivationKeyPressed(!0), flush();
|
|
2374
|
+
},
|
|
2375
|
+
keyup: (event) => {
|
|
2376
|
+
matchesKeyArray(event, _props.selectionKey) && actions.setSelectionKeyPressed(!1), matchesKeyArray(event, _props.multiSelectionKey) && actions.setMultiselectionKeyPressed(!1), matchesKeyArray(event, _props.deleteKey) && actions.setDeleteKeyPressed(!1), matchesKeyArray(event, _props.panActivationKey) && actions.setPanActivationKeyPressed(!1), matchesKeyArray(event, _props.zoomActivationKey) && actions.setZoomActivationKeyPressed(!1), flush();
|
|
2377
|
+
},
|
|
2378
|
+
blur: resetKeysAndSelection,
|
|
2379
|
+
contextmenu: resetKeysAndSelection
|
|
2380
|
+
}), null;
|
|
2381
|
+
}, SolidFlow = (props) => {
|
|
2382
|
+
let [domNodeRef, setDomNodeRef] = createSignal(), domNode, _props = merge({
|
|
2383
|
+
...getDefaultFlowStateProps(),
|
|
2384
|
+
colorMode: "light",
|
|
2385
|
+
deleteKeyCode: "Backspace",
|
|
2386
|
+
defaultViewport: {
|
|
2387
|
+
x: 0,
|
|
2388
|
+
y: 0,
|
|
2389
|
+
zoom: 1
|
|
2390
|
+
},
|
|
2391
|
+
multiSelectionKeyCode: isMacOs() ? "Meta" : "Control",
|
|
2392
|
+
nodeClickDistance: 0,
|
|
2393
|
+
panOnScroll: !1,
|
|
2394
|
+
panActivationKeyCode: "Space",
|
|
2395
|
+
preventScrolling: !0,
|
|
2396
|
+
panOnDrag: !0,
|
|
2397
|
+
panOnScrollSpeed: .5,
|
|
2398
|
+
panOnScrollMode: "free",
|
|
2399
|
+
paneClickDistance: 0,
|
|
2400
|
+
reconnectRadius: 10,
|
|
2401
|
+
selectionKeyCode: "Shift",
|
|
2402
|
+
selectionOnDrag: !1,
|
|
2403
|
+
translateExtent: infiniteExtent,
|
|
2404
|
+
zoomActivationKeyCode: isMacOs() ? "Meta" : "Control",
|
|
2405
|
+
zoomOnPinch: !0,
|
|
2406
|
+
zoomOnDoubleClick: !0,
|
|
2407
|
+
zoomOnScroll: !0
|
|
2408
|
+
}, props), htmlProps = omit(_props, "nodes", "edges", "nodeTypes", "edgeTypes", "width", "height", "fitView", "fitViewOptions", "nodeOrigin", "nodeDragThreshold", "paneClickDistance", "nodeClickDistance", "minZoom", "maxZoom", "zIndexMode", "initialViewport", "viewport", "translateExtent", "nodeExtent", "selectionKey", "panActivationKey", "deleteKey", "multiSelectionKey", "zoomActivationKey", "panOnDrag", "panOnScroll", "panOnScrollMode", "panOnScrollSpeed", "selectionOnDrag", "selectNodesOnDrag", "preventScrolling", "zoomOnScroll", "zoomOnDoubleClick", "zoomOnPinch", "onlyRenderVisibleElements", "autoPanOnConnect", "autoPanOnNodeDrag", "autoPanOnNodeFocus", "autoPanOnSelection", "autoPanSpeed", "connectionRadius", "connectionMode", "connectionLineType", "connectionLineComponent", "connectionLineStyle", "connectionLineContainerStyle", "connectionDragThreshold", "isValidConnection", "clickConnect", "reconnectRadius", "selectionMode", "elementsSelectable", "nodesDraggable", "nodesConnectable", "nodesFocusable", "edgesFocusable", "disableKeyboardA11y", "ariaLabelConfig", "ariaLiveMessage", "colorMode", "colorModeSSR", "class", "style", "snapGrid", "defaultMarkerColor", "defaultEdgeOptions", "elevateNodesOnSelect", "elevateEdgesOnSelect", "noDragClass", "noPanClass", "noWheelClass", "attributionPosition", "proOptions", "onInit", "onMoveStart", "onMove", "onMoveEnd", "onFlowError", "onNodeClick", "onNodeContextMenu", "onNodeDrag", "onNodeDragStart", "onNodeDragStop", "onNodePointerEnter", "onNodePointerMove", "onNodePointerLeave", "onEdgeClick", "onEdgeContextMenu", "onEdgePointerEnter", "onEdgePointerLeave", "onPaneClick", "onPaneContextMenu", "onSelectionChange", "onSelectionClick", "onSelectionContextMenu", "onSelectionDrag", "onSelectionDragStart", "onSelectionDragStop", "onSelectionStart", "onSelectionEnd", "onConnect", "onConnectStart", "onConnectEnd", "onReconnect", "onReconnectStart", "onReconnectEnd", "onClickConnectStart", "onClickConnectEnd", "onBeforeConnect", "onBeforeReconnect", "onDelete", "onBeforeDelete", "deleteKeyCode", "selectionKeyCode", "panActivationKeyCode", "multiSelectionKeyCode", "zoomActivationKeyCode", "children"), TypedSolidFlowContext = SolidFlowContext, solidFlow = useContext(TypedSolidFlowContext) ?? createSolidFlow(_props), { store, actions } = solidFlow;
|
|
2409
|
+
onSettled(() => (actions.applyInitialFitView(_props.fitView), actions.setConfig(_props), actions.setDomNode(domNode), () => {
|
|
2410
|
+
actions.reset();
|
|
2411
|
+
})), createEffect(() => domNodeRef(), (el) => {
|
|
2412
|
+
if (!el) return;
|
|
2413
|
+
let observer = new ResizeObserver(() => {
|
|
2414
|
+
actions.setWidth(el.clientWidth), actions.setHeight(el.clientHeight);
|
|
2415
|
+
});
|
|
2416
|
+
return observer.observe(el), () => observer.disconnect();
|
|
2417
|
+
}), createEffect(() => ({
|
|
2418
|
+
panZoom: store.panZoom,
|
|
2419
|
+
distance: _props.paneClickDistance
|
|
2420
|
+
}), ({ panZoom, distance }) => {
|
|
2421
|
+
panZoom?.setClickDistance(distance);
|
|
2422
|
+
});
|
|
2423
|
+
let selectedElements = createMemo(() => ({
|
|
2424
|
+
nodes: store.selectedNodes,
|
|
2425
|
+
edges: store.selectedEdges
|
|
2426
|
+
}), { equals: (a, b) => a.nodes.length === b.nodes.length && a.edges.length === b.edges.length && a.nodes.every((node, i) => node.id === b.nodes[i].id) && a.edges.every((edge, i) => edge.id === b.edges[i].id) });
|
|
2427
|
+
createEffect(() => selectedElements(), (params) => {
|
|
2428
|
+
untrack(() => _props.onSelectionChange)?.(params);
|
|
2429
|
+
});
|
|
2430
|
+
let rootStyle = () => ({
|
|
2431
|
+
width: toPxString(_props.width),
|
|
2432
|
+
height: toPxString(_props.height),
|
|
2433
|
+
..._props.style
|
|
2434
|
+
});
|
|
2435
|
+
return <div role="application" data-testid="solid-flow__wrapper" ref={(el) => {
|
|
2436
|
+
domNode = el, setDomNodeRef(el);
|
|
2437
|
+
}} class={[
|
|
2438
|
+
"solid-flow",
|
|
2439
|
+
"solid-flow__container",
|
|
2440
|
+
_props.class,
|
|
2441
|
+
store.colorMode
|
|
2442
|
+
]} style={rootStyle()} onScroll={(e) => {
|
|
2443
|
+
e.currentTarget.scrollTo({
|
|
2444
|
+
top: 0,
|
|
2445
|
+
left: 0,
|
|
2446
|
+
behavior: "auto"
|
|
2447
|
+
});
|
|
2448
|
+
}} {...htmlProps}>
|
|
2449
|
+
<TypedSolidFlowContext value={solidFlow}>
|
|
2450
|
+
<KeyHandler selectionKey={_props.selectionKey} deleteKey={_props.deleteKey} panActivationKey={_props.panActivationKey} multiSelectionKey={_props.multiSelectionKey} zoomActivationKey={_props.zoomActivationKey} />
|
|
2451
|
+
<Zoom panOnScrollMode={_props.panOnScrollMode} preventScrolling={_props.preventScrolling} zoomOnScroll={_props.zoomOnScroll} zoomOnDoubleClick={_props.zoomOnDoubleClick} zoomOnPinch={_props.zoomOnPinch} panOnScroll={_props.panOnScroll} panOnScrollSpeed={_props.panOnScrollSpeed} panOnDrag={_props.panOnDrag} paneClickDistance={_props.paneClickDistance} selectionOnDrag={_props.selectionOnDrag} onMoveStart={_props.onMoveStart} onMove={_props.onMove} onMoveEnd={_props.onMoveEnd} onViewportInitialized={_props.onInit} initialViewport={_props.viewport || _props.initialViewport}>
|
|
2452
|
+
<Pane onPaneClick={_props.onPaneClick} onPaneContextMenu={_props.onPaneContextMenu} onSelectionStart={_props.onSelectionStart} onSelectionEnd={_props.onSelectionEnd} panOnDrag={_props.panOnDrag} selectionOnDrag={_props.selectionOnDrag} paneClickDistance={_props.paneClickDistance} autoPanOnSelection={_props.autoPanOnSelection}>
|
|
2453
|
+
<Viewport>
|
|
2454
|
+
<div class="solid-flow__container solid-flow__viewport-back" />
|
|
2455
|
+
<EdgeRenderer reconnectRadius={_props.reconnectRadius} onEdgeClick={_props.onEdgeClick} onEdgeContextMenu={_props.onEdgeContextMenu} onEdgePointerEnter={_props.onEdgePointerEnter} onEdgePointerLeave={_props.onEdgePointerLeave} defaultEdgeOptions={_props.defaultEdgeOptions} />
|
|
2456
|
+
<div class="solid-flow__container solid-flow__edge-labels" />
|
|
2457
|
+
<ConnectionLine type={_props.connectionLineType} component={_props.connectionLineComponent} containerStyle={_props.connectionLineContainerStyle} style={_props.connectionLineStyle} />
|
|
2458
|
+
<NodeRenderer nodeClickDistance={_props.nodeClickDistance} onNodeClick={_props.onNodeClick} onNodeContextMenu={_props.onNodeContextMenu} onNodePointerEnter={_props.onNodePointerEnter} onNodePointerMove={_props.onNodePointerMove} onNodePointerLeave={_props.onNodePointerLeave} onNodeDrag={_props.onNodeDrag} onNodeDragStart={_props.onNodeDragStart} onNodeDragStop={_props.onNodeDragStop} />
|
|
2459
|
+
<NodeSelection onSelectionClick={_props.onSelectionClick} onSelectionContextMenu={_props.onSelectionContextMenu} onNodeDrag={_props.onNodeDrag} onNodeDragStart={_props.onNodeDragStart} onNodeDragStop={_props.onNodeDragStop} />
|
|
2460
|
+
</Viewport>
|
|
2461
|
+
<Selection isVisible={!!store.selectionRect && store.selectionRectMode === "user"} width={store.selectionRect?.width} height={store.selectionRect?.height} x={store.selectionRect?.x} y={store.selectionRect?.y} />
|
|
2462
|
+
</Pane>
|
|
2463
|
+
</Zoom>
|
|
2464
|
+
<Attribution proOptions={_props.proOptions} position={_props.attributionPosition} />
|
|
2465
|
+
<A11yDescriptions />
|
|
2466
|
+
{_props.children}
|
|
2467
|
+
</TypedSolidFlowContext>
|
|
2468
|
+
</div>;
|
|
2469
|
+
}, SolidFlowProvider = (props) => {
|
|
2470
|
+
let _props = merge(getDefaultFlowStateProps(), props), solidFlow = createSolidFlow(_props);
|
|
2471
|
+
onCleanup(() => {
|
|
2472
|
+
solidFlow.actions.reset();
|
|
2473
|
+
});
|
|
2474
|
+
let ContextProvider = SolidFlowContext;
|
|
2475
|
+
return <ContextProvider value={solidFlow}>{props.children}</ContextProvider>;
|
|
2476
|
+
};
|
|
2477
|
+
//#endregion
|
|
2478
|
+
//#region src/hooks/useColorMode.ts
|
|
2479
|
+
/**
|
|
2480
|
+
* Hook for receiving the current color mode class ('dark' or 'light').
|
|
2481
|
+
*
|
|
2482
|
+
* When the flow's `colorMode` prop is set to `"system"`, this resolves to the
|
|
2483
|
+
* user's current system preference.
|
|
2484
|
+
*
|
|
2485
|
+
* @public
|
|
2486
|
+
* @returns an accessor for the current color mode class
|
|
2487
|
+
*/
|
|
2488
|
+
function useColorMode() {
|
|
2489
|
+
let { flow } = useInternalSolidFlow();
|
|
2490
|
+
return () => flow.colorMode;
|
|
2491
|
+
}
|
|
2492
|
+
//#endregion
|
|
2493
|
+
//#region src/hooks/useConnection.ts
|
|
2494
|
+
/**
|
|
2495
|
+
* Hook for receiving the current connection.
|
|
2496
|
+
*
|
|
2497
|
+
* @public
|
|
2498
|
+
* @returns current connection as a readable store
|
|
2499
|
+
*/
|
|
2500
|
+
function useConnection() {
|
|
2501
|
+
let { flow } = useInternalSolidFlow();
|
|
2502
|
+
return () => flow.connection;
|
|
2503
|
+
}
|
|
2504
|
+
//#endregion
|
|
2505
|
+
//#region src/hooks/useGraph.ts
|
|
2506
|
+
/**
|
|
2507
|
+
* Hook for getting the current nodes from the store.
|
|
2508
|
+
*
|
|
2509
|
+
* @public
|
|
2510
|
+
* @returns store with an array of nodes
|
|
2511
|
+
*/
|
|
2512
|
+
function useNodes() {
|
|
2513
|
+
let { store } = useInternalSolidFlow();
|
|
2514
|
+
return () => store.nodes;
|
|
2515
|
+
}
|
|
2516
|
+
/**
|
|
2517
|
+
* Hook for getting the current edges from the store.
|
|
2518
|
+
*
|
|
2519
|
+
* @public
|
|
2520
|
+
* @returns store with an array of edges
|
|
2521
|
+
*/
|
|
2522
|
+
function useEdges() {
|
|
2523
|
+
let { store } = useInternalSolidFlow();
|
|
2524
|
+
return () => store.edges;
|
|
2525
|
+
}
|
|
2526
|
+
/**
|
|
2527
|
+
* Hook for getting the current viewport from the store.
|
|
2528
|
+
*
|
|
2529
|
+
* @public
|
|
2530
|
+
* @returns store with the viewport object
|
|
2531
|
+
*/
|
|
2532
|
+
function useViewport() {
|
|
2533
|
+
let { flow } = useInternalSolidFlow();
|
|
2534
|
+
return () => flow.viewport;
|
|
2535
|
+
}
|
|
2536
|
+
//#endregion
|
|
2537
|
+
//#region src/hooks/useHandleEdgeSelect.ts
|
|
2538
|
+
/** Returns a callback applying edge-selection semantics for the given edge id. */
|
|
2539
|
+
function useHandleEdgeSelect() {
|
|
2540
|
+
let { store, edgeLookup, actions } = useInternalSolidFlow();
|
|
2541
|
+
return (id) => {
|
|
2542
|
+
let edge = edgeLookup[id];
|
|
2543
|
+
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({
|
|
2544
|
+
nodes: [],
|
|
2545
|
+
edges: [edge]
|
|
2546
|
+
}) : actions.addSelectedEdges([id]));
|
|
2547
|
+
};
|
|
2548
|
+
}
|
|
2549
|
+
//#endregion
|
|
2550
|
+
//#region src/hooks/useInitialized.ts
|
|
2551
|
+
/**
|
|
2552
|
+
* Hook for seeing if all nodes have been measured.
|
|
2553
|
+
*
|
|
2554
|
+
* Returns `false` until every non-hidden node has been rendered and measured.
|
|
2555
|
+
* Useful for running layouting or fitView logic that depends on node dimensions.
|
|
2556
|
+
*
|
|
2557
|
+
* @public
|
|
2558
|
+
* @returns an accessor that indicates whether the nodes are initialized
|
|
2559
|
+
*/
|
|
2560
|
+
function useNodesInitialized() {
|
|
2561
|
+
let { flow } = useInternalSolidFlow();
|
|
2562
|
+
return () => flow.nodesInitialized;
|
|
2563
|
+
}
|
|
2564
|
+
/**
|
|
2565
|
+
* Hook for seeing if the viewport is initialized.
|
|
2566
|
+
*
|
|
2567
|
+
* Returns `true` once the pan/zoom instance has been created for the flow.
|
|
2568
|
+
*
|
|
2569
|
+
* @public
|
|
2570
|
+
* @returns an accessor that indicates whether the viewport is initialized
|
|
2571
|
+
*/
|
|
2572
|
+
function useViewportInitialized() {
|
|
2573
|
+
let { flow } = useInternalSolidFlow();
|
|
2574
|
+
return () => flow.viewportInitialized;
|
|
2575
|
+
}
|
|
2576
|
+
//#endregion
|
|
2577
|
+
//#region src/hooks/useInternalNode.ts
|
|
2578
|
+
/**
|
|
2579
|
+
* Hook to get an internal node by id.
|
|
2580
|
+
*
|
|
2581
|
+
* @public
|
|
2582
|
+
* @param id - the node id
|
|
2583
|
+
* @returns an accessor with an internal node or undefined
|
|
2584
|
+
*/
|
|
2585
|
+
function useInternalNode(id) {
|
|
2586
|
+
let { flow } = useInternalSolidFlow();
|
|
2587
|
+
return () => flow.internalNodes[id()];
|
|
2588
|
+
}
|
|
2589
|
+
//#endregion
|
|
2590
|
+
//#region src/hooks/useNodeConnections.ts
|
|
2591
|
+
/**
|
|
2592
|
+
* Hook to retrieve all edges connected to a node. Can be filtered by handle type and id.
|
|
2593
|
+
*
|
|
2594
|
+
* @public
|
|
2595
|
+
* @param param.id - node id - optional if called inside a custom node
|
|
2596
|
+
* @param param.handleType - filter by handle type 'source' or 'target'
|
|
2597
|
+
* @param param.handleId - filter by handle id (this is only needed if the node has multiple handles of the same type)
|
|
2598
|
+
* @todo @param param.onConnect - gets called when a connection is established
|
|
2599
|
+
* @todo @param param.onDisconnect - gets called when a connection is removed
|
|
2600
|
+
* @returns an array with connections
|
|
2601
|
+
*/
|
|
2602
|
+
const useNodeConnections = (params) => {
|
|
2603
|
+
let { flow } = useInternalSolidFlow(), ctxNodeId = () => {
|
|
2604
|
+
let id = useContext(NodeIdContext);
|
|
2605
|
+
return id ? id() : "";
|
|
2606
|
+
}, id = () => params().handleId, type = () => params().handleType, nodeId = () => params().id ?? ctxNodeId(), [connections, setConnections] = createSignal([]), prevConnections;
|
|
2607
|
+
return createEffect(() => {
|
|
2608
|
+
let rec = flow.connections[connectionKey(nodeId(), type(), id())], map = /* @__PURE__ */ new Map();
|
|
2609
|
+
for (let key of Object.keys(rec ?? {})) map.set(key, { ...rec[key] });
|
|
2610
|
+
return { connections: map };
|
|
2611
|
+
}, ({ connections: nextConnections }) => {
|
|
2612
|
+
areConnectionMapsEqual(nextConnections, prevConnections) || (prevConnections = nextConnections, setConnections(Array.from(nextConnections.values())));
|
|
2613
|
+
}), connections;
|
|
2614
|
+
};
|
|
2615
|
+
//#endregion
|
|
2616
|
+
//#region src/hooks/useNodesData.ts
|
|
2617
|
+
function useNodesData(nodeIds) {
|
|
2618
|
+
let { flow } = useInternalSolidFlow(), prevNodesData = [];
|
|
2619
|
+
return createMemo(() => {
|
|
2620
|
+
let nodesData = [], idValues = nodeIds();
|
|
2621
|
+
if (!idValues) return;
|
|
2622
|
+
let ids = Array.isArray(idValues) ? idValues : [idValues];
|
|
2623
|
+
for (let nodeId of ids) {
|
|
2624
|
+
let node = flow.internalNodes[nodeId]?.internals.userNode;
|
|
2625
|
+
node && nodesData.push({
|
|
2626
|
+
id: node.id,
|
|
2627
|
+
type: node.type,
|
|
2628
|
+
data: node.data
|
|
2629
|
+
});
|
|
2162
2630
|
}
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
}
|
|
2631
|
+
return shallowNodeData(nodesData, prevNodesData) || (prevNodesData = nodesData), Array.isArray(idValues) ? nodesData : nodesData[0];
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
//#endregion
|
|
2635
|
+
//#region src/hooks/useUpdateNodeInternals.ts
|
|
2636
|
+
/**
|
|
2637
|
+
* Hook for updating node internals. Sugar for `commands.updateNodeInternals`.
|
|
2638
|
+
*
|
|
2639
|
+
* @public
|
|
2640
|
+
* @returns function for updating node internals
|
|
2641
|
+
*/
|
|
2642
|
+
function useUpdateNodeInternals() {
|
|
2643
|
+
let { commands } = useInternalSolidFlow();
|
|
2644
|
+
return commands.updateNodeInternals;
|
|
2645
|
+
}
|
|
2646
|
+
//#endregion
|
|
2647
|
+
//#region src/plugins/background/DotPattern.tsx
|
|
2648
|
+
const DotPattern = (props) => {
|
|
2166
2649
|
let _props = propDefaults(props, { radius: 5 });
|
|
2167
2650
|
return <circle class={[
|
|
2168
2651
|
"solid-flow__background-pattern",
|
|
@@ -2275,19 +2758,6 @@ const Marker = (props) => {
|
|
|
2275
2758
|
{_props.children}
|
|
2276
2759
|
{_props.afterControls}
|
|
2277
2760
|
</Panel>;
|
|
2278
|
-
}, EdgeToolbar = (props) => {
|
|
2279
|
-
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");
|
|
2280
|
-
return <Show when={isActive()}>
|
|
2281
|
-
<EdgeLabel selectEdgeOnClick={props.selectEdgeOnClick} transparent>
|
|
2282
|
-
<div class={["solid-flow__edge-toolbar", props.class]} style={{
|
|
2283
|
-
position: "absolute",
|
|
2284
|
-
transform: transform(),
|
|
2285
|
-
"transform-origin": "0 0"
|
|
2286
|
-
}} data-id={edgeId()} {...rest}>
|
|
2287
|
-
{props.children}
|
|
2288
|
-
</div>
|
|
2289
|
-
</EdgeLabel>
|
|
2290
|
-
</Show>;
|
|
2291
2761
|
}, MiniMapNode = (props) => {
|
|
2292
2762
|
let _props = propDefaults(props, {
|
|
2293
2763
|
borderRadius: 5,
|
|
@@ -2480,209 +2950,20 @@ const Marker = (props) => {
|
|
|
2480
2950
|
{(position) => <ResizeControl position={position} class={props.handleClass} style={props.handleStyle} {...rest} />}
|
|
2481
2951
|
</For>
|
|
2482
2952
|
</Show>;
|
|
2483
|
-
}
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
return () => flow.colorMode;
|
|
2498
|
-
}
|
|
2499
|
-
//#endregion
|
|
2500
|
-
//#region src/hooks/useConnection.tsx
|
|
2501
|
-
/**
|
|
2502
|
-
* Hook for receiving the current connection.
|
|
2503
|
-
*
|
|
2504
|
-
* @public
|
|
2505
|
-
* @returns current connection as a readable store
|
|
2506
|
-
*/
|
|
2507
|
-
function useConnection() {
|
|
2508
|
-
let { flow } = useInternalSolidFlow();
|
|
2509
|
-
return () => flow.connection;
|
|
2510
|
-
}
|
|
2511
|
-
//#endregion
|
|
2512
|
-
//#region src/hooks/useGraph.ts
|
|
2513
|
-
/**
|
|
2514
|
-
* Hook for getting the current nodes from the store.
|
|
2515
|
-
*
|
|
2516
|
-
* @public
|
|
2517
|
-
* @returns store with an array of nodes
|
|
2518
|
-
*/
|
|
2519
|
-
function useNodes() {
|
|
2520
|
-
let { store } = useInternalSolidFlow();
|
|
2521
|
-
return () => store.nodes;
|
|
2522
|
-
}
|
|
2523
|
-
/**
|
|
2524
|
-
* Hook for getting the current edges from the store.
|
|
2525
|
-
*
|
|
2526
|
-
* @public
|
|
2527
|
-
* @returns store with an array of edges
|
|
2528
|
-
*/
|
|
2529
|
-
function useEdges() {
|
|
2530
|
-
let { store } = useInternalSolidFlow();
|
|
2531
|
-
return () => store.edges;
|
|
2532
|
-
}
|
|
2533
|
-
/**
|
|
2534
|
-
* Hook for getting the current viewport from the store.
|
|
2535
|
-
*
|
|
2536
|
-
* @public
|
|
2537
|
-
* @returns store with the viewport object
|
|
2538
|
-
*/
|
|
2539
|
-
function useViewport() {
|
|
2540
|
-
let { flow } = useInternalSolidFlow();
|
|
2541
|
-
return () => flow.viewport;
|
|
2542
|
-
}
|
|
2543
|
-
//#endregion
|
|
2544
|
-
//#region src/hooks/useHandleEdgeSelect.tsx
|
|
2545
|
-
function useHandleEdgeSelect() {
|
|
2546
|
-
let { store, edgeLookup, actions } = useInternalSolidFlow();
|
|
2547
|
-
return (id) => {
|
|
2548
|
-
let edge = edgeLookup[id];
|
|
2549
|
-
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({
|
|
2550
|
-
nodes: [],
|
|
2551
|
-
edges: [edge]
|
|
2552
|
-
}) : actions.addSelectedEdges([id]));
|
|
2553
|
-
};
|
|
2554
|
-
}
|
|
2555
|
-
//#endregion
|
|
2556
|
-
//#region src/hooks/useInitialized.ts
|
|
2557
|
-
/**
|
|
2558
|
-
* Hook for seeing if all nodes have been measured.
|
|
2559
|
-
*
|
|
2560
|
-
* Returns `false` until every non-hidden node has been rendered and measured.
|
|
2561
|
-
* Useful for running layouting or fitView logic that depends on node dimensions.
|
|
2562
|
-
*
|
|
2563
|
-
* @public
|
|
2564
|
-
* @returns an accessor that indicates whether the nodes are initialized
|
|
2565
|
-
*/
|
|
2566
|
-
function useNodesInitialized() {
|
|
2567
|
-
let { flow } = useInternalSolidFlow();
|
|
2568
|
-
return () => flow.nodesInitialized;
|
|
2569
|
-
}
|
|
2570
|
-
/**
|
|
2571
|
-
* Hook for seeing if the viewport is initialized.
|
|
2572
|
-
*
|
|
2573
|
-
* Returns `true` once the pan/zoom instance has been created for the flow.
|
|
2574
|
-
*
|
|
2575
|
-
* @public
|
|
2576
|
-
* @returns an accessor that indicates whether the viewport is initialized
|
|
2577
|
-
*/
|
|
2578
|
-
function useViewportInitialized() {
|
|
2579
|
-
let { flow } = useInternalSolidFlow();
|
|
2580
|
-
return () => flow.viewportInitialized;
|
|
2581
|
-
}
|
|
2582
|
-
//#endregion
|
|
2583
|
-
//#region src/hooks/useInternalNode.tsx
|
|
2584
|
-
/**
|
|
2585
|
-
* Hook to get an internal node by id.
|
|
2586
|
-
*
|
|
2587
|
-
* @public
|
|
2588
|
-
* @param id - the node id
|
|
2589
|
-
* @returns an accessor with an internal node or undefined
|
|
2590
|
-
*/
|
|
2591
|
-
function useInternalNode(id) {
|
|
2592
|
-
let { flow } = useInternalSolidFlow();
|
|
2593
|
-
return () => flow.internalNodes[id()];
|
|
2594
|
-
}
|
|
2595
|
-
//#endregion
|
|
2596
|
-
//#region src/hooks/useNodeConnections.ts
|
|
2597
|
-
/**
|
|
2598
|
-
* Hook to retrieve all edges connected to a node. Can be filtered by handle type and id.
|
|
2599
|
-
*
|
|
2600
|
-
* @public
|
|
2601
|
-
* @param param.id - node id - optional if called inside a custom node
|
|
2602
|
-
* @param param.handleType - filter by handle type 'source' or 'target'
|
|
2603
|
-
* @param param.handleId - filter by handle id (this is only needed if the node has multiple handles of the same type)
|
|
2604
|
-
* @todo @param param.onConnect - gets called when a connection is established
|
|
2605
|
-
* @todo @param param.onDisconnect - gets called when a connection is removed
|
|
2606
|
-
* @returns an array with connections
|
|
2607
|
-
*/
|
|
2608
|
-
const useNodeConnections = (params) => {
|
|
2609
|
-
let { flow } = useInternalSolidFlow(), ctxNodeId = () => {
|
|
2610
|
-
let id = useContext(NodeIdContext);
|
|
2611
|
-
return id ? id() : "";
|
|
2612
|
-
}, id = () => params().handleId, type = () => params().handleType, nodeId = () => params().id ?? ctxNodeId(), [connections, setConnections] = createSignal([]), prevConnections;
|
|
2613
|
-
return createEffect(() => {
|
|
2614
|
-
let rec = flow.connections[connectionKey(nodeId(), type(), id())], map = /* @__PURE__ */ new Map();
|
|
2615
|
-
for (let key of Object.keys(rec ?? {})) map.set(key, { ...rec[key] });
|
|
2616
|
-
return { connections: map };
|
|
2617
|
-
}, ({ connections: nextConnections }) => {
|
|
2618
|
-
areConnectionMapsEqual(nextConnections, prevConnections) || (prevConnections = nextConnections, setConnections(Array.from(nextConnections.values())));
|
|
2619
|
-
}), connections;
|
|
2620
|
-
};
|
|
2621
|
-
//#endregion
|
|
2622
|
-
//#region src/hooks/useNodesData.ts
|
|
2623
|
-
function useNodesData(nodeIds) {
|
|
2624
|
-
let { flow } = useInternalSolidFlow(), prevNodesData = [];
|
|
2625
|
-
return createMemo(() => {
|
|
2626
|
-
let nodesData = [], idValues = nodeIds();
|
|
2627
|
-
if (!idValues) return;
|
|
2628
|
-
let ids = Array.isArray(idValues) ? idValues : [idValues];
|
|
2629
|
-
for (let nodeId of ids) {
|
|
2630
|
-
let node = flow.internalNodes[nodeId]?.internals.userNode;
|
|
2631
|
-
node && nodesData.push({
|
|
2632
|
-
id: node.id,
|
|
2633
|
-
type: node.type,
|
|
2634
|
-
data: node.data
|
|
2635
|
-
});
|
|
2636
|
-
}
|
|
2637
|
-
return shallowNodeData(nodesData, prevNodesData) || (prevNodesData = nodesData), Array.isArray(idValues) ? nodesData : nodesData[0];
|
|
2638
|
-
});
|
|
2639
|
-
}
|
|
2640
|
-
//#endregion
|
|
2641
|
-
//#region src/hooks/useSolidFlow.tsx
|
|
2642
|
-
/**
|
|
2643
|
-
* Hook for accessing the flow instance: `{ flow, commands }` plus the
|
|
2644
|
-
* commands spread at the top level for upstream familiarity.
|
|
2645
|
-
*
|
|
2646
|
-
* `flow` and `commands` are stable identities, so destructuring them is safe:
|
|
2647
|
-
* `const { flow, commands } = useSolidFlow()`.
|
|
2648
|
-
*
|
|
2649
|
-
* @public
|
|
2650
|
-
* @returns the flow's read struct, write surface, and deprecated aliases
|
|
2651
|
-
*/
|
|
2652
|
-
function useSolidFlow() {
|
|
2653
|
-
let { flow, commands, store, edgeLookup } = useInternalSolidFlow(), getInternalNode = (id) => flow.internalNodes[id];
|
|
2654
|
-
return {
|
|
2655
|
-
...commands,
|
|
2656
|
-
flow,
|
|
2657
|
-
commands,
|
|
2658
|
-
getInternalNode,
|
|
2659
|
-
getNode: (id) => getInternalNode(id)?.internals.userNode,
|
|
2660
|
-
getNodes: (ids) => ids ? ids.flatMap((id) => {
|
|
2661
|
-
let userNode = flow.internalNodes[id]?.internals.userNode;
|
|
2662
|
-
return userNode ? [userNode] : [];
|
|
2663
|
-
}) : [...flow.nodes],
|
|
2664
|
-
getEdge: (id) => edgeLookup[id],
|
|
2665
|
-
getEdges: (ids) => ids ? ids.flatMap((id) => edgeLookup[id] ? [edgeLookup[id]] : []) : [...flow.edges],
|
|
2666
|
-
getViewport: () => snapshot(store.viewport),
|
|
2667
|
-
getZoom: () => flow.viewport.zoom,
|
|
2668
|
-
getHandleConnections: ({ type, id, nodeId }) => Object.values(flow.connections[connectionKey(nodeId, type, id ?? null)] ?? {})
|
|
2669
|
-
};
|
|
2670
|
-
}
|
|
2671
|
-
//#endregion
|
|
2672
|
-
//#region src/hooks/useUpdateNodeInternals.ts
|
|
2673
|
-
/**
|
|
2674
|
-
* Hook for updating node internals. Sugar for `commands.updateNodeInternals`.
|
|
2675
|
-
*
|
|
2676
|
-
* @public
|
|
2677
|
-
* @returns function for updating node internals
|
|
2678
|
-
*/
|
|
2679
|
-
function useUpdateNodeInternals() {
|
|
2680
|
-
let { commands } = useInternalSolidFlow();
|
|
2681
|
-
return commands.updateNodeInternals;
|
|
2682
|
-
}
|
|
2683
|
-
//#endregion
|
|
2684
|
-
//#region src/components/graph/plugins/NodeToolbar.tsx
|
|
2685
|
-
const NodeToolbar = (props) => {
|
|
2953
|
+
}, EdgeToolbar = (props) => {
|
|
2954
|
+
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");
|
|
2955
|
+
return <Show when={isActive()}>
|
|
2956
|
+
<EdgeLabel selectEdgeOnClick={props.selectEdgeOnClick} transparent>
|
|
2957
|
+
<div class={["solid-flow__edge-toolbar", props.class]} style={{
|
|
2958
|
+
position: "absolute",
|
|
2959
|
+
transform: transform(),
|
|
2960
|
+
"transform-origin": "0 0"
|
|
2961
|
+
}} data-id={edgeId()} {...rest}>
|
|
2962
|
+
{props.children}
|
|
2963
|
+
</div>
|
|
2964
|
+
</EdgeLabel>
|
|
2965
|
+
</Show>;
|
|
2966
|
+
}, NodeToolbar = (props) => {
|
|
2686
2967
|
let { store } = useInternalSolidFlow(), { getNodes, getNodesBounds, getInternalNode } = useSolidFlow(), _props = propDefaults(props, {
|
|
2687
2968
|
offset: 10,
|
|
2688
2969
|
position: "top",
|
|
@@ -2716,253 +2997,6 @@ const NodeToolbar = (props) => {
|
|
|
2716
2997
|
</div>
|
|
2717
2998
|
</Portal>
|
|
2718
2999
|
</Show>;
|
|
2719
|
-
},
|
|
2720
|
-
let _props = propDefaults(props, { isVisible: !0 }), styles = () => ({
|
|
2721
|
-
..._props.width != null && { width: typeof _props.width == "string" ? _props.width : toPxString(_props.width) },
|
|
2722
|
-
..._props.height != null && { height: typeof _props.height == "string" ? _props.height : toPxString(_props.height) },
|
|
2723
|
-
..._props.x != null && _props.y != null && { transform: `translate(${props.x}px, ${props.y}px)` }
|
|
2724
|
-
});
|
|
2725
|
-
return <Show when={_props.isVisible}>
|
|
2726
|
-
<div class="solid-flow__selection" style={styles()} />
|
|
2727
|
-
</Show>;
|
|
2728
|
-
}, NodeSelection = (props) => {
|
|
2729
|
-
let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref, setRef] = createSignal(), bounds = () => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null;
|
|
2730
|
-
createEffect(() => ({
|
|
2731
|
-
el: ref(),
|
|
2732
|
-
focusable: !store.disableKeyboardA11y
|
|
2733
|
-
}), ({ el, focusable }) => {
|
|
2734
|
-
focusable && el?.focus({ preventScroll: !0 });
|
|
2735
|
-
});
|
|
2736
|
-
let onContextMenu = (event) => {
|
|
2737
|
-
let selectedNodes = store.nodes.filter((n) => n.selected);
|
|
2738
|
-
props.onSelectionContextMenu?.({
|
|
2739
|
-
nodes: selectedNodes,
|
|
2740
|
-
event
|
|
2741
|
-
});
|
|
2742
|
-
}, onClick = (event) => {
|
|
2743
|
-
let selectedNodes = store.nodes.filter((n) => n.selected);
|
|
2744
|
-
props.onSelectionClick?.({
|
|
2745
|
-
nodes: selectedNodes,
|
|
2746
|
-
event
|
|
2747
|
-
});
|
|
2748
|
-
};
|
|
2749
|
-
createDraggable(ref, () => ({
|
|
2750
|
-
disabled: !1,
|
|
2751
|
-
onDrag: (event, _, __, nodes) => {
|
|
2752
|
-
props.onNodeDrag?.({
|
|
2753
|
-
event,
|
|
2754
|
-
targetNode: null,
|
|
2755
|
-
nodes
|
|
2756
|
-
});
|
|
2757
|
-
},
|
|
2758
|
-
onDragStart: (event, _, __, nodes) => {
|
|
2759
|
-
props.onNodeDragStart?.({
|
|
2760
|
-
event,
|
|
2761
|
-
targetNode: null,
|
|
2762
|
-
nodes
|
|
2763
|
-
});
|
|
2764
|
-
},
|
|
2765
|
-
onDragStop: (event, _, __, nodes) => {
|
|
2766
|
-
props.onNodeDragStop?.({
|
|
2767
|
-
event,
|
|
2768
|
-
targetNode: null,
|
|
2769
|
-
nodes
|
|
2770
|
-
});
|
|
2771
|
-
}
|
|
2772
|
-
}));
|
|
2773
|
-
let onKeyDown = (event) => {
|
|
2774
|
-
let diff = ARROW_KEY_DIFFS[event.key];
|
|
2775
|
-
diff && (event.preventDefault(), actions.moveSelectedNodes(diff, event.shiftKey ? 4 : 1));
|
|
2776
|
-
};
|
|
2777
|
-
return <Show when={store.selectionRectMode === "nodes" && bounds() && isNumeric(bounds()?.x) && isNumeric(bounds()?.y)}>
|
|
2778
|
-
<div ref={setRef} class={["solid-flow__selection-wrapper", store.noPanClass]} style={{
|
|
2779
|
-
width: toPxString(bounds()?.width),
|
|
2780
|
-
height: toPxString(bounds()?.height),
|
|
2781
|
-
transform: `translate(${bounds()?.x}px, ${bounds()?.y}px)`
|
|
2782
|
-
}} onClick={onClick} onContextMenu={onContextMenu} role={store.disableKeyboardA11y ? void 0 : "button"} tabindex={store.disableKeyboardA11y ? void 0 : -1} onKeyDown={store.disableKeyboardA11y ? void 0 : onKeyDown}>
|
|
2783
|
-
<Selection width="100%" height="100%" x={0} y={0} />
|
|
2784
|
-
</div>
|
|
2785
|
-
</Show>;
|
|
2786
|
-
}, Attribution = (props) => <Show when={!props.proOptions?.hideAttribution}>
|
|
2787
|
-
<Panel position={props.position ?? "bottom-right"} class="solid-flow__attribution" data-message="Feel free to remove the attribution or check out how you could support us: https://solidflow.dev/support-us">
|
|
2788
|
-
<a href="https://solidflow.dev" target="_blank" rel="noopener noreferrer" aria-label="Solid Flow attribution">
|
|
2789
|
-
Solid Flow
|
|
2790
|
-
</a>
|
|
2791
|
-
</Panel>
|
|
2792
|
-
</Show>;
|
|
2793
|
-
//#endregion
|
|
2794
|
-
//#region src/components/utility/KeyHandler.tsx
|
|
2795
|
-
function isKeyObject(key) {
|
|
2796
|
-
return typeof key == "object" && !!key;
|
|
2797
|
-
}
|
|
2798
|
-
function getModifier(key) {
|
|
2799
|
-
return isKeyObject(key) && key.modifier || [];
|
|
2800
|
-
}
|
|
2801
|
-
function getKeyString(key) {
|
|
2802
|
-
return key == null ? "" : isKeyObject(key) ? key.key : key;
|
|
2803
|
-
}
|
|
2804
|
-
function matchesKey(event, keyDef) {
|
|
2805
|
-
if (!keyDef) return !1;
|
|
2806
|
-
let keyString = getKeyString(keyDef);
|
|
2807
|
-
if (!keyString) return !1;
|
|
2808
|
-
let modifiers = getModifier(keyDef);
|
|
2809
|
-
if (Array.isArray(modifiers)) {
|
|
2810
|
-
let modifierMatch = modifiers.flatMap((mod) => mod).every((mod) => {
|
|
2811
|
-
switch (mod.toLowerCase()) {
|
|
2812
|
-
case "meta": return event.metaKey;
|
|
2813
|
-
case "ctrl": return event.ctrlKey;
|
|
2814
|
-
case "alt": return event.altKey;
|
|
2815
|
-
case "shift": return event.shiftKey;
|
|
2816
|
-
default: return !1;
|
|
2817
|
-
}
|
|
2818
|
-
});
|
|
2819
|
-
return event.key === keyString && modifierMatch;
|
|
2820
|
-
}
|
|
2821
|
-
return event.key === keyString;
|
|
2822
|
-
}
|
|
2823
|
-
function matchesKeyArray(event, keyDefs) {
|
|
2824
|
-
return keyDefs ? (Array.isArray(keyDefs) ? keyDefs : [keyDefs]).some((keyDef) => matchesKey(event, keyDef)) : !1;
|
|
2825
|
-
}
|
|
2826
|
-
const KeyHandler = (props) => {
|
|
2827
|
-
let { store, actions } = useInternalSolidFlow(), { deleteElements } = useSolidFlow(), _props = {
|
|
2828
|
-
get selectionKey() {
|
|
2829
|
-
return props.selectionKey ?? "Shift";
|
|
2830
|
-
},
|
|
2831
|
-
get multiSelectionKey() {
|
|
2832
|
-
return props.multiSelectionKey ?? (isMacOs() ? "Meta" : "Control");
|
|
2833
|
-
},
|
|
2834
|
-
get deleteKey() {
|
|
2835
|
-
return props.deleteKey ?? "Backspace";
|
|
2836
|
-
},
|
|
2837
|
-
get panActivationKey() {
|
|
2838
|
-
return props.panActivationKey ?? " ";
|
|
2839
|
-
},
|
|
2840
|
-
get zoomActivationKey() {
|
|
2841
|
-
return props.zoomActivationKey ?? (isMacOs() ? "Meta" : "Control");
|
|
2842
|
-
}
|
|
2843
|
-
}, resetKeysAndSelection = () => {
|
|
2844
|
-
actions.setSelectionRect(void 0), actions.setSelectionKeyPressed(!1), actions.setMultiselectionKeyPressed(!1), actions.setDeleteKeyPressed(!1), actions.setPanActivationKeyPressed(!1), actions.setZoomActivationKeyPressed(!1);
|
|
2845
|
-
}, handleDelete = async () => {
|
|
2846
|
-
let selectedNodes = store.nodes.filter((node) => node.selected), selectedEdges = store.edges.filter((edge) => edge.selected), { deletedNodes, deletedEdges } = await deleteElements({
|
|
2847
|
-
nodes: selectedNodes,
|
|
2848
|
-
edges: selectedEdges
|
|
2849
|
-
});
|
|
2850
|
-
(deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
|
|
2851
|
-
nodes: deletedNodes,
|
|
2852
|
-
edges: deletedEdges
|
|
2853
|
-
});
|
|
2854
|
-
};
|
|
2855
|
-
return isServer || createEventListenerMap(window, {
|
|
2856
|
-
keydown: (event) => {
|
|
2857
|
-
matchesKeyArray(event, _props.selectionKey) && actions.setSelectionKeyPressed(!0), matchesKeyArray(event, _props.multiSelectionKey) && actions.setMultiselectionKeyPressed(!0), matchesKeyArray(event, _props.deleteKey) && !isInputDOMNode(event) && (event.ctrlKey || event.metaKey || event.shiftKey || (actions.setDeleteKeyPressed(!0), handleDelete())), matchesKeyArray(event, _props.panActivationKey) && actions.setPanActivationKeyPressed(!0), matchesKeyArray(event, _props.zoomActivationKey) && actions.setZoomActivationKeyPressed(!0), flush();
|
|
2858
|
-
},
|
|
2859
|
-
keyup: (event) => {
|
|
2860
|
-
matchesKeyArray(event, _props.selectionKey) && actions.setSelectionKeyPressed(!1), matchesKeyArray(event, _props.multiSelectionKey) && actions.setMultiselectionKeyPressed(!1), matchesKeyArray(event, _props.deleteKey) && actions.setDeleteKeyPressed(!1), matchesKeyArray(event, _props.panActivationKey) && actions.setPanActivationKeyPressed(!1), matchesKeyArray(event, _props.zoomActivationKey) && actions.setZoomActivationKeyPressed(!1), flush();
|
|
2861
|
-
},
|
|
2862
|
-
blur: resetKeysAndSelection,
|
|
2863
|
-
contextmenu: resetKeysAndSelection
|
|
2864
|
-
}), null;
|
|
2865
|
-
}, SolidFlow = (props) => {
|
|
2866
|
-
let [domNodeRef, setDomNodeRef] = createSignal(), domNode, _props = merge({
|
|
2867
|
-
...getDefaultFlowStateProps(),
|
|
2868
|
-
colorMode: "light",
|
|
2869
|
-
deleteKeyCode: "Backspace",
|
|
2870
|
-
defaultViewport: {
|
|
2871
|
-
x: 0,
|
|
2872
|
-
y: 0,
|
|
2873
|
-
zoom: 1
|
|
2874
|
-
},
|
|
2875
|
-
multiSelectionKeyCode: isMacOs() ? "Meta" : "Control",
|
|
2876
|
-
nodeClickDistance: 0,
|
|
2877
|
-
panOnScroll: !1,
|
|
2878
|
-
panActivationKeyCode: "Space",
|
|
2879
|
-
preventScrolling: !0,
|
|
2880
|
-
panOnDrag: !0,
|
|
2881
|
-
panOnScrollSpeed: .5,
|
|
2882
|
-
panOnScrollMode: "free",
|
|
2883
|
-
paneClickDistance: 0,
|
|
2884
|
-
reconnectRadius: 10,
|
|
2885
|
-
selectionKeyCode: "Shift",
|
|
2886
|
-
selectionOnDrag: !1,
|
|
2887
|
-
translateExtent: infiniteExtent,
|
|
2888
|
-
zoomActivationKeyCode: isMacOs() ? "Meta" : "Control",
|
|
2889
|
-
zoomOnPinch: !0,
|
|
2890
|
-
zoomOnDoubleClick: !0,
|
|
2891
|
-
zoomOnScroll: !0
|
|
2892
|
-
}, props), htmlProps = omit(_props, "nodes", "edges", "nodeTypes", "edgeTypes", "width", "height", "fitView", "fitViewOptions", "nodeOrigin", "nodeDragThreshold", "paneClickDistance", "nodeClickDistance", "minZoom", "maxZoom", "zIndexMode", "initialViewport", "viewport", "translateExtent", "nodeExtent", "selectionKey", "panActivationKey", "deleteKey", "multiSelectionKey", "zoomActivationKey", "panOnDrag", "panOnScroll", "panOnScrollMode", "panOnScrollSpeed", "selectionOnDrag", "selectNodesOnDrag", "preventScrolling", "zoomOnScroll", "zoomOnDoubleClick", "zoomOnPinch", "onlyRenderVisibleElements", "autoPanOnConnect", "autoPanOnNodeDrag", "autoPanOnNodeFocus", "autoPanOnSelection", "autoPanSpeed", "connectionRadius", "connectionMode", "connectionLineType", "connectionLineComponent", "connectionLineStyle", "connectionLineContainerStyle", "connectionDragThreshold", "isValidConnection", "clickConnect", "reconnectRadius", "selectionMode", "elementsSelectable", "nodesDraggable", "nodesConnectable", "nodesFocusable", "edgesFocusable", "disableKeyboardA11y", "ariaLabelConfig", "ariaLiveMessage", "colorMode", "colorModeSSR", "class", "style", "snapGrid", "defaultMarkerColor", "defaultEdgeOptions", "elevateNodesOnSelect", "elevateEdgesOnSelect", "noDragClass", "noPanClass", "noWheelClass", "attributionPosition", "proOptions", "onInit", "onMoveStart", "onMove", "onMoveEnd", "onFlowError", "onNodeClick", "onNodeContextMenu", "onNodeDrag", "onNodeDragStart", "onNodeDragStop", "onNodePointerEnter", "onNodePointerMove", "onNodePointerLeave", "onEdgeClick", "onEdgeContextMenu", "onEdgePointerEnter", "onEdgePointerLeave", "onPaneClick", "onPaneContextMenu", "onSelectionChange", "onSelectionClick", "onSelectionContextMenu", "onSelectionDrag", "onSelectionDragStart", "onSelectionDragStop", "onSelectionStart", "onSelectionEnd", "onConnect", "onConnectStart", "onConnectEnd", "onReconnect", "onReconnectStart", "onReconnectEnd", "onClickConnectStart", "onClickConnectEnd", "onBeforeConnect", "onBeforeReconnect", "onDelete", "onBeforeDelete", "deleteKeyCode", "selectionKeyCode", "panActivationKeyCode", "multiSelectionKeyCode", "zoomActivationKeyCode", "children"), TypedSolidFlowContext = SolidFlowContext, solidFlow = useContext(TypedSolidFlowContext) ?? createSolidFlow(_props), { store, actions } = solidFlow;
|
|
2893
|
-
onSettled(() => (actions.applyInitialFitView(_props.fitView), actions.setConfig(_props), actions.setDomNode(domNode), () => {
|
|
2894
|
-
actions.reset();
|
|
2895
|
-
})), createEffect(() => domNodeRef(), (el) => {
|
|
2896
|
-
if (!el) return;
|
|
2897
|
-
let observer = new ResizeObserver(() => {
|
|
2898
|
-
actions.setWidth(el.clientWidth), actions.setHeight(el.clientHeight);
|
|
2899
|
-
});
|
|
2900
|
-
return observer.observe(el), () => observer.disconnect();
|
|
2901
|
-
}), createEffect(() => ({
|
|
2902
|
-
panZoom: store.panZoom,
|
|
2903
|
-
distance: _props.paneClickDistance
|
|
2904
|
-
}), ({ panZoom, distance }) => {
|
|
2905
|
-
panZoom?.setClickDistance(distance);
|
|
2906
|
-
});
|
|
2907
|
-
let selectedElements = createMemo(() => ({
|
|
2908
|
-
nodes: store.selectedNodes,
|
|
2909
|
-
edges: store.selectedEdges
|
|
2910
|
-
}), { equals: (a, b) => a.nodes.length === b.nodes.length && a.edges.length === b.edges.length && a.nodes.every((node, i) => node.id === b.nodes[i].id) && a.edges.every((edge, i) => edge.id === b.edges[i].id) });
|
|
2911
|
-
createEffect(() => selectedElements(), (params) => {
|
|
2912
|
-
untrack(() => _props.onSelectionChange)?.(params);
|
|
2913
|
-
});
|
|
2914
|
-
let rootStyle = () => ({
|
|
2915
|
-
width: toPxString(_props.width),
|
|
2916
|
-
height: toPxString(_props.height),
|
|
2917
|
-
..._props.style
|
|
2918
|
-
});
|
|
2919
|
-
return <div role="application" data-testid="solid-flow__wrapper" ref={(el) => {
|
|
2920
|
-
domNode = el, setDomNodeRef(el);
|
|
2921
|
-
}} class={[
|
|
2922
|
-
"solid-flow",
|
|
2923
|
-
"solid-flow__container",
|
|
2924
|
-
_props.class,
|
|
2925
|
-
store.colorMode
|
|
2926
|
-
]} style={rootStyle()} onScroll={(e) => {
|
|
2927
|
-
e.currentTarget.scrollTo({
|
|
2928
|
-
top: 0,
|
|
2929
|
-
left: 0,
|
|
2930
|
-
behavior: "auto"
|
|
2931
|
-
});
|
|
2932
|
-
}} {...htmlProps}>
|
|
2933
|
-
<TypedSolidFlowContext value={solidFlow}>
|
|
2934
|
-
<KeyHandler selectionKey={_props.selectionKey} deleteKey={_props.deleteKey} panActivationKey={_props.panActivationKey} multiSelectionKey={_props.multiSelectionKey} zoomActivationKey={_props.zoomActivationKey} />
|
|
2935
|
-
<Zoom panOnScrollMode={_props.panOnScrollMode} preventScrolling={_props.preventScrolling} zoomOnScroll={_props.zoomOnScroll} zoomOnDoubleClick={_props.zoomOnDoubleClick} zoomOnPinch={_props.zoomOnPinch} panOnScroll={_props.panOnScroll} panOnScrollSpeed={_props.panOnScrollSpeed} panOnDrag={_props.panOnDrag} paneClickDistance={_props.paneClickDistance} selectionOnDrag={_props.selectionOnDrag} onMoveStart={_props.onMoveStart} onMove={_props.onMove} onMoveEnd={_props.onMoveEnd} onViewportInitialized={_props.onInit} initialViewport={_props.viewport || _props.initialViewport}>
|
|
2936
|
-
<Pane onPaneClick={_props.onPaneClick} onPaneContextMenu={_props.onPaneContextMenu} onSelectionStart={_props.onSelectionStart} onSelectionEnd={_props.onSelectionEnd} panOnDrag={_props.panOnDrag} selectionOnDrag={_props.selectionOnDrag} paneClickDistance={_props.paneClickDistance} autoPanOnSelection={_props.autoPanOnSelection}>
|
|
2937
|
-
<Viewport>
|
|
2938
|
-
<div class="solid-flow__container solid-flow__viewport-back" />
|
|
2939
|
-
<EdgeRenderer reconnectRadius={_props.reconnectRadius} onEdgeClick={_props.onEdgeClick} onEdgeContextMenu={_props.onEdgeContextMenu} onEdgePointerEnter={_props.onEdgePointerEnter} onEdgePointerLeave={_props.onEdgePointerLeave} defaultEdgeOptions={_props.defaultEdgeOptions} />
|
|
2940
|
-
<div class="solid-flow__container solid-flow__edge-labels" />
|
|
2941
|
-
<ConnectionLine type={_props.connectionLineType} component={_props.connectionLineComponent} containerStyle={_props.connectionLineContainerStyle} style={_props.connectionLineStyle} />
|
|
2942
|
-
<NodeRenderer nodeClickDistance={_props.nodeClickDistance} onNodeClick={_props.onNodeClick} onNodeContextMenu={_props.onNodeContextMenu} onNodePointerEnter={_props.onNodePointerEnter} onNodePointerMove={_props.onNodePointerMove} onNodePointerLeave={_props.onNodePointerLeave} onNodeDrag={_props.onNodeDrag} onNodeDragStart={_props.onNodeDragStart} onNodeDragStop={_props.onNodeDragStop} />
|
|
2943
|
-
<NodeSelection onSelectionClick={_props.onSelectionClick} onSelectionContextMenu={_props.onSelectionContextMenu} onNodeDrag={_props.onNodeDrag} onNodeDragStart={_props.onNodeDragStart} onNodeDragStop={_props.onNodeDragStop} />
|
|
2944
|
-
</Viewport>
|
|
2945
|
-
<Selection isVisible={!!store.selectionRect && store.selectionRectMode === "user"} width={store.selectionRect?.width} height={store.selectionRect?.height} x={store.selectionRect?.x} y={store.selectionRect?.y} />
|
|
2946
|
-
</Pane>
|
|
2947
|
-
</Zoom>
|
|
2948
|
-
<Attribution proOptions={_props.proOptions} position={_props.attributionPosition} />
|
|
2949
|
-
<A11yDescriptions />
|
|
2950
|
-
{_props.children}
|
|
2951
|
-
</TypedSolidFlowContext>
|
|
2952
|
-
</div>;
|
|
2953
|
-
}, SolidFlowProvider = (props) => {
|
|
2954
|
-
let _props = merge(getDefaultFlowStateProps(), props), solidFlow = createSolidFlow(_props);
|
|
2955
|
-
onCleanup(() => {
|
|
2956
|
-
solidFlow.actions.reset();
|
|
2957
|
-
});
|
|
2958
|
-
let ContextProvider = SolidFlowContext;
|
|
2959
|
-
return <ContextProvider value={solidFlow}>{props.children}</ContextProvider>;
|
|
2960
|
-
}, createEdgeStore = (edges) => {
|
|
2961
|
-
let [store, setStore] = createStore(edges);
|
|
2962
|
-
return [store, setStore];
|
|
2963
|
-
}, createNodeStore = (nodes) => {
|
|
2964
|
-
let [store, setStore] = createStore(nodes);
|
|
2965
|
-
return [store, setStore];
|
|
2966
|
-
};
|
|
3000
|
+
}, SelectionMode = SelectionMode$1, getEdgeCenter = getEdgeCenter$1, getBezierEdgeCenter = getBezierEdgeCenter$1;
|
|
2967
3001
|
//#endregion
|
|
2968
3002
|
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 };
|