@bian-womp/spark-workbench 0.3.43 → 0.3.44
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
CHANGED
|
@@ -5846,6 +5846,13 @@ function useKeyboardShortcutToast() {
|
|
|
5846
5846
|
const SelectionBoundOverlay = ({ selection, rfInstance, viewportTick }) => {
|
|
5847
5847
|
const overlayRef = React.useRef(null);
|
|
5848
5848
|
const [parentRect, setParentRect] = React.useState(null);
|
|
5849
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
5850
|
+
const [bounds, setBounds] = React.useState(null);
|
|
5851
|
+
const dragStateRef = React.useRef(null);
|
|
5852
|
+
const moveListenerRef = React.useRef(null);
|
|
5853
|
+
const upListenerRef = React.useRef(null);
|
|
5854
|
+
React.useRef(null);
|
|
5855
|
+
const { wb } = useWorkbenchContext();
|
|
5849
5856
|
React.useEffect(() => {
|
|
5850
5857
|
if (!overlayRef.current)
|
|
5851
5858
|
return;
|
|
@@ -5865,56 +5872,190 @@ const SelectionBoundOverlay = ({ selection, rfInstance, viewportTick }) => {
|
|
|
5865
5872
|
window.removeEventListener("scroll", scrollHandler, true);
|
|
5866
5873
|
};
|
|
5867
5874
|
}, [viewportTick]);
|
|
5868
|
-
const
|
|
5875
|
+
const cleanupDragListeners = React.useCallback(() => {
|
|
5876
|
+
if (moveListenerRef.current) {
|
|
5877
|
+
window.removeEventListener("mousemove", moveListenerRef.current);
|
|
5878
|
+
moveListenerRef.current = null;
|
|
5879
|
+
}
|
|
5880
|
+
if (upListenerRef.current) {
|
|
5881
|
+
window.removeEventListener("mouseup", upListenerRef.current);
|
|
5882
|
+
upListenerRef.current = null;
|
|
5883
|
+
}
|
|
5884
|
+
dragStateRef.current = null;
|
|
5885
|
+
setIsDragging(false);
|
|
5886
|
+
}, []);
|
|
5887
|
+
React.useEffect(() => cleanupDragListeners, [cleanupDragListeners]);
|
|
5888
|
+
const handleMouseMove = React.useCallback((e) => {
|
|
5889
|
+
if (!rfInstance || !wb || !parentRect)
|
|
5890
|
+
return;
|
|
5891
|
+
const dragState = dragStateRef.current;
|
|
5892
|
+
if (!dragState)
|
|
5893
|
+
return;
|
|
5894
|
+
e.preventDefault();
|
|
5895
|
+
e.stopPropagation();
|
|
5896
|
+
const current = rfInstance.screenToFlowPosition({
|
|
5897
|
+
x: e.clientX,
|
|
5898
|
+
y: e.clientY,
|
|
5899
|
+
});
|
|
5900
|
+
const dx = current.x - dragState.startFlow.x;
|
|
5901
|
+
const dy = current.y - dragState.startFlow.y;
|
|
5902
|
+
// Update nodes directly via React Flow for immediate visual feedback
|
|
5903
|
+
const nodes = rfInstance.getNodes();
|
|
5904
|
+
const updatedNodes = nodes.map((node) => {
|
|
5905
|
+
if (dragState.initialPositions[node.id]) {
|
|
5906
|
+
const initialPos = dragState.initialPositions[node.id];
|
|
5907
|
+
return {
|
|
5908
|
+
...node,
|
|
5909
|
+
position: {
|
|
5910
|
+
x: initialPos.x + dx,
|
|
5911
|
+
y: initialPos.y + dy,
|
|
5912
|
+
},
|
|
5913
|
+
};
|
|
5914
|
+
}
|
|
5915
|
+
return node;
|
|
5916
|
+
});
|
|
5917
|
+
rfInstance.setNodes(updatedNodes);
|
|
5918
|
+
// Also update workbench state
|
|
5919
|
+
const nextPositions = {};
|
|
5920
|
+
for (const [nodeId, pos] of Object.entries(dragState.initialPositions)) {
|
|
5921
|
+
nextPositions[nodeId] = { x: pos.x + dx, y: pos.y + dy };
|
|
5922
|
+
}
|
|
5923
|
+
if (Object.keys(nextPositions).length) {
|
|
5924
|
+
wb.setPositions(nextPositions, { commit: false });
|
|
5925
|
+
}
|
|
5926
|
+
}, [rfInstance, wb, parentRect]);
|
|
5927
|
+
const handleMouseUp = React.useCallback((e) => {
|
|
5928
|
+
if (!rfInstance || !wb) {
|
|
5929
|
+
cleanupDragListeners();
|
|
5930
|
+
return;
|
|
5931
|
+
}
|
|
5932
|
+
const dragState = dragStateRef.current;
|
|
5933
|
+
if (!dragState) {
|
|
5934
|
+
cleanupDragListeners();
|
|
5935
|
+
return;
|
|
5936
|
+
}
|
|
5937
|
+
e.preventDefault();
|
|
5938
|
+
e.stopPropagation();
|
|
5939
|
+
const current = rfInstance.screenToFlowPosition({
|
|
5940
|
+
x: e.clientX,
|
|
5941
|
+
y: e.clientY,
|
|
5942
|
+
});
|
|
5943
|
+
const dx = current.x - dragState.startFlow.x;
|
|
5944
|
+
const dy = current.y - dragState.startFlow.y;
|
|
5945
|
+
const nextPositions = {};
|
|
5946
|
+
for (const [nodeId, pos] of Object.entries(dragState.initialPositions)) {
|
|
5947
|
+
nextPositions[nodeId] = { x: pos.x + dx, y: pos.y + dy };
|
|
5948
|
+
}
|
|
5949
|
+
if (Object.keys(nextPositions).length) {
|
|
5950
|
+
wb.setPositions(nextPositions, { commit: true });
|
|
5951
|
+
}
|
|
5952
|
+
cleanupDragListeners();
|
|
5953
|
+
}, [cleanupDragListeners, rfInstance, wb]);
|
|
5954
|
+
const handleMouseDown = React.useCallback((e) => {
|
|
5955
|
+
if (e.button !== 0)
|
|
5956
|
+
return;
|
|
5957
|
+
if (!rfInstance || !wb)
|
|
5958
|
+
return;
|
|
5959
|
+
if (selection.nodes.length < 2)
|
|
5960
|
+
return;
|
|
5961
|
+
e.preventDefault();
|
|
5962
|
+
e.stopPropagation();
|
|
5963
|
+
const startFlow = rfInstance.screenToFlowPosition({
|
|
5964
|
+
x: e.clientX,
|
|
5965
|
+
y: e.clientY,
|
|
5966
|
+
});
|
|
5967
|
+
const positions = wb.getPositions();
|
|
5968
|
+
const initialPositions = {};
|
|
5969
|
+
for (const nodeId of selection.nodes) {
|
|
5970
|
+
const pos = positions[nodeId];
|
|
5971
|
+
if (pos) {
|
|
5972
|
+
initialPositions[nodeId] = pos;
|
|
5973
|
+
}
|
|
5974
|
+
}
|
|
5975
|
+
if (!Object.keys(initialPositions).length)
|
|
5976
|
+
return;
|
|
5977
|
+
dragStateRef.current = { startFlow, initialPositions };
|
|
5978
|
+
setIsDragging(true);
|
|
5979
|
+
moveListenerRef.current = handleMouseMove;
|
|
5980
|
+
upListenerRef.current = handleMouseUp;
|
|
5981
|
+
window.addEventListener("mousemove", handleMouseMove, { passive: false });
|
|
5982
|
+
window.addEventListener("mouseup", handleMouseUp, { passive: false });
|
|
5983
|
+
}, [handleMouseMove, handleMouseUp, rfInstance, selection.nodes, wb]);
|
|
5984
|
+
// Continuous bounds update loop
|
|
5985
|
+
React.useEffect(() => {
|
|
5869
5986
|
if (typeof document === "undefined" ||
|
|
5870
5987
|
!rfInstance ||
|
|
5871
5988
|
!parentRect ||
|
|
5872
5989
|
selection.nodes.length < 2) {
|
|
5873
|
-
|
|
5990
|
+
setBounds(null);
|
|
5991
|
+
return;
|
|
5874
5992
|
}
|
|
5875
|
-
let
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
if (!
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
const
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5993
|
+
let animationFrameId = null;
|
|
5994
|
+
let isActive = true;
|
|
5995
|
+
const updateBounds = () => {
|
|
5996
|
+
if (!isActive)
|
|
5997
|
+
return;
|
|
5998
|
+
let calculatedBounds = null;
|
|
5999
|
+
for (const nodeId of selection.nodes) {
|
|
6000
|
+
const el = document.querySelector(`.react-flow__node[data-id="${nodeId}"]`);
|
|
6001
|
+
if (!el)
|
|
6002
|
+
continue;
|
|
6003
|
+
const rect = el.getBoundingClientRect();
|
|
6004
|
+
const relativeLeft = rect.left - parentRect.left;
|
|
6005
|
+
const relativeTop = rect.top - parentRect.top;
|
|
6006
|
+
const relativeRight = rect.right - parentRect.left;
|
|
6007
|
+
const relativeBottom = rect.bottom - parentRect.top;
|
|
6008
|
+
if (!calculatedBounds) {
|
|
6009
|
+
calculatedBounds = {
|
|
6010
|
+
left: relativeLeft,
|
|
6011
|
+
top: relativeTop,
|
|
6012
|
+
right: relativeRight,
|
|
6013
|
+
bottom: relativeBottom,
|
|
6014
|
+
};
|
|
6015
|
+
}
|
|
6016
|
+
else {
|
|
6017
|
+
calculatedBounds.left = Math.min(calculatedBounds.left, relativeLeft);
|
|
6018
|
+
calculatedBounds.top = Math.min(calculatedBounds.top, relativeTop);
|
|
6019
|
+
calculatedBounds.right = Math.max(calculatedBounds.right, relativeRight);
|
|
6020
|
+
calculatedBounds.bottom = Math.max(calculatedBounds.bottom, relativeBottom);
|
|
6021
|
+
}
|
|
5892
6022
|
}
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
bounds.bottom = Math.max(bounds.bottom, relativeBottom);
|
|
6023
|
+
setBounds(calculatedBounds);
|
|
6024
|
+
// Continue the animation loop
|
|
6025
|
+
if (isActive) {
|
|
6026
|
+
animationFrameId = requestAnimationFrame(updateBounds);
|
|
5898
6027
|
}
|
|
5899
|
-
}
|
|
5900
|
-
|
|
6028
|
+
};
|
|
6029
|
+
// Start the animation loop
|
|
6030
|
+
animationFrameId = requestAnimationFrame(updateBounds);
|
|
6031
|
+
return () => {
|
|
6032
|
+
isActive = false;
|
|
6033
|
+
if (animationFrameId !== null) {
|
|
6034
|
+
cancelAnimationFrame(animationFrameId);
|
|
6035
|
+
}
|
|
6036
|
+
};
|
|
5901
6037
|
}, [selection.nodes, rfInstance, viewportTick, parentRect]);
|
|
5902
|
-
if (!
|
|
6038
|
+
if (!bounds || selection.nodes.length < 2) {
|
|
5903
6039
|
return jsxRuntime.jsx("div", { ref: overlayRef, style: { display: "none" } });
|
|
5904
6040
|
}
|
|
5905
|
-
const { left, top, right, bottom } =
|
|
6041
|
+
const { left, top, right, bottom } = bounds;
|
|
5906
6042
|
const width = right - left;
|
|
5907
6043
|
const height = bottom - top;
|
|
5908
|
-
return (jsxRuntime.jsx("div", { ref: overlayRef, style: {
|
|
6044
|
+
return (jsxRuntime.jsx("div", { ref: overlayRef, onMouseDown: handleMouseDown, style: {
|
|
5909
6045
|
position: "absolute",
|
|
5910
6046
|
left: `${left}px`,
|
|
5911
6047
|
top: `${top}px`,
|
|
5912
6048
|
width: `${width}px`,
|
|
5913
6049
|
height: `${height}px`,
|
|
5914
|
-
border: "1px dashed #0ea5e9",
|
|
5915
|
-
|
|
6050
|
+
border: isDragging ? "2px solid #0ea5e9" : "1px dashed #0ea5e9",
|
|
6051
|
+
backgroundColor: isDragging
|
|
6052
|
+
? "rgba(14, 165, 233, 0.05)"
|
|
6053
|
+
: "transparent",
|
|
6054
|
+
pointerEvents: "auto",
|
|
6055
|
+
cursor: isDragging ? "grabbing" : "move",
|
|
5916
6056
|
zIndex: 4,
|
|
5917
6057
|
boxSizing: "border-box",
|
|
6058
|
+
transition: isDragging ? "none" : "border 0.1s ease",
|
|
5918
6059
|
} }));
|
|
5919
6060
|
};
|
|
5920
6061
|
|