@dschz/solid-flow 0.2.4 → 0.3.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index/index.d.ts +207 -250
- package/dist/index/index.js +2490 -2288
- package/dist/index/index.jsx +1682 -1448
- package/package.json +14 -20
package/dist/index/index.jsx
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { For,
|
|
2
|
-
import { ReactiveMap } from "@solid-primitives/map";
|
|
1
|
+
import { For, Show, createContext, createEffect, createMemo, createProjection, createSignal, createStore, flush, mapArray, merge, omit, onCleanup, onSettled, snapshot, untrack, useContext } from "solid-js";
|
|
3
2
|
import { createMediaQuery } from "@solid-primitives/media";
|
|
4
|
-
import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, ResizeControlVariant, SelectionMode, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getEdgeCenter, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isEdgeVisible, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import { Dynamic, Portal, isServer } from "solid-js/web";
|
|
8
|
-
import { createResizeObserver } from "@solid-primitives/resize-observer";
|
|
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
|
+
import { Dynamic, Portal, isServer } from "@solidjs/web";
|
|
5
|
+
import { createEventListener, createEventListenerMap } from "@solid-primitives/event-listener";
|
|
9
6
|
//#region src/components/contexts/edgeId.tsx
|
|
10
|
-
const EdgeIdContext = createContext();
|
|
7
|
+
const EdgeIdContext = createContext(null);
|
|
11
8
|
function useEdgeId() {
|
|
12
9
|
let ctx = useContext(EdgeIdContext);
|
|
13
10
|
if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useEdgeId");
|
|
@@ -39,104 +36,67 @@ const isNode = (element) => isNodeBase(element), isEdge = (element) => isEdgeBas
|
|
|
39
36
|
x: 1,
|
|
40
37
|
y: 0
|
|
41
38
|
}
|
|
42
|
-
};
|
|
39
|
+
}, scheduleIdleCallback = typeof requestIdleCallback == "function" ? requestIdleCallback : (callback) => setTimeout(callback, 0);
|
|
43
40
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* ```ts
|
|
50
|
-
* const [width, setWidth] = createWritable(() => config().width);
|
|
51
|
-
* // width() will return config().width initially
|
|
52
|
-
* // setWidth(100) will update the signal to 100
|
|
53
|
-
* // If config().width changes, a new signal width() is updated to the new value
|
|
54
|
-
* ```
|
|
41
|
+
* Reactive prop defaulting with skip-undefined semantics: a prop counts as
|
|
42
|
+
* "absent" when it reads `undefined`, so parents forwarding optional props
|
|
43
|
+
* (e.g. `<Handle position={props.targetPosition} />`) do not clobber defaults.
|
|
44
|
+
* This is deliberate policy on top of Solid 2.0's `merge`, where `undefined`
|
|
45
|
+
* is a real value that overrides.
|
|
55
46
|
*/
|
|
56
|
-
function
|
|
57
|
-
let
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
let [get, set] = createStore(accessor());
|
|
63
|
-
return {
|
|
64
|
-
get,
|
|
65
|
-
set
|
|
66
|
-
};
|
|
47
|
+
function propDefaults(props, defaults) {
|
|
48
|
+
let out = {}, keys = /* @__PURE__ */ new Set([...Object.keys(defaults), ...Object.keys(props)]);
|
|
49
|
+
for (let key of keys) Object.defineProperty(out, key, {
|
|
50
|
+
get: () => props[key] === void 0 ? defaults[key] : props[key],
|
|
51
|
+
enumerable: !0,
|
|
52
|
+
configurable: !0
|
|
67
53
|
});
|
|
68
|
-
return
|
|
69
|
-
get() {
|
|
70
|
-
return storeMemo().get;
|
|
71
|
-
},
|
|
72
|
-
get set() {
|
|
73
|
-
return storeMemo().set;
|
|
74
|
-
}
|
|
75
|
-
};
|
|
54
|
+
return out;
|
|
76
55
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
*/
|
|
81
|
-
const scheduleIdleCallback = typeof requestIdleCallback == "function" ? requestIdleCallback : (callback) => setTimeout(callback, 0), EdgeLabelRenderer = (props) => {
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/components/graph/edge/EdgeLabelRenderer.tsx
|
|
58
|
+
const EdgeLabelRenderer = (props) => {
|
|
82
59
|
let { store } = useInternalSolidFlow(), labelNode = () => store.domNode?.querySelector(".solid-flow__edge-labels");
|
|
83
60
|
return <Show when={labelNode()}>{(root) => <Portal mount={root()}>{props.children}</Portal>}</Show>;
|
|
84
61
|
}, EdgeLabel = (props) => {
|
|
85
|
-
let _props =
|
|
62
|
+
let _props = propDefaults(props, {
|
|
86
63
|
x: 0,
|
|
87
64
|
y: 0,
|
|
88
65
|
selectEdgeOnClick: !1,
|
|
89
66
|
transparent: !1,
|
|
90
67
|
style: {}
|
|
91
|
-
},
|
|
92
|
-
"x",
|
|
93
|
-
"y",
|
|
94
|
-
"width",
|
|
95
|
-
"height",
|
|
96
|
-
"selectEdgeOnClick",
|
|
97
|
-
"transparent",
|
|
98
|
-
"children",
|
|
99
|
-
"class",
|
|
100
|
-
"style"
|
|
101
|
-
]), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.getEdge(id())?.zIndex;
|
|
68
|
+
}), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.getEdge(id())?.zIndex;
|
|
102
69
|
return <EdgeLabelRenderer>
|
|
103
|
-
<div role="button"
|
|
70
|
+
<div role="button" tabindex={-1} class={[
|
|
71
|
+
"solid-flow__edge-label",
|
|
72
|
+
{ transparent: _props.transparent },
|
|
73
|
+
_props.class
|
|
74
|
+
]} style={{
|
|
104
75
|
"pointer-events": "all",
|
|
105
|
-
width: toPxString(
|
|
106
|
-
height: toPxString(
|
|
107
|
-
transform: `translate(-50%, -50%) translate(${
|
|
108
|
-
cursor:
|
|
76
|
+
width: toPxString(_props.width),
|
|
77
|
+
height: toPxString(_props.height),
|
|
78
|
+
transform: `translate(-50%, -50%) translate(${_props.x}px,${_props.y}px)`,
|
|
79
|
+
cursor: _props.selectEdgeOnClick ? "pointer" : void 0,
|
|
109
80
|
"z-index": zIndex(),
|
|
110
|
-
...
|
|
81
|
+
..._props.style
|
|
111
82
|
}} onClick={() => {
|
|
112
|
-
|
|
83
|
+
_props.selectEdgeOnClick && actions.handleEdgeSelection(id());
|
|
113
84
|
}} {...rest}>
|
|
114
|
-
{
|
|
85
|
+
{_props.children}
|
|
115
86
|
</div>
|
|
116
87
|
</EdgeLabelRenderer>;
|
|
117
88
|
}, BaseEdge = (props) => {
|
|
118
|
-
let _props =
|
|
119
|
-
"class",
|
|
120
|
-
"style",
|
|
121
|
-
"path",
|
|
122
|
-
"interactionWidth",
|
|
123
|
-
"label",
|
|
124
|
-
"labelStyle",
|
|
125
|
-
"labelX",
|
|
126
|
-
"labelY",
|
|
127
|
-
"markerStart",
|
|
128
|
-
"markerEnd"
|
|
129
|
-
]);
|
|
89
|
+
let _props = propDefaults(props, { interactionWidth: 20 }), rest = omit(_props, "class", "style", "path", "interactionWidth", "label", "labelStyle", "labelX", "labelY", "markerStart", "markerEnd");
|
|
130
90
|
return <>
|
|
131
|
-
<path d={
|
|
91
|
+
<path d={_props.path} class={["solid-flow__edge-path", _props.class]} marker-start={_props.markerStart} marker-end={_props.markerEnd} fill="none" style={_props.style} {...rest} />
|
|
132
92
|
|
|
133
|
-
<Show when={
|
|
134
|
-
<path d={
|
|
93
|
+
<Show when={_props.interactionWidth > 0}>
|
|
94
|
+
<path d={_props.path} stroke-opacity={0} stroke-width={_props.interactionWidth} fill="none" class="solid-flow__edge-interaction" />
|
|
135
95
|
</Show>
|
|
136
96
|
|
|
137
|
-
<Show when={
|
|
138
|
-
<EdgeLabel x={
|
|
139
|
-
{
|
|
97
|
+
<Show when={_props.label}>
|
|
98
|
+
<EdgeLabel x={_props.labelX} y={_props.labelY} style={_props.labelStyle}>
|
|
99
|
+
{_props.label}
|
|
140
100
|
</EdgeLabel>
|
|
141
101
|
</Show>
|
|
142
102
|
</>;
|
|
@@ -176,24 +136,16 @@ const scheduleIdleCallback = typeof requestIdleCallback == "function" ? requestI
|
|
|
176
136
|
};
|
|
177
137
|
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} />;
|
|
178
138
|
}, EdgeReconnectAnchor = (props) => {
|
|
179
|
-
let _props =
|
|
139
|
+
let _props = propDefaults(props, {
|
|
180
140
|
size: 25,
|
|
181
141
|
reconnecting: !1,
|
|
182
142
|
style: {}
|
|
183
|
-
},
|
|
184
|
-
"type",
|
|
185
|
-
"class",
|
|
186
|
-
"style",
|
|
187
|
-
"position",
|
|
188
|
-
"size",
|
|
189
|
-
"reconnecting",
|
|
190
|
-
"children"
|
|
191
|
-
]), { store, nodeLookup, edgeLookup, actions } = useInternalSolidFlow(), edgeId = useEdgeId(), [reconnecting, setReconnecting] = createSignal(!1);
|
|
143
|
+
}), rest = omit(_props, "type", "class", "style", "position", "size", "reconnecting", "children"), { store, nodeLookup, edgeLookup, actions } = useInternalSolidFlow(), edgeId = useEdgeId(), [reconnecting, setReconnecting] = createSignal(!1);
|
|
192
144
|
if (!edgeId()) throw Error("[solid-flow]: EdgeReconnectAnchor must be used within an Edge component");
|
|
193
|
-
let edge = () => edgeLookup
|
|
145
|
+
let edge = () => edgeLookup[edgeId()], onPointerDown = (event) => {
|
|
194
146
|
if (event.button !== 0) return;
|
|
195
|
-
setReconnecting(!0), store.onReconnectStart?.(event, edge(),
|
|
196
|
-
let opposite =
|
|
147
|
+
setReconnecting(!0), store.onReconnectStart?.(event, edge(), _props.type);
|
|
148
|
+
let opposite = _props.type === "target" ? {
|
|
197
149
|
nodeId: edge().source,
|
|
198
150
|
handleId: edge().sourceHandle ?? null,
|
|
199
151
|
type: "source"
|
|
@@ -237,16 +189,21 @@ const scheduleIdleCallback = typeof requestIdleCallback == "function" ? requestI
|
|
|
237
189
|
handleDomNode: event.currentTarget
|
|
238
190
|
});
|
|
239
191
|
};
|
|
240
|
-
return <EdgeLabel x={
|
|
241
|
-
<div onPointerDown={onPointerDown} class={
|
|
242
|
-
|
|
243
|
-
|
|
192
|
+
return <EdgeLabel x={_props.position?.x} y={_props.position?.y} style={_props.style} {...rest}>
|
|
193
|
+
<div onPointerDown={onPointerDown} class={[
|
|
194
|
+
"solid-flow__edgeupdater",
|
|
195
|
+
`solid-flow__edgeupdater-${_props.type}`,
|
|
196
|
+
store.noPanClass,
|
|
197
|
+
_props.class
|
|
198
|
+
]} style={{
|
|
199
|
+
width: toPxString(_props.size),
|
|
200
|
+
height: toPxString(_props.size),
|
|
244
201
|
background: "transparent",
|
|
245
202
|
border: "none",
|
|
246
203
|
cursor: "move",
|
|
247
|
-
...
|
|
204
|
+
..._props.style
|
|
248
205
|
}}>
|
|
249
|
-
<Show when={!reconnecting()}>{
|
|
206
|
+
<Show when={!reconnecting()}>{_props.children}</Show>
|
|
250
207
|
</div>
|
|
251
208
|
</EdgeLabel>;
|
|
252
209
|
}, ARIA_NODE_DESC_KEY = "solid-flow__node-desc", ARIA_EDGE_DESC_KEY = "solid-flow__edge-desc", A11yDescriptions = () => {
|
|
@@ -283,19 +240,24 @@ const scheduleIdleCallback = typeof requestIdleCallback == "function" ? requestI
|
|
|
283
240
|
}, onKeyDown = (event) => {
|
|
284
241
|
store.disableKeyboardA11y || !elementSelectionKeys.includes(event.key) || !selectable() || (event.key === "Escape" ? actions.unselectNodesAndEdges({ edges: [edge()] }) : actions.addSelectedEdges([edge().id]));
|
|
285
242
|
}, ariaLabel = () => edge().ariaLabel ?? `Edge from ${edge().source} to ${edge().target}`;
|
|
286
|
-
return <EdgeIdContext
|
|
243
|
+
return <EdgeIdContext value={edgeId}>
|
|
287
244
|
<Show when={!edge().hidden}>
|
|
288
245
|
<svg class="solid-flow__edge-wrapper" style={{ "z-index": edge().zIndex }}>
|
|
289
|
-
<g ref={edgeRef} data-id={edge().id}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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}>
|
|
294
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()} />
|
|
295
257
|
</g>
|
|
296
258
|
</svg>
|
|
297
259
|
</Show>
|
|
298
|
-
</EdgeIdContext
|
|
260
|
+
</EdgeIdContext>;
|
|
299
261
|
}, SmoothStepEdge = (props) => {
|
|
300
262
|
let pathData = createMemo(() => {
|
|
301
263
|
let [path, labelX, labelY] = getSmoothStepPath$1({
|
|
@@ -399,515 +361,305 @@ const scheduleIdleCallback = typeof requestIdleCallback == "function" ? requestI
|
|
|
399
361
|
};
|
|
400
362
|
};
|
|
401
363
|
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} />;
|
|
402
|
-
},
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
364
|
+
}, getDefaultFlowStateProps = () => ({
|
|
365
|
+
id: "1",
|
|
366
|
+
nodes: [],
|
|
367
|
+
edges: [],
|
|
368
|
+
nodeOrigin: [0, 0],
|
|
369
|
+
nodeExtent: infiniteExtent,
|
|
370
|
+
defaultEdgeOptions: {},
|
|
371
|
+
colorMode: "system",
|
|
372
|
+
colorModeSSR: "light",
|
|
373
|
+
connectionMode: "strict",
|
|
374
|
+
connectionLineType: "default",
|
|
375
|
+
connectionRadius: 20,
|
|
376
|
+
nodeDragThreshold: 1,
|
|
377
|
+
minZoom: .5,
|
|
378
|
+
maxZoom: 2,
|
|
379
|
+
selectionMode: "partial",
|
|
380
|
+
fitView: !1,
|
|
381
|
+
noPanClass: "nopan",
|
|
382
|
+
noDragClass: "nodrag",
|
|
383
|
+
noWheelClass: "nowheel",
|
|
384
|
+
autoPanOnNodeDrag: !0,
|
|
385
|
+
autoPanOnConnect: !0,
|
|
386
|
+
autoPanOnNodeFocus: !0,
|
|
387
|
+
autoPanOnSelection: !0,
|
|
388
|
+
autoPanSpeed: 15,
|
|
389
|
+
elevateEdgesOnSelect: !0,
|
|
390
|
+
nodesDraggable: !0,
|
|
391
|
+
nodesConnectable: !0,
|
|
392
|
+
nodesFocusable: !0,
|
|
393
|
+
edgesFocusable: !0,
|
|
394
|
+
elementsSelectable: !0,
|
|
395
|
+
selectNodesOnDrag: !0,
|
|
396
|
+
elevateNodesOnSelect: !0,
|
|
397
|
+
zIndexMode: "basic",
|
|
398
|
+
onlyRenderVisibleElements: !1,
|
|
399
|
+
disableKeyboardA11y: !1,
|
|
400
|
+
defaultMarkerColor: "#b1b1b7",
|
|
401
|
+
ariaLiveMessage: "",
|
|
402
|
+
style: {},
|
|
403
|
+
isValidConnection: (() => !0),
|
|
404
|
+
onFlowError: createDevWarn("Solid Flow", "https://solidflow.dev/")
|
|
405
|
+
});
|
|
411
406
|
//#endregion
|
|
412
|
-
//#region src/
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
height: toPxString(props.height)
|
|
543
|
-
}} />, InputNode = (props) => {
|
|
544
|
-
let _props = mergeProps({ sourcePosition: "bottom" }, props);
|
|
545
|
-
return <>
|
|
546
|
-
{props.data?.label}
|
|
547
|
-
<Handle type="source" position={_props.sourcePosition} isConnectable={_props.isConnectable} />
|
|
548
|
-
</>;
|
|
549
|
-
}, createDraggable = (elem, params) => {
|
|
550
|
-
let { store, nodeLookup, actions } = useInternalSolidFlow(), [dragging, setDragging] = createSignal(!1);
|
|
551
|
-
return onMount(() => {
|
|
552
|
-
let { onDrag, onDragStart, onDragStop, onNodeMouseDown } = params(), dragInstance = XYDrag({
|
|
553
|
-
onDrag,
|
|
554
|
-
onDragStart: (event, dragItems, node, nodes) => {
|
|
555
|
-
setDragging(!0), onDragStart?.(event, dragItems, node, nodes);
|
|
556
|
-
},
|
|
557
|
-
onDragStop: (event, dragItems, node, nodes) => {
|
|
558
|
-
setDragging(!1), onDragStop?.(event, dragItems, node, nodes);
|
|
559
|
-
},
|
|
560
|
-
onNodeMouseDown,
|
|
561
|
-
getStoreItems: () => ({
|
|
562
|
-
nodes: store.nodes,
|
|
563
|
-
nodeLookup,
|
|
564
|
-
edges: store.edges,
|
|
565
|
-
nodeExtent: store.nodeExtent,
|
|
566
|
-
snapGrid: store.snapGrid ?? [0, 0],
|
|
567
|
-
snapToGrid: !!store.snapGrid,
|
|
568
|
-
autoPanSpeed: store.autoPanSpeed,
|
|
569
|
-
nodeOrigin: store.nodeOrigin,
|
|
570
|
-
multiSelectionActive: store.multiselectionKeyPressed,
|
|
571
|
-
domNode: store.domNode,
|
|
572
|
-
transform: store.transform,
|
|
573
|
-
autoPanOnNodeDrag: store.autoPanOnNodeDrag,
|
|
574
|
-
nodesDraggable: store.nodesDraggable,
|
|
575
|
-
selectNodesOnDrag: store.selectNodesOnDrag,
|
|
576
|
-
nodeDragThreshold: store.nodeDragThreshold,
|
|
577
|
-
unselectNodesAndEdges: actions.unselectNodesAndEdges,
|
|
578
|
-
updateNodePositions: actions.updateNodePositions,
|
|
579
|
-
panBy: actions.panBy
|
|
580
|
-
})
|
|
581
|
-
});
|
|
582
|
-
function updateDrag(elem, params) {
|
|
583
|
-
if (params.disabled) {
|
|
584
|
-
dragInstance.destroy();
|
|
585
|
-
return;
|
|
407
|
+
//#region src/core/facades.ts
|
|
408
|
+
/**
|
|
409
|
+
* A read-only `Map` view over an id-keyed record projection, for
|
|
410
|
+
* @xyflow/system interop: system helpers take `Map`s, our reactive lookups
|
|
411
|
+
* are records. Every read passes through to the record, so reads inside
|
|
412
|
+
* tracked scopes subscribe normally — `get`/`has` check with `in` first,
|
|
413
|
+
* which also subscribes while the key is still absent (the projection
|
|
414
|
+
* absent-key footgun), and `size`/iteration read the key set structurally.
|
|
415
|
+
*
|
|
416
|
+
* The mutating `Map` methods throw: writes belong to the roots the
|
|
417
|
+
* projection derives from.
|
|
418
|
+
*/
|
|
419
|
+
var RecordMapFacade = class {
|
|
420
|
+
#record;
|
|
421
|
+
constructor(record) {
|
|
422
|
+
this.#record = record;
|
|
423
|
+
}
|
|
424
|
+
get(key) {
|
|
425
|
+
return key in this.#record ? this.#record[key] : void 0;
|
|
426
|
+
}
|
|
427
|
+
has(key) {
|
|
428
|
+
return key in this.#record;
|
|
429
|
+
}
|
|
430
|
+
get size() {
|
|
431
|
+
return Object.keys(this.#record).length;
|
|
432
|
+
}
|
|
433
|
+
*keys() {
|
|
434
|
+
yield* Object.keys(this.#record);
|
|
435
|
+
}
|
|
436
|
+
*values() {
|
|
437
|
+
for (let key of Object.keys(this.#record)) yield this.#record[key];
|
|
438
|
+
}
|
|
439
|
+
*entries() {
|
|
440
|
+
for (let key of Object.keys(this.#record)) yield [key, this.#record[key]];
|
|
441
|
+
}
|
|
442
|
+
[Symbol.iterator]() {
|
|
443
|
+
return this.entries();
|
|
444
|
+
}
|
|
445
|
+
forEach(callback, thisArg) {
|
|
446
|
+
for (let [key, value] of this.entries()) callback.call(thisArg, value, key, this);
|
|
447
|
+
}
|
|
448
|
+
[Symbol.toStringTag] = "RecordMapFacade";
|
|
449
|
+
set() {
|
|
450
|
+
throw Error("RecordMapFacade is read-only; write to the projection's source roots");
|
|
451
|
+
}
|
|
452
|
+
getOrInsert() {
|
|
453
|
+
throw Error("RecordMapFacade is read-only; write to the projection's source roots");
|
|
454
|
+
}
|
|
455
|
+
getOrInsertComputed() {
|
|
456
|
+
throw Error("RecordMapFacade is read-only; write to the projection's source roots");
|
|
457
|
+
}
|
|
458
|
+
delete() {
|
|
459
|
+
throw Error("RecordMapFacade is read-only; write to the projection's source roots");
|
|
460
|
+
}
|
|
461
|
+
clear() {
|
|
462
|
+
throw Error("RecordMapFacade is read-only; write to the projection's source roots");
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
//#endregion
|
|
466
|
+
//#region src/core/projections/connections.ts
|
|
467
|
+
/**
|
|
468
|
+
* Lookup keys for the connection index. Each edge is registered under six
|
|
469
|
+
* keys — for both of its endpoints: the node, the node+handle-type, and (when
|
|
470
|
+
* a handle id is present) the node+type+handle:
|
|
471
|
+
* `${nodeId}` · `${nodeId}-${type}` · `${nodeId}-${type}-${handleId}`
|
|
472
|
+
*/
|
|
473
|
+
const connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ? `-${type}-${handleId}` : `-${type}` : ""}`, pairKey = (aNode, aHandle, bNode, bHandle) => `${aNode}-${aHandle}--${bNode}-${bHandle}`, createConnections = (source) => createProjection(() => {
|
|
474
|
+
let out = {}, add = (key, entry, connection) => {
|
|
475
|
+
(out[key] ??= {})[entry] = connection;
|
|
476
|
+
};
|
|
477
|
+
for (let edge of source.edges) {
|
|
478
|
+
let sourceHandle = edge.sourceHandle ?? null, targetHandle = edge.targetHandle ?? null, connection = {
|
|
479
|
+
edgeId: edge.id,
|
|
480
|
+
source: edge.source,
|
|
481
|
+
target: edge.target,
|
|
482
|
+
sourceHandle,
|
|
483
|
+
targetHandle
|
|
484
|
+
}, sourceKey = pairKey(edge.source, sourceHandle, edge.target, targetHandle), targetKey = pairKey(edge.target, targetHandle, edge.source, sourceHandle);
|
|
485
|
+
add(edge.source, targetKey, connection), add(connectionKey(edge.source, "source"), targetKey, connection), sourceHandle && add(connectionKey(edge.source, "source", sourceHandle), targetKey, connection), add(edge.target, sourceKey, connection), add(connectionKey(edge.target, "target"), sourceKey, connection), targetHandle && add(connectionKey(edge.target, "target", targetHandle), sourceKey, connection);
|
|
486
|
+
}
|
|
487
|
+
return out;
|
|
488
|
+
}, {}, { key: "id" }), createEdgeLookup = (source) => createProjection(() => {
|
|
489
|
+
let out = {};
|
|
490
|
+
for (let edge of source.edges) out[edge.id] = edge;
|
|
491
|
+
return out;
|
|
492
|
+
}, {}, { key: "id" });
|
|
493
|
+
function isManualZIndexMode(zIndexMode) {
|
|
494
|
+
return zIndexMode === "manual";
|
|
495
|
+
}
|
|
496
|
+
function calculateZ(node, selectedNodeZ, zIndexMode) {
|
|
497
|
+
let zIndex = isNumeric(node.zIndex) ? node.zIndex : 0;
|
|
498
|
+
return isManualZIndexMode(zIndexMode) ? zIndex : zIndex + (node.selected ? selectedNodeZ : 0);
|
|
499
|
+
}
|
|
500
|
+
const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (source) => {
|
|
501
|
+
let autoIndex = createMemo(() => {
|
|
502
|
+
if (source.zIndexMode !== "auto") return EMPTY_AUTO_INDEX;
|
|
503
|
+
let index = /* @__PURE__ */ new Map(), rootIds = /* @__PURE__ */ new Set();
|
|
504
|
+
for (let node of source.nodes) node.parentId ? rootIds.has(node.parentId) && !index.has(node.parentId) && index.set(node.parentId, index.size + 1) : rootIds.add(node.id);
|
|
505
|
+
return index;
|
|
506
|
+
}), entryById = /* @__PURE__ */ new Map(), rowStores = mapArray(() => source.nodes, (userNodeAccessor, index) => {
|
|
507
|
+
let id = userNodeAccessor().id, store = createProjection(() => {
|
|
508
|
+
let userNode = userNodeAccessor(), { nodeOrigin, nodeExtent, zIndexMode } = source, selectedNodeZ = source.elevateNodesOnSelect && !isManualZIndexMode(zIndexMode) ? 1e3 : 0, measurement = userNode.id in source.measurements ? source.measurements[userNode.id] : void 0, measured = {
|
|
509
|
+
width: userNode.measured?.width ?? measurement?.measured.width,
|
|
510
|
+
height: userNode.measured?.height ?? measurement?.measured.height
|
|
511
|
+
}, dimensions = getNodeDimensions({
|
|
512
|
+
measured,
|
|
513
|
+
width: userNode.width,
|
|
514
|
+
height: userNode.height,
|
|
515
|
+
initialWidth: userNode.initialWidth,
|
|
516
|
+
initialHeight: userNode.initialHeight
|
|
517
|
+
}), rootParentIndex = autoIndex().get(userNode.id), row = {
|
|
518
|
+
...userNode,
|
|
519
|
+
measured,
|
|
520
|
+
internals: {
|
|
521
|
+
positionAbsolute: clampPosition(getNodePositionWithOrigin(userNode, nodeOrigin), isCoordinateExtent(userNode.extent) ? userNode.extent : nodeExtent, dimensions),
|
|
522
|
+
handleBounds: measurement?.handleBounds,
|
|
523
|
+
z: calculateZ(userNode, selectedNodeZ, zIndexMode) + (rootParentIndex === void 0 ? 0 : rootParentIndex * 10),
|
|
524
|
+
...rootParentIndex === void 0 ? {} : { rootParentIndex },
|
|
525
|
+
userNode
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
if (userNode.parentId) {
|
|
529
|
+
let parentEntry = entryById.get(userNode.parentId);
|
|
530
|
+
if (parentEntry && parentEntry.index() < index()) {
|
|
531
|
+
let { x, y, z } = calculateChildXYZ(row, parentEntry.store.row, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode);
|
|
532
|
+
row.internals.positionAbsolute = {
|
|
533
|
+
x,
|
|
534
|
+
y
|
|
535
|
+
}, row.internals.z = z;
|
|
536
|
+
} else source.nodes.length;
|
|
586
537
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
538
|
+
if (userNode.parentId) {
|
|
539
|
+
let parent = entryById.get(userNode.parentId);
|
|
540
|
+
parent?.store.row.internals.positionAbsolute.x, parent?.store.row.internals.z;
|
|
541
|
+
}
|
|
542
|
+
return { row };
|
|
543
|
+
}, {}, { key: "id" }), entry = {
|
|
544
|
+
store,
|
|
545
|
+
index
|
|
546
|
+
};
|
|
547
|
+
return entryById.set(id, entry), onCleanup(() => {
|
|
548
|
+
entryById.get(id) === entry && entryById.delete(id);
|
|
549
|
+
}), {
|
|
550
|
+
id,
|
|
551
|
+
store
|
|
552
|
+
};
|
|
553
|
+
}, { keyed: (userNode) => userNode.id }), assigned = /* @__PURE__ */ new Map();
|
|
554
|
+
return createProjection((draft) => {
|
|
555
|
+
let seen = /* @__PURE__ */ new Set();
|
|
556
|
+
for (let { id, store } of rowStores()) {
|
|
557
|
+
seen.add(id);
|
|
558
|
+
let row = store.row;
|
|
559
|
+
assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row);
|
|
595
560
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
561
|
+
for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
|
|
562
|
+
}, {}, {
|
|
563
|
+
key: null,
|
|
564
|
+
shallow: !0
|
|
565
|
+
});
|
|
566
|
+
};
|
|
567
|
+
function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode) {
|
|
568
|
+
let { x: parentX, y: parentY } = parentNode.internals.positionAbsolute, childDimensions = getNodeDimensions(childNode), positionWithOrigin = getNodePositionWithOrigin(childNode, nodeOrigin), clampedPosition = isCoordinateExtent(childNode.extent) ? clampPosition(positionWithOrigin, childNode.extent, childDimensions) : positionWithOrigin, absolutePosition = clampPosition({
|
|
569
|
+
x: parentX + clampedPosition.x,
|
|
570
|
+
y: parentY + clampedPosition.y
|
|
571
|
+
}, nodeExtent, childDimensions);
|
|
572
|
+
childNode.extent === "parent" && (absolutePosition = clampPositionToParent(absolutePosition, childDimensions, parentNode));
|
|
573
|
+
let childZ = calculateZ(childNode, selectedNodeZ, zIndexMode), parentZ = parentNode.internals.z ?? 0;
|
|
574
|
+
return {
|
|
575
|
+
x: absolutePosition.x,
|
|
576
|
+
y: absolutePosition.y,
|
|
577
|
+
z: parentZ >= childZ ? parentZ + 1 : childZ
|
|
578
|
+
};
|
|
607
579
|
}
|
|
608
580
|
//#endregion
|
|
609
|
-
//#region src/
|
|
610
|
-
const NodeWrapper = (props) => {
|
|
611
|
-
let { store, nodeLookup, parentLookup, actions } = useInternalSolidFlow(), [nodeRef, setNodeRef] = createSignal(), node = () => nodeLookup.get(props.nodeId), nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeType()], isParentNode = () => parentLookup.has(node().id), transform = () => {
|
|
612
|
-
let { x, y } = node().internals.positionAbsolute;
|
|
613
|
-
return `translate(${x}px, ${y}px)`;
|
|
614
|
-
}, sizeStyle = () => {
|
|
615
|
-
let w = node().width ?? node().initialWidth, h = node().height ?? node().initialHeight;
|
|
616
|
-
return {
|
|
617
|
-
...node().style,
|
|
618
|
-
...w ? { width: toPxString(w) } : {},
|
|
619
|
-
...h ? { height: toPxString(h) } : {}
|
|
620
|
-
};
|
|
621
|
-
}, style = () => ({
|
|
622
|
-
"z-index": node().internals.z,
|
|
623
|
-
transform: transform(),
|
|
624
|
-
visibility: nodeHasDimensions(node()) ? "visible" : "hidden",
|
|
625
|
-
...sizeStyle(),
|
|
626
|
-
...node().style ?? {}
|
|
627
|
-
});
|
|
628
|
-
createEffect(() => {
|
|
629
|
-
nodeTypeValid();
|
|
630
|
-
}), createEffect((prev) => prev && prev.sourcePosition === node().sourcePosition && prev.targetPosition === node().targetPosition && prev.nodeType === nodeType() ? prev : (actions.requestUpdateNodeInternals([[node().id, {
|
|
631
|
-
id: node().id,
|
|
632
|
-
nodeElement: nodeRef(),
|
|
633
|
-
force: !0
|
|
634
|
-
}]]), {
|
|
635
|
-
nodeType: nodeType(),
|
|
636
|
-
sourcePosition: node().sourcePosition,
|
|
637
|
-
targetPosition: node().targetPosition
|
|
638
|
-
})), createEffect((prevNodeRef) => {
|
|
639
|
-
let currentNodeRef = nodeRef();
|
|
640
|
-
return currentNodeRef === prevNodeRef && nodeHasDimensions(node()) ? prevNodeRef : (prevNodeRef && props.resizeObserver?.unobserve(prevNodeRef), currentNodeRef && props.resizeObserver?.observe(currentNodeRef), currentNodeRef);
|
|
641
|
-
});
|
|
642
|
-
let onSelectNodeHandler = (event) => {
|
|
643
|
-
selectable() && (!store.selectNodesOnDrag || !draggable() || store.nodeDragThreshold > 0) && actions.handleNodeSelection(node().id), props.onNodeClick?.({
|
|
644
|
-
node: userNode(),
|
|
645
|
-
event
|
|
646
|
-
});
|
|
647
|
-
}, onKeyDown = (event) => {
|
|
648
|
-
if (isInputDOMNode(event) || store.disableKeyboardA11y) return;
|
|
649
|
-
if (elementSelectionKeys.includes(event.key) && selectable()) {
|
|
650
|
-
actions.handleNodeSelection(node().id, event.key === "Escape", nodeRef());
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
let arrowKeyDiff = ARROW_KEY_DIFFS[event.key];
|
|
654
|
-
draggable() && node().selected && arrowKeyDiff && batch(() => {
|
|
655
|
-
event.preventDefault(), actions.setAriaLiveMessage(store.ariaLabelConfig["node.a11yDescription.ariaLiveMessage"]({
|
|
656
|
-
direction: event.key.replace("Arrow", "").toLowerCase(),
|
|
657
|
-
x: ~~node().internals.positionAbsolute.x,
|
|
658
|
-
y: ~~node().internals.positionAbsolute.y
|
|
659
|
-
})), actions.moveSelectedNodes(arrowKeyDiff, event.shiftKey ? 4 : 1);
|
|
660
|
-
});
|
|
661
|
-
}, onFocus = () => {
|
|
662
|
-
if (store.disableKeyboardA11y || !store.autoPanOnNodeFocus || !nodeRef()?.matches(":focus-visible")) return;
|
|
663
|
-
let { width, height, viewport } = store;
|
|
664
|
-
getNodesInside(/* @__PURE__ */ new Map([[node().id, node()]]), {
|
|
665
|
-
x: 0,
|
|
666
|
-
y: 0,
|
|
667
|
-
width,
|
|
668
|
-
height
|
|
669
|
-
}, [
|
|
670
|
-
viewport.x,
|
|
671
|
-
viewport.y,
|
|
672
|
-
viewport.zoom
|
|
673
|
-
], !0).length > 0 || actions.setCenter(node().position.x + (node().measured.width ?? 0) / 2, node().position.y + (node().measured.height ?? 0) / 2, { zoom: viewport.zoom });
|
|
674
|
-
}, dragging = createDraggable(nodeRef, () => ({
|
|
675
|
-
nodeId: node().id,
|
|
676
|
-
isSelectable: selectable(),
|
|
677
|
-
disabled: !draggable(),
|
|
678
|
-
handleSelector: node().dragHandle,
|
|
679
|
-
noDragClass: store.noDragClass,
|
|
680
|
-
nodeClickDistance: props.nodeClickDistance,
|
|
681
|
-
onNodeMouseDown: actions.handleNodeSelection,
|
|
682
|
-
onDrag: (event, _, targetNode, nodes) => {
|
|
683
|
-
props.onNodeDrag?.({
|
|
684
|
-
event,
|
|
685
|
-
targetNode,
|
|
686
|
-
nodes
|
|
687
|
-
});
|
|
688
|
-
},
|
|
689
|
-
onDragStart: (event, _, targetNode, nodes) => {
|
|
690
|
-
props.onNodeDragStart?.({
|
|
691
|
-
event,
|
|
692
|
-
targetNode,
|
|
693
|
-
nodes
|
|
694
|
-
});
|
|
695
|
-
},
|
|
696
|
-
onDragStop: (event, _, targetNode, nodes) => {
|
|
697
|
-
props.onNodeDragStop?.({
|
|
698
|
-
event,
|
|
699
|
-
targetNode,
|
|
700
|
-
nodes
|
|
701
|
-
});
|
|
702
|
-
}
|
|
703
|
-
}));
|
|
704
|
-
return <Show when={!node().hidden}>
|
|
705
|
-
<div ref={setNodeRef} data-id={node().id} class={clsx$1("solid-flow__node", `solid-flow__node-${nodeType()}`, {
|
|
706
|
-
connectable: connectable(),
|
|
707
|
-
draggable: draggable(),
|
|
708
|
-
dragging: dragging(),
|
|
709
|
-
nopan: draggable(),
|
|
710
|
-
parent: isParentNode(),
|
|
711
|
-
selectable: selectable(),
|
|
712
|
-
selected: node().selected
|
|
713
|
-
}, node().class)} style={style()} onClick={onSelectNodeHandler} onPointerEnter={(event) => props.onNodePointerEnter?.({
|
|
714
|
-
node: userNode(),
|
|
715
|
-
event
|
|
716
|
-
})} onPointerLeave={(event) => props.onNodePointerLeave?.({
|
|
717
|
-
node: userNode(),
|
|
718
|
-
event
|
|
719
|
-
})} onPointerMove={(event) => props.onNodePointerMove?.({
|
|
720
|
-
node: userNode(),
|
|
721
|
-
event
|
|
722
|
-
})} onContextMenu={(event) => props.onNodeContextMenu?.({
|
|
723
|
-
node: userNode(),
|
|
724
|
-
event
|
|
725
|
-
})} onKeyDown={(e) => focusable() && onKeyDown(e)} onFocus={() => focusable() && onFocus()} tabIndex={focusable() ? 0 : void 0} role={node().ariaRole ?? (focusable() ? "group" : void 0)} aria-roledescription="node" aria-describedby={store.disableKeyboardA11y ? void 0 : `${ARIA_NODE_DESC_KEY}-${store.id}`} {...node().domAttributes}>
|
|
726
|
-
<NodeIdContext.Provider value={nodeId}>
|
|
727
|
-
<NodeConnectableContext.Provider value={connectable}>
|
|
728
|
-
<Dynamic component={nodeComponent()} data={node().data} id={node().id} selected={!!node().selected} selectable={selectable()} deletable={deletable()} sourcePosition={node().sourcePosition} targetPosition={node().targetPosition} zIndex={node().internals.z} dragging={dragging()} draggable={draggable()} dragHandle={node().dragHandle} parentId={node().parentId} type={nodeType()} isConnectable={connectable()} positionAbsoluteX={node().internals.positionAbsolute.x} positionAbsoluteY={node().internals.positionAbsolute.y} width={node().width} height={node().height} />
|
|
729
|
-
</NodeConnectableContext.Provider>
|
|
730
|
-
</NodeIdContext.Provider>
|
|
731
|
-
</div>
|
|
732
|
-
</Show>;
|
|
733
|
-
}, OutputNode = (props) => {
|
|
734
|
-
let _props = mergeProps({ targetPosition: "top" }, props);
|
|
735
|
-
return <>
|
|
736
|
-
<Handle type="target" position={_props.targetPosition} isConnectable={_props.isConnectable} />
|
|
737
|
-
{props.data?.label}
|
|
738
|
-
</>;
|
|
739
|
-
}, getDefaultFlowStateProps = () => ({
|
|
740
|
-
id: "1",
|
|
741
|
-
nodes: [],
|
|
742
|
-
edges: [],
|
|
743
|
-
nodeOrigin: [0, 0],
|
|
744
|
-
nodeExtent: infiniteExtent,
|
|
745
|
-
defaultEdgeOptions: {},
|
|
746
|
-
colorMode: "system",
|
|
747
|
-
colorModeSSR: "light",
|
|
748
|
-
connectionMode: "strict",
|
|
749
|
-
connectionLineType: "default",
|
|
750
|
-
connectionRadius: 20,
|
|
751
|
-
nodeDragThreshold: 1,
|
|
752
|
-
minZoom: .5,
|
|
753
|
-
maxZoom: 2,
|
|
754
|
-
selectionMode: "partial",
|
|
755
|
-
fitView: !1,
|
|
756
|
-
noPanClass: "nopan",
|
|
757
|
-
noDragClass: "nodrag",
|
|
758
|
-
noWheelClass: "nowheel",
|
|
759
|
-
autoPanOnNodeDrag: !0,
|
|
760
|
-
autoPanOnConnect: !0,
|
|
761
|
-
autoPanOnNodeFocus: !0,
|
|
762
|
-
autoPanOnSelection: !0,
|
|
763
|
-
autoPanSpeed: 15,
|
|
764
|
-
elevateEdgesOnSelect: !0,
|
|
765
|
-
nodesDraggable: !0,
|
|
766
|
-
nodesConnectable: !0,
|
|
767
|
-
nodesFocusable: !0,
|
|
768
|
-
edgesFocusable: !0,
|
|
769
|
-
elementsSelectable: !0,
|
|
770
|
-
selectNodesOnDrag: !0,
|
|
771
|
-
elevateNodesOnSelect: !0,
|
|
772
|
-
zIndexMode: "basic",
|
|
773
|
-
onlyRenderVisibleElements: !1,
|
|
774
|
-
disableKeyboardA11y: !1,
|
|
775
|
-
defaultMarkerColor: "#b1b1b7",
|
|
776
|
-
ariaLiveMessage: "",
|
|
777
|
-
style: {},
|
|
778
|
-
isValidConnection: (() => !0),
|
|
779
|
-
onFlowError: createDevWarn("Solid Flow", "https://solidflow.dev/")
|
|
780
|
-
}), SELECTED_NODE_Z = 1e3, defaultOptions = {
|
|
781
|
-
nodeOrigin: [0, 0],
|
|
782
|
-
nodeExtent: infiniteExtent,
|
|
783
|
-
elevateNodesOnSelect: !0,
|
|
784
|
-
defaults: {},
|
|
785
|
-
zIndexMode: "basic"
|
|
786
|
-
};
|
|
787
|
-
function isManualZIndexMode(zIndexMode) {
|
|
788
|
-
return zIndexMode === "manual";
|
|
789
|
-
}
|
|
790
|
-
const adoptUserNodesDefaultOptions = {
|
|
791
|
-
...defaultOptions,
|
|
792
|
-
checkEquality: !0
|
|
793
|
-
};
|
|
794
|
-
function mergeObjects(base, incoming) {
|
|
795
|
-
let result = { ...base };
|
|
796
|
-
for (let key in incoming) incoming[key] !== void 0 && (result[key] = incoming[key]);
|
|
797
|
-
return result;
|
|
798
|
-
}
|
|
799
|
-
function adoptUserNodes(nodes, nodeLookup, parentLookup, options) {
|
|
800
|
-
let _options = mergeObjects(adoptUserNodesDefaultOptions, options), nodesInitialized = nodes.length > 0, rootParentIndex = { i: 0 }, tmpLookup = new Map(nodeLookup), selectedNodeZ = _options?.elevateNodesOnSelect && !isManualZIndexMode(_options.zIndexMode) ? SELECTED_NODE_Z : 0;
|
|
801
|
-
nodeLookup.clear(), parentLookup.clear();
|
|
802
|
-
for (let userNode of nodes) {
|
|
803
|
-
let internalNode = tmpLookup.get(userNode.id);
|
|
804
|
-
if (_options.checkEquality && userNode === internalNode?.internals.userNode) nodeLookup.set(userNode.id, internalNode);
|
|
805
|
-
else {
|
|
806
|
-
let positionWithOrigin = getNodePositionWithOrigin(userNode, _options.nodeOrigin), extent = isCoordinateExtent(userNode.extent) ? userNode.extent : _options.nodeExtent, clampedPosition = clampPosition(positionWithOrigin, extent, getNodeDimensions(userNode));
|
|
807
|
-
internalNode = {
|
|
808
|
-
..._options.defaults,
|
|
809
|
-
...userNode,
|
|
810
|
-
measured: {
|
|
811
|
-
width: userNode.measured?.width,
|
|
812
|
-
height: userNode.measured?.height
|
|
813
|
-
},
|
|
814
|
-
internals: {
|
|
815
|
-
positionAbsolute: clampedPosition,
|
|
816
|
-
handleBounds: userNode.measured ? internalNode?.internals.handleBounds : void 0,
|
|
817
|
-
z: calculateZ(userNode, selectedNodeZ, _options.zIndexMode),
|
|
818
|
-
userNode
|
|
819
|
-
}
|
|
820
|
-
}, nodeLookup.set(userNode.id, internalNode);
|
|
821
|
-
}
|
|
822
|
-
(internalNode.measured === void 0 || internalNode.measured.width === void 0 || internalNode.measured.height === void 0) && !internalNode.hidden && (nodesInitialized = !1), userNode.parentId && updateChildNode(internalNode, nodeLookup, parentLookup, options, rootParentIndex);
|
|
823
|
-
}
|
|
824
|
-
return nodesInitialized;
|
|
825
|
-
}
|
|
826
|
-
function updateParentLookup(node, parentLookup) {
|
|
827
|
-
if (!node.parentId) return;
|
|
828
|
-
let childNodes = parentLookup.get(node.parentId);
|
|
829
|
-
childNodes ? childNodes.set(node.id, node) : parentLookup.set(node.parentId, /* @__PURE__ */ new Map([[node.id, node]]));
|
|
830
|
-
}
|
|
581
|
+
//#region src/core/projections/layoutedEdges.ts
|
|
831
582
|
/**
|
|
832
|
-
*
|
|
583
|
+
* Edge layout join: user edges × internal nodes → screen-space edge geometry,
|
|
584
|
+
* decomposed into SUB-STORES (spike 13): each edge is its own keyed
|
|
585
|
+
* projection holding `{ row }` — the layouted row, or null while the edge
|
|
586
|
+
* produces none (missing/unready endpoints, culled) — and the public record
|
|
587
|
+
* is a SHALLOW projection holding the PRESENT rows' proxies by reference.
|
|
588
|
+
*
|
|
589
|
+
* Reads chain: `record[id].sourceX` goes through the shallow slot into the
|
|
590
|
+
* edge's own store, so every materialized leaf signal hangs off its EDGE's
|
|
591
|
+
* computed (defeating rc.1's per-update companion walk — see
|
|
592
|
+
* internalNodes.ts). The edge projection tracks exactly what the join reads —
|
|
593
|
+
* the edge's props and its endpoints' geometry leaves through nodeLookup
|
|
594
|
+
* (which chains into the node row stores) — so one node move re-runs only
|
|
595
|
+
* the adjacent edges' projections; the record computed re-runs only when
|
|
596
|
+
* membership or presence changes.
|
|
597
|
+
*
|
|
598
|
+
* The viewport participates only while onlyRenderVisibleElements is active —
|
|
599
|
+
* panning must not touch edge rows otherwise.
|
|
600
|
+
*
|
|
601
|
+
* Rows whose endpoints are missing or unmeasured simply drop out of the
|
|
602
|
+
* record — the same "no entry" contract the ReactiveMap pipeline had.
|
|
833
603
|
*/
|
|
834
|
-
|
|
835
|
-
let
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
z
|
|
604
|
+
const createLayoutedEdges = (source) => {
|
|
605
|
+
let rowStores = mapArray(() => source.edges, (edgeAccessor) => ({
|
|
606
|
+
id: edgeAccessor().id,
|
|
607
|
+
store: createProjection(() => {
|
|
608
|
+
let edge = edgeAccessor(), row = buildRow(source, edge);
|
|
609
|
+
return source.nodeLookup.get(edge.source)?.internals.handleBounds, source.nodeLookup.get(edge.target)?.internals.handleBounds, { row };
|
|
610
|
+
}, { row: null }, { key: "id" })
|
|
611
|
+
}), { keyed: (edge) => edge.id }), assigned = /* @__PURE__ */ new Map();
|
|
612
|
+
return createProjection((draft) => {
|
|
613
|
+
let seen = /* @__PURE__ */ new Set();
|
|
614
|
+
for (let { id, store } of rowStores()) {
|
|
615
|
+
let row = store.row;
|
|
616
|
+
row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
|
|
848
617
|
}
|
|
618
|
+
for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
|
|
619
|
+
}, {}, {
|
|
620
|
+
key: null,
|
|
621
|
+
shallow: !0
|
|
849
622
|
});
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
nodeMap && (nodeMap.delete(connectionKey), nodeMap.size === 0 && connectionLookup.delete(key)), key = `${nodeId}-${type}`;
|
|
891
|
-
let typeMap = connectionLookup.get(key);
|
|
892
|
-
if (typeMap && (typeMap.delete(connectionKey), typeMap.size === 0 && connectionLookup.delete(key)), handleId) {
|
|
893
|
-
key = `${nodeId}-${type}-${handleId}`;
|
|
894
|
-
let handleMap = connectionLookup.get(key);
|
|
895
|
-
handleMap && (handleMap.delete(connectionKey), handleMap.size === 0 && connectionLookup.delete(key));
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
//#endregion
|
|
899
|
-
//#region src/data/createSolidFlow.tsx
|
|
900
|
-
const InitialNodeTypesMap = {
|
|
901
|
-
input: InputNode,
|
|
902
|
-
output: OutputNode,
|
|
903
|
-
default: DefaultNode,
|
|
904
|
-
group: GroupNode
|
|
905
|
-
}, InitialEdgeTypesMap = {
|
|
906
|
-
straight: StraightEdgeInternal,
|
|
907
|
-
smoothstep: SmoothStepEdgeInternal,
|
|
908
|
-
default: BezierEdgeInternal,
|
|
909
|
-
step: StepEdgeInternal
|
|
910
|
-
}, getInitialViewport = (_nodesInitialized, fitView, initialViewport, width, height, nodeLookup) => {
|
|
623
|
+
}, buildRow = (source, edge) => {
|
|
624
|
+
let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
|
|
625
|
+
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
|
+
let edgePosition = getEdgePosition({
|
|
634
|
+
id: edge.id,
|
|
635
|
+
sourceNode,
|
|
636
|
+
targetNode,
|
|
637
|
+
sourceHandle: edge.sourceHandle || null,
|
|
638
|
+
targetHandle: edge.targetHandle || null,
|
|
639
|
+
connectionMode: source.connectionMode,
|
|
640
|
+
onError: source.onError
|
|
641
|
+
});
|
|
642
|
+
return edgePosition ? {
|
|
643
|
+
...source.defaultEdgeOptions,
|
|
644
|
+
...edge,
|
|
645
|
+
...edgePosition,
|
|
646
|
+
zIndex: getElevatedEdgeZIndex({
|
|
647
|
+
selected: edge.selected,
|
|
648
|
+
zIndex: edge.zIndex ?? source.defaultEdgeOptions.zIndex,
|
|
649
|
+
sourceNode,
|
|
650
|
+
targetNode,
|
|
651
|
+
elevateOnSelect: source.elevateEdgesOnSelect,
|
|
652
|
+
zIndexMode: source.zIndexMode
|
|
653
|
+
}),
|
|
654
|
+
sourceNode,
|
|
655
|
+
targetNode,
|
|
656
|
+
edge
|
|
657
|
+
} : null;
|
|
658
|
+
}, createParentIds = (source) => createProjection(() => {
|
|
659
|
+
let out = {};
|
|
660
|
+
for (let node of source.nodes) node.parentId && (out[node.parentId] = !0);
|
|
661
|
+
return out;
|
|
662
|
+
}, {}, { key: "id" }), getInitialViewport = (fitView, initialViewport, width, height, nodeLookup) => {
|
|
911
663
|
if (fitView && !initialViewport && width && height) {
|
|
912
664
|
let bounds = getInternalNodesBounds(nodeLookup, { filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)) });
|
|
913
665
|
return getViewportForBounds$1(bounds, width, height, .5, 2, .1);
|
|
@@ -917,23 +669,44 @@ const InitialNodeTypesMap = {
|
|
|
917
669
|
y: 0,
|
|
918
670
|
zoom: 1
|
|
919
671
|
};
|
|
920
|
-
},
|
|
921
|
-
let _props =
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
672
|
+
}, createFlowState = (props, injections = {}) => {
|
|
673
|
+
let _props = merge(getDefaultFlowStateProps(), props), initialNodeTypes = injections.initialNodeTypes ?? {}, initialEdgeTypes = injections.initialEdgeTypes ?? {}, prefersDark = injections.prefersDark ?? (() => _props.colorModeSSR === "dark"), [config, setConfig] = createSignal(_props), [ariaLabelConfig, setAriaLabelConfig] = createSignal(() => mergeAriaLabelConfig(config().ariaLabelConfig)), [ariaLiveMessage, setAriaLiveMessage] = createSignal(() => config().ariaLiveMessage), [clickConnectStartHandle, setClickConnectStartHandle] = createSignal(void 0), [connection, setConnection] = createSignal(initialConnection), [domNode, setDomNode] = createSignal(null), [dragging, setDragging] = createSignal(!1), [elementsSelectable, setElementsSelectable] = createSignal(() => config().elementsSelectable), [height, setHeight] = createSignal(() => config().height), [minZoom, _setMinZoom] = createSignal(() => config().minZoom), [maxZoom, _setMaxZoom] = createSignal(() => config().maxZoom), [nodesConnectable, setNodesConnectable] = createSignal(() => config().nodesDraggable), [nodesDraggable, setNodesDraggable] = createSignal(() => config().nodesDraggable), [panZoom, setPanZoom] = createSignal(null), [selectionRect, setSelectionRect] = createSignal(), [selectionRectMode, setSelectionRectMode] = createSignal(), [snapGrid, setSnapGrid] = createSignal(() => config().snapGrid), [translateExtent, _setTranslateExtent] = createSignal(() => config().translateExtent ?? infiniteExtent), [width, setWidth] = createSignal(() => config().width), [selectionKeyPressed, setSelectionKeyPressed] = createSignal(!1), [multiselectionKeyPressed, setMultiselectionKeyPressed] = createSignal(!1), [deleteKeyPressed, setDeleteKeyPressed] = createSignal(!1), [panActivationKeyPressed, setPanActivationKeyPressed] = createSignal(!1), [zoomActivationKeyPressed, setZoomActivationKeyPressed] = createSignal(!1), [nodesStore, setNodesStore] = createStore(_props.nodes), [edgesStore, setEdgesStore] = createStore(_props.edges), [measurementsStore, setMeasurementsStore] = createStore({}), internalNodes = createInternalNodes({
|
|
674
|
+
get nodes() {
|
|
675
|
+
return nodesStore;
|
|
676
|
+
},
|
|
677
|
+
get measurements() {
|
|
678
|
+
return measurementsStore;
|
|
679
|
+
},
|
|
680
|
+
get nodeOrigin() {
|
|
681
|
+
return config().nodeOrigin;
|
|
682
|
+
},
|
|
683
|
+
get nodeExtent() {
|
|
684
|
+
return config().nodeExtent;
|
|
685
|
+
},
|
|
686
|
+
get elevateNodesOnSelect() {
|
|
687
|
+
return config().elevateNodesOnSelect;
|
|
688
|
+
},
|
|
689
|
+
get zIndexMode() {
|
|
690
|
+
return config().zIndexMode;
|
|
691
|
+
}
|
|
692
|
+
}), nodeLookup = new RecordMapFacade(internalNodes), initialViewport = getInitialViewport(_props.fitView, _props.initialViewport, _props.width ?? 0, _props.height ?? 0, nodeLookup), [viewportStore, setViewportStore] = createStore(_props.viewport ?? initialViewport);
|
|
693
|
+
createEffect(() => config().nodes, (next) => {
|
|
694
|
+
setNodesStore(() => next);
|
|
695
|
+
}, { defer: !0 }), createEffect(() => config().edges, (next) => {
|
|
696
|
+
setEdgesStore(() => next);
|
|
697
|
+
}, { defer: !0 }), createEffect(() => config().viewport, (next) => {
|
|
698
|
+
next && setViewportStore(() => next);
|
|
699
|
+
}, { defer: !0 });
|
|
700
|
+
let transform = createMemo(() => [
|
|
701
|
+
viewportStore.x,
|
|
702
|
+
viewportStore.y,
|
|
703
|
+
viewportStore.zoom
|
|
931
704
|
]), nodesInitialized = createMemo(() => {
|
|
932
|
-
let nodes =
|
|
705
|
+
let nodes = nodesStore;
|
|
933
706
|
if (nodes.length === 0) return !1;
|
|
934
707
|
for (let node of nodes) if (!node.hidden && (node.measured?.width === void 0 || node.measured?.height === void 0)) return !1;
|
|
935
708
|
return !0;
|
|
936
|
-
}), store =
|
|
709
|
+
}), store = merge({
|
|
937
710
|
width: 0,
|
|
938
711
|
height: 0
|
|
939
712
|
}, config, {
|
|
@@ -962,7 +735,7 @@ const InitialNodeTypesMap = {
|
|
|
962
735
|
return clickConnectStartHandle();
|
|
963
736
|
},
|
|
964
737
|
get colorMode() {
|
|
965
|
-
return this._colorMode === "system" ?
|
|
738
|
+
return this._colorMode === "system" ? prefersDark() ? "dark" : "light" : this._colorMode;
|
|
966
739
|
},
|
|
967
740
|
get connection() {
|
|
968
741
|
let state = connection();
|
|
@@ -979,7 +752,7 @@ const InitialNodeTypesMap = {
|
|
|
979
752
|
},
|
|
980
753
|
get edgeTypes() {
|
|
981
754
|
return {
|
|
982
|
-
...
|
|
755
|
+
...initialEdgeTypes,
|
|
983
756
|
...this._edgeTypes
|
|
984
757
|
};
|
|
985
758
|
},
|
|
@@ -1001,8 +774,11 @@ const InitialNodeTypesMap = {
|
|
|
1001
774
|
get minZoom() {
|
|
1002
775
|
return minZoom();
|
|
1003
776
|
},
|
|
777
|
+
get edges() {
|
|
778
|
+
return edgesStore;
|
|
779
|
+
},
|
|
1004
780
|
get nodes() {
|
|
1005
|
-
return
|
|
781
|
+
return nodesStore;
|
|
1006
782
|
},
|
|
1007
783
|
get nodesConnectable() {
|
|
1008
784
|
return nodesConnectable();
|
|
@@ -1012,7 +788,7 @@ const InitialNodeTypesMap = {
|
|
|
1012
788
|
},
|
|
1013
789
|
get nodeTypes() {
|
|
1014
790
|
return {
|
|
1015
|
-
...
|
|
791
|
+
...initialNodeTypes,
|
|
1016
792
|
...this._nodeTypes
|
|
1017
793
|
};
|
|
1018
794
|
},
|
|
@@ -1020,10 +796,10 @@ const InitialNodeTypesMap = {
|
|
|
1020
796
|
return panZoom();
|
|
1021
797
|
},
|
|
1022
798
|
get selectedNodes() {
|
|
1023
|
-
return
|
|
799
|
+
return nodesStore.filter((node) => node.selected);
|
|
1024
800
|
},
|
|
1025
801
|
get selectedEdges() {
|
|
1026
|
-
return
|
|
802
|
+
return edgesStore.filter((edge) => edge.selected);
|
|
1027
803
|
},
|
|
1028
804
|
get selectionRect() {
|
|
1029
805
|
return selectionRect();
|
|
@@ -1035,7 +811,7 @@ const InitialNodeTypesMap = {
|
|
|
1035
811
|
return snapGrid();
|
|
1036
812
|
},
|
|
1037
813
|
get viewport() {
|
|
1038
|
-
return
|
|
814
|
+
return viewportStore;
|
|
1039
815
|
},
|
|
1040
816
|
get viewportInitialized() {
|
|
1041
817
|
return panZoom() !== null;
|
|
@@ -1076,7 +852,45 @@ const InitialNodeTypesMap = {
|
|
|
1076
852
|
get zoomActivationKeyPressed() {
|
|
1077
853
|
return zoomActivationKeyPressed();
|
|
1078
854
|
}
|
|
1079
|
-
}), visibleNodesMap = createMemo(() => nodeLookup), visibleNodeIds = createMemo(() =>
|
|
855
|
+
}), visibleNodesMap = createMemo(() => nodeLookup), visibleNodeIds = createMemo(() => Object.keys(internalNodes)), parentIds = createParentIds({ get nodes() {
|
|
856
|
+
return store.nodes;
|
|
857
|
+
} }), edgeLookup = createEdgeLookup({ get edges() {
|
|
858
|
+
return store.edges;
|
|
859
|
+
} }), connections = createConnections({ get edges() {
|
|
860
|
+
return store.edges;
|
|
861
|
+
} }), layoutedEdges = createLayoutedEdges({
|
|
862
|
+
get edges() {
|
|
863
|
+
return store.edges;
|
|
864
|
+
},
|
|
865
|
+
get connectionMode() {
|
|
866
|
+
return store.connectionMode;
|
|
867
|
+
},
|
|
868
|
+
get defaultEdgeOptions() {
|
|
869
|
+
return store.defaultEdgeOptions;
|
|
870
|
+
},
|
|
871
|
+
get elevateEdgesOnSelect() {
|
|
872
|
+
return store.elevateEdgesOnSelect;
|
|
873
|
+
},
|
|
874
|
+
get zIndexMode() {
|
|
875
|
+
return store.zIndexMode;
|
|
876
|
+
},
|
|
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
|
+
get onError() {
|
|
890
|
+
return store.onError;
|
|
891
|
+
},
|
|
892
|
+
nodeLookup
|
|
893
|
+
}), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)), getEdge = (id) => layoutedEdges[id], fitView = async (options) => store.panZoom ? await fitViewport({
|
|
1080
894
|
nodes: nodeLookup,
|
|
1081
895
|
width: store.width,
|
|
1082
896
|
height: store.height,
|
|
@@ -1084,55 +898,54 @@ const InitialNodeTypesMap = {
|
|
|
1084
898
|
minZoom: store.minZoom,
|
|
1085
899
|
maxZoom: store.maxZoom
|
|
1086
900
|
}, options ?? config().fitViewOptions) : !1, resetStoreValues = () => {
|
|
1087
|
-
setDragging(!1), setSelectionRect(void 0), setSelectionRectMode(void 0), setSelectionKeyPressed(!1), setMultiselectionKeyPressed(!1), setDeleteKeyPressed(!1), setPanActivationKeyPressed(!1), setZoomActivationKeyPressed(!1), setConnection({ ...initialConnection }), setClickConnectStartHandle(void 0),
|
|
901
|
+
setDragging(!1), setSelectionRect(void 0), setSelectionRectMode(void 0), setSelectionKeyPressed(!1), setMultiselectionKeyPressed(!1), setDeleteKeyPressed(!1), setPanActivationKeyPressed(!1), setZoomActivationKeyPressed(!1), setConnection({ ...initialConnection }), setClickConnectStartHandle(void 0), setViewportStore(() => config().initialViewport ?? {
|
|
1088
902
|
x: 0,
|
|
1089
903
|
y: 0,
|
|
1090
904
|
zoom: 1
|
|
1091
905
|
}), setAriaLiveMessage(""), setSnapGrid(void 0);
|
|
1092
906
|
}, addEdge = (edgeParams) => {
|
|
1093
|
-
|
|
907
|
+
setEdgesStore((edges) => {
|
|
908
|
+
let next = addEdge$1(edgeParams, edges);
|
|
909
|
+
next !== edges && edges.push(next[next.length - 1]);
|
|
910
|
+
});
|
|
1094
911
|
}, initialFitViewApplied = !1, initialNodesMeasured = !1, applyInitialFitView = (initialFitView) => {
|
|
1095
912
|
initialFitViewApplied = !initialFitView;
|
|
1096
913
|
}, tryInitialFitView = () => {
|
|
1097
914
|
initialFitViewApplied || !initialNodesMeasured || untrack(() => store.panZoom && store.width && store.height) && (initialFitViewApplied = !0, untrack(() => fitView()));
|
|
1098
915
|
}, updateNodePositions = (nodeDragItems, dragging = !1) => {
|
|
1099
|
-
|
|
1100
|
-
node.dragging = dragging, node.position = nodeDragItems.get(node.id).position;
|
|
1101
|
-
})
|
|
1102
|
-
},
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
let { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, store.domNode, store.nodeOrigin);
|
|
1112
|
-
if (!updatedInternals) return;
|
|
1113
|
-
updateAbsolutePositions(nodeLookup, parentLookup, {
|
|
1114
|
-
nodeOrigin: store.nodeOrigin,
|
|
1115
|
-
nodeExtent: store.nodeExtent,
|
|
1116
|
-
zIndexMode: store.zIndexMode
|
|
1117
|
-
});
|
|
1118
|
-
let nodeToChange = changes.reduce((acc, change) => {
|
|
1119
|
-
let node = nodeLookup.get(change.id)?.internals.userNode;
|
|
1120
|
-
return node && acc.set(node.id, change), acc;
|
|
1121
|
-
}, /* @__PURE__ */ new Map());
|
|
1122
|
-
nodesMemo.set((node) => nodeToChange.has(node.id), produce((node) => {
|
|
1123
|
-
let change = nodeToChange.get(node.id);
|
|
1124
|
-
switch (change.type) {
|
|
1125
|
-
case "dimensions":
|
|
1126
|
-
change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
|
|
1127
|
-
...node.measured,
|
|
1128
|
-
...change.dimensions
|
|
1129
|
-
};
|
|
1130
|
-
break;
|
|
1131
|
-
case "position": node.position = change.position ?? node.position;
|
|
1132
|
-
}
|
|
1133
|
-
})), initialNodesMeasured = !0, tryInitialFitView();
|
|
1134
|
-
});
|
|
916
|
+
setNodesStore((nodes) => {
|
|
917
|
+
for (let node of nodes) nodeDragItems.has(node.id) && (node.dragging = dragging, node.position = nodeDragItems.get(node.id).position);
|
|
918
|
+
});
|
|
919
|
+
}, applyMeasurementWrites = (writes) => {
|
|
920
|
+
setMeasurementsStore((draft) => {
|
|
921
|
+
for (let write of writes) if (write.hidden) {
|
|
922
|
+
let entry = draft[write.id];
|
|
923
|
+
entry && (entry.handleBounds = void 0);
|
|
924
|
+
} else draft[write.id] = {
|
|
925
|
+
measured: write.measured,
|
|
926
|
+
handleBounds: write.handleBounds
|
|
927
|
+
};
|
|
1135
928
|
});
|
|
929
|
+
}, applyNodeChanges = (changes) => {
|
|
930
|
+
changes.length !== 0 && setNodesStore((nodes) => {
|
|
931
|
+
let nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
932
|
+
for (let change of changes) {
|
|
933
|
+
let node = nodeById.get(change.id);
|
|
934
|
+
if (node) switch (change.type) {
|
|
935
|
+
case "dimensions":
|
|
936
|
+
change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
|
|
937
|
+
...node.measured,
|
|
938
|
+
...change.dimensions
|
|
939
|
+
};
|
|
940
|
+
break;
|
|
941
|
+
case "position": node.position = change.position ?? node.position;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
}, markInitialNodesMeasured = () => {
|
|
946
|
+
initialNodesMeasured = !0, tryInitialFitView();
|
|
947
|
+
}, requestMeasure = () => {}, setMeasureRequester = (fn) => {
|
|
948
|
+
requestMeasure = fn;
|
|
1136
949
|
}, zoomBy = async (factor, options) => store.panZoom ? store.panZoom.scaleBy(factor, options) : !1, zoomIn = (options) => zoomBy(1.2, options), zoomOut = (options) => zoomBy(1 / 1.2, options), setCenter = async (x, y, options) => {
|
|
1137
950
|
let nextZoom = options?.zoom === void 0 ? store.maxZoom : options.zoom, currentPanZoom = store.panZoom;
|
|
1138
951
|
return currentPanZoom ? (await currentPanZoom.setViewport({
|
|
@@ -1148,232 +961,876 @@ const InitialNodeTypesMap = {
|
|
|
1148
961
|
store.panZoom?.setClickDistance(distance);
|
|
1149
962
|
}, unselectNodesAndEdges = ({ nodes: _nodes, edges } = {}) => {
|
|
1150
963
|
let nodesToUnselect = new Set((_nodes || store.nodes).map(({ id }) => id));
|
|
1151
|
-
nodesToUnselect.size &&
|
|
1152
|
-
node.selected = !1;
|
|
1153
|
-
})
|
|
1154
|
-
let edgesToUnselect = new Set((edges
|
|
1155
|
-
edgesToUnselect.size &&
|
|
1156
|
-
edge.selected = !1;
|
|
1157
|
-
}));
|
|
964
|
+
nodesToUnselect.size && setNodesStore((nodes) => {
|
|
965
|
+
for (let node of nodes) nodesToUnselect.has(node.id) && (node.selected = !1);
|
|
966
|
+
});
|
|
967
|
+
let edgesToUnselect = new Set((edges ?? store.edges).map(({ id }) => id));
|
|
968
|
+
edgesToUnselect.size && setEdgesStore((edges) => {
|
|
969
|
+
for (let edge of edges) edgesToUnselect.has(edge.id) && (edge.selected = !1);
|
|
970
|
+
}), flush();
|
|
1158
971
|
}, addSelectedNodes = (ids) => {
|
|
1159
|
-
let isMultiSelection = store.multiselectionKeyPressed
|
|
1160
|
-
|
|
1161
|
-
let
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
})), isMultiSelection || unselectNodesAndEdges({ nodes: [] });
|
|
972
|
+
let isMultiSelection = store.multiselectionKeyPressed;
|
|
973
|
+
setNodesStore((nodes) => {
|
|
974
|
+
for (let node of nodes) {
|
|
975
|
+
let nodeWillBeSelected = ids.includes(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
|
|
976
|
+
node.selected !== selected && (node.selected = selected);
|
|
977
|
+
}
|
|
978
|
+
}), isMultiSelection || unselectNodesAndEdges({ nodes: [] }), flush();
|
|
1167
979
|
}, addSelectedEdges = (ids) => {
|
|
1168
|
-
let isMultiSelection = store.multiselectionKeyPressed
|
|
1169
|
-
|
|
1170
|
-
let
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
})
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
}));
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
980
|
+
let isMultiSelection = store.multiselectionKeyPressed;
|
|
981
|
+
setEdgesStore((edges) => {
|
|
982
|
+
for (let edge of edges) {
|
|
983
|
+
let edgeWillBeSelected = ids.includes(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
|
|
984
|
+
edge.selected !== selected && (edge.selected = selected);
|
|
985
|
+
}
|
|
986
|
+
}), isMultiSelection || unselectNodesAndEdges({ edges: [] }), flush();
|
|
987
|
+
}, handleNodeSelection = (id, unselect, nodeRef) => {
|
|
988
|
+
let node = store.nodes.find((n) => n.id === id);
|
|
989
|
+
node && (setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
|
|
990
|
+
nodes: [node],
|
|
991
|
+
edges: []
|
|
992
|
+
}), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
|
|
993
|
+
}, handleEdgeSelection = (id) => {
|
|
994
|
+
let edge = edgeLookup[id];
|
|
995
|
+
edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
|
|
996
|
+
nodes: [],
|
|
997
|
+
edges: [edge]
|
|
998
|
+
}) : addSelectedEdges([id]));
|
|
999
|
+
}, moveSelectedNodes = (direction, factor) => {
|
|
1000
|
+
let nodeUpdates = /* @__PURE__ */ new Map(), xVelo = store.snapGrid?.[0] ?? 5, yVelo = store.snapGrid?.[1] ?? 5, xDiff = direction.x * xVelo * factor, yDiff = direction.y * yVelo * factor;
|
|
1001
|
+
for (let node of nodeLookup.values()) {
|
|
1002
|
+
if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
|
|
1003
|
+
let nextPosition = {
|
|
1004
|
+
x: node.internals.positionAbsolute.x + xDiff,
|
|
1005
|
+
y: node.internals.positionAbsolute.y + yDiff
|
|
1006
|
+
};
|
|
1007
|
+
store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
|
|
1008
|
+
let { position } = calculateNodePosition({
|
|
1009
|
+
nodeId: node.id,
|
|
1010
|
+
nextPosition,
|
|
1011
|
+
nodeLookup,
|
|
1012
|
+
nodeExtent: store.nodeExtent,
|
|
1013
|
+
nodeOrigin: store.nodeOrigin,
|
|
1014
|
+
onError: store.onError
|
|
1015
|
+
});
|
|
1016
|
+
nodeUpdates.set(node.id, { position });
|
|
1017
|
+
}
|
|
1018
|
+
updateNodePositions(nodeUpdates);
|
|
1019
|
+
}, panBy$1 = (delta) => panBy({
|
|
1020
|
+
delta,
|
|
1021
|
+
panZoom: store.panZoom,
|
|
1022
|
+
transform: store.transform,
|
|
1023
|
+
translateExtent: store.translateExtent,
|
|
1024
|
+
width: store.width,
|
|
1025
|
+
height: store.height
|
|
1026
|
+
}), cancelConnection = () => {
|
|
1027
|
+
setConnection({ ...initialConnection });
|
|
1028
|
+
}, reset = () => {
|
|
1029
|
+
resetStoreValues(), unselectNodesAndEdges();
|
|
1030
|
+
}, flow = {
|
|
1031
|
+
get nodes() {
|
|
1032
|
+
return store.nodes;
|
|
1033
|
+
},
|
|
1034
|
+
get edges() {
|
|
1035
|
+
return store.edges;
|
|
1036
|
+
},
|
|
1037
|
+
get internalNodes() {
|
|
1038
|
+
return internalNodes;
|
|
1039
|
+
},
|
|
1040
|
+
get layoutedEdges() {
|
|
1041
|
+
return layoutedEdges;
|
|
1042
|
+
},
|
|
1043
|
+
get connections() {
|
|
1044
|
+
return connections;
|
|
1045
|
+
},
|
|
1046
|
+
selection: {
|
|
1047
|
+
get nodes() {
|
|
1048
|
+
return store.selectedNodes;
|
|
1049
|
+
},
|
|
1050
|
+
get edges() {
|
|
1051
|
+
return store.selectedEdges;
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
get nodesInitialized() {
|
|
1055
|
+
return store.nodesInitialized;
|
|
1056
|
+
},
|
|
1057
|
+
get viewportInitialized() {
|
|
1058
|
+
return store.viewportInitialized;
|
|
1059
|
+
},
|
|
1060
|
+
get viewport() {
|
|
1061
|
+
return store.viewport;
|
|
1062
|
+
},
|
|
1063
|
+
get width() {
|
|
1064
|
+
return store.width;
|
|
1065
|
+
},
|
|
1066
|
+
get height() {
|
|
1067
|
+
return store.height;
|
|
1068
|
+
},
|
|
1069
|
+
get colorMode() {
|
|
1070
|
+
return store.colorMode;
|
|
1071
|
+
},
|
|
1072
|
+
get connection() {
|
|
1073
|
+
return store.connection;
|
|
1074
|
+
},
|
|
1075
|
+
get dragging() {
|
|
1076
|
+
return store.dragging;
|
|
1077
|
+
},
|
|
1078
|
+
get minZoom() {
|
|
1079
|
+
return store.minZoom;
|
|
1080
|
+
},
|
|
1081
|
+
get maxZoom() {
|
|
1082
|
+
return store.maxZoom;
|
|
1083
|
+
},
|
|
1084
|
+
get nodesDraggable() {
|
|
1085
|
+
return store.nodesDraggable;
|
|
1086
|
+
},
|
|
1087
|
+
get nodesConnectable() {
|
|
1088
|
+
return store.nodesConnectable;
|
|
1089
|
+
},
|
|
1090
|
+
get elementsSelectable() {
|
|
1091
|
+
return store.elementsSelectable;
|
|
1092
|
+
},
|
|
1093
|
+
get snapGrid() {
|
|
1094
|
+
return store.snapGrid;
|
|
1095
|
+
}
|
|
1096
|
+
}, getNodeRect = (node) => {
|
|
1097
|
+
let nodeToUse = isNode(node) ? node : nodeLookup.get(node.id), position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, store.nodeOrigin) : nodeToUse.position, nodeWithPosition = {
|
|
1098
|
+
...nodeToUse,
|
|
1099
|
+
position,
|
|
1100
|
+
width: nodeToUse.measured?.width ?? nodeToUse.width,
|
|
1101
|
+
height: nodeToUse.measured?.height ?? nodeToUse.height
|
|
1102
|
+
};
|
|
1103
|
+
return nodeToRect(nodeWithPosition);
|
|
1104
|
+
}, updateNode = (id, nodeUpdate, options = { replace: !1 }) => {
|
|
1105
|
+
setNodesStore((nodes) => {
|
|
1106
|
+
let index = nodes.findIndex((node) => node.id === id);
|
|
1107
|
+
if (index === -1) return;
|
|
1108
|
+
let node = nodes[index], nextNode = typeof nodeUpdate == "function" ? nodeUpdate(node) : nodeUpdate;
|
|
1109
|
+
nodes[index] = options?.replace && isNode(nextNode) ? nextNode : {
|
|
1110
|
+
...node,
|
|
1111
|
+
...nextNode
|
|
1112
|
+
};
|
|
1113
|
+
});
|
|
1114
|
+
}, commands = {
|
|
1115
|
+
fitView,
|
|
1116
|
+
fitBounds: async (bounds, options) => {
|
|
1117
|
+
if (!store.panZoom) return !1;
|
|
1118
|
+
let viewport = getViewportForBounds$1(bounds, store.width, store.height, store.minZoom, store.maxZoom, options?.padding ?? .1);
|
|
1119
|
+
return await store.panZoom.setViewport(viewport, {
|
|
1120
|
+
duration: options?.duration,
|
|
1121
|
+
ease: options?.ease,
|
|
1122
|
+
interpolate: options?.interpolate
|
|
1123
|
+
}), !0;
|
|
1124
|
+
},
|
|
1125
|
+
zoomIn,
|
|
1126
|
+
zoomOut,
|
|
1127
|
+
setZoom: (zoomLevel, options) => {
|
|
1128
|
+
let currentPanZoom = store.panZoom;
|
|
1129
|
+
return currentPanZoom ? currentPanZoom.scaleTo(zoomLevel, { duration: options?.duration }) : Promise.resolve(!1);
|
|
1130
|
+
},
|
|
1131
|
+
setCenter,
|
|
1132
|
+
setViewport: async (nextViewport, options) => {
|
|
1133
|
+
let currentViewport = store.viewport;
|
|
1134
|
+
return store.panZoom ? (await store.panZoom.setViewport({
|
|
1135
|
+
x: nextViewport.x ?? currentViewport.x,
|
|
1136
|
+
y: nextViewport.y ?? currentViewport.y,
|
|
1137
|
+
zoom: nextViewport.zoom ?? currentViewport.zoom
|
|
1138
|
+
}, options), !0) : !1;
|
|
1139
|
+
},
|
|
1140
|
+
panBy: panBy$1,
|
|
1141
|
+
screenToFlowPosition: (position, options = { snapToGrid: !0 }) => {
|
|
1142
|
+
if (!store.domNode) return position;
|
|
1143
|
+
let _snapGrid = options.snapToGrid ? store.snapGrid : !1, { x, y, zoom } = store.viewport, { x: domX, y: domY } = store.domNode.getBoundingClientRect(), correctedPosition = {
|
|
1144
|
+
x: position.x - domX,
|
|
1145
|
+
y: position.y - domY
|
|
1146
|
+
};
|
|
1147
|
+
return pointToRendererPoint(correctedPosition, [
|
|
1148
|
+
x,
|
|
1149
|
+
y,
|
|
1150
|
+
zoom
|
|
1151
|
+
], _snapGrid !== null, _snapGrid || [1, 1]);
|
|
1152
|
+
},
|
|
1153
|
+
flowToScreenPosition: (position) => {
|
|
1154
|
+
if (!store.domNode) return position;
|
|
1155
|
+
let { x, y, zoom } = store.viewport, { x: domX, y: domY } = store.domNode.getBoundingClientRect(), rendererPosition = rendererPointToPoint(position, [
|
|
1156
|
+
x,
|
|
1157
|
+
y,
|
|
1158
|
+
zoom
|
|
1159
|
+
]);
|
|
1160
|
+
return {
|
|
1161
|
+
x: rendererPosition.x + domX,
|
|
1162
|
+
y: rendererPosition.y + domY
|
|
1163
|
+
};
|
|
1164
|
+
},
|
|
1165
|
+
addNodes: (payload) => {
|
|
1166
|
+
let newNodes = Array.isArray(payload) ? payload : [payload];
|
|
1167
|
+
setNodesStore((nodes) => [...nodes, ...newNodes]);
|
|
1168
|
+
},
|
|
1169
|
+
addEdges: (payload) => {
|
|
1170
|
+
let newEdges = Array.isArray(payload) ? payload : [payload];
|
|
1171
|
+
setEdgesStore((edges) => [...edges, ...newEdges]);
|
|
1172
|
+
},
|
|
1173
|
+
setNodes: setNodesStore,
|
|
1174
|
+
setEdges: setEdgesStore,
|
|
1175
|
+
updateNode,
|
|
1176
|
+
updateNodeData: (id, dataUpdate, options) => {
|
|
1177
|
+
let node = nodeLookup.get(id)?.internals.userNode;
|
|
1178
|
+
if (!node) return;
|
|
1179
|
+
let nextData = typeof dataUpdate == "function" ? dataUpdate(node) : dataUpdate;
|
|
1180
|
+
updateNode(id, (current) => ({
|
|
1181
|
+
...current,
|
|
1182
|
+
data: options?.replace ? nextData : {
|
|
1183
|
+
...current.data,
|
|
1184
|
+
...nextData
|
|
1185
|
+
}
|
|
1186
|
+
}));
|
|
1187
|
+
},
|
|
1188
|
+
updateEdge: (id, edgeUpdate, options = { replace: !1 }) => {
|
|
1189
|
+
setEdgesStore((edges) => {
|
|
1190
|
+
let index = edges.findIndex((edge) => edge.id === id);
|
|
1191
|
+
if (index === -1) return;
|
|
1192
|
+
let edge = edges[index], nextEdge = typeof edgeUpdate == "function" ? edgeUpdate(edge) : edgeUpdate;
|
|
1193
|
+
edges[index] = options.replace && isEdge(nextEdge) ? nextEdge : {
|
|
1194
|
+
...edge,
|
|
1195
|
+
...nextEdge
|
|
1196
|
+
};
|
|
1197
|
+
});
|
|
1198
|
+
},
|
|
1199
|
+
deleteElements: async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
|
|
1200
|
+
let { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
|
|
1201
|
+
nodesToRemove,
|
|
1202
|
+
edgesToRemove,
|
|
1203
|
+
nodes: store.nodes,
|
|
1204
|
+
edges: store.edges,
|
|
1205
|
+
onBeforeDelete: store.onBeforeDelete
|
|
1206
|
+
});
|
|
1207
|
+
if (matchingEdges) {
|
|
1208
|
+
let remainingEdges = store.edges.filter((edge) => !matchingEdges.some(({ id }) => id === edge.id));
|
|
1209
|
+
store.onEdgesDelete?.(matchingEdges), setEdgesStore(() => remainingEdges);
|
|
1210
|
+
}
|
|
1211
|
+
if (matchingNodes) {
|
|
1212
|
+
let remainingNodes = store.nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id));
|
|
1213
|
+
store.onNodesDelete?.(matchingNodes), setNodesStore(() => remainingNodes);
|
|
1214
|
+
}
|
|
1215
|
+
return {
|
|
1216
|
+
deletedNodes: matchingNodes,
|
|
1217
|
+
deletedEdges: matchingEdges
|
|
1218
|
+
};
|
|
1219
|
+
},
|
|
1220
|
+
getIntersectingNodes: (nodeOrRect, partially = !0, nodesToIntersect) => {
|
|
1221
|
+
let isRect = isRectObject(nodeOrRect), nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
|
|
1222
|
+
return nodeRect ? (nodesToIntersect || store.nodes).filter((n) => {
|
|
1223
|
+
let internalNode = nodeLookup.get(n.id);
|
|
1224
|
+
if (!internalNode || !isRect && n.id === nodeOrRect.id) return !1;
|
|
1225
|
+
let currNodeRect = nodeToRect(internalNode), overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
|
|
1226
|
+
return partially && overlappingArea > 0 || overlappingArea >= nodeRect.width * nodeRect.height;
|
|
1227
|
+
}) : [];
|
|
1228
|
+
},
|
|
1229
|
+
isNodeIntersecting: (nodeOrRect, area, partially = !0) => {
|
|
1230
|
+
let nodeRect = isRectObject(nodeOrRect) ? nodeOrRect : getNodeRect(nodeOrRect);
|
|
1231
|
+
if (!nodeRect) return !1;
|
|
1232
|
+
let overlappingArea = getOverlappingArea(nodeRect, area);
|
|
1233
|
+
return partially && overlappingArea > 0 || overlappingArea >= nodeRect.width * nodeRect.height;
|
|
1234
|
+
},
|
|
1235
|
+
getNodesBounds: (nodesToMeasure) => getNodesBounds$1(nodesToMeasure, {
|
|
1236
|
+
nodeLookup,
|
|
1237
|
+
nodeOrigin: store.nodeOrigin
|
|
1238
|
+
}),
|
|
1239
|
+
updateNodeInternals: (id) => {
|
|
1240
|
+
let updateIds = Array.isArray(id) ? id : [id], updates = [];
|
|
1241
|
+
for (let updateId of updateIds) {
|
|
1242
|
+
let nodeElement = store.domNode?.querySelector(`.solid-flow__node[data-id="${updateId}"]`);
|
|
1243
|
+
nodeElement && updates.push([updateId, {
|
|
1244
|
+
id: updateId,
|
|
1245
|
+
nodeElement,
|
|
1246
|
+
force: !0
|
|
1247
|
+
}]);
|
|
1248
|
+
}
|
|
1249
|
+
requestMeasure(updates);
|
|
1250
|
+
},
|
|
1251
|
+
toObject: () => structuredClone({
|
|
1252
|
+
nodes: [...snapshot(store.nodes)],
|
|
1253
|
+
edges: [...snapshot(store.edges)],
|
|
1254
|
+
viewport: { ...snapshot(store.viewport) }
|
|
1255
|
+
})
|
|
1256
|
+
};
|
|
1257
|
+
return createEffect(() => !!(width() && height() && panZoom()), (ready) => {
|
|
1258
|
+
ready && tryInitialFitView();
|
|
1259
|
+
}), createEffect(() => ({
|
|
1260
|
+
panZoom: store.panZoom,
|
|
1261
|
+
viewport: {
|
|
1262
|
+
x: store.viewport.x,
|
|
1263
|
+
y: store.viewport.y,
|
|
1264
|
+
zoom: store.viewport.zoom
|
|
1265
|
+
}
|
|
1266
|
+
}), ({ panZoom, viewport }) => {
|
|
1267
|
+
panZoom?.syncViewport(viewport);
|
|
1268
|
+
}), createEffect(() => ({
|
|
1269
|
+
panZoom: panZoom(),
|
|
1270
|
+
extent: [store.minZoom, store.maxZoom]
|
|
1271
|
+
}), ({ panZoom, extent }) => {
|
|
1272
|
+
panZoom?.setScaleExtent(extent);
|
|
1273
|
+
}), createEffect(() => ({
|
|
1274
|
+
panZoom: panZoom(),
|
|
1275
|
+
extent: store.translateExtent
|
|
1276
|
+
}), ({ panZoom, extent }) => {
|
|
1277
|
+
panZoom?.setTranslateExtent(extent);
|
|
1278
|
+
}), createEffect(() => new Set(store.nodes.map((n) => n.id)), (currentIds) => {
|
|
1279
|
+
setMeasurementsStore((draft) => {
|
|
1280
|
+
for (let id of Object.keys(draft)) currentIds.has(id) || delete draft[id];
|
|
1281
|
+
});
|
|
1282
|
+
}), {
|
|
1283
|
+
store,
|
|
1284
|
+
flow,
|
|
1285
|
+
commands,
|
|
1286
|
+
internalNodes,
|
|
1287
|
+
layoutedEdges,
|
|
1288
|
+
nodeLookup,
|
|
1289
|
+
edgeLookup,
|
|
1290
|
+
parentIds,
|
|
1291
|
+
connections,
|
|
1292
|
+
actions: {
|
|
1293
|
+
getEdge,
|
|
1294
|
+
applyInitialFitView,
|
|
1295
|
+
applyMeasurementWrites,
|
|
1296
|
+
applyNodeChanges,
|
|
1297
|
+
markInitialNodesMeasured,
|
|
1298
|
+
setMeasureRequester,
|
|
1299
|
+
resetStoreValues,
|
|
1300
|
+
setAriaLabelConfig,
|
|
1301
|
+
setAriaLiveMessage,
|
|
1302
|
+
setClickConnectStartHandle,
|
|
1303
|
+
setConfig,
|
|
1304
|
+
setConnection,
|
|
1305
|
+
setDeleteKeyPressed,
|
|
1306
|
+
setDomNode,
|
|
1307
|
+
setDragging,
|
|
1308
|
+
get setEdges() {
|
|
1309
|
+
return setEdgesStore;
|
|
1310
|
+
},
|
|
1311
|
+
setElementsSelectable,
|
|
1312
|
+
setHeight,
|
|
1313
|
+
setMultiselectionKeyPressed,
|
|
1314
|
+
get setNodes() {
|
|
1315
|
+
return setNodesStore;
|
|
1316
|
+
},
|
|
1317
|
+
setNodesConnectable,
|
|
1318
|
+
setNodesDraggable,
|
|
1319
|
+
setPanActivationKeyPressed,
|
|
1320
|
+
setPanZoom,
|
|
1321
|
+
setSelectionKeyPressed,
|
|
1322
|
+
setSelectionRect,
|
|
1323
|
+
setSelectionRectMode,
|
|
1324
|
+
get setViewport() {
|
|
1325
|
+
return (viewport) => setViewportStore(() => viewport);
|
|
1326
|
+
},
|
|
1327
|
+
setWidth,
|
|
1328
|
+
setZoomActivationKeyPressed,
|
|
1329
|
+
addEdge,
|
|
1330
|
+
updateNodePositions,
|
|
1331
|
+
zoomIn,
|
|
1332
|
+
zoomOut,
|
|
1333
|
+
fitView,
|
|
1334
|
+
setCenter,
|
|
1335
|
+
setPaneClickDistance,
|
|
1336
|
+
unselectNodesAndEdges,
|
|
1337
|
+
addSelectedNodes,
|
|
1338
|
+
addSelectedEdges,
|
|
1339
|
+
handleNodeSelection,
|
|
1340
|
+
handleEdgeSelection,
|
|
1341
|
+
moveSelectedNodes,
|
|
1342
|
+
panBy: panBy$1,
|
|
1343
|
+
cancelConnection,
|
|
1344
|
+
reset
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
}, getEdgeId = (connection) => {
|
|
1348
|
+
let { source, sourceHandle, target, targetHandle } = connection;
|
|
1349
|
+
return `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
|
|
1350
|
+
}, NodeConnectableContext = createContext(null);
|
|
1351
|
+
function useNodeConnectable() {
|
|
1352
|
+
let ctx = useContext(NodeConnectableContext);
|
|
1353
|
+
if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useNodeConnectable");
|
|
1354
|
+
return ctx;
|
|
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
|
|
1413
|
+
});
|
|
1414
|
+
}, onClick = (event) => {
|
|
1415
|
+
if (!nodeId() || !store.clickConnectStartHandle && !_props.isConnectableStart) return;
|
|
1416
|
+
if (!store.clickConnectStartHandle) {
|
|
1417
|
+
store.onClickConnectStart?.(event, {
|
|
1418
|
+
nodeId: nodeId(),
|
|
1419
|
+
handleId: handleId(),
|
|
1420
|
+
handleType: _props.type
|
|
1421
|
+
}), actions.setClickConnectStartHandle({
|
|
1422
|
+
nodeId: nodeId(),
|
|
1423
|
+
type: _props.type,
|
|
1424
|
+
id: handleId()
|
|
1425
|
+
});
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
let doc = getHostForElement(event.target), isValidConnectionHandler = _props.isValidConnection ?? store.isValidConnection, { connection, isValid } = XYHandle.isValid(event, {
|
|
1429
|
+
handle: {
|
|
1430
|
+
nodeId: nodeId(),
|
|
1431
|
+
id: handleId(),
|
|
1432
|
+
type: _props.type
|
|
1433
|
+
},
|
|
1434
|
+
connectionMode: store.connectionMode,
|
|
1435
|
+
fromNodeId: store.clickConnectStartHandle.nodeId,
|
|
1436
|
+
fromHandleId: store.clickConnectStartHandle.id ?? null,
|
|
1437
|
+
fromType: store.clickConnectStartHandle.type,
|
|
1438
|
+
isValidConnection: isValidConnectionHandler,
|
|
1439
|
+
flowId: store.id,
|
|
1440
|
+
doc,
|
|
1441
|
+
lib: store.lib,
|
|
1442
|
+
nodeLookup
|
|
1443
|
+
});
|
|
1444
|
+
isValid && connection && onConnectExtended(connection);
|
|
1445
|
+
let connectionClone = structuredClone(snapshot(store.connection));
|
|
1446
|
+
delete connectionClone.inProgress, connectionClone.toPosition = connectionClone.toHandle ? connectionClone.toHandle.position : null, store.onClickConnectEnd?.(event, connectionClone), actions.setClickConnectStartHandle(void 0);
|
|
1447
|
+
}, connectionIndicator = () => connectable() && (!connectionInProcess() || isPossibleTargetHandle()) && (connectionInProcess() || store.clickConnectStartHandle ? _props.isConnectableEnd : _props.isConnectableStart);
|
|
1448
|
+
return <div {...rest} role="button" aria-label={store.ariaLabelConfig["handle.ariaLabel"]} tabindex={-1} data-handleid={handleId()} data-nodeid={nodeId()} data-handlepos={_props.position} data-id={`${store.id}-${nodeId()}-${_props.id || null}-${_props.type}`} onClick={store.clickConnect ? onClick : void 0} onPointerDown={onPointerDown} style={_props.style} class={[
|
|
1449
|
+
"solid-flow__handle",
|
|
1450
|
+
`solid-flow__handle-${_props.position}`,
|
|
1451
|
+
store.noDragClass,
|
|
1452
|
+
store.noPanClass,
|
|
1453
|
+
_props.class,
|
|
1454
|
+
{
|
|
1455
|
+
valid: valid(),
|
|
1456
|
+
connectingto: !!connectingTo(),
|
|
1457
|
+
connectingfrom: !!connectingFrom(),
|
|
1458
|
+
source: !isTarget(),
|
|
1459
|
+
target: isTarget(),
|
|
1460
|
+
connectablestart: _props.isConnectableStart,
|
|
1461
|
+
connectableend: _props.isConnectableEnd,
|
|
1462
|
+
connectable: !!connectable(),
|
|
1463
|
+
connectionindicator: connectionIndicator()
|
|
1464
|
+
}
|
|
1465
|
+
]}>
|
|
1466
|
+
{_props.children}
|
|
1467
|
+
</div>;
|
|
1468
|
+
}, DefaultNode = (props) => {
|
|
1469
|
+
let _props = propDefaults(props, {
|
|
1470
|
+
targetPosition: Position$1.Top,
|
|
1471
|
+
sourcePosition: Position$1.Bottom
|
|
1472
|
+
});
|
|
1473
|
+
return <>
|
|
1474
|
+
<Handle type="target" position={_props.targetPosition} isConnectable={_props.isConnectable} />
|
|
1475
|
+
{props.data.label}
|
|
1476
|
+
<Handle type="source" position={_props.sourcePosition} isConnectable={_props.isConnectable} />
|
|
1477
|
+
</>;
|
|
1478
|
+
}, GroupNode = (props) => <div style={{
|
|
1479
|
+
position: "absolute",
|
|
1480
|
+
left: 0,
|
|
1481
|
+
top: 0,
|
|
1482
|
+
width: toPxString(props.width),
|
|
1483
|
+
height: toPxString(props.height)
|
|
1484
|
+
}} />, InputNode = (props) => {
|
|
1485
|
+
let _props = propDefaults(props, { sourcePosition: Position$1.Bottom });
|
|
1486
|
+
return <>
|
|
1487
|
+
{props.data?.label}
|
|
1488
|
+
<Handle type="source" position={_props.sourcePosition} isConnectable={_props.isConnectable} />
|
|
1489
|
+
</>;
|
|
1490
|
+
}, createDraggable = (elem, params) => {
|
|
1491
|
+
let { store, nodeLookup, actions } = useInternalSolidFlow(), [dragging, setDragging] = createSignal(!1);
|
|
1492
|
+
return createEffect(() => ({
|
|
1493
|
+
el: elem(),
|
|
1494
|
+
current: params()
|
|
1495
|
+
}), ({ el, current }) => {
|
|
1496
|
+
if (!el || current.disabled) return;
|
|
1497
|
+
let { onDrag, onDragStart, onDragStop, onNodeMouseDown } = current, dragInstance = XYDrag({
|
|
1498
|
+
onDrag,
|
|
1499
|
+
onDragStart: (event, dragItems, node, nodes) => {
|
|
1500
|
+
setDragging(!0), onDragStart?.(event, dragItems, node, nodes);
|
|
1501
|
+
},
|
|
1502
|
+
onDragStop: (event, dragItems, node, nodes) => {
|
|
1503
|
+
setDragging(!1), onDragStop?.(event, dragItems, node, nodes);
|
|
1504
|
+
},
|
|
1505
|
+
onNodeMouseDown,
|
|
1506
|
+
getStoreItems: () => ({
|
|
1507
|
+
nodes: store.nodes,
|
|
1508
|
+
nodeLookup,
|
|
1509
|
+
edges: store.edges,
|
|
1510
|
+
nodeExtent: store.nodeExtent,
|
|
1511
|
+
snapGrid: store.snapGrid ?? [0, 0],
|
|
1512
|
+
snapToGrid: !!store.snapGrid,
|
|
1513
|
+
autoPanSpeed: store.autoPanSpeed,
|
|
1514
|
+
nodeOrigin: store.nodeOrigin,
|
|
1515
|
+
multiSelectionActive: store.multiselectionKeyPressed,
|
|
1516
|
+
domNode: store.domNode,
|
|
1517
|
+
transform: store.transform,
|
|
1518
|
+
autoPanOnNodeDrag: store.autoPanOnNodeDrag,
|
|
1519
|
+
nodesDraggable: store.nodesDraggable,
|
|
1520
|
+
selectNodesOnDrag: store.selectNodesOnDrag,
|
|
1521
|
+
nodeDragThreshold: store.nodeDragThreshold,
|
|
1522
|
+
unselectNodesAndEdges: actions.unselectNodesAndEdges,
|
|
1523
|
+
updateNodePositions: actions.updateNodePositions,
|
|
1524
|
+
panBy: actions.panBy
|
|
1525
|
+
})
|
|
1526
|
+
});
|
|
1527
|
+
return dragInstance.update({
|
|
1528
|
+
domNode: el,
|
|
1529
|
+
nodeId: current.nodeId,
|
|
1530
|
+
noDragClassName: current.noDragClass,
|
|
1531
|
+
handleSelector: current.handleSelector,
|
|
1532
|
+
isSelectable: current.isSelectable,
|
|
1533
|
+
nodeClickDistance: current.nodeClickDistance
|
|
1534
|
+
}), () => {
|
|
1535
|
+
dragInstance.destroy();
|
|
1536
|
+
};
|
|
1537
|
+
}), dragging;
|
|
1538
|
+
}, NodeIdContext = createContext(null);
|
|
1539
|
+
function useNodeId() {
|
|
1540
|
+
let ctx = useContext(NodeIdContext);
|
|
1541
|
+
if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useNodeId");
|
|
1542
|
+
return ctx;
|
|
1543
|
+
}
|
|
1544
|
+
//#endregion
|
|
1545
|
+
//#region src/components/graph/node/NodeWrapper.tsx
|
|
1546
|
+
const NodeWrapper = (props) => {
|
|
1547
|
+
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
|
+
let { x, y } = node().internals.positionAbsolute;
|
|
1549
|
+
return `translate(${x}px, ${y}px)`;
|
|
1550
|
+
}, sizeStyle = () => {
|
|
1551
|
+
let w = node().width ?? node().initialWidth, h = node().height ?? node().initialHeight;
|
|
1552
|
+
return {
|
|
1553
|
+
...node().style,
|
|
1554
|
+
...w ? { width: toPxString(w) } : {},
|
|
1555
|
+
...h ? { height: toPxString(h) } : {}
|
|
1556
|
+
};
|
|
1557
|
+
}, style = () => ({
|
|
1558
|
+
"z-index": node().internals.z,
|
|
1559
|
+
transform: transform(),
|
|
1560
|
+
visibility: nodeHasDimensions(node()) ? "visible" : "hidden",
|
|
1561
|
+
...sizeStyle(),
|
|
1562
|
+
...node().style ?? {}
|
|
1563
|
+
});
|
|
1564
|
+
createEffect(() => ({
|
|
1565
|
+
valid: nodeTypeValid(),
|
|
1566
|
+
nodeType: nodeType()
|
|
1567
|
+
}), ({ valid, nodeType }) => {}), createEffect(() => ({
|
|
1568
|
+
id: node().id,
|
|
1569
|
+
nodeElement: nodeRef(),
|
|
1570
|
+
nodeType: nodeType(),
|
|
1571
|
+
sourcePosition: node().sourcePosition,
|
|
1572
|
+
targetPosition: node().targetPosition
|
|
1573
|
+
}), (current, prev) => {
|
|
1574
|
+
current.nodeElement && (prev && prev.nodeElement === current.nodeElement && prev.sourcePosition === current.sourcePosition && prev.targetPosition === current.targetPosition && prev.nodeType === current.nodeType || actions.requestUpdateNodeInternals([[current.id, {
|
|
1575
|
+
id: current.id,
|
|
1576
|
+
nodeElement: current.nodeElement,
|
|
1577
|
+
force: !0
|
|
1578
|
+
}]]));
|
|
1579
|
+
}), createEffect(() => ({
|
|
1580
|
+
nodeElement: nodeRef(),
|
|
1581
|
+
hasDimensions: nodeHasDimensions(node()),
|
|
1582
|
+
resizeObserver: props.resizeObserver
|
|
1583
|
+
}), (current, prev) => {
|
|
1584
|
+
current.nodeElement === prev?.nodeElement && current.resizeObserver === prev?.resizeObserver && current.hasDimensions || (prev?.nodeElement && prev.resizeObserver?.unobserve(prev.nodeElement), current.nodeElement && current.resizeObserver?.observe(current.nodeElement));
|
|
1585
|
+
});
|
|
1586
|
+
let onSelectNodeHandler = (event) => {
|
|
1587
|
+
selectable() && (!store.selectNodesOnDrag || !draggable() || store.nodeDragThreshold > 0) && actions.handleNodeSelection(node().id), props.onNodeClick?.({
|
|
1588
|
+
node: userNode(),
|
|
1589
|
+
event
|
|
1590
|
+
});
|
|
1591
|
+
}, onKeyDown = (event) => {
|
|
1592
|
+
if (isInputDOMNode(event) || store.disableKeyboardA11y) return;
|
|
1593
|
+
if (elementSelectionKeys.includes(event.key) && selectable()) {
|
|
1594
|
+
actions.handleNodeSelection(node().id, event.key === "Escape", nodeRef());
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1597
|
+
let arrowKeyDiff = ARROW_KEY_DIFFS[event.key];
|
|
1598
|
+
draggable() && node().selected && arrowKeyDiff && (event.preventDefault(), actions.setAriaLiveMessage(store.ariaLabelConfig["node.a11yDescription.ariaLiveMessage"]({
|
|
1599
|
+
direction: event.key.replace("Arrow", "").toLowerCase(),
|
|
1600
|
+
x: ~~node().internals.positionAbsolute.x,
|
|
1601
|
+
y: ~~node().internals.positionAbsolute.y
|
|
1602
|
+
})), actions.moveSelectedNodes(arrowKeyDiff, event.shiftKey ? 4 : 1));
|
|
1603
|
+
}, onFocus = () => {
|
|
1604
|
+
if (store.disableKeyboardA11y || !store.autoPanOnNodeFocus || !nodeRef()?.matches(":focus-visible")) return;
|
|
1605
|
+
let { width, height, viewport } = store;
|
|
1606
|
+
getNodesInside(/* @__PURE__ */ new Map([[node().id, node()]]), {
|
|
1607
|
+
x: 0,
|
|
1608
|
+
y: 0,
|
|
1609
|
+
width,
|
|
1610
|
+
height
|
|
1611
|
+
}, [
|
|
1612
|
+
viewport.x,
|
|
1613
|
+
viewport.y,
|
|
1614
|
+
viewport.zoom
|
|
1615
|
+
], !0).length > 0 || actions.setCenter(node().position.x + (node().measured.width ?? 0) / 2, node().position.y + (node().measured.height ?? 0) / 2, { zoom: viewport.zoom });
|
|
1616
|
+
}, dragging = createDraggable(nodeRef, () => ({
|
|
1617
|
+
nodeId: node().id,
|
|
1618
|
+
isSelectable: selectable(),
|
|
1619
|
+
disabled: !draggable(),
|
|
1620
|
+
handleSelector: node().dragHandle,
|
|
1621
|
+
noDragClass: store.noDragClass,
|
|
1622
|
+
nodeClickDistance: props.nodeClickDistance,
|
|
1623
|
+
onNodeMouseDown: actions.handleNodeSelection,
|
|
1624
|
+
onDrag: (event, _, targetNode, nodes) => {
|
|
1625
|
+
props.onNodeDrag?.({
|
|
1626
|
+
event,
|
|
1627
|
+
targetNode,
|
|
1628
|
+
nodes
|
|
1629
|
+
});
|
|
1630
|
+
},
|
|
1631
|
+
onDragStart: (event, _, targetNode, nodes) => {
|
|
1632
|
+
props.onNodeDragStart?.({
|
|
1633
|
+
event,
|
|
1634
|
+
targetNode,
|
|
1635
|
+
nodes
|
|
1636
|
+
});
|
|
1637
|
+
},
|
|
1638
|
+
onDragStop: (event, _, targetNode, nodes) => {
|
|
1639
|
+
props.onNodeDragStop?.({
|
|
1640
|
+
event,
|
|
1641
|
+
targetNode,
|
|
1642
|
+
nodes
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
}));
|
|
1646
|
+
return <Show when={!node().hidden}>
|
|
1647
|
+
<div ref={setNodeRef} data-id={node().id} class={[
|
|
1648
|
+
"solid-flow__node",
|
|
1649
|
+
`solid-flow__node-${nodeType()}`,
|
|
1650
|
+
{
|
|
1651
|
+
connectable: !!connectable(),
|
|
1652
|
+
draggable: !!draggable(),
|
|
1653
|
+
dragging: dragging(),
|
|
1654
|
+
nopan: !!draggable(),
|
|
1655
|
+
parent: isParentNode(),
|
|
1656
|
+
selectable: !!selectable(),
|
|
1657
|
+
selected: !!node().selected
|
|
1658
|
+
},
|
|
1659
|
+
node().class
|
|
1660
|
+
]} style={style()} onClick={onSelectNodeHandler} onPointerEnter={(event) => props.onNodePointerEnter?.({
|
|
1661
|
+
node: userNode(),
|
|
1662
|
+
event
|
|
1663
|
+
})} onPointerLeave={(event) => props.onNodePointerLeave?.({
|
|
1664
|
+
node: userNode(),
|
|
1665
|
+
event
|
|
1666
|
+
})} onPointerMove={(event) => props.onNodePointerMove?.({
|
|
1667
|
+
node: userNode(),
|
|
1668
|
+
event
|
|
1669
|
+
})} onContextMenu={(event) => props.onNodeContextMenu?.({
|
|
1670
|
+
node: userNode(),
|
|
1671
|
+
event
|
|
1672
|
+
})} onKeyDown={(e) => focusable() && onKeyDown(e)} onFocus={() => focusable() && onFocus()} tabindex={focusable() ? 0 : void 0} role={node().ariaRole ?? (focusable() ? "group" : void 0)} aria-roledescription="node" aria-describedby={store.disableKeyboardA11y ? void 0 : `${ARIA_NODE_DESC_KEY}-${store.id}`} {...node().domAttributes}>
|
|
1673
|
+
<NodeIdContext value={nodeId}>
|
|
1674
|
+
<NodeConnectableContext value={connectable}>
|
|
1675
|
+
<Dynamic component={nodeComponent()} data={node().data} id={node().id} selected={!!node().selected} selectable={selectable()} deletable={deletable()} sourcePosition={node().sourcePosition} targetPosition={node().targetPosition} zIndex={node().internals.z} dragging={dragging()} draggable={draggable()} dragHandle={node().dragHandle} parentId={node().parentId} type={nodeType()} isConnectable={connectable()} positionAbsoluteX={node().internals.positionAbsolute.x} positionAbsoluteY={node().internals.positionAbsolute.y} width={node().width} height={node().height} />
|
|
1676
|
+
</NodeConnectableContext>
|
|
1677
|
+
</NodeIdContext>
|
|
1678
|
+
</div>
|
|
1679
|
+
</Show>;
|
|
1680
|
+
}, OutputNode = (props) => {
|
|
1681
|
+
let _props = propDefaults(props, { targetPosition: Position$1.Top });
|
|
1682
|
+
return <>
|
|
1683
|
+
<Handle type="target" position={_props.targetPosition} isConnectable={_props.isConnectable} />
|
|
1684
|
+
{props.data?.label}
|
|
1685
|
+
</>;
|
|
1686
|
+
};
|
|
1687
|
+
//#endregion
|
|
1688
|
+
//#region src/data/xyflow.ts
|
|
1689
|
+
/**
|
|
1690
|
+
* The DOM side of the measurement pipeline (fork of @xyflow/system's
|
|
1691
|
+
* updateNodeInternals): reads each updated node element's dimensions and
|
|
1692
|
+
* handle bounds from the DOM and reports them as data — measurement writes
|
|
1693
|
+
* for the measurements root plus user-facing dimension/position changes —
|
|
1694
|
+
* instead of writing into a node lookup. The internalNodes projection turns
|
|
1695
|
+
* the measurement writes back into internal-node state.
|
|
1696
|
+
*
|
|
1697
|
+
* `parentExpandChildren` must be turned into changes via
|
|
1698
|
+
* {@link handleExpandParent} only AFTER the measurement writes have been
|
|
1699
|
+
* flushed, so parent geometry reflects this measuring pass.
|
|
1700
|
+
*/
|
|
1701
|
+
function measureNodeInternals(updates, nodeLookup, domNode, nodeExtent) {
|
|
1702
|
+
let measurementWrites = [], changes = [], parentExpandChildren = [], updatedInternals = !1, viewportNode = domNode?.querySelector(".xyflow__viewport");
|
|
1703
|
+
if (!viewportNode) return {
|
|
1704
|
+
updatedInternals,
|
|
1705
|
+
measurementWrites,
|
|
1706
|
+
changes,
|
|
1707
|
+
parentExpandChildren
|
|
1708
|
+
};
|
|
1709
|
+
let style = window.getComputedStyle(viewportNode), { m22: zoom } = new window.DOMMatrixReadOnly(style.transform);
|
|
1710
|
+
for (let update of updates.values()) {
|
|
1711
|
+
let node = nodeLookup.get(update.id);
|
|
1712
|
+
if (!node) continue;
|
|
1713
|
+
if (node.hidden) {
|
|
1714
|
+
measurementWrites.push({
|
|
1715
|
+
id: node.id,
|
|
1716
|
+
hidden: !0
|
|
1717
|
+
}), updatedInternals = !0;
|
|
1718
|
+
continue;
|
|
1719
|
+
}
|
|
1720
|
+
let dimensions = getDimensions(update.nodeElement), dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
|
|
1721
|
+
if (dimensions.width && dimensions.height && (dimensionChanged || !node.internals.handleBounds || update.force)) {
|
|
1722
|
+
let nodeBounds = update.nodeElement.getBoundingClientRect(), extent = isCoordinateExtent(node.extent) ? node.extent : nodeExtent, { positionAbsolute } = node.internals;
|
|
1723
|
+
node.parentId && node.extent === "parent" ? positionAbsolute = clampPositionToParent(positionAbsolute, dimensions, nodeLookup.get(node.parentId)) : extent && (positionAbsolute = clampPosition(positionAbsolute, extent, dimensions)), measurementWrites.push({
|
|
1724
|
+
id: node.id,
|
|
1725
|
+
measured: dimensions,
|
|
1726
|
+
handleBounds: {
|
|
1727
|
+
source: getHandleBounds("source", update.nodeElement, nodeBounds, zoom, node.id),
|
|
1728
|
+
target: getHandleBounds("target", update.nodeElement, nodeBounds, zoom, node.id)
|
|
1729
|
+
}
|
|
1730
|
+
}), updatedInternals = !0, dimensionChanged && (changes.push({
|
|
1731
|
+
id: node.id,
|
|
1732
|
+
type: "dimensions",
|
|
1733
|
+
dimensions
|
|
1734
|
+
}), node.expandParent && node.parentId && parentExpandChildren.push({
|
|
1735
|
+
id: node.id,
|
|
1736
|
+
parentId: node.parentId,
|
|
1737
|
+
rect: nodeToRect({
|
|
1738
|
+
...node,
|
|
1739
|
+
measured: dimensions,
|
|
1740
|
+
internals: {
|
|
1741
|
+
...node.internals,
|
|
1742
|
+
positionAbsolute
|
|
1743
|
+
}
|
|
1744
|
+
})
|
|
1745
|
+
}));
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
return {
|
|
1749
|
+
updatedInternals,
|
|
1750
|
+
measurementWrites,
|
|
1751
|
+
changes,
|
|
1752
|
+
parentExpandChildren
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
function handleExpandParent(children, nodeLookup, getChildNodes, nodeOrigin = [0, 0]) {
|
|
1756
|
+
let changes = [], parentExpansions = /* @__PURE__ */ new Map();
|
|
1757
|
+
for (let child of children) {
|
|
1758
|
+
let parent = nodeLookup.get(child.parentId);
|
|
1759
|
+
if (!parent) continue;
|
|
1760
|
+
let parentRect = parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent), expandedRect = getBoundsOfRects(parentRect, child.rect);
|
|
1761
|
+
parentExpansions.set(child.parentId, {
|
|
1762
|
+
expandedRect,
|
|
1763
|
+
parent
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
return parentExpansions.size > 0 && parentExpansions.forEach(({ expandedRect, parent }, parentId) => {
|
|
1767
|
+
let positionAbsolute = parent.internals.positionAbsolute, dimensions = getNodeDimensions(parent), origin = parent.origin ?? nodeOrigin, xChange = expandedRect.x < positionAbsolute.x ? Math.round(Math.abs(positionAbsolute.x - expandedRect.x)) : 0, yChange = expandedRect.y < positionAbsolute.y ? Math.round(Math.abs(positionAbsolute.y - expandedRect.y)) : 0, newWidth = Math.max(dimensions.width, Math.round(expandedRect.width)), newHeight = Math.max(dimensions.height, Math.round(expandedRect.height)), widthChange = (newWidth - dimensions.width) * origin[0], heightChange = (newHeight - dimensions.height) * origin[1];
|
|
1768
|
+
if (xChange > 0 || yChange > 0 || widthChange || heightChange) {
|
|
1769
|
+
changes.push({
|
|
1770
|
+
id: parentId,
|
|
1771
|
+
type: "position",
|
|
1772
|
+
position: {
|
|
1773
|
+
x: parent.position.x - xChange + widthChange,
|
|
1774
|
+
y: parent.position.y - yChange + heightChange
|
|
1200
1775
|
}
|
|
1201
|
-
};
|
|
1202
|
-
nodeLookup.set(userNode.id, updatedNodeInternals), userNode.parentId && updateChildNode(updatedNodeInternals, nodeLookup, parentLookup, {
|
|
1203
|
-
nodeOrigin: store.nodeOrigin,
|
|
1204
|
-
nodeExtent: store.nodeExtent,
|
|
1205
|
-
elevateNodesOnSelect: store.elevateNodesOnSelect,
|
|
1206
|
-
zIndexMode: store.zIndexMode,
|
|
1207
|
-
checkEquality: !0
|
|
1208
1776
|
});
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
source: sourceNodeId,
|
|
1217
|
-
target: targetNodeId,
|
|
1218
|
-
sourceHandle,
|
|
1219
|
-
targetHandle
|
|
1220
|
-
}, sourceKey = `${sourceNodeId}-${sourceHandle}--${targetNodeId}-${targetHandle}`, targetKey = `${targetNodeId}-${targetHandle}--${sourceNodeId}-${sourceHandle}`;
|
|
1221
|
-
createComputed(() => {
|
|
1222
|
-
batch(() => {
|
|
1223
|
-
addConnectionToLookup("source", connection, targetKey, connectionLookup, sourceNodeId, sourceHandle), addConnectionToLookup("target", connection, sourceKey, connectionLookup, targetNodeId, targetHandle), edgeLookup.set(edge.id, edge);
|
|
1777
|
+
for (let childNode of getChildNodes(parentId)) children.some((child) => child.id === childNode.id) || changes.push({
|
|
1778
|
+
id: childNode.id,
|
|
1779
|
+
type: "position",
|
|
1780
|
+
position: {
|
|
1781
|
+
x: childNode.position.x + xChange,
|
|
1782
|
+
y: childNode.position.y + yChange
|
|
1783
|
+
}
|
|
1224
1784
|
});
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
height: store.height ?? 0,
|
|
1234
|
-
transform: store.transform
|
|
1235
|
-
})) return;
|
|
1236
|
-
store.visibleNodesMap.set(sourceNode.id, sourceNode), store.visibleNodesMap.set(targetNode.id, targetNode);
|
|
1785
|
+
}
|
|
1786
|
+
(dimensions.width < expandedRect.width || dimensions.height < expandedRect.height || xChange || yChange) && changes.push({
|
|
1787
|
+
id: parentId,
|
|
1788
|
+
type: "dimensions",
|
|
1789
|
+
setAttributes: !0,
|
|
1790
|
+
dimensions: {
|
|
1791
|
+
width: newWidth + (xChange ? origin[0] * xChange - widthChange : 0),
|
|
1792
|
+
height: newHeight + (yChange ? origin[1] * yChange - heightChange : 0)
|
|
1237
1793
|
}
|
|
1238
|
-
let edgePosition = getEdgePosition({
|
|
1239
|
-
id: edge.id,
|
|
1240
|
-
sourceNode,
|
|
1241
|
-
targetNode,
|
|
1242
|
-
sourceHandle: edge.sourceHandle || null,
|
|
1243
|
-
targetHandle: edge.targetHandle || null,
|
|
1244
|
-
connectionMode: store.connectionMode,
|
|
1245
|
-
onError: store.onError
|
|
1246
|
-
});
|
|
1247
|
-
edgePosition && layoutedEdgesMap.set(edge.id, {
|
|
1248
|
-
...store.defaultEdgeOptions,
|
|
1249
|
-
...edge,
|
|
1250
|
-
...edgePosition,
|
|
1251
|
-
zIndex: getElevatedEdgeZIndex({
|
|
1252
|
-
selected: edge.selected,
|
|
1253
|
-
zIndex: edge.zIndex ?? store.defaultEdgeOptions.zIndex,
|
|
1254
|
-
sourceNode,
|
|
1255
|
-
targetNode,
|
|
1256
|
-
elevateOnSelect: store.elevateEdgesOnSelect,
|
|
1257
|
-
zIndexMode: store.zIndexMode
|
|
1258
|
-
}),
|
|
1259
|
-
sourceNode,
|
|
1260
|
-
targetNode,
|
|
1261
|
-
edge
|
|
1262
|
-
});
|
|
1263
|
-
}), onCleanup(() => {
|
|
1264
|
-
batch(() => {
|
|
1265
|
-
edgeLookup.delete(edge.id), layoutedEdgesMap.delete(edge.id), removeConnectionFromLookup("source", targetKey, connectionLookup, sourceNodeId, sourceHandle), removeConnectionFromLookup("target", sourceKey, connectionLookup, targetNodeId, targetHandle);
|
|
1266
|
-
});
|
|
1267
1794
|
});
|
|
1268
|
-
})
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1795
|
+
}), changes;
|
|
1796
|
+
}
|
|
1797
|
+
//#endregion
|
|
1798
|
+
//#region src/data/createSolidFlow.tsx
|
|
1799
|
+
const InitialNodeTypesMap = {
|
|
1800
|
+
input: InputNode,
|
|
1801
|
+
output: OutputNode,
|
|
1802
|
+
default: DefaultNode,
|
|
1803
|
+
group: GroupNode
|
|
1804
|
+
}, InitialEdgeTypesMap = {
|
|
1805
|
+
straight: StraightEdgeInternal,
|
|
1806
|
+
smoothstep: SmoothStepEdgeInternal,
|
|
1807
|
+
default: BezierEdgeInternal,
|
|
1808
|
+
step: StepEdgeInternal
|
|
1809
|
+
}, createSolidFlow = (props) => {
|
|
1810
|
+
let state = createFlowState(props, {
|
|
1811
|
+
prefersDark: createMediaQuery("(prefers-color-scheme: dark)", props.colorModeSSR === "dark"),
|
|
1812
|
+
initialNodeTypes: InitialNodeTypesMap,
|
|
1813
|
+
initialEdgeTypes: InitialEdgeTypesMap
|
|
1814
|
+
}), { store, nodeLookup, actions } = state, pendingEntries, requestUpdateNodeInternals = (updateEntries) => {
|
|
1815
|
+
if (pendingEntries) {
|
|
1816
|
+
pendingEntries.push(...updateEntries);
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
pendingEntries = updateEntries, scheduleIdleCallback(() => {
|
|
1820
|
+
let updates = new Map(pendingEntries);
|
|
1821
|
+
pendingEntries = void 0;
|
|
1822
|
+
let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode);
|
|
1823
|
+
updatedInternals && (actions.applyMeasurementWrites(measurementWrites), flush(), parentExpandChildren.length > 0 && changes.push(...handleExpandParent(parentExpandChildren, nodeLookup, (parentId) => store.nodes.filter((node) => node.parentId === parentId), store.nodeOrigin)), actions.applyNodeChanges(changes), flush(), actions.markInitialNodesMeasured());
|
|
1824
|
+
});
|
|
1825
|
+
};
|
|
1826
|
+
return actions.setMeasureRequester(requestUpdateNodeInternals), {
|
|
1827
|
+
...state,
|
|
1277
1828
|
actions: {
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
resetStoreValues,
|
|
1281
|
-
requestUpdateNodeInternals,
|
|
1282
|
-
setAriaLabelConfig,
|
|
1283
|
-
setAriaLiveMessage,
|
|
1284
|
-
setClickConnectStartHandle,
|
|
1285
|
-
setConfig,
|
|
1286
|
-
setConnection,
|
|
1287
|
-
setDeleteKeyPressed,
|
|
1288
|
-
setDomNode,
|
|
1289
|
-
setDragging,
|
|
1290
|
-
get setEdges() {
|
|
1291
|
-
return edgesMemo.set;
|
|
1292
|
-
},
|
|
1293
|
-
setElementsSelectable,
|
|
1294
|
-
setHeight,
|
|
1295
|
-
setMultiselectionKeyPressed,
|
|
1296
|
-
get setNodes() {
|
|
1297
|
-
return nodesMemo.set;
|
|
1298
|
-
},
|
|
1299
|
-
setNodesConnectable,
|
|
1300
|
-
setNodesDraggable,
|
|
1301
|
-
setPanActivationKeyPressed,
|
|
1302
|
-
setPanZoom,
|
|
1303
|
-
setSelectionKeyPressed,
|
|
1304
|
-
setSelectionRect,
|
|
1305
|
-
setSelectionRectMode,
|
|
1306
|
-
get setViewport() {
|
|
1307
|
-
return viewportMemo.set;
|
|
1308
|
-
},
|
|
1309
|
-
setWidth,
|
|
1310
|
-
setZoomActivationKeyPressed,
|
|
1311
|
-
addEdge,
|
|
1312
|
-
updateNodePositions,
|
|
1313
|
-
zoomIn,
|
|
1314
|
-
zoomOut,
|
|
1315
|
-
fitView,
|
|
1316
|
-
setCenter,
|
|
1317
|
-
setPaneClickDistance,
|
|
1318
|
-
unselectNodesAndEdges,
|
|
1319
|
-
addSelectedNodes,
|
|
1320
|
-
addSelectedEdges,
|
|
1321
|
-
handleNodeSelection: (id, unselect, nodeRef) => {
|
|
1322
|
-
let node = store.nodes.find((n) => n.id === id);
|
|
1323
|
-
node && (batch(() => {
|
|
1324
|
-
setSelectionRect(void 0), setSelectionRectMode(void 0);
|
|
1325
|
-
}), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
|
|
1326
|
-
nodes: [node],
|
|
1327
|
-
edges: []
|
|
1328
|
-
}), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
|
|
1329
|
-
},
|
|
1330
|
-
handleEdgeSelection: (id) => {
|
|
1331
|
-
let edge = edgeLookup.get(id);
|
|
1332
|
-
edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) && (batch(() => {
|
|
1333
|
-
setSelectionRect(void 0), setSelectionRectMode(void 0);
|
|
1334
|
-
}), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
|
|
1335
|
-
nodes: [],
|
|
1336
|
-
edges: [edge]
|
|
1337
|
-
}) : addSelectedEdges([id]));
|
|
1338
|
-
},
|
|
1339
|
-
moveSelectedNodes: (direction, factor) => {
|
|
1340
|
-
let nodeUpdates = /* @__PURE__ */ new Map(), xVelo = store.snapGrid?.[0] ?? 5, yVelo = store.snapGrid?.[1] ?? 5, xDiff = direction.x * xVelo * factor, yDiff = direction.y * yVelo * factor;
|
|
1341
|
-
for (let node of nodeLookup.values()) {
|
|
1342
|
-
if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
|
|
1343
|
-
let nextPosition = {
|
|
1344
|
-
x: node.internals.positionAbsolute.x + xDiff,
|
|
1345
|
-
y: node.internals.positionAbsolute.y + yDiff
|
|
1346
|
-
};
|
|
1347
|
-
store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
|
|
1348
|
-
let { position, positionAbsolute } = calculateNodePosition({
|
|
1349
|
-
nodeId: node.id,
|
|
1350
|
-
nextPosition,
|
|
1351
|
-
nodeLookup,
|
|
1352
|
-
nodeExtent: store.nodeExtent,
|
|
1353
|
-
nodeOrigin: store.nodeOrigin,
|
|
1354
|
-
onError: store.onError
|
|
1355
|
-
});
|
|
1356
|
-
node.position = position, node.internals.positionAbsolute = positionAbsolute, nodeUpdates.set(node.id, node);
|
|
1357
|
-
}
|
|
1358
|
-
updateNodePositions(nodeUpdates);
|
|
1359
|
-
},
|
|
1360
|
-
panBy: (delta) => panBy({
|
|
1361
|
-
delta,
|
|
1362
|
-
panZoom: store.panZoom,
|
|
1363
|
-
transform: store.transform,
|
|
1364
|
-
translateExtent: store.translateExtent,
|
|
1365
|
-
width: store.width,
|
|
1366
|
-
height: store.height
|
|
1367
|
-
}),
|
|
1368
|
-
cancelConnection: () => {
|
|
1369
|
-
setConnection({ ...initialConnection });
|
|
1370
|
-
},
|
|
1371
|
-
reset: () => {
|
|
1372
|
-
resetStoreValues(), unselectNodesAndEdges();
|
|
1373
|
-
}
|
|
1829
|
+
...actions,
|
|
1830
|
+
requestUpdateNodeInternals
|
|
1374
1831
|
}
|
|
1375
1832
|
};
|
|
1376
|
-
}, SolidFlowContext = createContext();
|
|
1833
|
+
}, SolidFlowContext = createContext(null);
|
|
1377
1834
|
function useInternalSolidFlow() {
|
|
1378
1835
|
let ctx = useContext(SolidFlowContext);
|
|
1379
1836
|
if (!ctx) throw Error("solid-flow: Your application must be wrapped with <SolidFlow> in order to invoke useInternalSolidFlow within your components");
|
|
@@ -1382,13 +1839,13 @@ function useInternalSolidFlow() {
|
|
|
1382
1839
|
//#endregion
|
|
1383
1840
|
//#region src/components/graph/marker/Marker.tsx
|
|
1384
1841
|
const Marker = (props) => {
|
|
1385
|
-
let _props =
|
|
1842
|
+
let _props = propDefaults(props, {
|
|
1386
1843
|
markerUnits: "strokeWidth",
|
|
1387
1844
|
orient: "auto-start-reverse",
|
|
1388
1845
|
width: 12.5,
|
|
1389
1846
|
height: 12.5,
|
|
1390
1847
|
color: "none"
|
|
1391
|
-
}
|
|
1848
|
+
}), color = () => _props.color ?? "var(--xy-edge-stroke)";
|
|
1392
1849
|
return <marker class="solid-flow__arrowhead" id={_props.id} markerWidth={_props.width} markerHeight={_props.height} viewBox="-10 -10 20 20" markerUnits={_props.markerUnits} orient={_props.orient} refX="0" refY="0">
|
|
1393
1850
|
<Show when={_props.type === "arrow"} fallback={<polyline class="arrowclosed" stroke={color()} fill={color()} stroke-linecap="round" stroke-linejoin="round" stroke-width={_props.strokeWidth} points="-5,-4 0,0 -5,4 -5,-4" />}>
|
|
1394
1851
|
<polyline class="arrow" stroke={color()} fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width={_props.strokeWidth} points="-5,-4 0,0 -5,4" />
|
|
@@ -1440,7 +1897,7 @@ const Marker = (props) => {
|
|
|
1440
1897
|
for (let item of a) if (!b.has(item)) return !1;
|
|
1441
1898
|
return !0;
|
|
1442
1899
|
}, Pane = (props) => {
|
|
1443
|
-
let { store, nodeLookup, edgeLookup,
|
|
1900
|
+
let { store, nodeLookup, edgeLookup, connections, actions } = useInternalSolidFlow(), [containerRef, setContainerRef] = createSignal(), container, containerBounds = null, connectionEndedOnPane = !1, selectionInProgress = !1, selectedNodeIds = /* @__PURE__ */ new Set(), selectedEdgeIds = /* @__PURE__ */ new Set(), autoPanId = 0, position = {
|
|
1444
1901
|
x: 0,
|
|
1445
1902
|
y: 0
|
|
1446
1903
|
}, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ?? 1, _panOnDrag = () => store.panActivationKeyPressed || props.panOnDrag, isSelecting = () => store.selectionKeyPressed || !!store.selectionRect || props.selectionOnDrag && _panOnDrag() !== !0, isSelectionEnabled = () => store.elementsSelectable && (isSelecting() || store.selectionRectMode === "user"), onClick = (event) => {
|
|
@@ -1449,9 +1906,7 @@ const Marker = (props) => {
|
|
|
1449
1906
|
selectionInProgress = !1, connectionEndedOnPane = !1;
|
|
1450
1907
|
return;
|
|
1451
1908
|
}
|
|
1452
|
-
props.onPaneClick?.({ event }),
|
|
1453
|
-
actions.unselectNodesAndEdges(), actions.setSelectionRectMode(void 0), actions.setSelectionRect(void 0);
|
|
1454
|
-
});
|
|
1909
|
+
props.onPaneClick?.({ event }), actions.unselectNodesAndEdges(), actions.setSelectionRectMode(void 0), actions.setSelectionRect(void 0);
|
|
1455
1910
|
}
|
|
1456
1911
|
}, onPointerDownCapture = (event) => {
|
|
1457
1912
|
if (event.pointerType === "touch" && _panOnDrag() !== !1 && !store.selectionKeyPressed || (containerBounds = container?.getBoundingClientRect() ?? null, !containerBounds)) return;
|
|
@@ -1469,7 +1924,7 @@ const Marker = (props) => {
|
|
|
1469
1924
|
startY: userSelectionFlowOrigin.y,
|
|
1470
1925
|
x,
|
|
1471
1926
|
y
|
|
1472
|
-
}), eventTargetIsContainer || (event.stopPropagation(), event.preventDefault());
|
|
1927
|
+
}), flush(), eventTargetIsContainer || (event.stopPropagation(), event.preventDefault());
|
|
1473
1928
|
}, commitUserSelectionRect = (mouseX, mouseY) => {
|
|
1474
1929
|
let selectionRect = store.selectionRect;
|
|
1475
1930
|
if (selectionRect?.startX === void 0 || selectionRect.startY === void 0) return;
|
|
@@ -1488,33 +1943,23 @@ const Marker = (props) => {
|
|
|
1488
1943
|
let edgesSelectable = store.defaultEdgeOptions.selectable ?? !0;
|
|
1489
1944
|
selectedEdgeIds = /* @__PURE__ */ new Set();
|
|
1490
1945
|
for (let nodeId of selectedNodeIds) {
|
|
1491
|
-
let
|
|
1492
|
-
if (
|
|
1493
|
-
let edge = edgeLookup
|
|
1946
|
+
let nodeConnections = connections[nodeId];
|
|
1947
|
+
if (nodeConnections) for (let { edgeId } of Object.values(nodeConnections)) {
|
|
1948
|
+
let edge = edgeLookup[edgeId];
|
|
1494
1949
|
edge && (edge.selectable ?? edgesSelectable) && selectedEdgeIds.add(edgeId);
|
|
1495
1950
|
}
|
|
1496
1951
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
let
|
|
1500
|
-
|
|
1501
|
-
let isSelected = selectedNodeIds.has(node.id);
|
|
1502
|
-
return selectionMap.set(node.id, isSelected), !!node.selected !== isSelected;
|
|
1503
|
-
}, produce((node) => {
|
|
1504
|
-
node.selected = selectionMap.get(node.id);
|
|
1505
|
-
}));
|
|
1952
|
+
isSetEqual(prevSelectedNodeIds, selectedNodeIds) || actions.setNodes((nodes) => {
|
|
1953
|
+
for (let node of nodes) {
|
|
1954
|
+
let isSelected = selectedNodeIds.has(node.id);
|
|
1955
|
+
!!node.selected !== isSelected && (node.selected = isSelected);
|
|
1506
1956
|
}
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
return selectionMap.set(edge.id, isSelected), !!edge.selected !== isSelected;
|
|
1512
|
-
}, produce((edge) => {
|
|
1513
|
-
edge.selected = selectionMap.get(edge.id);
|
|
1514
|
-
}));
|
|
1957
|
+
}), isSetEqual(prevSelectedEdgeIds, selectedEdgeIds) || actions.setEdges((edges) => {
|
|
1958
|
+
for (let edge of edges) {
|
|
1959
|
+
let isSelected = selectedEdgeIds.has(edge.id);
|
|
1960
|
+
!!edge.selected !== isSelected && (edge.selected = isSelected);
|
|
1515
1961
|
}
|
|
1516
|
-
|
|
1517
|
-
});
|
|
1962
|
+
}), actions.setSelectionRectMode("user"), actions.setSelectionRect(nextUserSelectRect), flush();
|
|
1518
1963
|
}, autoPan = () => {
|
|
1519
1964
|
if (!autoPanOnSelection() || !containerBounds) return;
|
|
1520
1965
|
let [x = 0, y = 0] = calcAutoPan(position, containerBounds, store.autoPanSpeed);
|
|
@@ -1556,14 +2001,18 @@ const Marker = (props) => {
|
|
|
1556
2001
|
event.target === container && store.connection.inProgress && (connectionEndedOnPane = !0);
|
|
1557
2002
|
return;
|
|
1558
2003
|
}
|
|
1559
|
-
event.button === 0 && (event.target?.releasePointerCapture?.(event.pointerId), !selectionInProgress && event.target === container && onClick(event),
|
|
1560
|
-
actions.setSelectionRect(void 0), selectionInProgress && actions.setSelectionRectMode(selectedNodeIds.size > 0 ? "nodes" : void 0);
|
|
1561
|
-
}), selectionInProgress && props.onSelectionEnd?.(event), cleanupAutoPan());
|
|
2004
|
+
event.button === 0 && (event.target?.releasePointerCapture?.(event.pointerId), !selectionInProgress && event.target === container && onClick(event), actions.setSelectionRect(void 0), selectionInProgress && actions.setSelectionRectMode(selectedNodeIds.size > 0 ? "nodes" : void 0), flush(), selectionInProgress && props.onSelectionEnd?.(event), cleanupAutoPan());
|
|
1562
2005
|
}, onPointerCancel = (event) => {
|
|
1563
2006
|
event.target?.releasePointerCapture?.(event.pointerId), cleanupAutoPan();
|
|
1564
2007
|
}, onClickCapture = (event) => {
|
|
1565
2008
|
selectionInProgress &&= (event.stopPropagation(), !1);
|
|
1566
|
-
}
|
|
2009
|
+
};
|
|
2010
|
+
createEventListener(containerRef, "pointerdown", (e) => {
|
|
2011
|
+
isSelectionEnabled() && onPointerDownCapture(e);
|
|
2012
|
+
}, { capture: !0 }), createEventListener(containerRef, "click", (e) => {
|
|
2013
|
+
isSelectionEnabled() && onClickCapture(e);
|
|
2014
|
+
}, { capture: !0 });
|
|
2015
|
+
let onContextMenu = (event) => {
|
|
1567
2016
|
if (event.target !== container) return;
|
|
1568
2017
|
let result = _panOnDrag();
|
|
1569
2018
|
if (Array.isArray(result) && result.includes(2)) {
|
|
@@ -1573,40 +2022,28 @@ const Marker = (props) => {
|
|
|
1573
2022
|
props.onPaneContextMenu?.({ event });
|
|
1574
2023
|
};
|
|
1575
2024
|
return <div ref={(el) => {
|
|
1576
|
-
container = el, el
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
}} class={clsx$1("solid-flow__container solid-flow__pane", {
|
|
1580
|
-
selection: isSelecting(),
|
|
2025
|
+
container = el, setContainerRef(el);
|
|
2026
|
+
}} class={["solid-flow__container solid-flow__pane", {
|
|
2027
|
+
selection: !!isSelecting(),
|
|
1581
2028
|
dragging: store.dragging,
|
|
1582
2029
|
draggable: props.panOnDrag === !0 || Array.isArray(props.panOnDrag) && props.panOnDrag.includes(0)
|
|
1583
|
-
}
|
|
1584
|
-
capture: !0,
|
|
1585
|
-
handleEvent: (e) => {
|
|
1586
|
-
isSelectionEnabled() && onPointerDownCapture(e);
|
|
1587
|
-
}
|
|
1588
|
-
}} onPointerMove={(e) => isSelectionEnabled() ? onPointerMove(e) : void 0} onPointerUp={onPointerUp} onPointerCancel={(e) => isSelectionEnabled() ? onPointerCancel(e) : void 0} onContextMenu={onContextMenu}>
|
|
2030
|
+
}]} onClick={(e) => isSelectionEnabled() ? void 0 : onClick(e)} onPointerMove={(e) => isSelectionEnabled() ? onPointerMove(e) : void 0} onPointerUp={onPointerUp} onPointerCancel={(e) => isSelectionEnabled() ? onPointerCancel(e) : void 0} onContextMenu={onContextMenu}>
|
|
1589
2031
|
{props.children}
|
|
1590
2032
|
</div>;
|
|
1591
2033
|
}, Panel = (props) => {
|
|
1592
|
-
let { store } = useInternalSolidFlow(), _props =
|
|
2034
|
+
let { store } = useInternalSolidFlow(), _props = propDefaults(props, {
|
|
1593
2035
|
position: "top-right",
|
|
1594
2036
|
style: {}
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
"position",
|
|
1598
|
-
"style",
|
|
1599
|
-
"children"
|
|
1600
|
-
]);
|
|
1601
|
-
return <div class={clsx$1([
|
|
2037
|
+
}), rest = omit(_props, "class", "position", "style", "children");
|
|
2038
|
+
return <div class={[
|
|
1602
2039
|
"solid-flow__panel",
|
|
1603
|
-
...
|
|
1604
|
-
|
|
1605
|
-
]
|
|
2040
|
+
..._props.position.split("-"),
|
|
2041
|
+
_props.class
|
|
2042
|
+
]} style={{
|
|
1606
2043
|
"pointer-events": store.selectionRectMode ? "none" : void 0,
|
|
1607
|
-
...
|
|
2044
|
+
..._props.style
|
|
1608
2045
|
}} {...rest}>
|
|
1609
|
-
{
|
|
2046
|
+
{_props.children}
|
|
1610
2047
|
</div>;
|
|
1611
2048
|
}, Viewport = (props) => {
|
|
1612
2049
|
let { store } = useInternalSolidFlow();
|
|
@@ -1621,7 +2058,7 @@ const Marker = (props) => {
|
|
|
1621
2058
|
</Portal>}
|
|
1622
2059
|
</Show>;
|
|
1623
2060
|
}, Zoom = (props) => {
|
|
1624
|
-
let ref, { store, actions } = useInternalSolidFlow(), viewPort = () => props.initialViewport || {
|
|
2061
|
+
let [ref, setRef] = createSignal(), { store, actions } = useInternalSolidFlow(), viewPort = () => props.initialViewport || {
|
|
1625
2062
|
x: 0,
|
|
1626
2063
|
y: 0,
|
|
1627
2064
|
zoom: 1
|
|
@@ -1633,9 +2070,10 @@ const Marker = (props) => {
|
|
|
1633
2070
|
zoom
|
|
1634
2071
|
});
|
|
1635
2072
|
};
|
|
1636
|
-
return
|
|
1637
|
-
|
|
1638
|
-
|
|
2073
|
+
return createEffect(() => ref(), (el) => {
|
|
2074
|
+
if (!el) return;
|
|
2075
|
+
let panZoomInstance = untrack(() => XYPanZoom({
|
|
2076
|
+
domNode: el,
|
|
1639
2077
|
minZoom: store.minZoom,
|
|
1640
2078
|
maxZoom: store.maxZoom,
|
|
1641
2079
|
translateExtent: store.translateExtent,
|
|
@@ -1644,43 +2082,46 @@ const Marker = (props) => {
|
|
|
1644
2082
|
onPanZoomStart: props.onMoveStart,
|
|
1645
2083
|
onPanZoom: props.onMove,
|
|
1646
2084
|
onPanZoomEnd: props.onMoveEnd
|
|
1647
|
-
}), vp = panZoomInstance.getViewport();
|
|
1648
|
-
(
|
|
2085
|
+
})), vp = panZoomInstance.getViewport(), initial = untrack(() => viewPort());
|
|
2086
|
+
(initial.x !== vp.x || initial.y !== vp.y || initial.zoom !== vp.zoom) && onTransformChange([
|
|
1649
2087
|
vp.x,
|
|
1650
2088
|
vp.y,
|
|
1651
2089
|
vp.zoom
|
|
1652
|
-
]),
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
2090
|
+
]), actions.setViewport(vp), actions.setPanZoom(panZoomInstance), props.onViewportInitialized?.();
|
|
2091
|
+
}), createEffect(() => ({
|
|
2092
|
+
panZoom: store.panZoom,
|
|
2093
|
+
options: {
|
|
2094
|
+
lib: store.lib,
|
|
2095
|
+
panActivationKeyPressed: store.panActivationKeyPressed,
|
|
2096
|
+
zoomActivationKeyPressed: store.zoomActivationKeyPressed,
|
|
2097
|
+
noPanClassName: store.noPanClass,
|
|
2098
|
+
noWheelClassName: store.noWheelClass,
|
|
2099
|
+
userSelectionActive: !!store.selectionRect,
|
|
2100
|
+
panOnScrollSpeed: props.panOnScrollSpeed,
|
|
2101
|
+
panOnDrag: panOnDrag(),
|
|
2102
|
+
panOnScroll: panOnScroll(),
|
|
2103
|
+
zoomOnScroll: props.zoomOnScroll,
|
|
2104
|
+
zoomOnDoubleClick: props.zoomOnDoubleClick,
|
|
2105
|
+
zoomOnPinch: props.zoomOnPinch,
|
|
2106
|
+
panOnScrollMode: props.panOnScrollMode,
|
|
2107
|
+
preventScrolling: typeof props.preventScrolling != "boolean" || props.preventScrolling,
|
|
2108
|
+
paneClickDistance: props.paneClickDistance,
|
|
2109
|
+
selectionOnDrag: props.selectionOnDrag,
|
|
2110
|
+
connectionInProgress: store.connection.inProgress
|
|
2111
|
+
}
|
|
2112
|
+
}), ({ panZoom, options }) => {
|
|
2113
|
+
panZoom?.update({
|
|
2114
|
+
...options,
|
|
2115
|
+
onTransformChange
|
|
1675
2116
|
});
|
|
1676
|
-
}), <div ref={
|
|
2117
|
+
}), <div ref={setRef} class="solid-flow__container solid-flow__zoom">
|
|
1677
2118
|
{props.children}
|
|
1678
2119
|
</div>;
|
|
1679
2120
|
}, ConnectionLine = (props) => {
|
|
1680
2121
|
let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid);
|
|
1681
2122
|
return <Show when={store.connection.inProgress}>
|
|
1682
2123
|
<svg class="solid-flow__container solid-flow__connectionline" width={store.width} height={store.height} style={props.containerStyle}>
|
|
1683
|
-
<g class={
|
|
2124
|
+
<g class={["solid-flow__connection", connectionStatus()]}>
|
|
1684
2125
|
<Show when={props.component} fallback={<InternalConnectionLine style={props.style} />}>
|
|
1685
2126
|
{(CustomComponent) => {
|
|
1686
2127
|
let UserConnectionLine = CustomComponent();
|
|
@@ -1722,24 +2163,32 @@ const Marker = (props) => {
|
|
|
1722
2163
|
};
|
|
1723
2164
|
return <path class="solid-flow__connection-path" fill="none" style={props.style} d={path()} />;
|
|
1724
2165
|
}, DotPattern = (props) => {
|
|
1725
|
-
let _props =
|
|
1726
|
-
return <circle class={
|
|
2166
|
+
let _props = propDefaults(props, { radius: 5 });
|
|
2167
|
+
return <circle class={[
|
|
2168
|
+
"solid-flow__background-pattern",
|
|
2169
|
+
"dots",
|
|
2170
|
+
_props.class
|
|
2171
|
+
]} cx={_props.radius} cy={_props.radius} r={_props.radius} />;
|
|
1727
2172
|
}, LinePattern = (props) => {
|
|
1728
|
-
let _props =
|
|
1729
|
-
return <path stroke-width={_props.lineWidth} d={`M${_props.dimensions[0] / 2} 0 V${_props.dimensions[1]} M0 ${_props.dimensions[1] / 2} H${_props.dimensions[0]}`} class={
|
|
2173
|
+
let _props = propDefaults(props, { lineWidth: 1 });
|
|
2174
|
+
return <path stroke-width={_props.lineWidth} d={`M${_props.dimensions[0] / 2} 0 V${_props.dimensions[1]} M0 ${_props.dimensions[1] / 2} H${_props.dimensions[0]}`} class={[
|
|
2175
|
+
"solid-flow__background-pattern",
|
|
2176
|
+
_props.variant,
|
|
2177
|
+
_props.class
|
|
2178
|
+
]} />;
|
|
1730
2179
|
}, DEFAULT_SIZE = {
|
|
1731
2180
|
dots: 1,
|
|
1732
2181
|
lines: 1,
|
|
1733
2182
|
cross: 6
|
|
1734
2183
|
}, Background = (props) => {
|
|
1735
|
-
let _props =
|
|
2184
|
+
let _props = propDefaults(props, {
|
|
1736
2185
|
variant: "dots",
|
|
1737
2186
|
gap: 20,
|
|
1738
2187
|
size: 1,
|
|
1739
2188
|
lineWidth: 1,
|
|
1740
2189
|
style: {}
|
|
1741
|
-
}
|
|
1742
|
-
return <svg data-testid="solid-flow__background" class={
|
|
2190
|
+
}), { store } = useInternalSolidFlow(), isDots = () => _props.variant === "dots", isCross = () => _props.variant === "cross", patternId = () => `background-pattern-${store.id}-${_props.id ?? ""}`, scaledSize = () => (_props.size ?? DEFAULT_SIZE[_props.variant]) * store.viewport.zoom, gapXY = () => Array.isArray(_props.gap) ? _props.gap : [_props.gap, _props.gap], scaledGap = () => [gapXY()[0] * store.viewport.zoom || 1, gapXY()[1] * store.viewport.zoom || 1], patternDimensions = () => isCross() ? [scaledSize(), scaledSize()] : scaledGap(), patternOffset = () => isDots() ? [scaledSize() / 2, scaledSize() / 2] : [patternDimensions()[0] / 2, patternDimensions()[1] / 2];
|
|
2191
|
+
return <svg data-testid="solid-flow__background" class={["solid-flow__container solid-flow__background", _props.class]} style={{
|
|
1743
2192
|
"--xy-background-color-props": _props.bgColor,
|
|
1744
2193
|
"--xy-background-pattern-color-props": _props.patternColor,
|
|
1745
2194
|
..._props.style
|
|
@@ -1752,24 +2201,15 @@ const Marker = (props) => {
|
|
|
1752
2201
|
<rect x="0" y="0" width="100%" height="100%" fill={`url(#${patternId()})`} />
|
|
1753
2202
|
</svg>;
|
|
1754
2203
|
}, ControlButton = (props) => {
|
|
1755
|
-
let
|
|
1756
|
-
"
|
|
1757
|
-
"
|
|
1758
|
-
"
|
|
1759
|
-
"color",
|
|
1760
|
-
"
|
|
1761
|
-
"borderColor",
|
|
1762
|
-
"onClick",
|
|
1763
|
-
"children"
|
|
1764
|
-
]), style = () => Object.entries({
|
|
1765
|
-
"--xy-controls-button-background-color-props": local.bgColor,
|
|
1766
|
-
"--xy-controls-button-background-color-hover-props": local.bgColorHover,
|
|
1767
|
-
"--xy-controls-button-color-props": local.color,
|
|
1768
|
-
"--xy-controls-button-color-hover-props": local.colorHover,
|
|
1769
|
-
"--xy-controls-button-border-color-props": local.borderColor
|
|
2204
|
+
let rest = omit(props, "class", "bgColor", "bgColorHover", "color", "colorHover", "borderColor", "onClick", "children"), style = () => Object.entries({
|
|
2205
|
+
"--xy-controls-button-background-color-props": props.bgColor,
|
|
2206
|
+
"--xy-controls-button-background-color-hover-props": props.bgColorHover,
|
|
2207
|
+
"--xy-controls-button-color-props": props.color,
|
|
2208
|
+
"--xy-controls-button-color-hover-props": props.colorHover,
|
|
2209
|
+
"--xy-controls-button-border-color-props": props.borderColor
|
|
1770
2210
|
}).filter(([_, value]) => value !== void 0).reduce((acc, [key, value]) => (acc[key] = value, acc), {});
|
|
1771
|
-
return <button type="button" class={
|
|
1772
|
-
{
|
|
2211
|
+
return <button type="button" class={["solid-flow__controls-button", props.class]} onClick={(e) => props.onClick?.(e)} style={style()} {...rest}>
|
|
2212
|
+
{props.children}
|
|
1773
2213
|
</button>;
|
|
1774
2214
|
}, Fit = () => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 30">
|
|
1775
2215
|
<path d="M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z" />
|
|
@@ -1782,54 +2222,35 @@ const Marker = (props) => {
|
|
|
1782
2222
|
</svg>, Unlock = () => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 32">
|
|
1783
2223
|
<path d="M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z" />
|
|
1784
2224
|
</svg>, Controls = (props) => {
|
|
1785
|
-
let { store, actions } = useInternalSolidFlow(), _props =
|
|
2225
|
+
let { store, actions } = useInternalSolidFlow(), _props = propDefaults(props, {
|
|
1786
2226
|
position: "bottom-left",
|
|
1787
2227
|
showZoom: !0,
|
|
1788
2228
|
showFitView: !0,
|
|
1789
2229
|
showLock: !0,
|
|
1790
2230
|
orientation: "vertical"
|
|
1791
|
-
},
|
|
1792
|
-
"class",
|
|
1793
|
-
"position",
|
|
1794
|
-
"showZoom",
|
|
1795
|
-
"showFitView",
|
|
1796
|
-
"showLock",
|
|
1797
|
-
"orientation",
|
|
1798
|
-
"fitViewOptions",
|
|
1799
|
-
"beforeControls",
|
|
1800
|
-
"afterControls",
|
|
1801
|
-
"buttonBgColor",
|
|
1802
|
-
"buttonBgColorHover",
|
|
1803
|
-
"buttonColor",
|
|
1804
|
-
"buttonColorHover",
|
|
1805
|
-
"buttonBorderColor",
|
|
1806
|
-
"style",
|
|
1807
|
-
"children"
|
|
1808
|
-
]), getMinZoomReached = () => store.viewport.zoom <= store.minZoom, getMaxZoomReached = () => store.viewport.zoom >= store.maxZoom, getIsInteractive = () => store.nodesDraggable || store.nodesConnectable || store.elementsSelectable, onZoomInHandler = () => {
|
|
2231
|
+
}), rest = omit(_props, "class", "position", "showZoom", "showFitView", "showLock", "orientation", "fitViewOptions", "beforeControls", "afterControls", "buttonBgColor", "buttonBgColorHover", "buttonColor", "buttonColorHover", "buttonBorderColor", "style", "children"), getMinZoomReached = () => store.viewport.zoom <= store.minZoom, getMaxZoomReached = () => store.viewport.zoom >= store.maxZoom, getIsInteractive = () => store.nodesDraggable || store.nodesConnectable || store.elementsSelectable, onZoomInHandler = () => {
|
|
1809
2232
|
actions.zoomIn();
|
|
1810
2233
|
}, onZoomOutHandler = () => {
|
|
1811
2234
|
actions.zoomOut();
|
|
1812
2235
|
}, onFitViewHandler = () => {
|
|
1813
|
-
actions.fitView(
|
|
2236
|
+
actions.fitView(_props.fitViewOptions);
|
|
1814
2237
|
}, onToggleInteractivity = () => {
|
|
1815
2238
|
let newValue = !getIsInteractive();
|
|
1816
|
-
|
|
1817
|
-
actions.setNodesDraggable(newValue), actions.setNodesConnectable(newValue), actions.setElementsSelectable(newValue);
|
|
1818
|
-
});
|
|
2239
|
+
actions.setNodesDraggable(newValue), actions.setNodesConnectable(newValue), actions.setElementsSelectable(newValue);
|
|
1819
2240
|
}, buttonProps = () => ({
|
|
1820
|
-
bgColor:
|
|
1821
|
-
bgColorHover:
|
|
1822
|
-
color:
|
|
1823
|
-
colorHover:
|
|
1824
|
-
borderColor:
|
|
2241
|
+
bgColor: _props.buttonBgColor,
|
|
2242
|
+
bgColorHover: _props.buttonBgColorHover,
|
|
2243
|
+
color: _props.buttonColor,
|
|
2244
|
+
colorHover: _props.buttonColorHover,
|
|
2245
|
+
borderColor: _props.buttonBorderColor
|
|
1825
2246
|
});
|
|
1826
|
-
return <Panel class={
|
|
2247
|
+
return <Panel class={[
|
|
1827
2248
|
"solid-flow__controls",
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
]
|
|
1831
|
-
{
|
|
1832
|
-
<Show when={
|
|
2249
|
+
_props.orientation,
|
|
2250
|
+
_props.class
|
|
2251
|
+
]} position={_props.position} data-testid="solid-flow__controls" aria-label={store.ariaLabelConfig["controls.ariaLabel"]} style={_props.style} {...rest}>
|
|
2252
|
+
{_props.beforeControls}
|
|
2253
|
+
<Show when={_props.showZoom}>
|
|
1833
2254
|
<>
|
|
1834
2255
|
<ControlButton onClick={onZoomInHandler} class="solid-flow__controls-zoomin" title={store.ariaLabelConfig["controls.zoomIn.ariaLabel"]} aria-label={store.ariaLabelConfig["controls.zoomIn.ariaLabel"]} disabled={getMaxZoomReached()} {...buttonProps()}>
|
|
1835
2256
|
<Plus />
|
|
@@ -1839,56 +2260,51 @@ const Marker = (props) => {
|
|
|
1839
2260
|
</ControlButton>
|
|
1840
2261
|
</>
|
|
1841
2262
|
</Show>
|
|
1842
|
-
<Show when={
|
|
2263
|
+
<Show when={_props.showFitView}>
|
|
1843
2264
|
<ControlButton class="solid-flow__controls-fitview" onClick={onFitViewHandler} title={store.ariaLabelConfig["controls.fitView.ariaLabel"]} aria-label={store.ariaLabelConfig["controls.fitView.ariaLabel"]} {...buttonProps()}>
|
|
1844
2265
|
<Fit />
|
|
1845
2266
|
</ControlButton>
|
|
1846
2267
|
</Show>
|
|
1847
|
-
<Show when={
|
|
2268
|
+
<Show when={_props.showLock}>
|
|
1848
2269
|
<ControlButton class="solid-flow__controls-interactive" onClick={onToggleInteractivity} title={store.ariaLabelConfig["controls.interactive.ariaLabel"]} aria-label={store.ariaLabelConfig["controls.interactive.ariaLabel"]} {...buttonProps()}>
|
|
1849
2270
|
<Show when={getIsInteractive()} fallback={<Lock />}>
|
|
1850
2271
|
<Unlock />
|
|
1851
2272
|
</Show>
|
|
1852
2273
|
</ControlButton>
|
|
1853
2274
|
</Show>
|
|
1854
|
-
{
|
|
1855
|
-
{
|
|
2275
|
+
{_props.children}
|
|
2276
|
+
{_props.afterControls}
|
|
1856
2277
|
</Panel>;
|
|
1857
2278
|
}, EdgeToolbar = (props) => {
|
|
1858
|
-
let
|
|
1859
|
-
"x",
|
|
1860
|
-
"y",
|
|
1861
|
-
"alignX",
|
|
1862
|
-
"alignY",
|
|
1863
|
-
"isVisible",
|
|
1864
|
-
"selectEdgeOnClick",
|
|
1865
|
-
"class",
|
|
1866
|
-
"children"
|
|
1867
|
-
]), { store, edgeLookup } = useInternalSolidFlow(), edgeId = useEdgeId(), isActive = () => typeof local.isVisible == "boolean" ? local.isVisible : !!edgeLookup.get(edgeId())?.selected, transform = () => getEdgeToolbarTransform(local.x, local.y, store.viewport.zoom, local.alignX ?? "center", local.alignY ?? "center");
|
|
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");
|
|
1868
2280
|
return <Show when={isActive()}>
|
|
1869
|
-
<EdgeLabel selectEdgeOnClick={
|
|
1870
|
-
<div class={
|
|
2281
|
+
<EdgeLabel selectEdgeOnClick={props.selectEdgeOnClick} transparent>
|
|
2282
|
+
<div class={["solid-flow__edge-toolbar", props.class]} style={{
|
|
1871
2283
|
position: "absolute",
|
|
1872
2284
|
transform: transform(),
|
|
1873
2285
|
"transform-origin": "0 0"
|
|
1874
2286
|
}} data-id={edgeId()} {...rest}>
|
|
1875
|
-
{
|
|
2287
|
+
{props.children}
|
|
1876
2288
|
</div>
|
|
1877
2289
|
</EdgeLabel>
|
|
1878
2290
|
</Show>;
|
|
1879
2291
|
}, MiniMapNode = (props) => {
|
|
1880
|
-
let _props =
|
|
2292
|
+
let _props = propDefaults(props, {
|
|
1881
2293
|
borderRadius: 5,
|
|
1882
2294
|
width: 0,
|
|
1883
2295
|
height: 0
|
|
1884
|
-
}
|
|
2296
|
+
}), style = () => Object.entries({
|
|
1885
2297
|
fill: _props.color,
|
|
1886
2298
|
stroke: _props.strokeColor,
|
|
1887
2299
|
"stroke-width": _props.strokeWidth
|
|
1888
2300
|
}).filter(([_, value]) => value !== void 0).reduce((acc, [key, value]) => (acc[key] = value, acc), {});
|
|
1889
|
-
return <rect class={
|
|
2301
|
+
return <rect class={[
|
|
2302
|
+
"solid-flow__minimap-node",
|
|
2303
|
+
{ selected: !!_props.selected },
|
|
2304
|
+
_props.class
|
|
2305
|
+
]} x={_props.x} y={_props.y} rx={_props.borderRadius} ry={_props.borderRadius} width={_props.width} height={_props.height} shape-rendering={_props.shapeRendering} style={style()} />;
|
|
1890
2306
|
}, getAttrFunction = (func) => func instanceof Function ? func : () => func, MiniMap = (props) => {
|
|
1891
|
-
let { store, nodeLookup } = useInternalSolidFlow(), _props =
|
|
2307
|
+
let { store, nodeLookup } = useInternalSolidFlow(), _props = propDefaults(props, {
|
|
1892
2308
|
position: "bottom-right",
|
|
1893
2309
|
nodeClass: "",
|
|
1894
2310
|
nodeStrokeColor: "transparent",
|
|
@@ -1899,26 +2315,7 @@ const Marker = (props) => {
|
|
|
1899
2315
|
nodeBorderRadius: 5,
|
|
1900
2316
|
nodeStrokeWidth: 2,
|
|
1901
2317
|
style: {}
|
|
1902
|
-
},
|
|
1903
|
-
"class",
|
|
1904
|
-
"style",
|
|
1905
|
-
"position",
|
|
1906
|
-
"nodeClass",
|
|
1907
|
-
"nodeStrokeColor",
|
|
1908
|
-
"nodeColor",
|
|
1909
|
-
"pannable",
|
|
1910
|
-
"zoomable",
|
|
1911
|
-
"inversePan",
|
|
1912
|
-
"zoomStep",
|
|
1913
|
-
"bgColor",
|
|
1914
|
-
"width",
|
|
1915
|
-
"height",
|
|
1916
|
-
"maskColor",
|
|
1917
|
-
"maskStrokeColor",
|
|
1918
|
-
"maskStrokeWidth",
|
|
1919
|
-
"nodeBorderRadius",
|
|
1920
|
-
"nodeStrokeWidth"
|
|
1921
|
-
]), nodeColorFunc = () => local.nodeColor === void 0 ? void 0 : getAttrFunction(local.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(local.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(local.nodeClass), shapeRendering = () => typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision", labelledBy = createMemo(() => `solid-flow__minimap-desc-${store.id}`), getViewBB = () => ({
|
|
2318
|
+
}), paneProps = omit(_props, "class", "style", "position", "nodeClass", "nodeStrokeColor", "nodeColor", "pannable", "zoomable", "inversePan", "zoomStep", "bgColor", "width", "height", "maskColor", "maskStrokeColor", "maskStrokeWidth", "nodeBorderRadius", "nodeStrokeWidth"), nodeColorFunc = () => _props.nodeColor === void 0 ? void 0 : getAttrFunction(_props.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(_props.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(_props.nodeClass), shapeRendering = () => typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision", labelledBy = createMemo(() => `solid-flow__minimap-desc-${store.id}`), getViewBB = () => ({
|
|
1922
2319
|
x: -store.viewport.x / store.viewport.zoom,
|
|
1923
2320
|
y: -store.viewport.y / store.viewport.zoom,
|
|
1924
2321
|
width: store.width / store.viewport.zoom,
|
|
@@ -1926,57 +2323,64 @@ const Marker = (props) => {
|
|
|
1926
2323
|
}), getBoundingRect = () => {
|
|
1927
2324
|
let viewBB = getViewBB();
|
|
1928
2325
|
return nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(nodeLookup), viewBB) : viewBB;
|
|
1929
|
-
}, getScaledWidth = () => getBoundingRect().width /
|
|
2326
|
+
}, getScaledWidth = () => getBoundingRect().width / _props.width, getScaledHeight = () => getBoundingRect().height / _props.height, getViewScale = () => Math.max(getScaledWidth(), getScaledHeight()), getViewWidth = () => getViewScale() * _props.width, getViewHeight = () => getViewScale() * _props.height, getOffset = () => 5 * getViewScale(), getX = () => {
|
|
1930
2327
|
let boundingRect = getBoundingRect();
|
|
1931
2328
|
return boundingRect.x - (getViewWidth() - boundingRect.width) / 2 - getOffset();
|
|
1932
2329
|
}, getY = () => {
|
|
1933
2330
|
let boundingRect = getBoundingRect();
|
|
1934
2331
|
return boundingRect.y - (getViewHeight() - boundingRect.height) / 2 - getOffset();
|
|
1935
|
-
}, getViewboxWidth = () => getViewWidth() + getOffset() * 2, getViewboxHeight = () => getViewHeight() + getOffset() * 2, strokeWidth = () =>
|
|
2332
|
+
}, getViewboxWidth = () => getViewWidth() + getOffset() * 2, getViewboxHeight = () => getViewHeight() + getOffset() * 2, strokeWidth = () => _props.maskStrokeWidth ? _props.maskStrokeWidth * getViewScale() : void 0, prevNodeIds = [], nodeIds = () => {
|
|
1936
2333
|
let currentNodeIds = store.nodes.map((node) => node.id), currentSet = new Set(currentNodeIds);
|
|
1937
2334
|
return (prevNodeIds.length !== currentNodeIds.length || !prevNodeIds.every((id) => currentSet.has(id))) && (prevNodeIds = currentNodeIds), prevNodeIds;
|
|
1938
2335
|
};
|
|
1939
|
-
return <Panel position={
|
|
1940
|
-
"--xy-minimap-background-color-props":
|
|
1941
|
-
...
|
|
2336
|
+
return <Panel position={_props.position} data-testid="solid-flow__minimap" class={["solid-flow__minimap", _props.class]} style={{
|
|
2337
|
+
"--xy-minimap-background-color-props": _props.bgColor,
|
|
2338
|
+
..._props.style
|
|
1942
2339
|
}} {...paneProps}>
|
|
1943
2340
|
<Show when={store.panZoom}>
|
|
1944
2341
|
{(panZoom) => {
|
|
1945
|
-
let [ref, setRef] = createSignal();
|
|
1946
|
-
return
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2342
|
+
let [ref, setRef] = createSignal(), [minimap, setMinimap] = createSignal();
|
|
2343
|
+
return createEffect(() => ({
|
|
2344
|
+
el: ref(),
|
|
2345
|
+
panZoom: panZoom()
|
|
2346
|
+
}), ({ el, panZoom }) => {
|
|
2347
|
+
if (!el) return;
|
|
2348
|
+
let instance = XYMinimap({
|
|
2349
|
+
domNode: el,
|
|
2350
|
+
panZoom,
|
|
1950
2351
|
getTransform: () => store.transform,
|
|
1951
2352
|
getViewScale
|
|
1952
2353
|
});
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2354
|
+
return setMinimap(instance), () => {
|
|
2355
|
+
instance.destroy();
|
|
2356
|
+
};
|
|
2357
|
+
}), createEffect(() => ({
|
|
2358
|
+
instance: minimap(),
|
|
2359
|
+
options: {
|
|
2360
|
+
translateExtent: store.translateExtent,
|
|
2361
|
+
width: store.width,
|
|
2362
|
+
height: store.height,
|
|
2363
|
+
inversePan: _props.inversePan,
|
|
2364
|
+
zoomStep: _props.zoomStep,
|
|
2365
|
+
pannable: _props.pannable,
|
|
2366
|
+
zoomable: _props.zoomable
|
|
2367
|
+
}
|
|
2368
|
+
}), ({ instance, options }) => {
|
|
2369
|
+
instance?.update(options);
|
|
2370
|
+
}), <svg ref={setRef} width={_props.width} height={_props.height} viewBox={`${getX()} ${getY()} ${getViewboxWidth()} ${getViewboxHeight()}`} class="solid-flow__minimap-svg" role="img" aria-labelledby={labelledBy()} style={{
|
|
2371
|
+
"--xy-minimap-mask-background-color-props": _props.maskColor,
|
|
2372
|
+
"--xy-minimap-mask-stroke-color-props": _props.maskStrokeColor,
|
|
1969
2373
|
"--xy-minimap-mask-stroke-width-props": strokeWidth()
|
|
1970
2374
|
}}>
|
|
1971
2375
|
<title id={labelledBy()}>{store.ariaLabelConfig["minimap.ariaLabel"]}</title>
|
|
1972
|
-
<
|
|
2376
|
+
<For keyed={!1} each={nodeIds()}>
|
|
1973
2377
|
{(nodeId) => {
|
|
1974
2378
|
let node = createMemo(() => nodeLookup.get(nodeId())), nodeVisible = () => !!(node() && nodeHasDimensions(node()) && !node().hidden);
|
|
1975
2379
|
return <Show when={nodeVisible() && getNodeDimensions(node())}>
|
|
1976
|
-
{(nodeDimensions) => <MiniMapNode x={node().internals.positionAbsolute.x} y={node().internals.positionAbsolute.y} borderRadius={
|
|
2380
|
+
{(nodeDimensions) => <MiniMapNode x={node().internals.positionAbsolute.x} y={node().internals.positionAbsolute.y} borderRadius={_props.nodeBorderRadius} strokeWidth={_props.nodeStrokeWidth} shapeRendering={shapeRendering()} width={nodeDimensions().width} height={nodeDimensions().height} selected={node().selected} color={nodeColorFunc()?.call(null, node())} strokeColor={nodeStrokeColorFunc().call(null, node())} class={nodeClassFunc().call(null, node())} />}
|
|
1977
2381
|
</Show>;
|
|
1978
2382
|
}}
|
|
1979
|
-
</
|
|
2383
|
+
</For>
|
|
1980
2384
|
<path class="solid-flow__minimap-mask" d={`M${getX() - getOffset()},${getY() - getOffset()}h${getViewboxWidth() + getOffset() * 2}v${getViewboxHeight() + getOffset() * 2}h${-getViewboxWidth() - getOffset() * 2}z
|
|
1981
2385
|
M${getViewBB().x},${getViewBB().y}h${getViewBB().width}v${getViewBB().height}h${-getViewBB().width}z`} fill-rule="evenodd" pointer-events="none" />
|
|
1982
2386
|
</svg>;
|
|
@@ -1984,7 +2388,7 @@ const Marker = (props) => {
|
|
|
1984
2388
|
</Show>
|
|
1985
2389
|
</Panel>;
|
|
1986
2390
|
}, ResizeControl = (props) => {
|
|
1987
|
-
let _props =
|
|
2391
|
+
let _props = propDefaults(props, {
|
|
1988
2392
|
variant: "handle",
|
|
1989
2393
|
minWidth: 10,
|
|
1990
2394
|
minHeight: 10,
|
|
@@ -1993,28 +2397,11 @@ const Marker = (props) => {
|
|
|
1993
2397
|
keepAspectRatio: !1,
|
|
1994
2398
|
autoScale: !0,
|
|
1995
2399
|
style: {}
|
|
1996
|
-
},
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
"minHeight",
|
|
2002
|
-
"maxWidth",
|
|
2003
|
-
"maxHeight",
|
|
2004
|
-
"keepAspectRatio",
|
|
2005
|
-
"autoScale",
|
|
2006
|
-
"onResizeStart",
|
|
2007
|
-
"onResize",
|
|
2008
|
-
"onResizeEnd",
|
|
2009
|
-
"shouldResize",
|
|
2010
|
-
"class",
|
|
2011
|
-
"children",
|
|
2012
|
-
"color",
|
|
2013
|
-
"style"
|
|
2014
|
-
]), resizeControlRef, { store, nodeLookup, actions } = useInternalSolidFlow(), ctxNodeId = useNodeId(), nodeId = () => local.nodeId ?? ctxNodeId(), isLineVariant = () => local.variant === "line", controlPosition = () => local.position ?? (isLineVariant() ? "right" : "bottom-right"), positionClassNames = () => controlPosition().split("-");
|
|
2015
|
-
return onMount(() => {
|
|
2016
|
-
let resizer = XYResizer({
|
|
2017
|
-
domNode: resizeControlRef,
|
|
2400
|
+
}), rest = omit(_props, "nodeId", "variant", "position", "minWidth", "minHeight", "maxWidth", "maxHeight", "keepAspectRatio", "autoScale", "onResizeStart", "onResize", "onResizeEnd", "shouldResize", "class", "children", "color", "style"), [resizeControlRef, setResizeControlRef] = createSignal(), { store, nodeLookup, actions } = useInternalSolidFlow(), ctxNodeId = useNodeId(), nodeId = () => _props.nodeId ?? ctxNodeId(), isLineVariant = () => _props.variant === "line", controlPosition = () => _props.position ?? (isLineVariant() ? "right" : "bottom-right"), positionClassNames = () => controlPosition().split("-"), [resizer, setResizer] = createSignal();
|
|
2401
|
+
return createEffect(() => resizeControlRef(), (el) => {
|
|
2402
|
+
if (!el) return;
|
|
2403
|
+
let instance = XYResizer({
|
|
2404
|
+
domNode: el,
|
|
2018
2405
|
nodeId: nodeId(),
|
|
2019
2406
|
getStoreItems: () => ({
|
|
2020
2407
|
nodeLookup,
|
|
@@ -2034,63 +2421,63 @@ const Marker = (props) => {
|
|
|
2034
2421
|
position
|
|
2035
2422
|
});
|
|
2036
2423
|
for (let childChange of childChanges) changes.set(childChange.id, { position: childChange.position });
|
|
2037
|
-
actions.setNodes((
|
|
2038
|
-
let
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2424
|
+
actions.setNodes((nodes) => {
|
|
2425
|
+
for (let node of nodes) {
|
|
2426
|
+
let nodeChange = changes.get(node.id);
|
|
2427
|
+
nodeChange && (node.width = nodeChange.width, node.height = nodeChange.height, node.position = {
|
|
2428
|
+
x: nodeChange.position?.x ?? node.position.x,
|
|
2429
|
+
y: nodeChange.position?.y ?? node.position.y
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
});
|
|
2044
2433
|
}
|
|
2045
2434
|
});
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2435
|
+
return setResizer(instance), () => {
|
|
2436
|
+
instance.destroy();
|
|
2437
|
+
};
|
|
2438
|
+
}), createEffect(() => ({
|
|
2439
|
+
instance: resizer(),
|
|
2440
|
+
options: {
|
|
2441
|
+
controlPosition: controlPosition(),
|
|
2442
|
+
boundaries: {
|
|
2443
|
+
minWidth: _props.minWidth,
|
|
2444
|
+
minHeight: _props.minHeight,
|
|
2445
|
+
maxWidth: _props.maxWidth,
|
|
2446
|
+
maxHeight: _props.maxHeight
|
|
2447
|
+
},
|
|
2448
|
+
keepAspectRatio: !!_props.keepAspectRatio,
|
|
2449
|
+
onResizeStart: _props.onResizeStart,
|
|
2450
|
+
onResize: _props.onResize,
|
|
2451
|
+
onResizeEnd: _props.onResizeEnd,
|
|
2452
|
+
shouldResize: _props.shouldResize
|
|
2453
|
+
}
|
|
2454
|
+
}), ({ instance, options }) => {
|
|
2455
|
+
instance?.update(options);
|
|
2456
|
+
}), <div ref={setResizeControlRef} class={[
|
|
2065
2457
|
"solid-flow__resize-control",
|
|
2066
|
-
|
|
2458
|
+
_props.variant,
|
|
2067
2459
|
store.noDragClass,
|
|
2068
2460
|
...positionClassNames(),
|
|
2069
|
-
|
|
2070
|
-
]
|
|
2071
|
-
"border-color": isLineVariant() ?
|
|
2072
|
-
"background-color": isLineVariant() ? void 0 :
|
|
2073
|
-
scale: isLineVariant() || !
|
|
2074
|
-
...
|
|
2461
|
+
_props.class
|
|
2462
|
+
]} style={{
|
|
2463
|
+
"border-color": isLineVariant() ? _props.color : void 0,
|
|
2464
|
+
"background-color": isLineVariant() ? void 0 : _props.color,
|
|
2465
|
+
scale: isLineVariant() || !_props.autoScale ? void 0 : Math.max(1 / store.viewport.zoom, 1),
|
|
2466
|
+
..._props.style
|
|
2075
2467
|
}} {...rest}>
|
|
2076
|
-
{
|
|
2468
|
+
{_props.children}
|
|
2077
2469
|
</div>;
|
|
2078
2470
|
}, NodeResizer = (props) => {
|
|
2079
|
-
let _props =
|
|
2471
|
+
let _props = propDefaults(props, {
|
|
2080
2472
|
autoScale: !0,
|
|
2081
2473
|
visible: !0
|
|
2082
|
-
}
|
|
2083
|
-
"handleClass",
|
|
2084
|
-
"handleStyle",
|
|
2085
|
-
"lineClass",
|
|
2086
|
-
"lineStyle"
|
|
2087
|
-
]);
|
|
2474
|
+
}), rest = omit(props, "handleClass", "handleStyle", "lineClass", "lineStyle");
|
|
2088
2475
|
return <Show when={_props.visible}>
|
|
2089
2476
|
<For each={XY_RESIZER_LINE_POSITIONS}>
|
|
2090
|
-
{(position) => <ResizeControl variant="line" position={position} class={
|
|
2477
|
+
{(position) => <ResizeControl variant="line" position={position} class={props.lineClass} style={props.lineStyle} {...rest} />}
|
|
2091
2478
|
</For>
|
|
2092
2479
|
<For each={XY_RESIZER_HANDLE_POSITIONS}>
|
|
2093
|
-
{(position) => <ResizeControl position={position} class={
|
|
2480
|
+
{(position) => <ResizeControl position={position} class={props.handleClass} style={props.handleStyle} {...rest} />}
|
|
2094
2481
|
</For>
|
|
2095
2482
|
</Show>;
|
|
2096
2483
|
};
|
|
@@ -2106,8 +2493,8 @@ const Marker = (props) => {
|
|
|
2106
2493
|
* @returns an accessor for the current color mode class
|
|
2107
2494
|
*/
|
|
2108
2495
|
function useColorMode() {
|
|
2109
|
-
let {
|
|
2110
|
-
return () =>
|
|
2496
|
+
let { flow } = useInternalSolidFlow();
|
|
2497
|
+
return () => flow.colorMode;
|
|
2111
2498
|
}
|
|
2112
2499
|
//#endregion
|
|
2113
2500
|
//#region src/hooks/useConnection.tsx
|
|
@@ -2118,8 +2505,8 @@ function useColorMode() {
|
|
|
2118
2505
|
* @returns current connection as a readable store
|
|
2119
2506
|
*/
|
|
2120
2507
|
function useConnection() {
|
|
2121
|
-
let {
|
|
2122
|
-
return () =>
|
|
2508
|
+
let { flow } = useInternalSolidFlow();
|
|
2509
|
+
return () => flow.connection;
|
|
2123
2510
|
}
|
|
2124
2511
|
//#endregion
|
|
2125
2512
|
//#region src/hooks/useGraph.ts
|
|
@@ -2150,21 +2537,19 @@ function useEdges() {
|
|
|
2150
2537
|
* @returns store with the viewport object
|
|
2151
2538
|
*/
|
|
2152
2539
|
function useViewport() {
|
|
2153
|
-
let {
|
|
2154
|
-
return () =>
|
|
2540
|
+
let { flow } = useInternalSolidFlow();
|
|
2541
|
+
return () => flow.viewport;
|
|
2155
2542
|
}
|
|
2156
2543
|
//#endregion
|
|
2157
2544
|
//#region src/hooks/useHandleEdgeSelect.tsx
|
|
2158
2545
|
function useHandleEdgeSelect() {
|
|
2159
2546
|
let { store, edgeLookup, actions } = useInternalSolidFlow();
|
|
2160
2547
|
return (id) => {
|
|
2161
|
-
let edge = edgeLookup
|
|
2162
|
-
edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) &&
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
}) : actions.addSelectedEdges([id]);
|
|
2167
|
-
});
|
|
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]));
|
|
2168
2553
|
};
|
|
2169
2554
|
}
|
|
2170
2555
|
//#endregion
|
|
@@ -2179,8 +2564,8 @@ function useHandleEdgeSelect() {
|
|
|
2179
2564
|
* @returns an accessor that indicates whether the nodes are initialized
|
|
2180
2565
|
*/
|
|
2181
2566
|
function useNodesInitialized() {
|
|
2182
|
-
let {
|
|
2183
|
-
return () =>
|
|
2567
|
+
let { flow } = useInternalSolidFlow();
|
|
2568
|
+
return () => flow.nodesInitialized;
|
|
2184
2569
|
}
|
|
2185
2570
|
/**
|
|
2186
2571
|
* Hook for seeing if the viewport is initialized.
|
|
@@ -2191,8 +2576,8 @@ function useNodesInitialized() {
|
|
|
2191
2576
|
* @returns an accessor that indicates whether the viewport is initialized
|
|
2192
2577
|
*/
|
|
2193
2578
|
function useViewportInitialized() {
|
|
2194
|
-
let {
|
|
2195
|
-
return () =>
|
|
2579
|
+
let { flow } = useInternalSolidFlow();
|
|
2580
|
+
return () => flow.viewportInitialized;
|
|
2196
2581
|
}
|
|
2197
2582
|
//#endregion
|
|
2198
2583
|
//#region src/hooks/useInternalNode.tsx
|
|
@@ -2204,8 +2589,8 @@ function useViewportInitialized() {
|
|
|
2204
2589
|
* @returns an accessor with an internal node or undefined
|
|
2205
2590
|
*/
|
|
2206
2591
|
function useInternalNode(id) {
|
|
2207
|
-
let {
|
|
2208
|
-
return () =>
|
|
2592
|
+
let { flow } = useInternalSolidFlow();
|
|
2593
|
+
return () => flow.internalNodes[id()];
|
|
2209
2594
|
}
|
|
2210
2595
|
//#endregion
|
|
2211
2596
|
//#region src/hooks/useNodeConnections.ts
|
|
@@ -2221,25 +2606,28 @@ function useInternalNode(id) {
|
|
|
2221
2606
|
* @returns an array with connections
|
|
2222
2607
|
*/
|
|
2223
2608
|
const useNodeConnections = (params) => {
|
|
2224
|
-
let {
|
|
2609
|
+
let { flow } = useInternalSolidFlow(), ctxNodeId = () => {
|
|
2225
2610
|
let id = useContext(NodeIdContext);
|
|
2226
2611
|
return id ? id() : "";
|
|
2227
|
-
}, id = () => params().handleId, type = () => params().handleType, nodeId = () => params().id ?? ctxNodeId(), [connections, setConnections] = createSignal([]),
|
|
2228
|
-
return createEffect((
|
|
2229
|
-
let
|
|
2230
|
-
|
|
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())));
|
|
2231
2619
|
}), connections;
|
|
2232
2620
|
};
|
|
2233
2621
|
//#endregion
|
|
2234
2622
|
//#region src/hooks/useNodesData.ts
|
|
2235
2623
|
function useNodesData(nodeIds) {
|
|
2236
|
-
let {
|
|
2624
|
+
let { flow } = useInternalSolidFlow(), prevNodesData = [];
|
|
2237
2625
|
return createMemo(() => {
|
|
2238
2626
|
let nodesData = [], idValues = nodeIds();
|
|
2239
2627
|
if (!idValues) return;
|
|
2240
2628
|
let ids = Array.isArray(idValues) ? idValues : [idValues];
|
|
2241
2629
|
for (let nodeId of ids) {
|
|
2242
|
-
let node =
|
|
2630
|
+
let node = flow.internalNodes[nodeId]?.internals.userNode;
|
|
2243
2631
|
node && nodesData.push({
|
|
2244
2632
|
id: node.id,
|
|
2245
2633
|
type: node.type,
|
|
@@ -2252,235 +2640,69 @@ function useNodesData(nodeIds) {
|
|
|
2252
2640
|
//#endregion
|
|
2253
2641
|
//#region src/hooks/useSolidFlow.tsx
|
|
2254
2642
|
/**
|
|
2255
|
-
* Hook for accessing the
|
|
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()`.
|
|
2256
2648
|
*
|
|
2257
2649
|
* @public
|
|
2258
|
-
* @returns
|
|
2650
|
+
* @returns the flow's read struct, write surface, and deprecated aliases
|
|
2259
2651
|
*/
|
|
2260
2652
|
function useSolidFlow() {
|
|
2261
|
-
let {
|
|
2262
|
-
let nodeToUse = isNode(node) ? node : nodeLookup.get(node.id), position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, store.nodeOrigin) : nodeToUse.position, nodeWithPosition = {
|
|
2263
|
-
...nodeToUse,
|
|
2264
|
-
position,
|
|
2265
|
-
width: nodeToUse.measured?.width ?? nodeToUse.width,
|
|
2266
|
-
height: nodeToUse.measured?.height ?? nodeToUse.height
|
|
2267
|
-
};
|
|
2268
|
-
return nodeToRect(nodeWithPosition);
|
|
2269
|
-
}, updateNode = (id, nodeUpdate, options = { replace: !1 }) => {
|
|
2270
|
-
actions.setNodes((node) => node.id === id, (node) => {
|
|
2271
|
-
let nextNode = typeof nodeUpdate == "function" ? nodeUpdate(node) : nodeUpdate;
|
|
2272
|
-
return options?.replace && isNode(nextNode) ? nextNode : {
|
|
2273
|
-
...node,
|
|
2274
|
-
...nextNode
|
|
2275
|
-
};
|
|
2276
|
-
});
|
|
2277
|
-
}, updateEdge = (id, edgeUpdate, options = { replace: !1 }) => {
|
|
2278
|
-
actions.setEdges((edge) => edge.id === id, (edge) => {
|
|
2279
|
-
let nextEdge = typeof edgeUpdate == "function" ? edgeUpdate(edge) : edgeUpdate;
|
|
2280
|
-
return options.replace && isEdge(nextEdge) ? nextEdge : {
|
|
2281
|
-
...edge,
|
|
2282
|
-
...nextEdge
|
|
2283
|
-
};
|
|
2284
|
-
});
|
|
2285
|
-
}, getInternalNode = (id) => nodeLookup.get(id);
|
|
2653
|
+
let { flow, commands, store, edgeLookup } = useInternalSolidFlow(), getInternalNode = (id) => flow.internalNodes[id];
|
|
2286
2654
|
return {
|
|
2287
|
-
|
|
2288
|
-
|
|
2655
|
+
...commands,
|
|
2656
|
+
flow,
|
|
2657
|
+
commands,
|
|
2289
2658
|
getInternalNode,
|
|
2290
|
-
setCenter: actions.setCenter,
|
|
2291
|
-
fitView: actions.fitView,
|
|
2292
2659
|
getNode: (id) => getInternalNode(id)?.internals.userNode,
|
|
2293
|
-
getNodes: (ids) => ids ?
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
actions.setEdges((edges) => [...edges, ...newEdges]);
|
|
2303
|
-
},
|
|
2304
|
-
getViewport: () => unwrap(store.viewport),
|
|
2305
|
-
setViewport: async (nextViewport, options) => {
|
|
2306
|
-
let currentViewport = store.viewport;
|
|
2307
|
-
return store.panZoom ? (await store.panZoom.setViewport({
|
|
2308
|
-
x: nextViewport.x ?? currentViewport.x,
|
|
2309
|
-
y: nextViewport.y ?? currentViewport.y,
|
|
2310
|
-
zoom: nextViewport.zoom ?? currentViewport.zoom
|
|
2311
|
-
}, options), Promise.resolve(!0)) : Promise.resolve(!1);
|
|
2312
|
-
},
|
|
2313
|
-
getZoom: () => store.viewport.zoom,
|
|
2314
|
-
setZoom: (zoomLevel, options) => {
|
|
2315
|
-
let panZoom = store.panZoom;
|
|
2316
|
-
return panZoom ? panZoom.scaleTo(zoomLevel, { duration: options?.duration }) : Promise.resolve(!1);
|
|
2317
|
-
},
|
|
2318
|
-
fitBounds: async (bounds, options) => {
|
|
2319
|
-
if (!store.panZoom) return Promise.resolve(!1);
|
|
2320
|
-
let viewport = getViewportForBounds$1(bounds, store.width, store.height, store.minZoom, store.maxZoom, options?.padding ?? .1);
|
|
2321
|
-
return await store.panZoom.setViewport(viewport, {
|
|
2322
|
-
duration: options?.duration,
|
|
2323
|
-
ease: options?.ease,
|
|
2324
|
-
interpolate: options?.interpolate
|
|
2325
|
-
}), Promise.resolve(!0);
|
|
2326
|
-
},
|
|
2327
|
-
getIntersectingNodes: (nodeOrRect, partially = !0, nodesToIntersect) => {
|
|
2328
|
-
let isRect = isRectObject(nodeOrRect), nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
|
|
2329
|
-
return nodeRect ? (nodesToIntersect || store.nodes).filter((n) => {
|
|
2330
|
-
let internalNode = nodeLookup.get(n.id);
|
|
2331
|
-
if (!internalNode || !isRect && n.id === nodeOrRect.id) return !1;
|
|
2332
|
-
let currNodeRect = nodeToRect(internalNode), overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
|
|
2333
|
-
return partially && overlappingArea > 0 || overlappingArea >= nodeRect.width * nodeRect.height;
|
|
2334
|
-
}) : [];
|
|
2335
|
-
},
|
|
2336
|
-
isNodeIntersecting: (nodeOrRect, area, partially = !0) => {
|
|
2337
|
-
let nodeRect = isRectObject(nodeOrRect) ? nodeOrRect : getNodeRect(nodeOrRect);
|
|
2338
|
-
if (!nodeRect) return !1;
|
|
2339
|
-
let overlappingArea = getOverlappingArea(nodeRect, area);
|
|
2340
|
-
return partially && overlappingArea > 0 || overlappingArea >= nodeRect.width * nodeRect.height;
|
|
2341
|
-
},
|
|
2342
|
-
deleteElements: async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
|
|
2343
|
-
let { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
|
|
2344
|
-
nodesToRemove,
|
|
2345
|
-
edgesToRemove,
|
|
2346
|
-
nodes: store.nodes,
|
|
2347
|
-
edges: store.edges,
|
|
2348
|
-
onBeforeDelete: store.onBeforeDelete
|
|
2349
|
-
});
|
|
2350
|
-
return batch(() => {
|
|
2351
|
-
if (matchingEdges) {
|
|
2352
|
-
let remmainingEdges = store.edges.filter((edge) => !matchingEdges.some(({ id }) => id === edge.id));
|
|
2353
|
-
store.onEdgesDelete?.(matchingEdges), actions.setEdges(remmainingEdges);
|
|
2354
|
-
}
|
|
2355
|
-
if (matchingNodes) {
|
|
2356
|
-
let remmainingNodes = store.nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id));
|
|
2357
|
-
store.onNodesDelete?.(matchingNodes), actions.setNodes(remmainingNodes);
|
|
2358
|
-
}
|
|
2359
|
-
}), {
|
|
2360
|
-
deletedNodes: matchingNodes,
|
|
2361
|
-
deletedEdges: matchingEdges
|
|
2362
|
-
};
|
|
2363
|
-
},
|
|
2364
|
-
screenToFlowPosition: (position, options = { snapToGrid: !0 }) => {
|
|
2365
|
-
if (!store.domNode) return position;
|
|
2366
|
-
let _snapGrid = options.snapToGrid ? store.snapGrid : !1, { x, y, zoom } = store.viewport, { x: domX, y: domY } = store.domNode.getBoundingClientRect(), correctedPosition = {
|
|
2367
|
-
x: position.x - domX,
|
|
2368
|
-
y: position.y - domY
|
|
2369
|
-
};
|
|
2370
|
-
return pointToRendererPoint(correctedPosition, [
|
|
2371
|
-
x,
|
|
2372
|
-
y,
|
|
2373
|
-
zoom
|
|
2374
|
-
], _snapGrid !== null, _snapGrid || [1, 1]);
|
|
2375
|
-
},
|
|
2376
|
-
/**
|
|
2377
|
-
*
|
|
2378
|
-
* @param position
|
|
2379
|
-
* @returns
|
|
2380
|
-
*/
|
|
2381
|
-
flowToScreenPosition: (position) => {
|
|
2382
|
-
if (!store.domNode) return position;
|
|
2383
|
-
let { x, y, zoom } = store.viewport, { x: domX, y: domY } = store.domNode.getBoundingClientRect(), rendererPosition = rendererPointToPoint(position, [
|
|
2384
|
-
x,
|
|
2385
|
-
y,
|
|
2386
|
-
zoom
|
|
2387
|
-
]);
|
|
2388
|
-
return {
|
|
2389
|
-
x: rendererPosition.x + domX,
|
|
2390
|
-
y: rendererPosition.y + domY
|
|
2391
|
-
};
|
|
2392
|
-
},
|
|
2393
|
-
toObject: () => structuredClone({
|
|
2394
|
-
nodes: [...unwrap(store.nodes)],
|
|
2395
|
-
edges: [...unwrap(store.edges)],
|
|
2396
|
-
viewport: { ...unwrap(store.viewport) }
|
|
2397
|
-
}),
|
|
2398
|
-
updateNode,
|
|
2399
|
-
updateNodeData: (id, dataUpdate, options) => {
|
|
2400
|
-
let node = nodeLookup.get(id)?.internals.userNode;
|
|
2401
|
-
if (!node) return;
|
|
2402
|
-
let nextData = typeof dataUpdate == "function" ? dataUpdate(node) : dataUpdate;
|
|
2403
|
-
updateNode(id, (node) => ({
|
|
2404
|
-
...node,
|
|
2405
|
-
data: options?.replace ? nextData : {
|
|
2406
|
-
...node.data,
|
|
2407
|
-
...nextData
|
|
2408
|
-
}
|
|
2409
|
-
}));
|
|
2410
|
-
},
|
|
2411
|
-
updateEdge,
|
|
2412
|
-
getNodesBounds: (nodes) => getNodesBounds$1(nodes, {
|
|
2413
|
-
nodeLookup,
|
|
2414
|
-
nodeOrigin: store.nodeOrigin
|
|
2415
|
-
}),
|
|
2416
|
-
getHandleConnections: ({ type, id, nodeId }) => Array.from(connectionLookup.get(`${nodeId}-${type}-${id ?? null}`)?.values() ?? [])
|
|
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)] ?? {})
|
|
2417
2669
|
};
|
|
2418
2670
|
}
|
|
2419
|
-
function getElements(lookup, ids) {
|
|
2420
|
-
let result = [];
|
|
2421
|
-
for (let id of ids) {
|
|
2422
|
-
let item = lookup.get(id);
|
|
2423
|
-
if (item) {
|
|
2424
|
-
let element = "internals" in item ? item.internals?.userNode : item;
|
|
2425
|
-
result.push(element);
|
|
2426
|
-
}
|
|
2427
|
-
}
|
|
2428
|
-
return result;
|
|
2429
|
-
}
|
|
2430
2671
|
//#endregion
|
|
2431
2672
|
//#region src/hooks/useUpdateNodeInternals.ts
|
|
2432
2673
|
/**
|
|
2433
|
-
* Hook for updating node internals.
|
|
2674
|
+
* Hook for updating node internals. Sugar for `commands.updateNodeInternals`.
|
|
2434
2675
|
*
|
|
2435
2676
|
* @public
|
|
2436
2677
|
* @returns function for updating node internals
|
|
2437
2678
|
*/
|
|
2438
2679
|
function useUpdateNodeInternals() {
|
|
2439
|
-
let {
|
|
2440
|
-
return
|
|
2441
|
-
let updateIds = Array.isArray(id) ? id : [id], updates = [];
|
|
2442
|
-
for (let updateId of updateIds) {
|
|
2443
|
-
let nodeElement = store.domNode?.querySelector(`.solid-flow__node[data-id="${updateId}"]`);
|
|
2444
|
-
nodeElement && updates.push([updateId, {
|
|
2445
|
-
id: updateId,
|
|
2446
|
-
nodeElement,
|
|
2447
|
-
force: !0
|
|
2448
|
-
}]);
|
|
2449
|
-
}
|
|
2450
|
-
actions.requestUpdateNodeInternals(updates);
|
|
2451
|
-
};
|
|
2680
|
+
let { commands } = useInternalSolidFlow();
|
|
2681
|
+
return commands.updateNodeInternals;
|
|
2452
2682
|
}
|
|
2453
2683
|
//#endregion
|
|
2454
2684
|
//#region src/components/graph/plugins/NodeToolbar.tsx
|
|
2455
2685
|
const NodeToolbar = (props) => {
|
|
2456
|
-
let { store } = useInternalSolidFlow(), { getNodes, getNodesBounds, getInternalNode } = useSolidFlow(), _props =
|
|
2686
|
+
let { store } = useInternalSolidFlow(), { getNodes, getNodesBounds, getInternalNode } = useSolidFlow(), _props = propDefaults(props, {
|
|
2457
2687
|
offset: 10,
|
|
2458
2688
|
position: "top",
|
|
2459
2689
|
align: "center",
|
|
2460
2690
|
style: {}
|
|
2461
|
-
}
|
|
2462
|
-
"nodeId",
|
|
2463
|
-
"position",
|
|
2464
|
-
"align",
|
|
2465
|
-
"offset",
|
|
2466
|
-
"isVisible",
|
|
2467
|
-
"style",
|
|
2468
|
-
"children"
|
|
2469
|
-
]), ctxNodeId = () => {
|
|
2691
|
+
}), divProps = omit(_props, "nodeId", "position", "align", "offset", "isVisible", "style", "children"), ctxNodeId = () => {
|
|
2470
2692
|
let id = useContext(NodeIdContext);
|
|
2471
2693
|
return id ? id() : "";
|
|
2472
|
-
}, toolbarNodes = () => (Array.isArray(
|
|
2694
|
+
}, toolbarNodes = () => (Array.isArray(_props.nodeId) ? _props.nodeId : [_props.nodeId ?? ctxNodeId()]).reduce((res, nodeId) => {
|
|
2473
2695
|
let node = getInternalNode(nodeId);
|
|
2474
2696
|
return node && res.push(node), res;
|
|
2475
2697
|
}, []), transform = () => {
|
|
2476
2698
|
let nodeRect = getNodesBounds(toolbarNodes());
|
|
2477
|
-
return nodeRect ? getNodeToolbarTransform(nodeRect, store.viewport,
|
|
2699
|
+
return nodeRect ? getNodeToolbarTransform(nodeRect, store.viewport, _props.position, _props.offset, _props.align) : "";
|
|
2478
2700
|
}, zIndex = () => {
|
|
2479
2701
|
let nodes = toolbarNodes();
|
|
2480
2702
|
return nodes.length === 0 ? 1 : Math.max(...nodes.map((node) => (node.internals.z || 5) + 1));
|
|
2481
2703
|
}, selectedNodesCount = () => getNodes().filter((node) => node.selected).length, isActive = () => {
|
|
2482
2704
|
let nodes = toolbarNodes();
|
|
2483
|
-
return typeof
|
|
2705
|
+
return typeof _props.isVisible == "boolean" ? _props.isVisible : nodes.length === 1 && !!nodes[0].selected && selectedNodesCount() === 1;
|
|
2484
2706
|
}, showPortal = () => !!(store.domNode && isActive() && toolbarNodes().length > 0);
|
|
2485
2707
|
return <Show when={showPortal()}>
|
|
2486
2708
|
<Portal mount={store.domNode}>
|
|
@@ -2488,14 +2710,14 @@ const NodeToolbar = (props) => {
|
|
|
2488
2710
|
position: "absolute",
|
|
2489
2711
|
transform: transform(),
|
|
2490
2712
|
"z-index": zIndex(),
|
|
2491
|
-
...
|
|
2713
|
+
..._props.style
|
|
2492
2714
|
}} {...divProps}>
|
|
2493
|
-
{
|
|
2715
|
+
{_props.children}
|
|
2494
2716
|
</div>
|
|
2495
2717
|
</Portal>
|
|
2496
2718
|
</Show>;
|
|
2497
2719
|
}, Selection = (props) => {
|
|
2498
|
-
let _props =
|
|
2720
|
+
let _props = propDefaults(props, { isVisible: !0 }), styles = () => ({
|
|
2499
2721
|
..._props.width != null && { width: typeof _props.width == "string" ? _props.width : toPxString(_props.width) },
|
|
2500
2722
|
..._props.height != null && { height: typeof _props.height == "string" ? _props.height : toPxString(_props.height) },
|
|
2501
2723
|
..._props.x != null && _props.y != null && { transform: `translate(${props.x}px, ${props.y}px)` }
|
|
@@ -2505,8 +2727,11 @@ const NodeToolbar = (props) => {
|
|
|
2505
2727
|
</Show>;
|
|
2506
2728
|
}, NodeSelection = (props) => {
|
|
2507
2729
|
let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref, setRef] = createSignal(), bounds = () => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null;
|
|
2508
|
-
createEffect(() => {
|
|
2509
|
-
|
|
2730
|
+
createEffect(() => ({
|
|
2731
|
+
el: ref(),
|
|
2732
|
+
focusable: !store.disableKeyboardA11y
|
|
2733
|
+
}), ({ el, focusable }) => {
|
|
2734
|
+
focusable && el?.focus({ preventScroll: !0 });
|
|
2510
2735
|
});
|
|
2511
2736
|
let onContextMenu = (event) => {
|
|
2512
2737
|
let selectedNodes = store.nodes.filter((n) => n.selected);
|
|
@@ -2550,11 +2775,11 @@ const NodeToolbar = (props) => {
|
|
|
2550
2775
|
diff && (event.preventDefault(), actions.moveSelectedNodes(diff, event.shiftKey ? 4 : 1));
|
|
2551
2776
|
};
|
|
2552
2777
|
return <Show when={store.selectionRectMode === "nodes" && bounds() && isNumeric(bounds()?.x) && isNumeric(bounds()?.y)}>
|
|
2553
|
-
<div ref={setRef} class={
|
|
2778
|
+
<div ref={setRef} class={["solid-flow__selection-wrapper", store.noPanClass]} style={{
|
|
2554
2779
|
width: toPxString(bounds()?.width),
|
|
2555
2780
|
height: toPxString(bounds()?.height),
|
|
2556
2781
|
transform: `translate(${bounds()?.x}px, ${bounds()?.y}px)`
|
|
2557
|
-
}} onClick={onClick} onContextMenu={onContextMenu} role={store.disableKeyboardA11y ? void 0 : "button"}
|
|
2782
|
+
}} onClick={onClick} onContextMenu={onContextMenu} role={store.disableKeyboardA11y ? void 0 : "button"} tabindex={store.disableKeyboardA11y ? void 0 : -1} onKeyDown={store.disableKeyboardA11y ? void 0 : onKeyDown}>
|
|
2558
2783
|
<Selection width="100%" height="100%" x={0} y={0} />
|
|
2559
2784
|
</div>
|
|
2560
2785
|
</Show>;
|
|
@@ -2599,16 +2824,24 @@ function matchesKeyArray(event, keyDefs) {
|
|
|
2599
2824
|
return keyDefs ? (Array.isArray(keyDefs) ? keyDefs : [keyDefs]).some((keyDef) => matchesKey(event, keyDef)) : !1;
|
|
2600
2825
|
}
|
|
2601
2826
|
const KeyHandler = (props) => {
|
|
2602
|
-
let { store, actions } = useInternalSolidFlow(), { deleteElements } = useSolidFlow(), _props =
|
|
2603
|
-
selectionKey
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
}
|
|
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);
|
|
2612
2845
|
}, handleDelete = async () => {
|
|
2613
2846
|
let selectedNodes = store.nodes.filter((node) => node.selected), selectedEdges = store.edges.filter((edge) => edge.selected), { deletedNodes, deletedEdges } = await deleteElements({
|
|
2614
2847
|
nodes: selectedNodes,
|
|
@@ -2618,22 +2851,19 @@ const KeyHandler = (props) => {
|
|
|
2618
2851
|
nodes: deletedNodes,
|
|
2619
2852
|
edges: deletedEdges
|
|
2620
2853
|
});
|
|
2621
|
-
}, handleKeyDown = (event) => {
|
|
2622
|
-
batch(() => {
|
|
2623
|
-
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);
|
|
2624
|
-
});
|
|
2625
|
-
}, handleKeyUp = (event) => {
|
|
2626
|
-
batch(() => {
|
|
2627
|
-
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);
|
|
2628
|
-
});
|
|
2629
2854
|
};
|
|
2630
|
-
return
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
}
|
|
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
|
|
2634
2864
|
}), null;
|
|
2635
2865
|
}, SolidFlow = (props) => {
|
|
2636
|
-
let domNode, _props =
|
|
2866
|
+
let [domNodeRef, setDomNodeRef] = createSignal(), domNode, _props = merge({
|
|
2637
2867
|
...getDefaultFlowStateProps(),
|
|
2638
2868
|
colorMode: "light",
|
|
2639
2869
|
deleteKeyCode: "Backspace",
|
|
@@ -2659,69 +2889,73 @@ const KeyHandler = (props) => {
|
|
|
2659
2889
|
zoomOnPinch: !0,
|
|
2660
2890
|
zoomOnDoubleClick: !0,
|
|
2661
2891
|
zoomOnScroll: !0
|
|
2662
|
-
}, props),
|
|
2663
|
-
|
|
2664
|
-
actions.
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
actions.setPaneClickDistance(flowProps.paneClickDistance);
|
|
2670
|
-
}), onCleanup(() => {
|
|
2671
|
-
actions.reset();
|
|
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);
|
|
2672
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);
|
|
2673
2906
|
});
|
|
2674
2907
|
let selectedElements = createMemo(() => ({
|
|
2675
2908
|
nodes: store.selectedNodes,
|
|
2676
2909
|
edges: store.selectedEdges
|
|
2677
|
-
}),
|
|
2678
|
-
createEffect(() => {
|
|
2679
|
-
|
|
2680
|
-
untrack(() => flowProps.onSelectionChange)?.(params);
|
|
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);
|
|
2681
2913
|
});
|
|
2682
2914
|
let rootStyle = () => ({
|
|
2683
|
-
width: toPxString(
|
|
2684
|
-
height: toPxString(
|
|
2685
|
-
...
|
|
2915
|
+
width: toPxString(_props.width),
|
|
2916
|
+
height: toPxString(_props.height),
|
|
2917
|
+
..._props.style
|
|
2686
2918
|
});
|
|
2687
|
-
return <div role="application" data-testid="solid-flow__wrapper" ref={
|
|
2919
|
+
return <div role="application" data-testid="solid-flow__wrapper" ref={(el) => {
|
|
2920
|
+
domNode = el, setDomNodeRef(el);
|
|
2921
|
+
}} class={[
|
|
2688
2922
|
"solid-flow",
|
|
2689
2923
|
"solid-flow__container",
|
|
2690
|
-
|
|
2924
|
+
_props.class,
|
|
2691
2925
|
store.colorMode
|
|
2692
|
-
]
|
|
2926
|
+
]} style={rootStyle()} onScroll={(e) => {
|
|
2693
2927
|
e.currentTarget.scrollTo({
|
|
2694
2928
|
top: 0,
|
|
2695
2929
|
left: 0,
|
|
2696
2930
|
behavior: "auto"
|
|
2697
2931
|
});
|
|
2698
2932
|
}} {...htmlProps}>
|
|
2699
|
-
<TypedSolidFlowContext
|
|
2700
|
-
<KeyHandler selectionKey={
|
|
2701
|
-
<Zoom panOnScrollMode={
|
|
2702
|
-
<Pane onPaneClick={
|
|
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}>
|
|
2703
2937
|
<Viewport>
|
|
2704
2938
|
<div class="solid-flow__container solid-flow__viewport-back" />
|
|
2705
|
-
<EdgeRenderer reconnectRadius={
|
|
2939
|
+
<EdgeRenderer reconnectRadius={_props.reconnectRadius} onEdgeClick={_props.onEdgeClick} onEdgeContextMenu={_props.onEdgeContextMenu} onEdgePointerEnter={_props.onEdgePointerEnter} onEdgePointerLeave={_props.onEdgePointerLeave} defaultEdgeOptions={_props.defaultEdgeOptions} />
|
|
2706
2940
|
<div class="solid-flow__container solid-flow__edge-labels" />
|
|
2707
|
-
<ConnectionLine type={
|
|
2708
|
-
<NodeRenderer nodeClickDistance={
|
|
2709
|
-
<NodeSelection onSelectionClick={
|
|
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} />
|
|
2710
2944
|
</Viewport>
|
|
2711
2945
|
<Selection isVisible={!!store.selectionRect && store.selectionRectMode === "user"} width={store.selectionRect?.width} height={store.selectionRect?.height} x={store.selectionRect?.x} y={store.selectionRect?.y} />
|
|
2712
2946
|
</Pane>
|
|
2713
2947
|
</Zoom>
|
|
2714
|
-
<Attribution proOptions={
|
|
2948
|
+
<Attribution proOptions={_props.proOptions} position={_props.attributionPosition} />
|
|
2715
2949
|
<A11yDescriptions />
|
|
2716
|
-
{
|
|
2717
|
-
</TypedSolidFlowContext
|
|
2950
|
+
{_props.children}
|
|
2951
|
+
</TypedSolidFlowContext>
|
|
2718
2952
|
</div>;
|
|
2719
2953
|
}, SolidFlowProvider = (props) => {
|
|
2720
|
-
let _props =
|
|
2954
|
+
let _props = merge(getDefaultFlowStateProps(), props), solidFlow = createSolidFlow(_props);
|
|
2721
2955
|
onCleanup(() => {
|
|
2722
2956
|
solidFlow.actions.reset();
|
|
2723
2957
|
});
|
|
2724
|
-
let ContextProvider = SolidFlowContext
|
|
2958
|
+
let ContextProvider = SolidFlowContext;
|
|
2725
2959
|
return <ContextProvider value={solidFlow}>{props.children}</ContextProvider>;
|
|
2726
2960
|
}, createEdgeStore = (edges) => {
|
|
2727
2961
|
let [store, setStore] = createStore(edges);
|
|
@@ -2731,4 +2965,4 @@ const KeyHandler = (props) => {
|
|
|
2731
2965
|
return [store, setStore];
|
|
2732
2966
|
};
|
|
2733
2967
|
//#endregion
|
|
2734
|
-
export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdges, useHandleEdgeSelect, useInternalNode, useNodeConnections, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };
|
|
2968
|
+
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 };
|