@bian-womp/spark-workbench 0.3.62 → 0.3.64
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/lib/cjs/index.cjs +18 -219
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/core/InMemoryWorkbench.d.ts.map +1 -1
- package/lib/cjs/src/misc/SelectionActiveSync.d.ts +10 -0
- package/lib/cjs/src/misc/SelectionActiveSync.d.ts.map +1 -0
- package/lib/cjs/src/misc/WorkbenchCanvas.d.ts.map +1 -1
- package/lib/esm/index.js +19 -220
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/core/InMemoryWorkbench.d.ts.map +1 -1
- package/lib/esm/src/misc/SelectionActiveSync.d.ts +10 -0
- package/lib/esm/src/misc/SelectionActiveSync.d.ts.map +1 -0
- package/lib/esm/src/misc/WorkbenchCanvas.d.ts.map +1 -1
- package/package.json +4 -4
- package/lib/cjs/src/misc/SelectionBoundOverlay.d.ts +0 -11
- package/lib/cjs/src/misc/SelectionBoundOverlay.d.ts.map +0 -1
- package/lib/esm/src/misc/SelectionBoundOverlay.d.ts +0 -11
- package/lib/esm/src/misc/SelectionBoundOverlay.d.ts.map +0 -1
package/lib/cjs/index.cjs
CHANGED
|
@@ -416,8 +416,9 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
416
416
|
setViewport(viewport) {
|
|
417
417
|
if (lod.isEqual(this.viewport, viewport))
|
|
418
418
|
return;
|
|
419
|
+
const init = this.viewport === null;
|
|
419
420
|
this.viewport = { ...viewport };
|
|
420
|
-
this.emit("graphUiChanged", { change: { type: "viewport" } });
|
|
421
|
+
this.emit("graphUiChanged", { change: { type: "viewport" }, init });
|
|
421
422
|
}
|
|
422
423
|
getViewport() {
|
|
423
424
|
return this.viewport ? { ...this.viewport } : null;
|
|
@@ -1687,7 +1688,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
|
|
|
1687
1688
|
this.clientPromise = promise = (async () => {
|
|
1688
1689
|
// Build client config from backend config
|
|
1689
1690
|
const clientConfig = this.buildClientConfig(backend);
|
|
1690
|
-
// Wrap custom event handler to intercept
|
|
1691
|
+
// Wrap custom event handler to intercept viewport events and emit viewport event
|
|
1691
1692
|
const wrappedOnCustomEvent = (event) => {
|
|
1692
1693
|
const msg = event?.message;
|
|
1693
1694
|
if (msg &&
|
|
@@ -5890,220 +5891,22 @@ function useKeyboardShortcutToast() {
|
|
|
5890
5891
|
return { toast, showToast, hideToast };
|
|
5891
5892
|
}
|
|
5892
5893
|
|
|
5893
|
-
const
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
const
|
|
5897
|
-
const
|
|
5898
|
-
const
|
|
5899
|
-
const
|
|
5900
|
-
const upListenerRef = React.useRef(null);
|
|
5901
|
-
React.useRef(null);
|
|
5902
|
-
const { wb } = useWorkbenchContext();
|
|
5894
|
+
const selectionActiveSelector = (state) => state.nodesSelectionActive;
|
|
5895
|
+
const selectionDragActiveSelector = (state) => state.userSelectionActive;
|
|
5896
|
+
const SelectionActiveSync = ({ selection }) => {
|
|
5897
|
+
const store = react.useStoreApi();
|
|
5898
|
+
const currentActive = react.useStore(selectionActiveSelector);
|
|
5899
|
+
const draggingSelection = react.useStore(selectionDragActiveSelector);
|
|
5900
|
+
const active = selection.nodes.length > 1;
|
|
5903
5901
|
React.useEffect(() => {
|
|
5904
|
-
if (
|
|
5905
|
-
return;
|
|
5906
|
-
const parent = overlayRef.current.parentElement;
|
|
5907
|
-
if (!parent)
|
|
5908
|
-
return;
|
|
5909
|
-
const updateRect = () => {
|
|
5910
|
-
setParentRect(parent.getBoundingClientRect());
|
|
5911
|
-
};
|
|
5912
|
-
updateRect();
|
|
5913
|
-
const resizeObserver = new ResizeObserver(updateRect);
|
|
5914
|
-
resizeObserver.observe(parent);
|
|
5915
|
-
const scrollHandler = () => updateRect();
|
|
5916
|
-
window.addEventListener("scroll", scrollHandler, true);
|
|
5917
|
-
return () => {
|
|
5918
|
-
resizeObserver.disconnect();
|
|
5919
|
-
window.removeEventListener("scroll", scrollHandler, true);
|
|
5920
|
-
};
|
|
5921
|
-
}, [viewportTick]);
|
|
5922
|
-
const cleanupDragListeners = React.useCallback(() => {
|
|
5923
|
-
if (moveListenerRef.current) {
|
|
5924
|
-
window.removeEventListener("mousemove", moveListenerRef.current);
|
|
5925
|
-
moveListenerRef.current = null;
|
|
5926
|
-
}
|
|
5927
|
-
if (upListenerRef.current) {
|
|
5928
|
-
window.removeEventListener("mouseup", upListenerRef.current);
|
|
5929
|
-
upListenerRef.current = null;
|
|
5930
|
-
}
|
|
5931
|
-
dragStateRef.current = null;
|
|
5932
|
-
setIsDragging(false);
|
|
5933
|
-
}, []);
|
|
5934
|
-
React.useEffect(() => cleanupDragListeners, [cleanupDragListeners]);
|
|
5935
|
-
const handleMouseMove = React.useCallback((e) => {
|
|
5936
|
-
if (!rfInstance || !wb || !parentRect)
|
|
5937
|
-
return;
|
|
5938
|
-
const dragState = dragStateRef.current;
|
|
5939
|
-
if (!dragState)
|
|
5940
|
-
return;
|
|
5941
|
-
e.preventDefault();
|
|
5942
|
-
e.stopPropagation();
|
|
5943
|
-
const current = rfInstance.screenToFlowPosition({
|
|
5944
|
-
x: e.clientX,
|
|
5945
|
-
y: e.clientY,
|
|
5946
|
-
});
|
|
5947
|
-
const dx = current.x - dragState.startFlow.x;
|
|
5948
|
-
const dy = current.y - dragState.startFlow.y;
|
|
5949
|
-
// Update nodes directly via React Flow for immediate visual feedback
|
|
5950
|
-
const nodes = rfInstance.getNodes();
|
|
5951
|
-
const updatedNodes = nodes.map((node) => {
|
|
5952
|
-
if (dragState.initialPositions[node.id]) {
|
|
5953
|
-
const initialPos = dragState.initialPositions[node.id];
|
|
5954
|
-
return {
|
|
5955
|
-
...node,
|
|
5956
|
-
position: {
|
|
5957
|
-
x: initialPos.x + dx,
|
|
5958
|
-
y: initialPos.y + dy,
|
|
5959
|
-
},
|
|
5960
|
-
};
|
|
5961
|
-
}
|
|
5962
|
-
return node;
|
|
5963
|
-
});
|
|
5964
|
-
rfInstance.setNodes(updatedNodes);
|
|
5965
|
-
// Also update workbench state
|
|
5966
|
-
const nextPositions = {};
|
|
5967
|
-
for (const [nodeId, pos] of Object.entries(dragState.initialPositions)) {
|
|
5968
|
-
nextPositions[nodeId] = { x: pos.x + dx, y: pos.y + dy };
|
|
5969
|
-
}
|
|
5970
|
-
if (Object.keys(nextPositions).length) {
|
|
5971
|
-
wb.setPositions(nextPositions, { commit: false });
|
|
5972
|
-
}
|
|
5973
|
-
}, [rfInstance, wb, parentRect]);
|
|
5974
|
-
const handleMouseUp = React.useCallback((e) => {
|
|
5975
|
-
if (!rfInstance || !wb) {
|
|
5976
|
-
cleanupDragListeners();
|
|
5902
|
+
if (draggingSelection)
|
|
5977
5903
|
return;
|
|
5904
|
+
if (currentActive !== active) {
|
|
5905
|
+
console.log("[SelectionActiveSync] setting active selection to", active);
|
|
5906
|
+
store.setState({ nodesSelectionActive: active });
|
|
5978
5907
|
}
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
cleanupDragListeners();
|
|
5982
|
-
return;
|
|
5983
|
-
}
|
|
5984
|
-
e.preventDefault();
|
|
5985
|
-
e.stopPropagation();
|
|
5986
|
-
const current = rfInstance.screenToFlowPosition({
|
|
5987
|
-
x: e.clientX,
|
|
5988
|
-
y: e.clientY,
|
|
5989
|
-
});
|
|
5990
|
-
const dx = current.x - dragState.startFlow.x;
|
|
5991
|
-
const dy = current.y - dragState.startFlow.y;
|
|
5992
|
-
const nextPositions = {};
|
|
5993
|
-
for (const [nodeId, pos] of Object.entries(dragState.initialPositions)) {
|
|
5994
|
-
nextPositions[nodeId] = { x: pos.x + dx, y: pos.y + dy };
|
|
5995
|
-
}
|
|
5996
|
-
if (Object.keys(nextPositions).length) {
|
|
5997
|
-
wb.setPositions(nextPositions, { commit: true });
|
|
5998
|
-
}
|
|
5999
|
-
cleanupDragListeners();
|
|
6000
|
-
}, [cleanupDragListeners, rfInstance, wb]);
|
|
6001
|
-
const handleMouseDown = React.useCallback((e) => {
|
|
6002
|
-
if (e.button !== 0)
|
|
6003
|
-
return;
|
|
6004
|
-
if (!rfInstance || !wb)
|
|
6005
|
-
return;
|
|
6006
|
-
if (selection.nodes.length < 2)
|
|
6007
|
-
return;
|
|
6008
|
-
e.preventDefault();
|
|
6009
|
-
e.stopPropagation();
|
|
6010
|
-
const startFlow = rfInstance.screenToFlowPosition({
|
|
6011
|
-
x: e.clientX,
|
|
6012
|
-
y: e.clientY,
|
|
6013
|
-
});
|
|
6014
|
-
const positions = wb.getPositions();
|
|
6015
|
-
const initialPositions = {};
|
|
6016
|
-
for (const nodeId of selection.nodes) {
|
|
6017
|
-
const pos = positions[nodeId];
|
|
6018
|
-
if (pos) {
|
|
6019
|
-
initialPositions[nodeId] = pos;
|
|
6020
|
-
}
|
|
6021
|
-
}
|
|
6022
|
-
if (!Object.keys(initialPositions).length)
|
|
6023
|
-
return;
|
|
6024
|
-
dragStateRef.current = { startFlow, initialPositions };
|
|
6025
|
-
setIsDragging(true);
|
|
6026
|
-
moveListenerRef.current = handleMouseMove;
|
|
6027
|
-
upListenerRef.current = handleMouseUp;
|
|
6028
|
-
window.addEventListener("mousemove", handleMouseMove, { passive: false });
|
|
6029
|
-
window.addEventListener("mouseup", handleMouseUp, { passive: false });
|
|
6030
|
-
}, [handleMouseMove, handleMouseUp, rfInstance, selection.nodes, wb]);
|
|
6031
|
-
// Continuous bounds update loop
|
|
6032
|
-
React.useEffect(() => {
|
|
6033
|
-
if (typeof document === "undefined" ||
|
|
6034
|
-
!rfInstance ||
|
|
6035
|
-
!parentRect ||
|
|
6036
|
-
selection.nodes.length < 2) {
|
|
6037
|
-
setBounds(null);
|
|
6038
|
-
return;
|
|
6039
|
-
}
|
|
6040
|
-
let animationFrameId = null;
|
|
6041
|
-
let isActive = true;
|
|
6042
|
-
const updateBounds = () => {
|
|
6043
|
-
if (!isActive)
|
|
6044
|
-
return;
|
|
6045
|
-
let calculatedBounds = null;
|
|
6046
|
-
for (const nodeId of selection.nodes) {
|
|
6047
|
-
const el = document.querySelector(`.react-flow__node[data-id="${nodeId}"]`);
|
|
6048
|
-
if (!el)
|
|
6049
|
-
continue;
|
|
6050
|
-
const rect = el.getBoundingClientRect();
|
|
6051
|
-
const relativeLeft = rect.left - parentRect.left;
|
|
6052
|
-
const relativeTop = rect.top - parentRect.top;
|
|
6053
|
-
const relativeRight = rect.right - parentRect.left;
|
|
6054
|
-
const relativeBottom = rect.bottom - parentRect.top;
|
|
6055
|
-
if (!calculatedBounds) {
|
|
6056
|
-
calculatedBounds = {
|
|
6057
|
-
left: relativeLeft,
|
|
6058
|
-
top: relativeTop,
|
|
6059
|
-
right: relativeRight,
|
|
6060
|
-
bottom: relativeBottom,
|
|
6061
|
-
};
|
|
6062
|
-
}
|
|
6063
|
-
else {
|
|
6064
|
-
calculatedBounds.left = Math.min(calculatedBounds.left, relativeLeft);
|
|
6065
|
-
calculatedBounds.top = Math.min(calculatedBounds.top, relativeTop);
|
|
6066
|
-
calculatedBounds.right = Math.max(calculatedBounds.right, relativeRight);
|
|
6067
|
-
calculatedBounds.bottom = Math.max(calculatedBounds.bottom, relativeBottom);
|
|
6068
|
-
}
|
|
6069
|
-
}
|
|
6070
|
-
setBounds(calculatedBounds);
|
|
6071
|
-
// Continue the animation loop
|
|
6072
|
-
if (isActive) {
|
|
6073
|
-
animationFrameId = requestAnimationFrame(updateBounds);
|
|
6074
|
-
}
|
|
6075
|
-
};
|
|
6076
|
-
// Start the animation loop
|
|
6077
|
-
animationFrameId = requestAnimationFrame(updateBounds);
|
|
6078
|
-
return () => {
|
|
6079
|
-
isActive = false;
|
|
6080
|
-
if (animationFrameId !== null) {
|
|
6081
|
-
cancelAnimationFrame(animationFrameId);
|
|
6082
|
-
}
|
|
6083
|
-
};
|
|
6084
|
-
}, [selection.nodes, rfInstance, viewportTick, parentRect]);
|
|
6085
|
-
if (!bounds || selection.nodes.length < 2) {
|
|
6086
|
-
return jsxRuntime.jsx("div", { ref: overlayRef, style: { display: "none" } });
|
|
6087
|
-
}
|
|
6088
|
-
const { left, top, right, bottom } = bounds;
|
|
6089
|
-
const width = right - left;
|
|
6090
|
-
const height = bottom - top;
|
|
6091
|
-
return (jsxRuntime.jsx("div", { ref: overlayRef, onMouseDown: handleMouseDown, style: {
|
|
6092
|
-
position: "absolute",
|
|
6093
|
-
left: `${left}px`,
|
|
6094
|
-
top: `${top}px`,
|
|
6095
|
-
width: `${width}px`,
|
|
6096
|
-
height: `${height}px`,
|
|
6097
|
-
border: isDragging ? "2px solid #0ea5e9" : "1px dashed #0ea5e9",
|
|
6098
|
-
backgroundColor: isDragging
|
|
6099
|
-
? "rgba(14, 165, 233, 0.05)"
|
|
6100
|
-
: "transparent",
|
|
6101
|
-
pointerEvents: "auto",
|
|
6102
|
-
cursor: isDragging ? "grabbing" : "move",
|
|
6103
|
-
zIndex: 4,
|
|
6104
|
-
boxSizing: "border-box",
|
|
6105
|
-
transition: isDragging ? "none" : "border 0.1s ease",
|
|
6106
|
-
} }));
|
|
5908
|
+
}, [active, currentActive, draggingSelection, store]);
|
|
5909
|
+
return null;
|
|
6107
5910
|
};
|
|
6108
5911
|
|
|
6109
5912
|
const WorkbenchCanvasComponent = React.forwardRef((props, ref) => {
|
|
@@ -6746,10 +6549,6 @@ const WorkbenchCanvasComponent = React.forwardRef((props, ref) => {
|
|
|
6746
6549
|
connectionLineRenderer: ui.getConnectionLineRenderer(),
|
|
6747
6550
|
};
|
|
6748
6551
|
}, [ui, uiVersion]);
|
|
6749
|
-
const [selectionOverlayTick, setSelectionOverlayTick] = React.useState(0);
|
|
6750
|
-
const onMove = React.useCallback(() => {
|
|
6751
|
-
setSelectionOverlayTick((t) => t + 1);
|
|
6752
|
-
}, []);
|
|
6753
6552
|
const onMoveEnd = React.useCallback(() => {
|
|
6754
6553
|
if (rfInstanceRef.current) {
|
|
6755
6554
|
const viewport = rfInstanceRef.current.getViewport();
|
|
@@ -6781,11 +6580,11 @@ const WorkbenchCanvasComponent = React.forwardRef((props, ref) => {
|
|
|
6781
6580
|
if (userOnInit) {
|
|
6782
6581
|
userOnInit(inst);
|
|
6783
6582
|
}
|
|
6784
|
-
}, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange,
|
|
6583
|
+
}, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, onMoveEnd: onMoveEnd, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan", children: [children, BackgroundRenderer ? (jsxRuntime.jsx(BackgroundRenderer, {})) : (jsxRuntime.jsx(react.Background, { id: "workbench-canvas-background", variant: react.BackgroundVariant.Dots, gap: 12, size: 1 })), MinimapRenderer ? jsxRuntime.jsx(MinimapRenderer, {}) : jsxRuntime.jsx(react.MiniMap, {}), ControlsRenderer ? jsxRuntime.jsx(ControlsRenderer, {}) : jsxRuntime.jsx(react.Controls, {}), menuState?.type === "default" &&
|
|
6785
6584
|
(DefaultContextMenuRenderer ? (jsxRuntime.jsx(DefaultContextMenuRenderer, { open: true, clientPos: menuState.menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, keyboardShortcuts: keyboardShortcuts })) : (jsxRuntime.jsx(DefaultContextMenu, { open: true, clientPos: menuState.menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, keyboardShortcuts: keyboardShortcuts }))), menuState?.type === "node" &&
|
|
6786
6585
|
nodeContextMenuHandlers &&
|
|
6787
6586
|
(NodeContextMenuRenderer ? (jsxRuntime.jsx(NodeContextMenuRenderer, { open: true, clientPos: menuState.menuPos, nodeId: menuState.nodeId, handlers: nodeContextMenuHandlers, bakeableOutputs: bakeableOutputs, runMode: runMode, wb: wb, keyboardShortcuts: keyboardShortcuts })) : (jsxRuntime.jsx(NodeContextMenu, { open: true, clientPos: menuState.menuPos, nodeId: menuState.nodeId, handlers: nodeContextMenuHandlers, bakeableOutputs: bakeableOutputs, runMode: runMode }))), menuState?.type === "selection" &&
|
|
6788
|
-
(SelectionContextMenuRenderer ? (jsxRuntime.jsx(SelectionContextMenuRenderer, { open: true, clientPos: menuState.menuPos, handlers: selectionContextMenuHandlers, keyboardShortcuts: keyboardShortcuts })) : (jsxRuntime.jsx(SelectionContextMenu, { open: true, clientPos: menuState.menuPos, handlers: selectionContextMenuHandlers, keyboardShortcuts: keyboardShortcuts })))] }), jsxRuntime.jsx(
|
|
6587
|
+
(SelectionContextMenuRenderer ? (jsxRuntime.jsx(SelectionContextMenuRenderer, { open: true, clientPos: menuState.menuPos, handlers: selectionContextMenuHandlers, keyboardShortcuts: keyboardShortcuts })) : (jsxRuntime.jsx(SelectionContextMenu, { open: true, clientPos: menuState.menuPos, handlers: selectionContextMenuHandlers, keyboardShortcuts: keyboardShortcuts })))] }), jsxRuntime.jsx(SelectionActiveSync, { selection: selection })] }), toast && (jsxRuntime.jsx(KeyboardShortcutToast, { message: toast.message, onClose: hideToast }, toast.id))] }));
|
|
6789
6588
|
});
|
|
6790
6589
|
const WorkbenchCanvas = WorkbenchCanvasComponent;
|
|
6791
6590
|
|