@dschz/solid-flow 1.0.0-next.6 → 1.0.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/index/index.d.ts +157 -103
- package/dist/index/index.js +773 -460
- package/dist/index/index.jsx +716 -400
- package/dist/styles/index.css +16 -4
- package/package.json +6 -5
package/dist/index/index.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter as getBezierEdgeCenter$1, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter as getEdgeCenter$1, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
|
|
1
|
+
import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, errorMessages, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter as getBezierEdgeCenter$1, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter as getEdgeCenter$1, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
|
|
2
2
|
import { For, Show, createContext, createEffect, createMemo, createProjection, createSignal, createStore, flush, mapArray, merge, omit, onCleanup, onSettled, snapshot, untrack, useContext } from "solid-js";
|
|
3
3
|
import { createMediaQuery } from "@solid-primitives/media";
|
|
4
4
|
import { Dynamic, Portal, isServer } from "@solidjs/web";
|
|
@@ -65,6 +65,8 @@ function propDefaults(props, defaults) {
|
|
|
65
65
|
const getEdgeId = (connection) => {
|
|
66
66
|
let { source, sourceHandle, target, targetHandle } = connection;
|
|
67
67
|
return `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
|
|
68
|
+
}, isEdgeSelectable = (edge, store) => edge.selectable ?? store.defaultEdgeOptions.selectable ?? store.elementsSelectable, emitFlowError = (onError, id, message) => {
|
|
69
|
+
onError && onError(id, message);
|
|
68
70
|
}, EdgeLabelRenderer = (props) => {
|
|
69
71
|
let { store } = useInternalSolidFlow(), labelNode = () => store.domNode?.querySelector(".solid-flow__edge-labels");
|
|
70
72
|
return <Show when={labelNode()}>{(root) => <Portal mount={root()}>{props.children}</Portal>}</Show>;
|
|
@@ -75,7 +77,7 @@ const getEdgeId = (connection) => {
|
|
|
75
77
|
selectEdgeOnClick: !1,
|
|
76
78
|
transparent: !1,
|
|
77
79
|
style: {}
|
|
78
|
-
}), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.
|
|
80
|
+
}), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.getLayoutedEdge(id())?.zIndex;
|
|
79
81
|
return <EdgeLabelRenderer>
|
|
80
82
|
<div role="button" tabindex={-1} class={[
|
|
81
83
|
"solid-flow__edge-label",
|
|
@@ -145,6 +147,205 @@ const getEdgeId = (connection) => {
|
|
|
145
147
|
};
|
|
146
148
|
};
|
|
147
149
|
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} />;
|
|
150
|
+
};
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/core/spatial/grid.ts
|
|
153
|
+
/**
|
|
154
|
+
* A uniform spatial hash over axis-aligned rects — the plain, NON-reactive
|
|
155
|
+
* building block behind the flow's spatial queries (RFC-4239 dossier:
|
|
156
|
+
* gesture-scoped snapshots and epoch-rebuilt indexes; deliberately never a
|
|
157
|
+
* live-maintained reactive structure, which would re-create the round-6
|
|
158
|
+
* central-collection anti-pattern).
|
|
159
|
+
*
|
|
160
|
+
* Every operation is O(cells touched); with cellSize on the order of the
|
|
161
|
+
* query radius or median node size, inserts and queries touch O(1) cells.
|
|
162
|
+
* No balancing, no extent-known-up-front requirement, no dependency —
|
|
163
|
+
* upstream's own bake-off (quadtree vs BVH vs rbush) is why: fixed-radius
|
|
164
|
+
* neighborhood and rect-vs-box queries are the textbook grid case.
|
|
165
|
+
*/
|
|
166
|
+
var SpatialGrid = class {
|
|
167
|
+
cellSize;
|
|
168
|
+
cells = /* @__PURE__ */ new Map();
|
|
169
|
+
rects = /* @__PURE__ */ new Map();
|
|
170
|
+
constructor(cellSize) {
|
|
171
|
+
this.cellSize = cellSize;
|
|
172
|
+
}
|
|
173
|
+
cellRange(rect) {
|
|
174
|
+
let size = this.cellSize;
|
|
175
|
+
return {
|
|
176
|
+
minX: Math.floor(rect.x / size),
|
|
177
|
+
maxX: Math.floor((rect.x + rect.width) / size),
|
|
178
|
+
minY: Math.floor(rect.y / size),
|
|
179
|
+
maxY: Math.floor((rect.y + rect.height) / size)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
insert(id, rect) {
|
|
183
|
+
this.rects.set(id, rect);
|
|
184
|
+
let { minX, maxX, minY, maxY } = this.cellRange(rect);
|
|
185
|
+
for (let cx = minX; cx <= maxX; cx++) for (let cy = minY; cy <= maxY; cy++) {
|
|
186
|
+
let key = `${cx}:${cy}`, bucket = this.cells.get(key);
|
|
187
|
+
bucket ? bucket.push(id) : this.cells.set(key, [id]);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** Ids of entries whose rect overlaps the query rect (touching counts). */
|
|
191
|
+
queryRect(query) {
|
|
192
|
+
let { minX, maxX, minY, maxY } = this.cellRange(query), seen = /* @__PURE__ */ new Set(), result = [];
|
|
193
|
+
for (let cx = minX; cx <= maxX; cx++) for (let cy = minY; cy <= maxY; cy++) {
|
|
194
|
+
let bucket = this.cells.get(`${cx}:${cy}`);
|
|
195
|
+
if (bucket) for (let id of bucket) {
|
|
196
|
+
if (seen.has(id)) continue;
|
|
197
|
+
seen.add(id);
|
|
198
|
+
let rect = this.rects.get(id);
|
|
199
|
+
rect.x <= query.x + query.width && rect.x + rect.width >= query.x && rect.y <= query.y + query.height && rect.y + rect.height >= query.y && result.push(id);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
get size() {
|
|
205
|
+
return this.rects.size;
|
|
206
|
+
}
|
|
207
|
+
}, GestureSpatialLookup = class {
|
|
208
|
+
#real;
|
|
209
|
+
#cellSize;
|
|
210
|
+
#grid = null;
|
|
211
|
+
#queryRect = null;
|
|
212
|
+
constructor(real, cellSize) {
|
|
213
|
+
this.#real = real, this.#cellSize = cellSize;
|
|
214
|
+
}
|
|
215
|
+
/** Snapshot the current geometry into the grid (gesture start). */
|
|
216
|
+
arm(rectOf) {
|
|
217
|
+
let grid = new SpatialGrid(this.#cellSize);
|
|
218
|
+
for (let [id, value] of this.#real.entries()) grid.insert(id, rectOf(value));
|
|
219
|
+
this.#grid = grid, this.#queryRect = null;
|
|
220
|
+
}
|
|
221
|
+
/** Focus iteration on the neighborhood of the pointer (per move). */
|
|
222
|
+
setQueryCenter(center, radius) {
|
|
223
|
+
this.#queryRect = {
|
|
224
|
+
x: center.x - radius,
|
|
225
|
+
y: center.y - radius,
|
|
226
|
+
width: radius * 2,
|
|
227
|
+
height: radius * 2
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/** Focus iteration on an explicit rect (box-selection gestures). */
|
|
231
|
+
setQueryRect(rect) {
|
|
232
|
+
this.#queryRect = rect;
|
|
233
|
+
}
|
|
234
|
+
/** Back to plain pass-through (gesture end). */
|
|
235
|
+
disarm() {
|
|
236
|
+
this.#grid = null, this.#queryRect = null;
|
|
237
|
+
}
|
|
238
|
+
#candidateIds() {
|
|
239
|
+
return !this.#grid || !this.#queryRect ? null : this.#grid.queryRect(this.#queryRect);
|
|
240
|
+
}
|
|
241
|
+
get(key) {
|
|
242
|
+
return this.#real.get(key);
|
|
243
|
+
}
|
|
244
|
+
has(key) {
|
|
245
|
+
return this.#real.has(key);
|
|
246
|
+
}
|
|
247
|
+
get size() {
|
|
248
|
+
return this.#real.size;
|
|
249
|
+
}
|
|
250
|
+
*keys() {
|
|
251
|
+
let candidates = this.#candidateIds();
|
|
252
|
+
if (!candidates) {
|
|
253
|
+
yield* this.#real.keys();
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
for (let id of candidates) this.#real.has(id) && (yield id);
|
|
257
|
+
}
|
|
258
|
+
*values() {
|
|
259
|
+
let candidates = this.#candidateIds();
|
|
260
|
+
if (!candidates) {
|
|
261
|
+
yield* this.#real.values();
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
for (let id of candidates) {
|
|
265
|
+
let value = this.#real.get(id);
|
|
266
|
+
value !== void 0 && (yield value);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
*entries() {
|
|
270
|
+
let candidates = this.#candidateIds();
|
|
271
|
+
if (!candidates) {
|
|
272
|
+
yield* this.#real.entries();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
for (let id of candidates) {
|
|
276
|
+
let value = this.#real.get(id);
|
|
277
|
+
value !== void 0 && (yield [id, value]);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
[Symbol.iterator]() {
|
|
281
|
+
return this.entries();
|
|
282
|
+
}
|
|
283
|
+
forEach(callback, thisArg) {
|
|
284
|
+
for (let [key, value] of this.entries()) callback.call(thisArg, value, key, this);
|
|
285
|
+
}
|
|
286
|
+
[Symbol.toStringTag] = "GestureSpatialLookup";
|
|
287
|
+
set() {
|
|
288
|
+
throw Error("GestureSpatialLookup is read-only");
|
|
289
|
+
}
|
|
290
|
+
getOrInsert() {
|
|
291
|
+
throw Error("GestureSpatialLookup is read-only");
|
|
292
|
+
}
|
|
293
|
+
getOrInsertComputed() {
|
|
294
|
+
throw Error("GestureSpatialLookup is read-only");
|
|
295
|
+
}
|
|
296
|
+
delete() {
|
|
297
|
+
throw Error("GestureSpatialLookup is read-only");
|
|
298
|
+
}
|
|
299
|
+
clear() {
|
|
300
|
+
throw Error("GestureSpatialLookup is read-only");
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/components/handle/connectionGestureLookup.ts
|
|
305
|
+
/**
|
|
306
|
+
* Upstream `getClosestHandle` prefilters nodes within
|
|
307
|
+
* `connectionRadius + ADDITIONAL_DISTANCE` of the pointer; ADDITIONAL_DISTANCE
|
|
308
|
+
* is hardcoded to 250 in @xyflow/system (xyhandle/utils.ts). Tracked here with
|
|
309
|
+
* a safety pad: a superset of candidates is always correct (their exact
|
|
310
|
+
* distance filter runs after), so the pad only costs a few extra candidates.
|
|
311
|
+
*/
|
|
312
|
+
const armConnectionGestureLookup = (options) => {
|
|
313
|
+
let { event, real, domNode, getTransform, connectionRadius } = options, containerBounds = domNode?.getBoundingClientRect();
|
|
314
|
+
if (!containerBounds) return real;
|
|
315
|
+
let radius = connectionRadius + 250 + 50, lookup = new GestureSpatialLookup(real, radius);
|
|
316
|
+
lookup.arm((node) => nodeToRect(node));
|
|
317
|
+
let update = (moveEvent) => {
|
|
318
|
+
lookup.setQueryCenter(pointToRendererPoint(getEventPosition(moveEvent, containerBounds), getTransform(), !1, [1, 1]), radius);
|
|
319
|
+
};
|
|
320
|
+
update(event);
|
|
321
|
+
let doc = getHostForElement(event.target), dispose = () => {
|
|
322
|
+
doc.removeEventListener("mousemove", update, !0), doc.removeEventListener("touchmove", update, !0), doc.removeEventListener("mouseup", dispose, !0), doc.removeEventListener("touchend", dispose, !0), lookup.disarm();
|
|
323
|
+
};
|
|
324
|
+
return doc.addEventListener("mousemove", update, !0), doc.addEventListener("touchmove", update, !0), doc.addEventListener("mouseup", dispose, !0), doc.addEventListener("touchend", dispose, !0), lookup;
|
|
325
|
+
}, buildConnectionGestureParams = (options) => {
|
|
326
|
+
let { event, store, actions, gestureLookup } = options;
|
|
327
|
+
return {
|
|
328
|
+
lib: store.lib,
|
|
329
|
+
flowId: store.id,
|
|
330
|
+
domNode: store.domNode,
|
|
331
|
+
autoPanOnConnect: store.autoPanOnConnect,
|
|
332
|
+
autoPanSpeed: store.autoPanSpeed,
|
|
333
|
+
connectionMode: store.connectionMode,
|
|
334
|
+
connectionRadius: store.connectionRadius,
|
|
335
|
+
nodeLookup: gestureLookup,
|
|
336
|
+
cancelConnection: actions.cancelConnection,
|
|
337
|
+
panBy: actions.panBy,
|
|
338
|
+
updateConnection: ((connection) => {
|
|
339
|
+
actions.setConnection(connection), flush();
|
|
340
|
+
}),
|
|
341
|
+
isValidConnection: store.isValidConnection,
|
|
342
|
+
onConnectStart: store.onConnectStart,
|
|
343
|
+
onConnectEnd: store.onConnectEnd,
|
|
344
|
+
getTransform: () => store.transform,
|
|
345
|
+
getFromHandle: () => store.connection.fromHandle,
|
|
346
|
+
dragThreshold: store.connectionDragThreshold,
|
|
347
|
+
handleDomNode: event.currentTarget
|
|
348
|
+
};
|
|
148
349
|
}, EdgeReconnectAnchor = (props) => {
|
|
149
350
|
let _props = propDefaults(props, {
|
|
150
351
|
size: 25,
|
|
@@ -165,27 +366,24 @@ const getEdgeId = (connection) => {
|
|
|
165
366
|
nodeId: edge().target,
|
|
166
367
|
handleId: edge().targetHandle ?? null,
|
|
167
368
|
type: "target"
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
flowId: store.id,
|
|
369
|
+
}, gestureLookup = armConnectionGestureLookup({
|
|
370
|
+
event,
|
|
371
|
+
real: nodeLookup,
|
|
172
372
|
domNode: store.domNode,
|
|
373
|
+
getTransform: () => store.transform,
|
|
374
|
+
connectionRadius: store.connectionRadius
|
|
375
|
+
});
|
|
376
|
+
XYHandle.onPointerDown(event, {
|
|
377
|
+
...buildConnectionGestureParams({
|
|
378
|
+
event,
|
|
379
|
+
store,
|
|
380
|
+
actions,
|
|
381
|
+
gestureLookup
|
|
382
|
+
}),
|
|
173
383
|
nodeId: opposite.nodeId,
|
|
174
384
|
handleId: opposite.handleId,
|
|
175
|
-
autoPanOnConnect: store.autoPanOnConnect,
|
|
176
|
-
connectionMode: store.connectionMode,
|
|
177
|
-
connectionRadius: store.connectionRadius,
|
|
178
|
-
nodeLookup,
|
|
179
385
|
isTarget: opposite.type === "target",
|
|
180
386
|
edgeUpdaterType: opposite.type,
|
|
181
|
-
cancelConnection: actions.cancelConnection,
|
|
182
|
-
panBy: actions.panBy,
|
|
183
|
-
updateConnection: (connection) => {
|
|
184
|
-
actions.setConnection(connection), flush();
|
|
185
|
-
},
|
|
186
|
-
isValidConnection: store.isValidConnection,
|
|
187
|
-
onConnectStart: store.onConnectStart,
|
|
188
|
-
onConnectEnd: store.onConnectEnd,
|
|
189
387
|
onConnect: (connection) => {
|
|
190
388
|
let newEdge = {
|
|
191
389
|
...edge(),
|
|
@@ -195,12 +393,7 @@ const getEdgeId = (connection) => {
|
|
|
195
393
|
},
|
|
196
394
|
onReconnectEnd: (event, connectionState) => {
|
|
197
395
|
setReconnectingState(!1), store.onReconnectEnd?.(event, edge(), opposite.type, connectionState);
|
|
198
|
-
}
|
|
199
|
-
getTransform: () => store.transform,
|
|
200
|
-
getFromHandle: () => store.connection.fromHandle,
|
|
201
|
-
autoPanSpeed: store.autoPanSpeed,
|
|
202
|
-
dragThreshold: store.connectionDragThreshold,
|
|
203
|
-
handleDomNode: event.currentTarget
|
|
396
|
+
}
|
|
204
397
|
});
|
|
205
398
|
};
|
|
206
399
|
return <EdgeLabel x={_props.position?.x} y={_props.position?.y} style={_props.style} {...rest}>
|
|
@@ -236,9 +429,81 @@ const getEdgeId = (connection) => {
|
|
|
236
429
|
</div>
|
|
237
430
|
</Show>
|
|
238
431
|
</>;
|
|
239
|
-
},
|
|
240
|
-
let
|
|
241
|
-
|
|
432
|
+
}, createSelectionCommands = ({ store, setNodesStore, setEdgesStore, setSelectionRect, setSelectionRectMode, nodeLookup, edgeLookup, updateNodePositions }) => {
|
|
433
|
+
let unselectNodesAndEdges = ({ nodes: _nodes, edges } = {}) => {
|
|
434
|
+
let nodesToUnselect = new Set((_nodes || store.nodes).map(({ id }) => id));
|
|
435
|
+
nodesToUnselect.size && setNodesStore((nodes) => {
|
|
436
|
+
for (let node of nodes) nodesToUnselect.has(node.id) && (node.selected = !1);
|
|
437
|
+
});
|
|
438
|
+
let edgesToUnselect = new Set((edges ?? store.edges).map(({ id }) => id));
|
|
439
|
+
edgesToUnselect.size && setEdgesStore((edges) => {
|
|
440
|
+
for (let edge of edges) edgesToUnselect.has(edge.id) && (edge.selected = !1);
|
|
441
|
+
}), flush();
|
|
442
|
+
}, addSelectedNodes = (ids) => {
|
|
443
|
+
let isMultiSelection = store.multiselectionKeyPressed, idSet = new Set(ids);
|
|
444
|
+
setNodesStore((nodes) => {
|
|
445
|
+
for (let node of nodes) {
|
|
446
|
+
let nodeWillBeSelected = idSet.has(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
|
|
447
|
+
node.selected !== selected && (node.selected = selected);
|
|
448
|
+
}
|
|
449
|
+
}), isMultiSelection || unselectNodesAndEdges({ nodes: [] }), flush();
|
|
450
|
+
}, addSelectedEdges = (ids) => {
|
|
451
|
+
let isMultiSelection = store.multiselectionKeyPressed, idSet = new Set(ids);
|
|
452
|
+
setEdgesStore((edges) => {
|
|
453
|
+
for (let edge of edges) {
|
|
454
|
+
let edgeWillBeSelected = idSet.has(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
|
|
455
|
+
edge.selected !== selected && (edge.selected = selected);
|
|
456
|
+
}
|
|
457
|
+
}), isMultiSelection || unselectNodesAndEdges({ edges: [] }), flush();
|
|
458
|
+
};
|
|
459
|
+
return {
|
|
460
|
+
unselectNodesAndEdges,
|
|
461
|
+
addSelectedNodes,
|
|
462
|
+
addSelectedEdges,
|
|
463
|
+
handleNodeSelection: (id, unselect, nodeRef) => {
|
|
464
|
+
let node = store.nodes.find((n) => n.id === id);
|
|
465
|
+
if (!node) {
|
|
466
|
+
emitFlowError(store.onError, "012", errorMessages.error012(id));
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
|
|
470
|
+
nodes: [node],
|
|
471
|
+
edges: []
|
|
472
|
+
}), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]);
|
|
473
|
+
},
|
|
474
|
+
handleEdgeSelection: (id) => {
|
|
475
|
+
let edge = edgeLookup[id];
|
|
476
|
+
if (!edge) {
|
|
477
|
+
emitFlowError(store.onError, "012", errorMessages.error012(id));
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
isEdgeSelectable(edge, store) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
|
|
481
|
+
nodes: [],
|
|
482
|
+
edges: [edge]
|
|
483
|
+
}) : addSelectedEdges([id]));
|
|
484
|
+
},
|
|
485
|
+
moveSelectedNodes: (direction, factor) => {
|
|
486
|
+
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;
|
|
487
|
+
for (let node of nodeLookup.values()) {
|
|
488
|
+
if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
|
|
489
|
+
let nextPosition = {
|
|
490
|
+
x: node.internals.positionAbsolute.x + xDiff,
|
|
491
|
+
y: node.internals.positionAbsolute.y + yDiff
|
|
492
|
+
};
|
|
493
|
+
store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
|
|
494
|
+
let { position } = calculateNodePosition({
|
|
495
|
+
nodeId: node.id,
|
|
496
|
+
nextPosition,
|
|
497
|
+
nodeLookup,
|
|
498
|
+
nodeExtent: store.nodeExtent,
|
|
499
|
+
nodeOrigin: store.nodeOrigin,
|
|
500
|
+
onError: store.onError
|
|
501
|
+
});
|
|
502
|
+
nodeUpdates.set(node.id, { position });
|
|
503
|
+
}
|
|
504
|
+
updateNodePositions(nodeUpdates);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
242
507
|
}, STEP = .5 / 2, rectsEqual = (a, b) => a === b || !!a && !!b && a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height, rectsOverlap = (a, b) => a.x <= b.x + b.width && a.x + a.width >= b.x && a.y <= b.y + b.height && a.y + a.height >= b.y, createCullingViewport = (source) => createMemo(() => {
|
|
243
508
|
let { width, height } = source;
|
|
244
509
|
if (!width || !height) return null;
|
|
@@ -369,14 +634,48 @@ var RecordMapFacade = class {
|
|
|
369
634
|
}
|
|
370
635
|
};
|
|
371
636
|
//#endregion
|
|
372
|
-
//#region src/core/
|
|
637
|
+
//#region src/core/measurementIngest.ts
|
|
373
638
|
/**
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
639
|
+
* The measurement ingest lifecycle (WP3): everything that flows FROM the DOM
|
|
640
|
+
* measuring pass INTO the data graph, plus the garbage collection that keeps
|
|
641
|
+
* the measurements root aligned with graph membership. The DOM side (resize
|
|
642
|
+
* observers, the idle-scheduled measuring pass) lives in createSolidFlow;
|
|
643
|
+
* headless usage never calls these.
|
|
378
644
|
*/
|
|
379
|
-
const
|
|
645
|
+
const createMeasurementIngest = ({ setMeasurementsStore, setNodesStore, nodes }) => (createEffect(() => new Set(nodes().map((n) => n.id)), (currentIds) => {
|
|
646
|
+
setMeasurementsStore((draft) => {
|
|
647
|
+
for (let id of Object.keys(draft)) currentIds.has(id) || delete draft[id];
|
|
648
|
+
});
|
|
649
|
+
}), {
|
|
650
|
+
applyMeasurementWrites: (writes) => {
|
|
651
|
+
setMeasurementsStore((draft) => {
|
|
652
|
+
for (let write of writes) if (write.hidden) {
|
|
653
|
+
let entry = draft[write.id];
|
|
654
|
+
entry && (entry.handleBounds = void 0);
|
|
655
|
+
} else draft[write.id] = {
|
|
656
|
+
measured: write.measured,
|
|
657
|
+
handleBounds: write.handleBounds
|
|
658
|
+
};
|
|
659
|
+
});
|
|
660
|
+
},
|
|
661
|
+
applyNodeChanges: (changes) => {
|
|
662
|
+
changes.length !== 0 && setNodesStore((nodes) => {
|
|
663
|
+
let nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
664
|
+
for (let change of changes) {
|
|
665
|
+
let node = nodeById.get(change.id);
|
|
666
|
+
if (node) switch (change.type) {
|
|
667
|
+
case "dimensions":
|
|
668
|
+
change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
|
|
669
|
+
...node.measured,
|
|
670
|
+
...change.dimensions
|
|
671
|
+
};
|
|
672
|
+
break;
|
|
673
|
+
case "position": node.position = change.position ?? node.position;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
}), connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ? `-${type}-${handleId}` : `-${type}` : ""}`, pairKey = (aNode, aHandle, bNode, bHandle) => `${aNode}-${aHandle}--${bNode}-${bHandle}`, createConnections = (source) => createProjection(() => {
|
|
380
679
|
let out = {}, add = (key, entry, connection) => {
|
|
381
680
|
(out[key] ??= {})[entry] = connection;
|
|
382
681
|
};
|
|
@@ -395,7 +694,20 @@ const connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ?
|
|
|
395
694
|
let out = {};
|
|
396
695
|
for (let edge of source.edges) out[edge.id] = edge;
|
|
397
696
|
return out;
|
|
398
|
-
}, {}, { key: "id" })
|
|
697
|
+
}, {}, { key: "id" }), createRowRecordProjection = (rowStores) => {
|
|
698
|
+
let assigned = /* @__PURE__ */ new Map();
|
|
699
|
+
return createProjection((draft) => {
|
|
700
|
+
let seen = /* @__PURE__ */ new Set();
|
|
701
|
+
for (let { id, store } of rowStores()) {
|
|
702
|
+
let row = store.row;
|
|
703
|
+
row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
|
|
704
|
+
}
|
|
705
|
+
for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
|
|
706
|
+
}, {}, {
|
|
707
|
+
key: null,
|
|
708
|
+
shallow: !0
|
|
709
|
+
});
|
|
710
|
+
};
|
|
399
711
|
function isManualZIndexMode(zIndexMode) {
|
|
400
712
|
return zIndexMode === "manual";
|
|
401
713
|
}
|
|
@@ -439,11 +751,7 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
|
|
|
439
751
|
x,
|
|
440
752
|
y
|
|
441
753
|
}, row.internals.z = z;
|
|
442
|
-
} else source.nodes.length;
|
|
443
|
-
}
|
|
444
|
-
if (userNode.parentId) {
|
|
445
|
-
let parent = entryById.get(userNode.parentId);
|
|
446
|
-
parent?.store.row.internals.positionAbsolute.x, parent?.store.row.internals.z;
|
|
754
|
+
} else source.nodes.length, emitFlowError(source.onError, "parent-missing", `Parent node ${userNode.parentId} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);
|
|
447
755
|
}
|
|
448
756
|
return { row };
|
|
449
757
|
}, {}, { key: "id" }), entry = {
|
|
@@ -456,19 +764,8 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
|
|
|
456
764
|
id,
|
|
457
765
|
store
|
|
458
766
|
};
|
|
459
|
-
}, { keyed: (userNode) => userNode.id })
|
|
460
|
-
return
|
|
461
|
-
let seen = /* @__PURE__ */ new Set();
|
|
462
|
-
for (let { id, store } of rowStores()) {
|
|
463
|
-
seen.add(id);
|
|
464
|
-
let row = store.row;
|
|
465
|
-
assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row);
|
|
466
|
-
}
|
|
467
|
-
for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
|
|
468
|
-
}, {}, {
|
|
469
|
-
key: null,
|
|
470
|
-
shallow: !0
|
|
471
|
-
});
|
|
767
|
+
}, { keyed: (userNode) => userNode.id });
|
|
768
|
+
return createRowRecordProjection(rowStores);
|
|
472
769
|
};
|
|
473
770
|
function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode) {
|
|
474
771
|
let { x: parentX, y: parentY } = parentNode.internals.positionAbsolute, childDimensions = getNodeDimensions(childNode), positionWithOrigin = getNodePositionWithOrigin(childNode, nodeOrigin), clampedPosition = isCoordinateExtent(childNode.extent) ? clampPosition(positionWithOrigin, childNode.extent, childDimensions) : positionWithOrigin, absolutePosition = clampPosition({
|
|
@@ -513,24 +810,14 @@ const createLayoutedEdges = (source) => {
|
|
|
513
810
|
let rowStores = mapArray(() => source.edges, (edgeAccessor) => ({
|
|
514
811
|
id: edgeAccessor().id,
|
|
515
812
|
store: createProjection(() => {
|
|
516
|
-
let edge = edgeAccessor()
|
|
517
|
-
return
|
|
813
|
+
let edge = edgeAccessor();
|
|
814
|
+
return { row: buildRow(source, edge) };
|
|
518
815
|
}, { row: null }, { key: "id" })
|
|
519
|
-
}), { keyed: (edge) => edge.id })
|
|
520
|
-
return
|
|
521
|
-
let seen = /* @__PURE__ */ new Set();
|
|
522
|
-
for (let { id, store } of rowStores()) {
|
|
523
|
-
let row = store.row;
|
|
524
|
-
row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
|
|
525
|
-
}
|
|
526
|
-
for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
|
|
527
|
-
}, {}, {
|
|
528
|
-
key: null,
|
|
529
|
-
shallow: !0
|
|
530
|
-
});
|
|
816
|
+
}), { keyed: (edge) => edge.id });
|
|
817
|
+
return createRowRecordProjection(rowStores);
|
|
531
818
|
}, buildRow = (source, edge) => {
|
|
532
819
|
let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
|
|
533
|
-
if (!sourceNode || !targetNode) return
|
|
820
|
+
if (!sourceNode || !targetNode) return null;
|
|
534
821
|
let edgePosition = getEdgePosition({
|
|
535
822
|
id: edge.id,
|
|
536
823
|
sourceNode,
|
|
@@ -560,7 +847,33 @@ const createLayoutedEdges = (source) => {
|
|
|
560
847
|
let out = {};
|
|
561
848
|
for (let node of source.nodes) node.parentId && (out[node.parentId] = !0);
|
|
562
849
|
return out;
|
|
563
|
-
}, {}, { key: "id" }),
|
|
850
|
+
}, {}, { key: "id" }), createSeededGraphStores = (props, config) => {
|
|
851
|
+
props.nodes !== void 0 && props.defaultNodes, props.edges !== void 0 && props.defaultEdges;
|
|
852
|
+
let [nodesStore, setNodesStore] = createStore(props.nodes ?? [...props.defaultNodes ?? []]), [edgesStore, setEdgesStore] = createStore(props.edges ?? [...props.defaultEdges ?? []]), nodeSeedAdopted = props.nodes !== void 0 || props.defaultNodes !== void 0, edgeSeedAdopted = props.edges !== void 0 || props.defaultEdges !== void 0;
|
|
853
|
+
return createEffect(() => {
|
|
854
|
+
let next = config().nodes;
|
|
855
|
+
if (next) for (let node of next);
|
|
856
|
+
return { next };
|
|
857
|
+
}, ({ next }) => {
|
|
858
|
+
next && (nodeSeedAdopted = !0, setNodesStore(() => next));
|
|
859
|
+
}, { defer: !0 }), createEffect(() => {
|
|
860
|
+
let next = config().edges;
|
|
861
|
+
if (next) for (let edge of next);
|
|
862
|
+
return { next };
|
|
863
|
+
}, ({ next }) => {
|
|
864
|
+
next && (edgeSeedAdopted = !0, setEdgesStore(() => next));
|
|
865
|
+
}, { defer: !0 }), createEffect(() => ({
|
|
866
|
+
nodes: config().defaultNodes,
|
|
867
|
+
edges: config().defaultEdges
|
|
868
|
+
}), ({ nodes: defaultNodes, edges: defaultEdges }) => {
|
|
869
|
+
defaultNodes && !nodeSeedAdopted && config().nodes === void 0 && (nodeSeedAdopted = !0, setNodesStore(() => [...defaultNodes])), defaultEdges && !edgeSeedAdopted && config().edges === void 0 && (edgeSeedAdopted = !0, setEdgesStore(() => [...defaultEdges]));
|
|
870
|
+
}, { defer: !0 }), {
|
|
871
|
+
nodesStore,
|
|
872
|
+
setNodesStore,
|
|
873
|
+
edgesStore,
|
|
874
|
+
setEdgesStore
|
|
875
|
+
};
|
|
876
|
+
}, getInitialViewport = (fitView, initialViewport, width, height, nodeLookup) => {
|
|
564
877
|
if (fitView && !initialViewport && width && height) {
|
|
565
878
|
let bounds = getInternalNodesBounds(nodeLookup, { filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)) });
|
|
566
879
|
return getViewportForBounds$1(bounds, width, height, .5, 2, .1);
|
|
@@ -571,9 +884,7 @@ const createLayoutedEdges = (source) => {
|
|
|
571
884
|
zoom: 1
|
|
572
885
|
};
|
|
573
886
|
}, createFlowState = (props, injections = {}) => {
|
|
574
|
-
let _props = merge(getDefaultFlowStateProps(), props), initialNodeTypes = injections.initialNodeTypes ?? {}, initialEdgeTypes = injections.initialEdgeTypes ?? {}, prefersDark = injections.prefersDark ?? (() => _props.colorModeSSR === "dark"), [config, setConfig] = createSignal(_props),
|
|
575
|
-
props.nodes !== void 0 && props.defaultNodes, props.edges !== void 0 && props.defaultEdges;
|
|
576
|
-
let [nodesStore, setNodesStore] = createStore(props.nodes ?? [...props.defaultNodes ?? []]), [edgesStore, setEdgesStore] = createStore(props.edges ?? [...props.defaultEdges ?? []]), nodeSeedAdopted = props.nodes !== void 0 || props.defaultNodes !== void 0, edgeSeedAdopted = props.edges !== void 0 || props.defaultEdges !== void 0, [measurementsStore, setMeasurementsStore] = createStore({}), internalNodes = createInternalNodes({
|
|
887
|
+
let _props = merge(getDefaultFlowStateProps(), props), initialNodeTypes = injections.initialNodeTypes ?? {}, initialEdgeTypes = injections.initialEdgeTypes ?? {}, prefersDark = injections.prefersDark ?? (() => _props.colorModeSSR === "dark"), [config, setConfig] = createSignal(_props), ariaLabelConfig = createMemo(() => 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 = createMemo(() => config().minZoom), maxZoom = createMemo(() => config().maxZoom), [nodesConnectable, setNodesConnectable] = createSignal(() => config().nodesConnectable), [nodesDraggable, setNodesDraggable] = createSignal(() => config().nodesDraggable), [panZoom, setPanZoom] = createSignal(null), [selectionRect, setSelectionRect] = createSignal(), [selectionRectMode, setSelectionRectMode] = createSignal(), [snapGrid, setSnapGrid] = createSignal(() => config().snapGrid), translateExtent = createMemo(() => 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, edgesStore, setEdgesStore } = createSeededGraphStores(props, config), [measurementsStore, setMeasurementsStore] = createStore({}), internalNodes = createInternalNodes({
|
|
577
888
|
get nodes() {
|
|
578
889
|
return nodesStore;
|
|
579
890
|
},
|
|
@@ -591,26 +902,12 @@ const createLayoutedEdges = (source) => {
|
|
|
591
902
|
},
|
|
592
903
|
get zIndexMode() {
|
|
593
904
|
return config().zIndexMode;
|
|
905
|
+
},
|
|
906
|
+
get onError() {
|
|
907
|
+
return config().onFlowError;
|
|
594
908
|
}
|
|
595
909
|
}), nodeLookup = new RecordMapFacade(internalNodes), initialViewport = getInitialViewport(_props.fitView, _props.initialViewport, _props.width ?? 0, _props.height ?? 0, nodeLookup), [viewportStore, setViewportStore] = createStore(_props.viewport ?? initialViewport);
|
|
596
|
-
createEffect(() => {
|
|
597
|
-
let next = config().nodes;
|
|
598
|
-
if (next) for (let node of next);
|
|
599
|
-
return { next };
|
|
600
|
-
}, ({ next }) => {
|
|
601
|
-
next && (nodeSeedAdopted = !0, setNodesStore(() => next));
|
|
602
|
-
}, { defer: !0 }), createEffect(() => {
|
|
603
|
-
let next = config().edges;
|
|
604
|
-
if (next) for (let edge of next);
|
|
605
|
-
return { next };
|
|
606
|
-
}, ({ next }) => {
|
|
607
|
-
next && (edgeSeedAdopted = !0, setEdgesStore(() => next));
|
|
608
|
-
}, { defer: !0 }), createEffect(() => ({
|
|
609
|
-
nodes: config().defaultNodes,
|
|
610
|
-
edges: config().defaultEdges
|
|
611
|
-
}), ({ nodes: defaultNodes, edges: defaultEdges }) => {
|
|
612
|
-
defaultNodes && !nodeSeedAdopted && config().nodes === void 0 && (nodeSeedAdopted = !0, setNodesStore(() => [...defaultNodes])), defaultEdges && !edgeSeedAdopted && config().edges === void 0 && (edgeSeedAdopted = !0, setEdgesStore(() => [...defaultEdges]));
|
|
613
|
-
}, { defer: !0 }), createEffect(() => config().viewport, (next) => {
|
|
910
|
+
createEffect(() => config().viewport, (next) => {
|
|
614
911
|
next && setViewportStore(() => next);
|
|
615
912
|
}, { defer: !0 });
|
|
616
913
|
let transform = createMemo(() => [
|
|
@@ -622,25 +919,33 @@ const createLayoutedEdges = (source) => {
|
|
|
622
919
|
if (nodes.length === 0) return !1;
|
|
623
920
|
for (let node of nodes) if (!node.hidden && (node.measured?.width === void 0 || node.measured?.height === void 0)) return !1;
|
|
624
921
|
return !0;
|
|
625
|
-
}),
|
|
922
|
+
}), resolvedColorMode = createMemo(() => {
|
|
923
|
+
let mode = config().colorMode;
|
|
924
|
+
return mode === "system" ? prefersDark() ? "dark" : "light" : mode;
|
|
925
|
+
}), projectedConnection = createMemo(() => {
|
|
926
|
+
let state = connection();
|
|
927
|
+
return state.inProgress ? {
|
|
928
|
+
...state,
|
|
929
|
+
to: pointToRendererPoint(state.to, transform())
|
|
930
|
+
} : state;
|
|
931
|
+
}), connectionFromHandle = createMemo(() => connection().fromHandle ?? null, { equals: (a, b) => a === b || !!a && !!b && a.nodeId === b.nodeId && a.type === b.type && a.id === b.id }), connectionTargetByHandle = createProjection((draft) => {
|
|
932
|
+
let state = connection(), toHandle = state.inProgress ? state.toHandle : null, key = toHandle ? connectionKey(toHandle.nodeId, toHandle.type, toHandle.id ?? null) : null;
|
|
933
|
+
for (let existing of Object.keys(draft)) existing !== key && delete draft[existing];
|
|
934
|
+
key && (draft[key] = state.isValid ? "valid" : "invalid");
|
|
935
|
+
}, {}, { key: null }), connectionOriginByHandle = createProjection((draft) => {
|
|
936
|
+
let fromHandle = connection().fromHandle ?? clickConnectStartHandle(), fromKey = fromHandle ? connectionKey(fromHandle.nodeId, fromHandle.type, fromHandle.id ?? null) : null, siblingKey = fromHandle ? connectionKey(fromHandle.nodeId, fromHandle.type === "source" ? "target" : "source", fromHandle.id ?? null) : null;
|
|
937
|
+
for (let existing of Object.keys(draft)) existing !== fromKey && existing !== siblingKey && delete draft[existing];
|
|
938
|
+
fromKey && (draft[fromKey] = "from"), siblingKey && (draft[siblingKey] = "excluded");
|
|
939
|
+
}, {}, { key: null }), mergedNodeTypes = createMemo(() => ({
|
|
940
|
+
...initialNodeTypes,
|
|
941
|
+
...config().nodeTypes
|
|
942
|
+
})), mergedEdgeTypes = createMemo(() => ({
|
|
943
|
+
...initialEdgeTypes,
|
|
944
|
+
...config().edgeTypes
|
|
945
|
+
})), selectedNodesView = createMemo(() => nodesStore.filter((node) => node.selected)), selectedEdgesView = createMemo(() => edgesStore.filter((edge) => edge.selected)), store = merge({
|
|
626
946
|
width: 0,
|
|
627
947
|
height: 0
|
|
628
948
|
}, config, {
|
|
629
|
-
get _colorMode() {
|
|
630
|
-
return config().colorMode;
|
|
631
|
-
},
|
|
632
|
-
get _colorModeSSR() {
|
|
633
|
-
return config().colorModeSSR;
|
|
634
|
-
},
|
|
635
|
-
get _connection() {
|
|
636
|
-
return connection();
|
|
637
|
-
},
|
|
638
|
-
get _nodeTypes() {
|
|
639
|
-
return config().nodeTypes;
|
|
640
|
-
},
|
|
641
|
-
get _edgeTypes() {
|
|
642
|
-
return config().edgeTypes;
|
|
643
|
-
},
|
|
644
949
|
get ariaLabelConfig() {
|
|
645
950
|
return ariaLabelConfig();
|
|
646
951
|
},
|
|
@@ -651,14 +956,19 @@ const createLayoutedEdges = (source) => {
|
|
|
651
956
|
return clickConnectStartHandle();
|
|
652
957
|
},
|
|
653
958
|
get colorMode() {
|
|
654
|
-
return
|
|
959
|
+
return resolvedColorMode();
|
|
655
960
|
},
|
|
656
961
|
get connection() {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
962
|
+
return projectedConnection();
|
|
963
|
+
},
|
|
964
|
+
get connectionFromHandle() {
|
|
965
|
+
return connectionFromHandle();
|
|
966
|
+
},
|
|
967
|
+
get connectionTargetByHandle() {
|
|
968
|
+
return connectionTargetByHandle;
|
|
969
|
+
},
|
|
970
|
+
get connectionOriginByHandle() {
|
|
971
|
+
return connectionOriginByHandle;
|
|
662
972
|
},
|
|
663
973
|
get domNode() {
|
|
664
974
|
return domNode();
|
|
@@ -667,10 +977,7 @@ const createLayoutedEdges = (source) => {
|
|
|
667
977
|
return dragging();
|
|
668
978
|
},
|
|
669
979
|
get edgeTypes() {
|
|
670
|
-
return
|
|
671
|
-
...initialEdgeTypes,
|
|
672
|
-
...this._edgeTypes
|
|
673
|
-
};
|
|
980
|
+
return mergedEdgeTypes();
|
|
674
981
|
},
|
|
675
982
|
get elementsSelectable() {
|
|
676
983
|
return elementsSelectable();
|
|
@@ -703,19 +1010,16 @@ const createLayoutedEdges = (source) => {
|
|
|
703
1010
|
return nodesDraggable();
|
|
704
1011
|
},
|
|
705
1012
|
get nodeTypes() {
|
|
706
|
-
return
|
|
707
|
-
...initialNodeTypes,
|
|
708
|
-
...this._nodeTypes
|
|
709
|
-
};
|
|
1013
|
+
return mergedNodeTypes();
|
|
710
1014
|
},
|
|
711
1015
|
get panZoom() {
|
|
712
1016
|
return panZoom();
|
|
713
1017
|
},
|
|
714
1018
|
get selectedNodes() {
|
|
715
|
-
return
|
|
1019
|
+
return selectedNodesView();
|
|
716
1020
|
},
|
|
717
1021
|
get selectedEdges() {
|
|
718
|
-
return
|
|
1022
|
+
return selectedEdgesView();
|
|
719
1023
|
},
|
|
720
1024
|
get selectionRect() {
|
|
721
1025
|
return selectionRect();
|
|
@@ -804,7 +1108,7 @@ const createLayoutedEdges = (source) => {
|
|
|
804
1108
|
return store.onError;
|
|
805
1109
|
},
|
|
806
1110
|
nodeLookup
|
|
807
|
-
}), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)),
|
|
1111
|
+
}), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)), getLayoutedEdge = (id) => layoutedEdges[id], fitView = async (options) => store.panZoom ? await fitViewport({
|
|
808
1112
|
nodes: nodeLookup,
|
|
809
1113
|
width: store.width,
|
|
810
1114
|
height: store.height,
|
|
@@ -830,33 +1134,11 @@ const createLayoutedEdges = (source) => {
|
|
|
830
1134
|
setNodesStore((nodes) => {
|
|
831
1135
|
for (let node of nodes) nodeDragItems.has(node.id) && (node.dragging = dragging, node.position = nodeDragItems.get(node.id).position);
|
|
832
1136
|
});
|
|
833
|
-
}, applyMeasurementWrites = (
|
|
834
|
-
setMeasurementsStore
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
} else draft[write.id] = {
|
|
839
|
-
measured: write.measured,
|
|
840
|
-
handleBounds: write.handleBounds
|
|
841
|
-
};
|
|
842
|
-
});
|
|
843
|
-
}, applyNodeChanges = (changes) => {
|
|
844
|
-
changes.length !== 0 && setNodesStore((nodes) => {
|
|
845
|
-
let nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
846
|
-
for (let change of changes) {
|
|
847
|
-
let node = nodeById.get(change.id);
|
|
848
|
-
if (node) switch (change.type) {
|
|
849
|
-
case "dimensions":
|
|
850
|
-
change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
|
|
851
|
-
...node.measured,
|
|
852
|
-
...change.dimensions
|
|
853
|
-
};
|
|
854
|
-
break;
|
|
855
|
-
case "position": node.position = change.position ?? node.position;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
});
|
|
859
|
-
}, markInitialNodesMeasured = () => {
|
|
1137
|
+
}, { applyMeasurementWrites, applyNodeChanges } = createMeasurementIngest({
|
|
1138
|
+
setMeasurementsStore,
|
|
1139
|
+
setNodesStore,
|
|
1140
|
+
nodes: () => nodesStore
|
|
1141
|
+
}), markInitialNodesMeasured = () => {
|
|
860
1142
|
initialNodesMeasured = !0, tryInitialFitView();
|
|
861
1143
|
}, requestMeasure = () => {}, setMeasureRequester = (fn) => {
|
|
862
1144
|
requestMeasure = fn;
|
|
@@ -871,66 +1153,16 @@ const createLayoutedEdges = (source) => {
|
|
|
871
1153
|
ease: options?.ease,
|
|
872
1154
|
interpolate: options?.interpolate
|
|
873
1155
|
}), Promise.resolve(!0)) : Promise.resolve(!1);
|
|
874
|
-
},
|
|
875
|
-
store
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
}), flush();
|
|
885
|
-
}, addSelectedNodes = (ids) => {
|
|
886
|
-
let isMultiSelection = store.multiselectionKeyPressed;
|
|
887
|
-
setNodesStore((nodes) => {
|
|
888
|
-
for (let node of nodes) {
|
|
889
|
-
let nodeWillBeSelected = ids.includes(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
|
|
890
|
-
node.selected !== selected && (node.selected = selected);
|
|
891
|
-
}
|
|
892
|
-
}), isMultiSelection || unselectNodesAndEdges({ nodes: [] }), flush();
|
|
893
|
-
}, addSelectedEdges = (ids) => {
|
|
894
|
-
let isMultiSelection = store.multiselectionKeyPressed;
|
|
895
|
-
setEdgesStore((edges) => {
|
|
896
|
-
for (let edge of edges) {
|
|
897
|
-
let edgeWillBeSelected = ids.includes(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
|
|
898
|
-
edge.selected !== selected && (edge.selected = selected);
|
|
899
|
-
}
|
|
900
|
-
}), isMultiSelection || unselectNodesAndEdges({ edges: [] }), flush();
|
|
901
|
-
}, handleNodeSelection = (id, unselect, nodeRef) => {
|
|
902
|
-
let node = store.nodes.find((n) => n.id === id);
|
|
903
|
-
node && (setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
|
|
904
|
-
nodes: [node],
|
|
905
|
-
edges: []
|
|
906
|
-
}), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
|
|
907
|
-
}, handleEdgeSelection = (id) => {
|
|
908
|
-
let edge = edgeLookup[id];
|
|
909
|
-
edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
|
|
910
|
-
nodes: [],
|
|
911
|
-
edges: [edge]
|
|
912
|
-
}) : addSelectedEdges([id]));
|
|
913
|
-
}, moveSelectedNodes = (direction, factor) => {
|
|
914
|
-
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;
|
|
915
|
-
for (let node of nodeLookup.values()) {
|
|
916
|
-
if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
|
|
917
|
-
let nextPosition = {
|
|
918
|
-
x: node.internals.positionAbsolute.x + xDiff,
|
|
919
|
-
y: node.internals.positionAbsolute.y + yDiff
|
|
920
|
-
};
|
|
921
|
-
store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
|
|
922
|
-
let { position } = calculateNodePosition({
|
|
923
|
-
nodeId: node.id,
|
|
924
|
-
nextPosition,
|
|
925
|
-
nodeLookup,
|
|
926
|
-
nodeExtent: store.nodeExtent,
|
|
927
|
-
nodeOrigin: store.nodeOrigin,
|
|
928
|
-
onError: store.onError
|
|
929
|
-
});
|
|
930
|
-
nodeUpdates.set(node.id, { position });
|
|
931
|
-
}
|
|
932
|
-
updateNodePositions(nodeUpdates);
|
|
933
|
-
}, panBy$1 = (delta) => panBy({
|
|
1156
|
+
}, stableSetViewport = (viewport) => setViewportStore(() => viewport), { unselectNodesAndEdges, addSelectedNodes, addSelectedEdges, handleNodeSelection, handleEdgeSelection, moveSelectedNodes } = createSelectionCommands({
|
|
1157
|
+
store,
|
|
1158
|
+
setNodesStore,
|
|
1159
|
+
setEdgesStore,
|
|
1160
|
+
setSelectionRect,
|
|
1161
|
+
setSelectionRectMode,
|
|
1162
|
+
nodeLookup,
|
|
1163
|
+
edgeLookup,
|
|
1164
|
+
updateNodePositions
|
|
1165
|
+
}), panBy$1 = (delta) => panBy({
|
|
934
1166
|
delta,
|
|
935
1167
|
panZoom: store.panZoom,
|
|
936
1168
|
transform: store.transform,
|
|
@@ -1007,8 +1239,27 @@ const createLayoutedEdges = (source) => {
|
|
|
1007
1239
|
get snapGrid() {
|
|
1008
1240
|
return store.snapGrid;
|
|
1009
1241
|
}
|
|
1010
|
-
},
|
|
1011
|
-
|
|
1242
|
+
}, intersectionGrid = null, intersectionRows = null, queryIntersectionCandidates = (rect) => untrack(() => {
|
|
1243
|
+
if (!intersectionGrid) {
|
|
1244
|
+
let grid = new SpatialGrid(300), rows = /* @__PURE__ */ new Map();
|
|
1245
|
+
for (let node of store.nodes) {
|
|
1246
|
+
let internalNode = nodeLookup.get(node.id);
|
|
1247
|
+
internalNode && (grid.insert(node.id, nodeToRect(internalNode)), rows.set(node.id, node));
|
|
1248
|
+
}
|
|
1249
|
+
intersectionGrid = grid, intersectionRows = rows, queueMicrotask(() => {
|
|
1250
|
+
intersectionGrid = null, intersectionRows = null;
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
let rows = intersectionRows, result = [];
|
|
1254
|
+
for (let id of intersectionGrid.queryRect(rect)) {
|
|
1255
|
+
let row = rows.get(id);
|
|
1256
|
+
row && result.push(row);
|
|
1257
|
+
}
|
|
1258
|
+
return result;
|
|
1259
|
+
}), getNodeRect = (node) => {
|
|
1260
|
+
let nodeToUse = isNode(node) ? node : nodeLookup.get(node.id);
|
|
1261
|
+
if (!nodeToUse) return null;
|
|
1262
|
+
let position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, store.nodeOrigin) : nodeToUse.position, nodeWithPosition = {
|
|
1012
1263
|
...nodeToUse,
|
|
1013
1264
|
position,
|
|
1014
1265
|
width: nodeToUse.measured?.width ?? nodeToUse.width,
|
|
@@ -1062,7 +1313,7 @@ const createLayoutedEdges = (source) => {
|
|
|
1062
1313
|
x,
|
|
1063
1314
|
y,
|
|
1064
1315
|
zoom
|
|
1065
|
-
], _snapGrid
|
|
1316
|
+
], !!_snapGrid, _snapGrid || [1, 1]);
|
|
1066
1317
|
},
|
|
1067
1318
|
flowToScreenPosition: (position) => {
|
|
1068
1319
|
if (!store.domNode) return position;
|
|
@@ -1126,14 +1377,18 @@ const createLayoutedEdges = (source) => {
|
|
|
1126
1377
|
let remainingNodes = store.nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id));
|
|
1127
1378
|
store.onNodesDelete?.(matchingNodes), setNodesStore(() => remainingNodes);
|
|
1128
1379
|
}
|
|
1129
|
-
|
|
1380
|
+
let deletedNodes = matchingNodes ?? [], deletedEdges = matchingEdges ?? [];
|
|
1381
|
+
return (deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
|
|
1382
|
+
nodes: deletedNodes,
|
|
1383
|
+
edges: deletedEdges
|
|
1384
|
+
}), {
|
|
1130
1385
|
deletedNodes: matchingNodes,
|
|
1131
1386
|
deletedEdges: matchingEdges
|
|
1132
1387
|
};
|
|
1133
1388
|
},
|
|
1134
1389
|
getIntersectingNodes: (nodeOrRect, partially = !0, nodesToIntersect) => {
|
|
1135
1390
|
let isRect = isRectObject(nodeOrRect), nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
|
|
1136
|
-
return nodeRect ? (nodesToIntersect
|
|
1391
|
+
return nodeRect ? (nodesToIntersect ?? queryIntersectionCandidates(nodeRect)).filter((n) => {
|
|
1137
1392
|
let internalNode = nodeLookup.get(n.id);
|
|
1138
1393
|
if (!internalNode || !isRect && n.id === nodeOrRect.id) return !1;
|
|
1139
1394
|
let currNodeRect = nodeToRect(internalNode), overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
|
|
@@ -1189,10 +1444,6 @@ const createLayoutedEdges = (source) => {
|
|
|
1189
1444
|
extent: store.translateExtent
|
|
1190
1445
|
}), ({ panZoom, extent }) => {
|
|
1191
1446
|
panZoom?.setTranslateExtent(extent);
|
|
1192
|
-
}), createEffect(() => new Set(store.nodes.map((n) => n.id)), (currentIds) => {
|
|
1193
|
-
setMeasurementsStore((draft) => {
|
|
1194
|
-
for (let id of Object.keys(draft)) currentIds.has(id) || delete draft[id];
|
|
1195
|
-
});
|
|
1196
1447
|
}), {
|
|
1197
1448
|
store,
|
|
1198
1449
|
flow,
|
|
@@ -1204,14 +1455,12 @@ const createLayoutedEdges = (source) => {
|
|
|
1204
1455
|
parentIds,
|
|
1205
1456
|
connections,
|
|
1206
1457
|
actions: {
|
|
1207
|
-
|
|
1458
|
+
getLayoutedEdge,
|
|
1208
1459
|
applyInitialFitView,
|
|
1209
1460
|
applyMeasurementWrites,
|
|
1210
1461
|
applyNodeChanges,
|
|
1211
1462
|
markInitialNodesMeasured,
|
|
1212
1463
|
setMeasureRequester,
|
|
1213
|
-
resetStoreValues,
|
|
1214
|
-
setAriaLabelConfig,
|
|
1215
1464
|
setAriaLiveMessage,
|
|
1216
1465
|
setClickConnectStartHandle,
|
|
1217
1466
|
setConfig,
|
|
@@ -1219,15 +1468,11 @@ const createLayoutedEdges = (source) => {
|
|
|
1219
1468
|
setDeleteKeyPressed,
|
|
1220
1469
|
setDomNode,
|
|
1221
1470
|
setDragging,
|
|
1222
|
-
|
|
1223
|
-
return setEdgesStore;
|
|
1224
|
-
},
|
|
1471
|
+
setEdges: setEdgesStore,
|
|
1225
1472
|
setElementsSelectable,
|
|
1226
1473
|
setHeight,
|
|
1227
1474
|
setMultiselectionKeyPressed,
|
|
1228
|
-
|
|
1229
|
-
return setNodesStore;
|
|
1230
|
-
},
|
|
1475
|
+
setNodes: setNodesStore,
|
|
1231
1476
|
setNodesConnectable,
|
|
1232
1477
|
setNodesDraggable,
|
|
1233
1478
|
setPanActivationKeyPressed,
|
|
@@ -1235,9 +1480,7 @@ const createLayoutedEdges = (source) => {
|
|
|
1235
1480
|
setSelectionKeyPressed,
|
|
1236
1481
|
setSelectionRect,
|
|
1237
1482
|
setSelectionRectMode,
|
|
1238
|
-
|
|
1239
|
-
return (viewport) => setViewportStore(() => viewport);
|
|
1240
|
-
},
|
|
1483
|
+
setViewport: stableSetViewport,
|
|
1241
1484
|
setWidth,
|
|
1242
1485
|
setZoomActivationKeyPressed,
|
|
1243
1486
|
addEdge,
|
|
@@ -1246,7 +1489,6 @@ const createLayoutedEdges = (source) => {
|
|
|
1246
1489
|
zoomOut,
|
|
1247
1490
|
fitView,
|
|
1248
1491
|
setCenter,
|
|
1249
|
-
setPaneClickDistance,
|
|
1250
1492
|
unselectNodesAndEdges,
|
|
1251
1493
|
addSelectedNodes,
|
|
1252
1494
|
addSelectedEdges,
|
|
@@ -1258,25 +1500,35 @@ const createLayoutedEdges = (source) => {
|
|
|
1258
1500
|
reset
|
|
1259
1501
|
}
|
|
1260
1502
|
};
|
|
1503
|
+
}, createEdgeStore = (edges) => {
|
|
1504
|
+
let [store, setStore] = typeof edges == "function" ? createStore(edges, []) : createStore(edges);
|
|
1505
|
+
return [store, setStore];
|
|
1261
1506
|
}, createNodeStore = (nodes) => {
|
|
1262
|
-
let [store, setStore] = createStore(nodes);
|
|
1507
|
+
let [store, setStore] = typeof nodes == "function" ? createStore(nodes, []) : createStore(nodes);
|
|
1263
1508
|
return [store, setStore];
|
|
1264
1509
|
}, EdgeWrapper = (props) => {
|
|
1265
|
-
let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.
|
|
1510
|
+
let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.getLayoutedEdge(edgeId()), edgeType = () => edge().type ?? "default", selectable = () => isEdgeSelectable(edge(), store), focusable = () => edge().focusable ?? store.edgesFocusable, edgeTypeValid = () => edgeType() in store.edgeTypes, edgeComponent = () => store.edgeTypes[edgeTypeValid() ? edgeType() : "default"];
|
|
1511
|
+
createEffect(() => ({
|
|
1512
|
+
valid: edgeTypeValid(),
|
|
1513
|
+
edgeType: edgeType()
|
|
1514
|
+
}), ({ valid, edgeType }) => {
|
|
1515
|
+
valid || emitFlowError(store.onError, "011", errorMessages.error011(edgeType));
|
|
1516
|
+
});
|
|
1517
|
+
let markerStartUrl = () => edge().markerStart ? `url('#${getMarkerId(edge().markerStart, store.id)}')` : void 0, markerEndUrl = () => edge().markerEnd ? `url('#${getMarkerId(edge().markerEnd, store.id)}')` : void 0, onClick = (event) => {
|
|
1266
1518
|
selectable() && actions.handleEdgeSelection(edgeId()), props.onEdgeClick?.({
|
|
1267
1519
|
edge: edge(),
|
|
1268
1520
|
event
|
|
1269
1521
|
});
|
|
1270
|
-
},
|
|
1271
|
-
(
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
}, onKeyDown = (event) => {
|
|
1522
|
+
}, onContextMenu = (event) => props.onEdgeContextMenu?.({
|
|
1523
|
+
edge: edge(),
|
|
1524
|
+
event
|
|
1525
|
+
}), onPointerEnter = (event) => props.onEdgePointerEnter?.({
|
|
1526
|
+
edge: edge(),
|
|
1527
|
+
event
|
|
1528
|
+
}), onPointerLeave = (event) => props.onEdgePointerLeave?.({
|
|
1529
|
+
edge: edge(),
|
|
1530
|
+
event
|
|
1531
|
+
}), onKeyDown = (event) => {
|
|
1280
1532
|
store.disableKeyboardA11y || !elementSelectionKeys.includes(event.key) || !selectable() || (event.key === "Escape" ? actions.unselectNodesAndEdges({ edges: [edge()] }) : actions.addSelectedEdges([edge().id]));
|
|
1281
1533
|
}, ariaLabel = () => edge().ariaLabel ?? `Edge from ${edge().source} to ${edge().target}`, culled = createMemo(() => isEdgeCulled(edge(), store.cullingViewport));
|
|
1282
1534
|
return <EdgeIdContext value={edgeId}>
|
|
@@ -1295,7 +1547,7 @@ const createLayoutedEdges = (source) => {
|
|
|
1295
1547
|
selectable: !!selectable()
|
|
1296
1548
|
},
|
|
1297
1549
|
edge().class
|
|
1298
|
-
]} onClick={onClick} onKeyDown={(e) => focusable() && onKeyDown(e)} onContextMenu={
|
|
1550
|
+
]} onClick={onClick} onKeyDown={(e) => focusable() && onKeyDown(e)} onContextMenu={onContextMenu} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave} {...edge().domAttributes}>
|
|
1299
1551
|
<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()} />
|
|
1300
1552
|
</g>
|
|
1301
1553
|
</svg>
|
|
@@ -1419,7 +1671,7 @@ const Handle = (props) => {
|
|
|
1419
1671
|
position: "top",
|
|
1420
1672
|
isConnectableStart: !0,
|
|
1421
1673
|
isConnectableEnd: !0
|
|
1422
|
-
}), { 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,
|
|
1674
|
+
}), { store, nodeLookup, connections, actions } = useInternalSolidFlow(), rest = omit(_props, "id", "type", "position", "isConnectable", "isConnectableStart", "isConnectableEnd", "isValidConnection", "onConnect", "onDisconnect", "children", "class", "style"), nodeId = useNodeId(), nodeConnectable = useNodeConnectable(), connectable = () => _props.isConnectable ?? nodeConnectable(), isTarget = () => _props.type === "target", handleId = () => _props.id ?? null, originState = () => store.connectionOriginByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingFrom = () => originState() === "from", targetState = () => store.connectionTargetByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingTo = () => targetState() !== void 0, valid = () => targetState() === "valid", prevConnections = null;
|
|
1423
1675
|
createEffect(() => {
|
|
1424
1676
|
if (!_props.onConnect && !_props.onDisconnect) return null;
|
|
1425
1677
|
let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
|
|
@@ -1437,37 +1689,25 @@ const Handle = (props) => {
|
|
|
1437
1689
|
}, edge = store.onBeforeConnect?.(handleConnection) ?? handleConnection;
|
|
1438
1690
|
actions.addEdge(edge), store.onConnect?.(handleConnection);
|
|
1439
1691
|
}, onPointerDown = (event) => {
|
|
1692
|
+
let gestureLookup = armConnectionGestureLookup({
|
|
1693
|
+
event,
|
|
1694
|
+
real: nodeLookup,
|
|
1695
|
+
domNode: store.domNode,
|
|
1696
|
+
getTransform: () => store.transform,
|
|
1697
|
+
connectionRadius: store.connectionRadius
|
|
1698
|
+
});
|
|
1440
1699
|
XYHandle.onPointerDown(event, {
|
|
1700
|
+
...buildConnectionGestureParams({
|
|
1701
|
+
event,
|
|
1702
|
+
store,
|
|
1703
|
+
actions,
|
|
1704
|
+
gestureLookup
|
|
1705
|
+
}),
|
|
1441
1706
|
handleId: handleId(),
|
|
1442
1707
|
nodeId: nodeId(),
|
|
1443
1708
|
isTarget: isTarget(),
|
|
1444
|
-
connectionRadius: store.connectionRadius,
|
|
1445
|
-
domNode: store.domNode,
|
|
1446
|
-
nodeLookup,
|
|
1447
|
-
connectionMode: store.connectionMode,
|
|
1448
|
-
lib: store.lib,
|
|
1449
|
-
autoPanOnConnect: store.autoPanOnConnect,
|
|
1450
|
-
flowId: store.id,
|
|
1451
1709
|
isValidConnection: _props.isValidConnection ?? store.isValidConnection,
|
|
1452
|
-
|
|
1453
|
-
actions.setConnection(connection), flush();
|
|
1454
|
-
}),
|
|
1455
|
-
cancelConnection: actions.cancelConnection,
|
|
1456
|
-
panBy: actions.panBy,
|
|
1457
|
-
onConnect: onConnectExtended,
|
|
1458
|
-
onConnectStart: (event, startParams) => {
|
|
1459
|
-
store.onConnectStart?.(event, {
|
|
1460
|
-
nodeId: startParams.nodeId,
|
|
1461
|
-
handleId: startParams.handleId,
|
|
1462
|
-
handleType: startParams.handleType
|
|
1463
|
-
});
|
|
1464
|
-
},
|
|
1465
|
-
onConnectEnd: store.onConnectEnd,
|
|
1466
|
-
getTransform: () => store.transform,
|
|
1467
|
-
getFromHandle: () => store.connection.fromHandle,
|
|
1468
|
-
autoPanSpeed: store.autoPanSpeed,
|
|
1469
|
-
dragThreshold: store.connectionDragThreshold,
|
|
1470
|
-
handleDomNode: event.currentTarget
|
|
1710
|
+
onConnect: onConnectExtended
|
|
1471
1711
|
});
|
|
1472
1712
|
}, onClick = (event) => {
|
|
1473
1713
|
if (!nodeId() || !store.clickConnectStartHandle && !_props.isConnectableStart) return;
|
|
@@ -1502,7 +1742,7 @@ const Handle = (props) => {
|
|
|
1502
1742
|
isValid && connection && onConnectExtended(connection);
|
|
1503
1743
|
let connectionClone = structuredClone(snapshot(store.connection));
|
|
1504
1744
|
delete connectionClone.inProgress, connectionClone.toPosition = connectionClone.toHandle ? connectionClone.toHandle.position : null, store.onClickConnectEnd?.(event, connectionClone), actions.setClickConnectStartHandle(void 0);
|
|
1505
|
-
}
|
|
1745
|
+
};
|
|
1506
1746
|
return <div {...rest} role="button" aria-label={store.ariaLabelConfig["handle.ariaLabel"]} tabindex={-1} data-handleid={handleId()} data-nodeid={nodeId()} data-handlepos={_props.position} data-id={`${store.id}-${nodeId()}-${_props.id || null}-${_props.type}`} onClick={store.clickConnect ? onClick : void 0} onPointerDown={onPointerDown} style={_props.style} class={[
|
|
1507
1747
|
"solid-flow__handle",
|
|
1508
1748
|
`solid-flow__handle-${_props.position}`,
|
|
@@ -1518,7 +1758,7 @@ const Handle = (props) => {
|
|
|
1518
1758
|
connectablestart: _props.isConnectableStart,
|
|
1519
1759
|
connectableend: _props.isConnectableEnd,
|
|
1520
1760
|
connectable: !!connectable(),
|
|
1521
|
-
|
|
1761
|
+
excluded: !!originState()
|
|
1522
1762
|
}
|
|
1523
1763
|
]}>
|
|
1524
1764
|
{_props.children}
|
|
@@ -1617,7 +1857,7 @@ const NodeWrapper = (props) => {
|
|
|
1617
1857
|
let el = nodeRef();
|
|
1618
1858
|
el && props.resizeObserver?.unobserve(el);
|
|
1619
1859
|
});
|
|
1620
|
-
let nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeType()], isParentNode = () => !!parentIds[node().id], transform = () => {
|
|
1860
|
+
let nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeTypeValid() ? nodeType() : "default"], isParentNode = () => !!parentIds[node().id], transform = () => {
|
|
1621
1861
|
let { x, y } = node().internals.positionAbsolute;
|
|
1622
1862
|
return `translate(${x}px, ${y}px)`;
|
|
1623
1863
|
}, sizeStyle = () => {
|
|
@@ -1628,17 +1868,18 @@ const NodeWrapper = (props) => {
|
|
|
1628
1868
|
...h ? { height: toPxString(h) } : {}
|
|
1629
1869
|
};
|
|
1630
1870
|
}, culled = createMemo(() => isNodeCulled(node(), store.cullingViewport)), style = () => ({
|
|
1871
|
+
...sizeStyle(),
|
|
1631
1872
|
"z-index": node().internals.z,
|
|
1632
1873
|
transform: transform(),
|
|
1633
1874
|
visibility: culled() || !nodeHasDimensions(node()) ? "hidden" : "visible",
|
|
1634
|
-
"pointer-events": culled() ? "none" : void 0
|
|
1635
|
-
...sizeStyle(),
|
|
1636
|
-
...node().style ?? {}
|
|
1875
|
+
"pointer-events": culled() ? "none" : void 0
|
|
1637
1876
|
});
|
|
1638
1877
|
createEffect(() => ({
|
|
1639
1878
|
valid: nodeTypeValid(),
|
|
1640
1879
|
nodeType: nodeType()
|
|
1641
|
-
}), ({ valid, nodeType }) => {
|
|
1880
|
+
}), ({ valid, nodeType }) => {
|
|
1881
|
+
valid || emitFlowError(store.onError, "003", errorMessages.error003(nodeType));
|
|
1882
|
+
}), createEffect(() => ({
|
|
1642
1883
|
id: node().id,
|
|
1643
1884
|
nodeElement: nodeRef(),
|
|
1644
1885
|
nodeType: nodeType(),
|
|
@@ -1893,7 +2134,7 @@ const InitialNodeTypesMap = {
|
|
|
1893
2134
|
pendingEntries = updateEntries, scheduleIdleCallback(() => {
|
|
1894
2135
|
let updates = new Map(pendingEntries);
|
|
1895
2136
|
pendingEntries = void 0;
|
|
1896
|
-
let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode);
|
|
2137
|
+
let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode, store.nodeExtent);
|
|
1897
2138
|
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());
|
|
1898
2139
|
});
|
|
1899
2140
|
};
|
|
@@ -1914,29 +2155,31 @@ function useInternalSolidFlow() {
|
|
|
1914
2155
|
//#region src/components/connection/ConnectionLine.tsx
|
|
1915
2156
|
/** Internal component rendering the in-progress connection line. */
|
|
1916
2157
|
const ConnectionLine = (props) => {
|
|
1917
|
-
let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid)
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
2158
|
+
let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid), inProgress = createMemo(() => {
|
|
2159
|
+
let state = store.connection;
|
|
2160
|
+
return state.inProgress ? state : null;
|
|
2161
|
+
});
|
|
2162
|
+
return <Show when={inProgress()}>
|
|
2163
|
+
{(connection) => <svg class="solid-flow__container solid-flow__connectionline" width={store.width} height={store.height} style={props.containerStyle}>
|
|
2164
|
+
<g class={["solid-flow__connection", connectionStatus()]}>
|
|
2165
|
+
<Show when={props.component} fallback={<InternalConnectionLine style={props.style} connection={connection()} />}>
|
|
2166
|
+
{(CustomComponent) => {
|
|
1923
2167
|
let UserConnectionLine = CustomComponent();
|
|
1924
|
-
return <UserConnectionLine connectionLineType={store.connectionLineType} connectionLineStyle={props.style} fromNode={
|
|
2168
|
+
return <UserConnectionLine connectionLineType={store.connectionLineType} connectionLineStyle={props.style} fromNode={connection().fromNode} fromHandle={connection().fromHandle} fromX={connection().from.x} fromY={connection().from.y} toX={connection().to.x} toY={connection().to.y} fromPosition={connection().fromPosition} toPosition={connection().toPosition} connectionStatus={connectionStatus()} toNode={connection().toNode} toHandle={connection().toHandle} />;
|
|
1925
2169
|
}}
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
2170
|
+
</Show>
|
|
2171
|
+
</g>
|
|
2172
|
+
</svg>}
|
|
1929
2173
|
</Show>;
|
|
1930
2174
|
}, InternalConnectionLine = (props) => {
|
|
1931
2175
|
let { store } = useInternalSolidFlow(), path = () => {
|
|
1932
|
-
if (!store.connection.inProgress) return;
|
|
1933
2176
|
let pathParams = {
|
|
1934
|
-
sourceX:
|
|
1935
|
-
sourceY:
|
|
1936
|
-
sourcePosition:
|
|
1937
|
-
targetX:
|
|
1938
|
-
targetY:
|
|
1939
|
-
targetPosition:
|
|
2177
|
+
sourceX: props.connection.from.x,
|
|
2178
|
+
sourceY: props.connection.from.y,
|
|
2179
|
+
sourcePosition: props.connection.fromPosition,
|
|
2180
|
+
targetX: props.connection.to.x,
|
|
2181
|
+
targetY: props.connection.to.y,
|
|
2182
|
+
targetPosition: props.connection.toPosition
|
|
1940
2183
|
};
|
|
1941
2184
|
switch (store.connectionLineType) {
|
|
1942
2185
|
case "default": {
|
|
@@ -1985,19 +2228,26 @@ const ConnectionLine = (props) => {
|
|
|
1985
2228
|
</defs>
|
|
1986
2229
|
</svg>
|
|
1987
2230
|
</Show>;
|
|
1988
|
-
},
|
|
1989
|
-
let
|
|
1990
|
-
|
|
1991
|
-
|
|
2231
|
+
}, createFocusedIdTracker = () => {
|
|
2232
|
+
let [focusedId, setFocusedId] = createSignal(null);
|
|
2233
|
+
return {
|
|
2234
|
+
focusedId,
|
|
2235
|
+
onFocusIn: (event) => {
|
|
2236
|
+
let element = event.target.closest("[data-id]");
|
|
2237
|
+
setFocusedId(element?.getAttribute("data-id") ?? null);
|
|
2238
|
+
},
|
|
2239
|
+
onFocusOut: () => setFocusedId(null)
|
|
1992
2240
|
};
|
|
1993
|
-
|
|
2241
|
+
}, EdgeRenderer = (props) => {
|
|
2242
|
+
let { store, actions } = useInternalSolidFlow(), { focusedId: focusedEdgeId, onFocusIn, onFocusOut } = createFocusedIdTracker();
|
|
2243
|
+
return <div class="solid-flow__edges" onFocusIn={onFocusIn} onFocusOut={onFocusOut}>
|
|
1994
2244
|
<MarkerDefinition />
|
|
1995
2245
|
|
|
1996
2246
|
<For each={store.visibleEdgeIds}>
|
|
1997
2247
|
{(edgeId) => {
|
|
1998
2248
|
let unmounted = createMemo(() => {
|
|
1999
2249
|
if (!store.onlyRenderVisibleElements || focusedEdgeId() === edgeId) return !1;
|
|
2000
|
-
let edge = actions.
|
|
2250
|
+
let edge = actions.getLayoutedEdge(edgeId);
|
|
2001
2251
|
return !!edge && isEdgeCulled(edge, store.cullingViewport);
|
|
2002
2252
|
});
|
|
2003
2253
|
return <Show when={!unmounted()}>
|
|
@@ -2020,11 +2270,8 @@ const ConnectionLine = (props) => {
|
|
|
2020
2270
|
onCleanup(() => {
|
|
2021
2271
|
resizeObserver?.disconnect();
|
|
2022
2272
|
});
|
|
2023
|
-
let
|
|
2024
|
-
|
|
2025
|
-
setFocusedNodeId(nodeElement?.getAttribute("data-id") ?? null);
|
|
2026
|
-
};
|
|
2027
|
-
return <div class="solid-flow__container solid-flow__nodes" onFocusIn={onFocusIn} onFocusOut={() => setFocusedNodeId(null)}>
|
|
2273
|
+
let { focusedId: focusedNodeId, onFocusIn, onFocusOut } = createFocusedIdTracker();
|
|
2274
|
+
return <div class="solid-flow__container solid-flow__nodes" onFocusIn={onFocusIn} onFocusOut={onFocusOut}>
|
|
2028
2275
|
<For each={store.visibleNodeIds}>
|
|
2029
2276
|
{(nodeId) => {
|
|
2030
2277
|
let unmounted = createMemo(() => {
|
|
@@ -2043,10 +2290,10 @@ const ConnectionLine = (props) => {
|
|
|
2043
2290
|
for (let item of a) if (!b.has(item)) return !1;
|
|
2044
2291
|
return !0;
|
|
2045
2292
|
}, Pane = (props) => {
|
|
2046
|
-
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 = {
|
|
2293
|
+
let { store, nodeLookup, edgeLookup, connections, actions } = useInternalSolidFlow(), [containerRef, setContainerRef] = createSignal(), container, containerBounds = null, connectionEndedOnPane = !1, selectionInProgress = !1, selectionSpatialLookup = new GestureSpatialLookup(nodeLookup, 400), selectedNodeIds = /* @__PURE__ */ new Set(), selectedEdgeIds = /* @__PURE__ */ new Set(), autoPanId = 0, position = {
|
|
2047
2294
|
x: 0,
|
|
2048
2295
|
y: 0
|
|
2049
|
-
}, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ??
|
|
2296
|
+
}, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ?? 0, _panOnDrag = () => store.panActivationKeyPressed || props.panOnDrag, isSelecting = () => store.selectionKeyPressed || !!store.selectionRect || props.selectionOnDrag && _panOnDrag() !== !0, isSelectionEnabled = () => store.elementsSelectable && (isSelecting() || store.selectionRectMode === "user"), onClick = (event) => {
|
|
2050
2297
|
if (event.target === container) {
|
|
2051
2298
|
if (selectionInProgress || store.connection.inProgress || connectionEndedOnPane) {
|
|
2052
2299
|
selectionInProgress = !1, connectionEndedOnPane = !1;
|
|
@@ -2058,7 +2305,7 @@ const ConnectionLine = (props) => {
|
|
|
2058
2305
|
if (event.pointerType === "touch" && _panOnDrag() !== !1 && !store.selectionKeyPressed || (containerBounds = container?.getBoundingClientRect() ?? null, !containerBounds)) return;
|
|
2059
2306
|
let eventTargetIsContainer = event.target === container, isNoKeyEvent = !eventTargetIsContainer && !!event.target.closest(".nokey"), isSelectionActive = props.selectionOnDrag && eventTargetIsContainer || store.selectionKeyPressed;
|
|
2060
2307
|
if (isNoKeyEvent || !isSelecting() || !isSelectionActive || event.button !== 0 || !event.isPrimary) return;
|
|
2061
|
-
event.target?.setPointerCapture?.(event.pointerId), selectionInProgress = !1, autoPanStarted = !1;
|
|
2308
|
+
event.target?.setPointerCapture?.(event.pointerId), selectionSpatialLookup.arm((node) => nodeToRect(node)), selectionInProgress = !1, autoPanStarted = !1;
|
|
2062
2309
|
let { x, y } = getEventPosition(event, containerBounds), userSelectionFlowOrigin = pointToRendererPoint({
|
|
2063
2310
|
x,
|
|
2064
2311
|
y
|
|
@@ -2085,14 +2332,21 @@ const ConnectionLine = (props) => {
|
|
|
2085
2332
|
width: Math.abs(mouseX - screenStart.x),
|
|
2086
2333
|
height: Math.abs(mouseY - screenStart.y)
|
|
2087
2334
|
}, prevSelectedNodeIds = selectedNodeIds, prevSelectedEdgeIds = selectedEdgeIds;
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2335
|
+
{
|
|
2336
|
+
let [tx, ty, zoom] = store.transform;
|
|
2337
|
+
selectionSpatialLookup.setQueryRect({
|
|
2338
|
+
x: (nextUserSelectRect.x - tx) / zoom,
|
|
2339
|
+
y: (nextUserSelectRect.y - ty) / zoom,
|
|
2340
|
+
width: nextUserSelectRect.width / zoom,
|
|
2341
|
+
height: nextUserSelectRect.height / zoom
|
|
2342
|
+
});
|
|
2343
|
+
}
|
|
2344
|
+
selectedNodeIds = new Set(getNodesInside(selectionSpatialLookup, nextUserSelectRect, store.transform, store.selectionMode === SelectionMode$1.Partial, !0).map((n) => n.id)), selectedEdgeIds = /* @__PURE__ */ new Set();
|
|
2091
2345
|
for (let nodeId of selectedNodeIds) {
|
|
2092
2346
|
let nodeConnections = connections[nodeId];
|
|
2093
2347
|
if (nodeConnections) for (let { edgeId } of Object.values(nodeConnections)) {
|
|
2094
2348
|
let edge = edgeLookup[edgeId];
|
|
2095
|
-
edge && (edge
|
|
2349
|
+
edge && isEdgeSelectable(edge, store) && selectedEdgeIds.add(edgeId);
|
|
2096
2350
|
}
|
|
2097
2351
|
}
|
|
2098
2352
|
isSetEqual(prevSelectedNodeIds, selectedNodeIds) || actions.setNodes((nodes) => {
|
|
@@ -2273,7 +2527,7 @@ const ConnectionLine = (props) => {
|
|
|
2273
2527
|
<div class="solid-flow__selection" style={styles()} />
|
|
2274
2528
|
</Show>;
|
|
2275
2529
|
}, NodeSelection = (props) => {
|
|
2276
|
-
let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref, setRef] = createSignal(), bounds = () => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null;
|
|
2530
|
+
let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref, setRef] = createSignal(), bounds = createMemo(() => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null);
|
|
2277
2531
|
createEffect(() => ({
|
|
2278
2532
|
el: ref(),
|
|
2279
2533
|
focusable: !store.disableKeyboardA11y
|
|
@@ -2281,13 +2535,13 @@ const ConnectionLine = (props) => {
|
|
|
2281
2535
|
focusable && el?.focus({ preventScroll: !0 });
|
|
2282
2536
|
});
|
|
2283
2537
|
let onContextMenu = (event) => {
|
|
2284
|
-
let selectedNodes = store.
|
|
2538
|
+
let selectedNodes = store.selectedNodes;
|
|
2285
2539
|
props.onSelectionContextMenu?.({
|
|
2286
2540
|
nodes: selectedNodes,
|
|
2287
2541
|
event
|
|
2288
2542
|
});
|
|
2289
2543
|
}, onClick = (event) => {
|
|
2290
|
-
let selectedNodes = store.
|
|
2544
|
+
let selectedNodes = store.selectedNodes;
|
|
2291
2545
|
props.onSelectionClick?.({
|
|
2292
2546
|
nodes: selectedNodes,
|
|
2293
2547
|
event
|
|
@@ -2336,29 +2590,13 @@ const ConnectionLine = (props) => {
|
|
|
2336
2590
|
Solid Flow
|
|
2337
2591
|
</a>
|
|
2338
2592
|
</Panel>
|
|
2339
|
-
</Show
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
* `flow` and `commands` are stable identities, so destructuring them is safe:
|
|
2347
|
-
* `const { flow, commands } = useSolidFlow()`.
|
|
2348
|
-
*
|
|
2349
|
-
* @public
|
|
2350
|
-
* @returns the flow's read struct and write surface
|
|
2351
|
-
*/
|
|
2352
|
-
function useSolidFlow() {
|
|
2353
|
-
let { flow, commands } = useInternalSolidFlow();
|
|
2354
|
-
return {
|
|
2355
|
-
...commands,
|
|
2356
|
-
flow,
|
|
2357
|
-
commands
|
|
2358
|
-
};
|
|
2359
|
-
}
|
|
2360
|
-
//#endregion
|
|
2361
|
-
//#region src/components/utility/KeyHandler.ts
|
|
2593
|
+
</Show>, MODIFIER_FLAG = {
|
|
2594
|
+
alt: "altKey",
|
|
2595
|
+
control: "ctrlKey",
|
|
2596
|
+
ctrl: "ctrlKey",
|
|
2597
|
+
meta: "metaKey",
|
|
2598
|
+
shift: "shiftKey"
|
|
2599
|
+
};
|
|
2362
2600
|
function isKeyObject(key) {
|
|
2363
2601
|
return typeof key == "object" && !!key;
|
|
2364
2602
|
}
|
|
@@ -2390,18 +2628,13 @@ function matchesKey(event, keyDef) {
|
|
|
2390
2628
|
function matchesKeyArray(event, keyDefs) {
|
|
2391
2629
|
return keyDefs ? (Array.isArray(keyDefs) ? keyDefs : [keyDefs]).some((keyDef) => matchesKey(event, keyDef)) : !1;
|
|
2392
2630
|
}
|
|
2393
|
-
const MODIFIER_FLAG = {
|
|
2394
|
-
alt: "altKey",
|
|
2395
|
-
control: "ctrlKey",
|
|
2396
|
-
ctrl: "ctrlKey",
|
|
2397
|
-
meta: "metaKey",
|
|
2398
|
-
shift: "shiftKey"
|
|
2399
|
-
};
|
|
2400
2631
|
/**
|
|
2401
2632
|
* Whether an event's modifier flags PROVE this key definition cannot be held
|
|
2402
2633
|
* right now: the key itself is a modifier whose flag is off, or one of its
|
|
2403
2634
|
* required modifiers is off. Definitions built on non-modifier keys are never
|
|
2404
|
-
* contradicted (their state isn't derivable from flags).
|
|
2635
|
+
* contradicted (their state isn't derivable from flags). This is the
|
|
2636
|
+
* self-heal for OS overlays that swallow keyups without blurring the window
|
|
2637
|
+
* (upstream xyflow#5679).
|
|
2405
2638
|
*/
|
|
2406
2639
|
function isContradicted(flags, keyDef) {
|
|
2407
2640
|
let keyFlag = MODIFIER_FLAG[getKeyString(keyDef).toLowerCase()];
|
|
@@ -2418,6 +2651,28 @@ function allContradicted(flags, keyDefs) {
|
|
|
2418
2651
|
let keys = Array.isArray(keyDefs) ? keyDefs : [keyDefs];
|
|
2419
2652
|
return keys.length > 0 && keys.every((keyDef) => isContradicted(flags, keyDef));
|
|
2420
2653
|
}
|
|
2654
|
+
//#endregion
|
|
2655
|
+
//#region src/hooks/useSolidFlow.ts
|
|
2656
|
+
/**
|
|
2657
|
+
* Hook for accessing the flow instance: `{ flow, commands }` plus the
|
|
2658
|
+
* commands spread at the top level for upstream familiarity.
|
|
2659
|
+
*
|
|
2660
|
+
* `flow` and `commands` are stable identities, so destructuring them is safe:
|
|
2661
|
+
* `const { flow, commands } = useSolidFlow()`.
|
|
2662
|
+
*
|
|
2663
|
+
* @public
|
|
2664
|
+
* @returns the flow's read struct and write surface
|
|
2665
|
+
*/
|
|
2666
|
+
function useSolidFlow() {
|
|
2667
|
+
let { flow, commands } = useInternalSolidFlow();
|
|
2668
|
+
return {
|
|
2669
|
+
...commands,
|
|
2670
|
+
flow,
|
|
2671
|
+
commands
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
//#endregion
|
|
2675
|
+
//#region src/components/utility/KeyHandler.ts
|
|
2421
2676
|
const KeyHandler = (props) => {
|
|
2422
2677
|
let { store, actions } = useInternalSolidFlow(), { deleteElements } = useSolidFlow(), _props = {
|
|
2423
2678
|
get selectionKey() {
|
|
@@ -2452,14 +2707,11 @@ const KeyHandler = (props) => {
|
|
|
2452
2707
|
}, handleWindowBlur = () => {
|
|
2453
2708
|
resetKeysAndSelection(), cancelPointerGestures();
|
|
2454
2709
|
}, handleDelete = async () => {
|
|
2455
|
-
let selectedNodes = store.
|
|
2710
|
+
let selectedNodes = store.selectedNodes, selectedEdges = store.selectedEdges;
|
|
2711
|
+
await deleteElements({
|
|
2456
2712
|
nodes: selectedNodes,
|
|
2457
2713
|
edges: selectedEdges
|
|
2458
2714
|
});
|
|
2459
|
-
(deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
|
|
2460
|
-
nodes: deletedNodes,
|
|
2461
|
-
edges: deletedEdges
|
|
2462
|
-
});
|
|
2463
2715
|
};
|
|
2464
2716
|
return isServer || (createEventListenerMap(window, {
|
|
2465
2717
|
keydown: (event) => {
|
|
@@ -2477,34 +2729,23 @@ const KeyHandler = (props) => {
|
|
|
2477
2729
|
capture: !0,
|
|
2478
2730
|
passive: !0
|
|
2479
2731
|
})), null;
|
|
2480
|
-
}, SolidFlow = (props) => {
|
|
2732
|
+
}, FLOW_PROP_KEYS = /* @__PURE__ */ "ariaLabelConfig.ariaLiveMessage.attributionPosition.autoPanOnConnect.autoPanOnNodeDrag.autoPanOnNodeFocus.autoPanOnSelection.autoPanSpeed.class.clickConnect.colorMode.colorModeSSR.connectionDragThreshold.connectionLineComponent.connectionLineContainerStyle.connectionLineStyle.connectionLineType.connectionMode.connectionRadius.defaultEdgeOptions.defaultEdges.defaultMarkerColor.defaultNodes.deleteKey.disableKeyboardA11y.edgeTypes.edges.edgesFocusable.elementsSelectable.elevateEdgesOnSelect.elevateNodesOnSelect.fitView.fitViewOptions.height.id.initialViewport.isValidConnection.maxZoom.minZoom.multiSelectionKey.noDragClass.noPanClass.noWheelClass.nodeClickDistance.nodeDragThreshold.nodeExtent.nodeOrigin.nodeTypes.nodes.nodesConnectable.nodesDraggable.nodesFocusable.onBeforeConnect.onBeforeDelete.onBeforeReconnect.onClickConnectEnd.onClickConnectStart.onConnect.onConnectEnd.onConnectStart.onDelete.onEdgeClick.onEdgeContextMenu.onEdgePointerEnter.onEdgePointerLeave.onEdgesDelete.onFlowError.onInit.onMove.onMoveEnd.onMoveStart.onNodeClick.onNodeContextMenu.onNodeDrag.onNodeDragStart.onNodeDragStop.onNodePointerEnter.onNodePointerLeave.onNodePointerMove.onNodesDelete.onPaneClick.onPaneContextMenu.onReconnect.onReconnectEnd.onReconnectStart.onSelectionChange.onSelectionClick.onSelectionContextMenu.onSelectionDrag.onSelectionDragStart.onSelectionDragStop.onSelectionEnd.onSelectionStart.onlyRenderVisibleElements.panActivationKey.panOnDrag.panOnScroll.panOnScrollMode.panOnScrollSpeed.paneClickDistance.preventScrolling.proOptions.selectNodesOnDrag.selectionKey.selectionMode.selectionOnDrag.snapGrid.style.translateExtent.viewport.width.zIndexMode.zoomActivationKey.zoomOnDoubleClick.zoomOnPinch.zoomOnScroll".split("."), SolidFlow = (props) => {
|
|
2481
2733
|
let [domNodeRef, setDomNodeRef] = createSignal(), domNode, _props = merge({
|
|
2482
2734
|
...getDefaultFlowStateProps(),
|
|
2483
2735
|
colorMode: "light",
|
|
2484
|
-
deleteKeyCode: "Backspace",
|
|
2485
|
-
defaultViewport: {
|
|
2486
|
-
x: 0,
|
|
2487
|
-
y: 0,
|
|
2488
|
-
zoom: 1
|
|
2489
|
-
},
|
|
2490
|
-
multiSelectionKeyCode: isMacOs() ? "Meta" : "Control",
|
|
2491
2736
|
nodeClickDistance: 0,
|
|
2492
2737
|
panOnScroll: !1,
|
|
2493
|
-
panActivationKeyCode: "Space",
|
|
2494
2738
|
preventScrolling: !0,
|
|
2495
2739
|
panOnDrag: !0,
|
|
2496
2740
|
panOnScrollSpeed: .5,
|
|
2497
2741
|
panOnScrollMode: "free",
|
|
2498
2742
|
paneClickDistance: 0,
|
|
2499
|
-
reconnectRadius: 10,
|
|
2500
|
-
selectionKeyCode: "Shift",
|
|
2501
2743
|
selectionOnDrag: !1,
|
|
2502
2744
|
translateExtent: infiniteExtent,
|
|
2503
|
-
zoomActivationKeyCode: isMacOs() ? "Meta" : "Control",
|
|
2504
2745
|
zoomOnPinch: !0,
|
|
2505
2746
|
zoomOnDoubleClick: !0,
|
|
2506
2747
|
zoomOnScroll: !0
|
|
2507
|
-
}, props), htmlProps = omit(_props,
|
|
2748
|
+
}, props), htmlProps = omit(_props, ...FLOW_PROP_KEYS, "children"), TypedSolidFlowContext = SolidFlowContext, solidFlow = useContext(TypedSolidFlowContext) ?? createSolidFlow(_props), { store, actions } = solidFlow;
|
|
2508
2749
|
onSettled(() => (actions.applyInitialFitView(_props.fitView), actions.setConfig(_props), actions.setDomNode(domNode), () => {
|
|
2509
2750
|
actions.reset();
|
|
2510
2751
|
})), createEffect(() => domNodeRef(), (el) => {
|
|
@@ -2513,11 +2754,6 @@ const KeyHandler = (props) => {
|
|
|
2513
2754
|
actions.setWidth(el.clientWidth), actions.setHeight(el.clientHeight);
|
|
2514
2755
|
});
|
|
2515
2756
|
return observer.observe(el), () => observer.disconnect();
|
|
2516
|
-
}), createEffect(() => ({
|
|
2517
|
-
panZoom: store.panZoom,
|
|
2518
|
-
distance: _props.paneClickDistance
|
|
2519
|
-
}), ({ panZoom, distance }) => {
|
|
2520
|
-
panZoom?.setClickDistance(distance);
|
|
2521
2757
|
});
|
|
2522
2758
|
let selectedElements = createMemo(() => ({
|
|
2523
2759
|
nodes: store.selectedNodes,
|
|
@@ -2526,7 +2762,7 @@ const KeyHandler = (props) => {
|
|
|
2526
2762
|
createEffect(() => selectedElements(), (params) => {
|
|
2527
2763
|
untrack(() => _props.onSelectionChange)?.(params);
|
|
2528
2764
|
});
|
|
2529
|
-
let rootStyle = () => ({
|
|
2765
|
+
let asyncSeedGuard = () => (_props.nodes?.length, _props.edges?.length, null), rootStyle = () => ({
|
|
2530
2766
|
width: toPxString(_props.width),
|
|
2531
2767
|
height: toPxString(_props.height),
|
|
2532
2768
|
..._props.style
|
|
@@ -2537,7 +2773,13 @@ const KeyHandler = (props) => {
|
|
|
2537
2773
|
"solid-flow",
|
|
2538
2774
|
"solid-flow__container",
|
|
2539
2775
|
_props.class,
|
|
2540
|
-
store.colorMode
|
|
2776
|
+
store.colorMode,
|
|
2777
|
+
{
|
|
2778
|
+
connecting: !!store.connectionFromHandle || !!store.clickConnectStartHandle,
|
|
2779
|
+
"connecting-from-source": (store.connectionFromHandle ?? store.clickConnectStartHandle)?.type === "source",
|
|
2780
|
+
"connecting-from-target": (store.connectionFromHandle ?? store.clickConnectStartHandle)?.type === "target",
|
|
2781
|
+
"connection-strict": store.connectionMode === "strict"
|
|
2782
|
+
}
|
|
2541
2783
|
]} style={rootStyle()} onScroll={(e) => {
|
|
2542
2784
|
e.currentTarget.scrollTo({
|
|
2543
2785
|
top: 0,
|
|
@@ -2546,12 +2788,13 @@ const KeyHandler = (props) => {
|
|
|
2546
2788
|
});
|
|
2547
2789
|
}} {...htmlProps}>
|
|
2548
2790
|
<TypedSolidFlowContext value={solidFlow}>
|
|
2791
|
+
{asyncSeedGuard()}
|
|
2549
2792
|
<KeyHandler selectionKey={_props.selectionKey} deleteKey={_props.deleteKey} panActivationKey={_props.panActivationKey} multiSelectionKey={_props.multiSelectionKey} zoomActivationKey={_props.zoomActivationKey} />
|
|
2550
2793
|
<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}>
|
|
2551
2794
|
<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}>
|
|
2552
2795
|
<Viewport>
|
|
2553
2796
|
<div class="solid-flow__container solid-flow__viewport-back" />
|
|
2554
|
-
<EdgeRenderer
|
|
2797
|
+
<EdgeRenderer onEdgeClick={_props.onEdgeClick} onEdgeContextMenu={_props.onEdgeContextMenu} onEdgePointerEnter={_props.onEdgePointerEnter} onEdgePointerLeave={_props.onEdgePointerLeave} />
|
|
2555
2798
|
<div class="solid-flow__container solid-flow__edge-labels" />
|
|
2556
2799
|
<ConnectionLine type={_props.connectionLineType} component={_props.connectionLineComponent} containerStyle={_props.connectionLineContainerStyle} style={_props.connectionLineStyle} />
|
|
2557
2800
|
<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} />
|
|
@@ -2609,8 +2852,8 @@ function useConnection() {
|
|
|
2609
2852
|
* @returns store with an array of nodes
|
|
2610
2853
|
*/
|
|
2611
2854
|
function useNodes() {
|
|
2612
|
-
let {
|
|
2613
|
-
return () =>
|
|
2855
|
+
let { flow } = useInternalSolidFlow();
|
|
2856
|
+
return () => flow.nodes;
|
|
2614
2857
|
}
|
|
2615
2858
|
/**
|
|
2616
2859
|
* Hook for getting the current edges from the store.
|
|
@@ -2619,8 +2862,8 @@ function useNodes() {
|
|
|
2619
2862
|
* @returns store with an array of edges
|
|
2620
2863
|
*/
|
|
2621
2864
|
function useEdges() {
|
|
2622
|
-
let {
|
|
2623
|
-
return () =>
|
|
2865
|
+
let { flow } = useInternalSolidFlow();
|
|
2866
|
+
return () => flow.edges;
|
|
2624
2867
|
}
|
|
2625
2868
|
/**
|
|
2626
2869
|
* Hook for getting the current viewport from the store.
|
|
@@ -2678,6 +2921,52 @@ function useInternalNode(id) {
|
|
|
2678
2921
|
return () => flow.internalNodes[id()];
|
|
2679
2922
|
}
|
|
2680
2923
|
//#endregion
|
|
2924
|
+
//#region src/hooks/useKeyPress.ts
|
|
2925
|
+
/**
|
|
2926
|
+
* Reactive "is this key (combo) held right now?" — the Solid Flow
|
|
2927
|
+
* counterpart of React Flow's `useKeyPress`, usable anywhere (no flow
|
|
2928
|
+
* context required).
|
|
2929
|
+
*
|
|
2930
|
+
* The definition is an Accessor per house convention — `useKeyPress(() =>
|
|
2931
|
+
* "a")`, `useKeyPress(() => ["a", "d"])`, or `useKeyPress(() => ({ key:
|
|
2932
|
+
* "s", modifier: ["meta"] }))`; swapping the definition resets the state.
|
|
2933
|
+
*
|
|
2934
|
+
* Hardened beyond upstream:
|
|
2935
|
+
* - Combos re-activate when the base key is re-pressed while the modifier
|
|
2936
|
+
* stays held (upstream's oldest open key bug, xyflow#2248).
|
|
2937
|
+
* - Stuck modifiers self-heal from the flags later keyboard/pointer/wheel
|
|
2938
|
+
* events carry (OS overlays swallow keyups without blurring — the macOS
|
|
2939
|
+
* screenshot HUD; xyflow#5679), and window blur resets.
|
|
2940
|
+
*/
|
|
2941
|
+
function useKeyPress(keys) {
|
|
2942
|
+
let [pressed, setPressed] = createSignal(!1);
|
|
2943
|
+
if (createEffect(() => keys(), () => {
|
|
2944
|
+
setPressed(!1);
|
|
2945
|
+
}, { defer: !0 }), !isServer) {
|
|
2946
|
+
let reconcile = (event) => {
|
|
2947
|
+
pressed() && allContradicted(event, keys()) && (setPressed(!1), flush());
|
|
2948
|
+
};
|
|
2949
|
+
createEventListenerMap(window, {
|
|
2950
|
+
keydown: (event) => {
|
|
2951
|
+
reconcile(event), matchesKeyArray(event, keys()) && (setPressed(!0), flush());
|
|
2952
|
+
},
|
|
2953
|
+
keyup: (event) => {
|
|
2954
|
+
reconcile(event), matchesKeyArray(event, keys()) && (setPressed(!1), flush());
|
|
2955
|
+
},
|
|
2956
|
+
blur: () => {
|
|
2957
|
+
setPressed(!1), flush();
|
|
2958
|
+
}
|
|
2959
|
+
}), createEventListenerMap(window, {
|
|
2960
|
+
pointerdown: reconcile,
|
|
2961
|
+
wheel: reconcile
|
|
2962
|
+
}, {
|
|
2963
|
+
capture: !0,
|
|
2964
|
+
passive: !0
|
|
2965
|
+
});
|
|
2966
|
+
}
|
|
2967
|
+
return pressed;
|
|
2968
|
+
}
|
|
2969
|
+
//#endregion
|
|
2681
2970
|
//#region src/hooks/useNodeConnections.ts
|
|
2682
2971
|
/**
|
|
2683
2972
|
* Hook to retrieve all edges connected to a node. Can be filtered by handle type and id.
|
|
@@ -2863,7 +3152,7 @@ const DotPattern = (props) => {
|
|
|
2863
3152
|
{ selected: !!_props.selected },
|
|
2864
3153
|
_props.class
|
|
2865
3154
|
]} x={_props.x} y={_props.y} rx={_props.borderRadius} ry={_props.borderRadius} width={_props.width} height={_props.height} shape-rendering={_props.shapeRendering} style={style()} onClick={_props.onClick ? (event) => _props.onClick(event, _props.id) : void 0} />;
|
|
2866
|
-
}, getAttrFunction = (
|
|
3155
|
+
}, getAttrFunction = (value) => value instanceof Function ? value : () => value, MiniMap = (props) => {
|
|
2867
3156
|
let { store, nodeLookup } = useInternalSolidFlow(), _props = propDefaults(props, {
|
|
2868
3157
|
position: "bottom-right",
|
|
2869
3158
|
nodeClass: "",
|
|
@@ -2873,26 +3162,47 @@ const DotPattern = (props) => {
|
|
|
2873
3162
|
width: 200,
|
|
2874
3163
|
height: 150,
|
|
2875
3164
|
nodeBorderRadius: 5,
|
|
3165
|
+
offsetScale: 5,
|
|
2876
3166
|
nodeStrokeWidth: 2,
|
|
2877
3167
|
style: {}
|
|
2878
|
-
}), paneProps = omit(_props, "class", "style", "position", "nodeClass", "nodeStrokeColor", "nodeColor", "pannable", "zoomable", "inversePan", "zoomStep", "bgColor", "width", "height", "maskColor", "maskStrokeColor", "maskStrokeWidth", "nodeBorderRadius", "nodeStrokeWidth", "nodeComponent", "onClick", "onNodeClick"), nodeColorFunc = () => _props.nodeColor === void 0 ? void 0 : getAttrFunction(_props.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(_props.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(_props.nodeClass), shapeRendering =
|
|
3168
|
+
}), paneProps = omit(_props, "class", "style", "position", "nodeClass", "nodeStrokeColor", "nodeColor", "pannable", "zoomable", "inversePan", "zoomStep", "offsetScale", "bgColor", "width", "height", "maskColor", "maskStrokeColor", "maskStrokeWidth", "nodeBorderRadius", "nodeStrokeWidth", "nodeComponent", "onClick", "onNodeClick"), nodeColorFunc = () => _props.nodeColor === void 0 ? void 0 : getAttrFunction(_props.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(_props.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(_props.nodeClass), shapeRendering = typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision", labelledBy = createMemo(() => `solid-flow__minimap-desc-${store.id}`), viewBB = createMemo(() => ({
|
|
2879
3169
|
x: -store.viewport.x / store.viewport.zoom,
|
|
2880
3170
|
y: -store.viewport.y / store.viewport.zoom,
|
|
2881
3171
|
width: store.width / store.viewport.zoom,
|
|
2882
3172
|
height: store.height / store.viewport.zoom
|
|
2883
|
-
}),
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
3173
|
+
})), rectsEqual = (a, b) => a === b || !!a && !!b && a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height, sampleBounds = () => untrack(() => {
|
|
3174
|
+
if (nodeLookup.size === 0) return null;
|
|
3175
|
+
let bounds = getInternalNodesBounds(nodeLookup);
|
|
3176
|
+
return Number.isFinite(bounds.x) && Number.isFinite(bounds.width) ? bounds : null;
|
|
3177
|
+
}), [graphBounds, setGraphBounds] = createSignal(sampleBounds(), { equals: rectsEqual });
|
|
3178
|
+
createEffect(() => store.dragging, (dragging) => {
|
|
3179
|
+
if (!dragging) {
|
|
3180
|
+
setGraphBounds(sampleBounds());
|
|
3181
|
+
return;
|
|
3182
|
+
}
|
|
3183
|
+
let raf = requestAnimationFrame(function tick() {
|
|
3184
|
+
setGraphBounds(sampleBounds()), raf = requestAnimationFrame(tick);
|
|
3185
|
+
});
|
|
3186
|
+
return () => cancelAnimationFrame(raf);
|
|
3187
|
+
}), createEffect(() => ({
|
|
3188
|
+
count: store.nodes.length,
|
|
3189
|
+
initialized: store.nodesInitialized
|
|
3190
|
+
}), () => {
|
|
3191
|
+
setGraphBounds(sampleBounds());
|
|
3192
|
+
}), createEffect(() => null, () => {
|
|
3193
|
+
let interval = setInterval(() => setGraphBounds(sampleBounds()), 500);
|
|
3194
|
+
return () => clearInterval(interval);
|
|
3195
|
+
});
|
|
3196
|
+
let boundingRect = createMemo(() => {
|
|
3197
|
+
let view = viewBB(), bounds = graphBounds();
|
|
3198
|
+
return bounds ? getBoundsOfRects(bounds, view) : view;
|
|
3199
|
+
}), viewScale = createMemo(() => Math.max(boundingRect().width / _props.width, boundingRect().height / _props.height)), getViewWidth = () => viewScale() * _props.width, getViewHeight = () => viewScale() * _props.height, getOffset = () => _props.offsetScale * viewScale(), getX = () => {
|
|
3200
|
+
let rect = boundingRect();
|
|
3201
|
+
return rect.x - (getViewWidth() - rect.width) / 2 - getOffset();
|
|
2889
3202
|
}, getY = () => {
|
|
2890
|
-
let
|
|
2891
|
-
return
|
|
2892
|
-
}, getViewboxWidth = () => getViewWidth() + getOffset() * 2, getViewboxHeight = () => getViewHeight() + getOffset() * 2, strokeWidth = () => _props.maskStrokeWidth ? _props.maskStrokeWidth *
|
|
2893
|
-
let currentNodeIds = store.nodes.map((node) => node.id), currentSet = new Set(currentNodeIds);
|
|
2894
|
-
return (prevNodeIds.length !== currentNodeIds.length || !prevNodeIds.every((id) => currentSet.has(id))) && (prevNodeIds = currentNodeIds), prevNodeIds;
|
|
2895
|
-
};
|
|
3203
|
+
let rect = boundingRect();
|
|
3204
|
+
return rect.y - (getViewHeight() - rect.height) / 2 - getOffset();
|
|
3205
|
+
}, getViewboxWidth = () => getViewWidth() + getOffset() * 2, getViewboxHeight = () => getViewHeight() + getOffset() * 2, strokeWidth = () => _props.maskStrokeWidth ? _props.maskStrokeWidth * viewScale() : void 0, nodeIds = createMemo(() => store.nodes.map((node) => node.id), { equals: (a, b) => a.length === b.length && a.every((id, i) => id === b[i]) });
|
|
2896
3206
|
return <Panel position={_props.position} data-testid="solid-flow__minimap" class={["solid-flow__minimap", _props.class]} style={{
|
|
2897
3207
|
"--xy-minimap-background-color-props": _props.bgColor,
|
|
2898
3208
|
..._props.style
|
|
@@ -2909,7 +3219,7 @@ const DotPattern = (props) => {
|
|
|
2909
3219
|
domNode: el,
|
|
2910
3220
|
panZoom,
|
|
2911
3221
|
getTransform: () => store.transform,
|
|
2912
|
-
getViewScale
|
|
3222
|
+
getViewScale: viewScale
|
|
2913
3223
|
});
|
|
2914
3224
|
return setMinimap(instance), () => {
|
|
2915
3225
|
instance.destroy();
|
|
@@ -2947,14 +3257,20 @@ const DotPattern = (props) => {
|
|
|
2947
3257
|
<title id={labelledBy()}>{store.ariaLabelConfig["minimap.ariaLabel"]}</title>
|
|
2948
3258
|
<For keyed={!1} each={nodeIds()}>
|
|
2949
3259
|
{(nodeId) => {
|
|
2950
|
-
let
|
|
2951
|
-
|
|
2952
|
-
|
|
3260
|
+
let visibleNode = createMemo(() => {
|
|
3261
|
+
let row = nodeLookup.get(nodeId());
|
|
3262
|
+
return row && nodeHasDimensions(row) && !row.hidden ? row : null;
|
|
3263
|
+
});
|
|
3264
|
+
return <Show when={visibleNode()}>
|
|
3265
|
+
{(node) => {
|
|
3266
|
+
let dimensions = () => getNodeDimensions(node()), userNode = () => node().internals.userNode;
|
|
3267
|
+
return <Dynamic component={_props.nodeComponent ?? MiniMapNode} id={nodeId()} x={node().internals.positionAbsolute.x} y={node().internals.positionAbsolute.y} borderRadius={_props.nodeBorderRadius} strokeWidth={_props.nodeStrokeWidth} shapeRendering={shapeRendering} width={dimensions().width} height={dimensions().height} selected={node().selected} color={nodeColorFunc()?.call(null, userNode())} strokeColor={nodeStrokeColorFunc().call(null, userNode())} class={nodeClassFunc().call(null, userNode())} style={node().style} onClick={_props.onNodeClick ? onSvgNodeClick : void 0} />;
|
|
3268
|
+
}}
|
|
2953
3269
|
</Show>;
|
|
2954
3270
|
}}
|
|
2955
3271
|
</For>
|
|
2956
3272
|
<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
|
|
2957
|
-
M${
|
|
3273
|
+
M${viewBB().x},${viewBB().y}h${viewBB().width}v${viewBB().height}h${-viewBB().width}z`} fill-rule="evenodd" pointer-events="none" />
|
|
2958
3274
|
</svg>;
|
|
2959
3275
|
}}
|
|
2960
3276
|
</Show>
|
|
@@ -3066,7 +3382,7 @@ const DotPattern = (props) => {
|
|
|
3066
3382
|
</EdgeLabel>
|
|
3067
3383
|
</Show>;
|
|
3068
3384
|
}, NodeToolbar = (props) => {
|
|
3069
|
-
let { store
|
|
3385
|
+
let { store, flow, commands } = useInternalSolidFlow(), _props = propDefaults(props, {
|
|
3070
3386
|
offset: 10,
|
|
3071
3387
|
position: "top",
|
|
3072
3388
|
align: "center",
|
|
@@ -3078,7 +3394,7 @@ const DotPattern = (props) => {
|
|
|
3078
3394
|
let node = flow.internalNodes[nodeId];
|
|
3079
3395
|
return node && res.push(node), res;
|
|
3080
3396
|
}, []), transform = () => {
|
|
3081
|
-
let nodeRect = getNodesBounds(toolbarNodes());
|
|
3397
|
+
let nodeRect = commands.getNodesBounds(toolbarNodes());
|
|
3082
3398
|
return nodeRect ? getNodeToolbarTransform(nodeRect, store.viewport, _props.position, _props.offset, _props.align) : "";
|
|
3083
3399
|
}, zIndex = () => {
|
|
3084
3400
|
let nodes = toolbarNodes();
|
|
@@ -3101,4 +3417,4 @@ const DotPattern = (props) => {
|
|
|
3101
3417
|
</Show>;
|
|
3102
3418
|
}, SelectionMode = SelectionMode$1, getEdgeCenter = getEdgeCenter$1, getBezierEdgeCenter = getBezierEdgeCenter$1;
|
|
3103
3419
|
//#endregion
|
|
3104
|
-
export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, MiniMapNode, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, connectionKey, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdgeId, useEdges, useInternalNode, useNodeConnections, useNodeId, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };
|
|
3420
|
+
export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, MiniMapNode, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, connectionKey, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdgeId, useEdges, useInternalNode, useKeyPress, useNodeConnections, useNodeId, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };
|