@bian-womp/spark-workbench 0.3.62 → 0.3.63

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.
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ type SelectionActiveSyncProps = {
3
+ selection: {
4
+ nodes: string[];
5
+ edges: string[];
6
+ };
7
+ };
8
+ declare const SelectionActiveSync: React.FC<SelectionActiveSyncProps>;
9
+ export default SelectionActiveSync;
10
+ //# sourceMappingURL=SelectionActiveSync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectionActiveSync.d.ts","sourceRoot":"","sources":["../../../../src/misc/SelectionActiveSync.tsx"],"names":[],"mappings":"AACA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAEzC,KAAK,wBAAwB,GAAG;IAC9B,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACjD,CAAC;AAMF,QAAA,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAgB3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"WorkbenchCanvas.d.ts","sourceRoot":"","sources":["../../../../src/misc/WorkbenchCanvas.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AACf,OAAO,EAOL,iBAAiB,EACjB,IAAI,EACJ,IAAI,EACJ,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAuB1D,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC3C,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IACvD,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC;IAC7D,kBAAkB,CAAC,EAAE,CACnB,MAAM,EAAE,MAAM,KACX;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACnD,cAAc,CAAC,EAAE,OAAO,CACtB,IAAI,CACF,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,EACxB,OAAO,GACP,OAAO,GACP,WAAW,GACX,WAAW,GACX,yBAAyB,GACzB,QAAQ,GACR,WAAW,GACX,eAAe,GACf,eAAe,GACf,eAAe,GACf,eAAe,GACf,WAAW,CACd,CACF,GAAG;QACF,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC;KAC5D,CAAC;IACF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,eAAO,MAAM,wBAAwB,oGAggCnC,CAAC;AAEH,eAAO,MAAM,eAAe,oGAA2B,CAAC"}
1
+ {"version":3,"file":"WorkbenchCanvas.d.ts","sourceRoot":"","sources":["../../../../src/misc/WorkbenchCanvas.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AACf,OAAO,EAOL,iBAAiB,EACjB,IAAI,EACJ,IAAI,EACJ,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAuB1D,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC3C,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IACvD,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC;IAC7D,kBAAkB,CAAC,EAAE,CACnB,MAAM,EAAE,MAAM,KACX;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACnD,cAAc,CAAC,EAAE,OAAO,CACtB,IAAI,CACF,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,EACxB,OAAO,GACP,OAAO,GACP,WAAW,GACX,WAAW,GACX,yBAAyB,GACzB,QAAQ,GACR,WAAW,GACX,eAAe,GACf,eAAe,GACf,eAAe,GACf,eAAe,GACf,WAAW,CACd,CACF,GAAG;QACF,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC;KAC5D,CAAC;IACF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,eAAO,MAAM,wBAAwB,oGAq/BnC,CAAC;AAEH,eAAO,MAAM,eAAe,oGAA2B,CAAC"}
package/lib/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { generateId, createSimpleGraphRegistry, GraphBuilder, unwrapValue, isTyped, getInputDeclaredTypes, LocalEngine, parseJsonPath, setValueAtPathWithCreation, buildValueConverter, convertSnapshot, unwrapTypeId, isInputPrivate, mergeInputHandleDescriptors, getInputTypeId, getInputHandleMetadata, offsetImportedPositions, createSimpleGraphDef, createAsyncGraphDef, createAsyncGraphRegistry, createProgressGraphDef, createProgressGraphRegistry, createValidationGraphDef, createValidationGraphRegistry } from '@bian-womp/spark-graph';
2
2
  import lod from 'lodash';
3
3
  import { RemoteRuntimeClient } from '@bian-womp/spark-remote';
4
- import { Position, Handle, NodeResizer, getBezierPath, BaseEdge, useReactFlow, ReactFlowProvider, ReactFlow, Background, BackgroundVariant, MiniMap, Controls } from '@xyflow/react';
4
+ import { Position, Handle, NodeResizer, getBezierPath, BaseEdge, useReactFlow, useStoreApi, useStore, ReactFlowProvider, ReactFlow, Background, BackgroundVariant, MiniMap, Controls } from '@xyflow/react';
5
5
  import React, { useCallback, useState, useEffect, useRef, useMemo, createContext, useContext, useImperativeHandle } from 'react';
6
6
  import cx from 'classnames';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -5888,220 +5888,22 @@ function useKeyboardShortcutToast() {
5888
5888
  return { toast, showToast, hideToast };
5889
5889
  }
5890
5890
 
5891
- const SelectionBoundOverlay = ({ selection, rfInstance, viewportTick }) => {
5892
- const overlayRef = useRef(null);
5893
- const [parentRect, setParentRect] = useState(null);
5894
- const [isDragging, setIsDragging] = useState(false);
5895
- const [bounds, setBounds] = useState(null);
5896
- const dragStateRef = useRef(null);
5897
- const moveListenerRef = useRef(null);
5898
- const upListenerRef = useRef(null);
5899
- useRef(null);
5900
- const { wb } = useWorkbenchContext();
5891
+ const selectionActiveSelector = (state) => state.nodesSelectionActive;
5892
+ const selectionDragActiveSelector = (state) => state.userSelectionActive;
5893
+ const SelectionActiveSync = ({ selection }) => {
5894
+ const store = useStoreApi();
5895
+ const currentActive = useStore(selectionActiveSelector);
5896
+ const draggingSelection = useStore(selectionDragActiveSelector);
5897
+ const active = selection.nodes.length > 1;
5901
5898
  useEffect(() => {
5902
- if (!overlayRef.current)
5903
- return;
5904
- const parent = overlayRef.current.parentElement;
5905
- if (!parent)
5906
- return;
5907
- const updateRect = () => {
5908
- setParentRect(parent.getBoundingClientRect());
5909
- };
5910
- updateRect();
5911
- const resizeObserver = new ResizeObserver(updateRect);
5912
- resizeObserver.observe(parent);
5913
- const scrollHandler = () => updateRect();
5914
- window.addEventListener("scroll", scrollHandler, true);
5915
- return () => {
5916
- resizeObserver.disconnect();
5917
- window.removeEventListener("scroll", scrollHandler, true);
5918
- };
5919
- }, [viewportTick]);
5920
- const cleanupDragListeners = useCallback(() => {
5921
- if (moveListenerRef.current) {
5922
- window.removeEventListener("mousemove", moveListenerRef.current);
5923
- moveListenerRef.current = null;
5924
- }
5925
- if (upListenerRef.current) {
5926
- window.removeEventListener("mouseup", upListenerRef.current);
5927
- upListenerRef.current = null;
5928
- }
5929
- dragStateRef.current = null;
5930
- setIsDragging(false);
5931
- }, []);
5932
- useEffect(() => cleanupDragListeners, [cleanupDragListeners]);
5933
- const handleMouseMove = useCallback((e) => {
5934
- if (!rfInstance || !wb || !parentRect)
5935
- return;
5936
- const dragState = dragStateRef.current;
5937
- if (!dragState)
5938
- return;
5939
- e.preventDefault();
5940
- e.stopPropagation();
5941
- const current = rfInstance.screenToFlowPosition({
5942
- x: e.clientX,
5943
- y: e.clientY,
5944
- });
5945
- const dx = current.x - dragState.startFlow.x;
5946
- const dy = current.y - dragState.startFlow.y;
5947
- // Update nodes directly via React Flow for immediate visual feedback
5948
- const nodes = rfInstance.getNodes();
5949
- const updatedNodes = nodes.map((node) => {
5950
- if (dragState.initialPositions[node.id]) {
5951
- const initialPos = dragState.initialPositions[node.id];
5952
- return {
5953
- ...node,
5954
- position: {
5955
- x: initialPos.x + dx,
5956
- y: initialPos.y + dy,
5957
- },
5958
- };
5959
- }
5960
- return node;
5961
- });
5962
- rfInstance.setNodes(updatedNodes);
5963
- // Also update workbench state
5964
- const nextPositions = {};
5965
- for (const [nodeId, pos] of Object.entries(dragState.initialPositions)) {
5966
- nextPositions[nodeId] = { x: pos.x + dx, y: pos.y + dy };
5967
- }
5968
- if (Object.keys(nextPositions).length) {
5969
- wb.setPositions(nextPositions, { commit: false });
5970
- }
5971
- }, [rfInstance, wb, parentRect]);
5972
- const handleMouseUp = useCallback((e) => {
5973
- if (!rfInstance || !wb) {
5974
- cleanupDragListeners();
5899
+ if (draggingSelection)
5975
5900
  return;
5901
+ if (currentActive !== active) {
5902
+ console.log("[SelectionActiveSync] setting active selection to", active);
5903
+ store.setState({ nodesSelectionActive: active });
5976
5904
  }
5977
- const dragState = dragStateRef.current;
5978
- if (!dragState) {
5979
- cleanupDragListeners();
5980
- return;
5981
- }
5982
- e.preventDefault();
5983
- e.stopPropagation();
5984
- const current = rfInstance.screenToFlowPosition({
5985
- x: e.clientX,
5986
- y: e.clientY,
5987
- });
5988
- const dx = current.x - dragState.startFlow.x;
5989
- const dy = current.y - dragState.startFlow.y;
5990
- const nextPositions = {};
5991
- for (const [nodeId, pos] of Object.entries(dragState.initialPositions)) {
5992
- nextPositions[nodeId] = { x: pos.x + dx, y: pos.y + dy };
5993
- }
5994
- if (Object.keys(nextPositions).length) {
5995
- wb.setPositions(nextPositions, { commit: true });
5996
- }
5997
- cleanupDragListeners();
5998
- }, [cleanupDragListeners, rfInstance, wb]);
5999
- const handleMouseDown = useCallback((e) => {
6000
- if (e.button !== 0)
6001
- return;
6002
- if (!rfInstance || !wb)
6003
- return;
6004
- if (selection.nodes.length < 2)
6005
- return;
6006
- e.preventDefault();
6007
- e.stopPropagation();
6008
- const startFlow = rfInstance.screenToFlowPosition({
6009
- x: e.clientX,
6010
- y: e.clientY,
6011
- });
6012
- const positions = wb.getPositions();
6013
- const initialPositions = {};
6014
- for (const nodeId of selection.nodes) {
6015
- const pos = positions[nodeId];
6016
- if (pos) {
6017
- initialPositions[nodeId] = pos;
6018
- }
6019
- }
6020
- if (!Object.keys(initialPositions).length)
6021
- return;
6022
- dragStateRef.current = { startFlow, initialPositions };
6023
- setIsDragging(true);
6024
- moveListenerRef.current = handleMouseMove;
6025
- upListenerRef.current = handleMouseUp;
6026
- window.addEventListener("mousemove", handleMouseMove, { passive: false });
6027
- window.addEventListener("mouseup", handleMouseUp, { passive: false });
6028
- }, [handleMouseMove, handleMouseUp, rfInstance, selection.nodes, wb]);
6029
- // Continuous bounds update loop
6030
- useEffect(() => {
6031
- if (typeof document === "undefined" ||
6032
- !rfInstance ||
6033
- !parentRect ||
6034
- selection.nodes.length < 2) {
6035
- setBounds(null);
6036
- return;
6037
- }
6038
- let animationFrameId = null;
6039
- let isActive = true;
6040
- const updateBounds = () => {
6041
- if (!isActive)
6042
- return;
6043
- let calculatedBounds = null;
6044
- for (const nodeId of selection.nodes) {
6045
- const el = document.querySelector(`.react-flow__node[data-id="${nodeId}"]`);
6046
- if (!el)
6047
- continue;
6048
- const rect = el.getBoundingClientRect();
6049
- const relativeLeft = rect.left - parentRect.left;
6050
- const relativeTop = rect.top - parentRect.top;
6051
- const relativeRight = rect.right - parentRect.left;
6052
- const relativeBottom = rect.bottom - parentRect.top;
6053
- if (!calculatedBounds) {
6054
- calculatedBounds = {
6055
- left: relativeLeft,
6056
- top: relativeTop,
6057
- right: relativeRight,
6058
- bottom: relativeBottom,
6059
- };
6060
- }
6061
- else {
6062
- calculatedBounds.left = Math.min(calculatedBounds.left, relativeLeft);
6063
- calculatedBounds.top = Math.min(calculatedBounds.top, relativeTop);
6064
- calculatedBounds.right = Math.max(calculatedBounds.right, relativeRight);
6065
- calculatedBounds.bottom = Math.max(calculatedBounds.bottom, relativeBottom);
6066
- }
6067
- }
6068
- setBounds(calculatedBounds);
6069
- // Continue the animation loop
6070
- if (isActive) {
6071
- animationFrameId = requestAnimationFrame(updateBounds);
6072
- }
6073
- };
6074
- // Start the animation loop
6075
- animationFrameId = requestAnimationFrame(updateBounds);
6076
- return () => {
6077
- isActive = false;
6078
- if (animationFrameId !== null) {
6079
- cancelAnimationFrame(animationFrameId);
6080
- }
6081
- };
6082
- }, [selection.nodes, rfInstance, viewportTick, parentRect]);
6083
- if (!bounds || selection.nodes.length < 2) {
6084
- return jsx("div", { ref: overlayRef, style: { display: "none" } });
6085
- }
6086
- const { left, top, right, bottom } = bounds;
6087
- const width = right - left;
6088
- const height = bottom - top;
6089
- return (jsx("div", { ref: overlayRef, onMouseDown: handleMouseDown, style: {
6090
- position: "absolute",
6091
- left: `${left}px`,
6092
- top: `${top}px`,
6093
- width: `${width}px`,
6094
- height: `${height}px`,
6095
- border: isDragging ? "2px solid #0ea5e9" : "1px dashed #0ea5e9",
6096
- backgroundColor: isDragging
6097
- ? "rgba(14, 165, 233, 0.05)"
6098
- : "transparent",
6099
- pointerEvents: "auto",
6100
- cursor: isDragging ? "grabbing" : "move",
6101
- zIndex: 4,
6102
- boxSizing: "border-box",
6103
- transition: isDragging ? "none" : "border 0.1s ease",
6104
- } }));
5905
+ }, [active, currentActive, draggingSelection, store]);
5906
+ return null;
6105
5907
  };
6106
5908
 
6107
5909
  const WorkbenchCanvasComponent = React.forwardRef((props, ref) => {
@@ -6744,10 +6546,6 @@ const WorkbenchCanvasComponent = React.forwardRef((props, ref) => {
6744
6546
  connectionLineRenderer: ui.getConnectionLineRenderer(),
6745
6547
  };
6746
6548
  }, [ui, uiVersion]);
6747
- const [selectionOverlayTick, setSelectionOverlayTick] = useState(0);
6748
- const onMove = useCallback(() => {
6749
- setSelectionOverlayTick((t) => t + 1);
6750
- }, []);
6751
6549
  const onMoveEnd = useCallback(() => {
6752
6550
  if (rfInstanceRef.current) {
6753
6551
  const viewport = rfInstanceRef.current.getViewport();
@@ -6779,11 +6577,11 @@ const WorkbenchCanvasComponent = React.forwardRef((props, ref) => {
6779
6577
  if (userOnInit) {
6780
6578
  userOnInit(inst);
6781
6579
  }
6782
- }, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, onMove: onMove, onMoveEnd: onMoveEnd, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan", children: [children, BackgroundRenderer ? (jsx(BackgroundRenderer, {})) : (jsx(Background, { id: "workbench-canvas-background", variant: BackgroundVariant.Dots, gap: 12, size: 1 })), MinimapRenderer ? jsx(MinimapRenderer, {}) : jsx(MiniMap, {}), ControlsRenderer ? jsx(ControlsRenderer, {}) : jsx(Controls, {}), menuState?.type === "default" &&
6580
+ }, 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 ? (jsx(BackgroundRenderer, {})) : (jsx(Background, { id: "workbench-canvas-background", variant: BackgroundVariant.Dots, gap: 12, size: 1 })), MinimapRenderer ? jsx(MinimapRenderer, {}) : jsx(MiniMap, {}), ControlsRenderer ? jsx(ControlsRenderer, {}) : jsx(Controls, {}), menuState?.type === "default" &&
6783
6581
  (DefaultContextMenuRenderer ? (jsx(DefaultContextMenuRenderer, { open: true, clientPos: menuState.menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, keyboardShortcuts: keyboardShortcuts })) : (jsx(DefaultContextMenu, { open: true, clientPos: menuState.menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, keyboardShortcuts: keyboardShortcuts }))), menuState?.type === "node" &&
6784
6582
  nodeContextMenuHandlers &&
6785
6583
  (NodeContextMenuRenderer ? (jsx(NodeContextMenuRenderer, { open: true, clientPos: menuState.menuPos, nodeId: menuState.nodeId, handlers: nodeContextMenuHandlers, bakeableOutputs: bakeableOutputs, runMode: runMode, wb: wb, keyboardShortcuts: keyboardShortcuts })) : (jsx(NodeContextMenu, { open: true, clientPos: menuState.menuPos, nodeId: menuState.nodeId, handlers: nodeContextMenuHandlers, bakeableOutputs: bakeableOutputs, runMode: runMode }))), menuState?.type === "selection" &&
6786
- (SelectionContextMenuRenderer ? (jsx(SelectionContextMenuRenderer, { open: true, clientPos: menuState.menuPos, handlers: selectionContextMenuHandlers, keyboardShortcuts: keyboardShortcuts })) : (jsx(SelectionContextMenu, { open: true, clientPos: menuState.menuPos, handlers: selectionContextMenuHandlers, keyboardShortcuts: keyboardShortcuts })))] }), jsx(SelectionBoundOverlay, { selection: selection, rfInstance: rfInstanceRef.current, viewportTick: selectionOverlayTick })] }), toast && (jsx(KeyboardShortcutToast, { message: toast.message, onClose: hideToast }, toast.id))] }));
6584
+ (SelectionContextMenuRenderer ? (jsx(SelectionContextMenuRenderer, { open: true, clientPos: menuState.menuPos, handlers: selectionContextMenuHandlers, keyboardShortcuts: keyboardShortcuts })) : (jsx(SelectionContextMenu, { open: true, clientPos: menuState.menuPos, handlers: selectionContextMenuHandlers, keyboardShortcuts: keyboardShortcuts })))] }), jsx(SelectionActiveSync, { selection: selection })] }), toast && (jsx(KeyboardShortcutToast, { message: toast.message, onClose: hideToast }, toast.id))] }));
6787
6585
  });
6788
6586
  const WorkbenchCanvas = WorkbenchCanvasComponent;
6789
6587