Merge pull request #4426 from xyflow/next
React Flow 12.0.0-next.28 and Svelte Flow 0.1.10
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import Basic from '../examples/Basic';
|
import Basic from '../examples/Basic';
|
||||||
import Backgrounds from '../examples/Backgrounds';
|
import Backgrounds from '../examples/Backgrounds';
|
||||||
import ColorMode from '../examples/ColorMode';
|
import ColorMode from '../examples/ColorMode';
|
||||||
|
import ClickDistance from '../examples/ClickDistance';
|
||||||
import ControlledUncontrolled from '../examples/ControlledUncontrolled';
|
import ControlledUncontrolled from '../examples/ControlledUncontrolled';
|
||||||
import ControlledViewport from '../examples/ControlledViewport';
|
import ControlledViewport from '../examples/ControlledViewport';
|
||||||
import CustomConnectionLine from '../examples/CustomConnectionLine';
|
import CustomConnectionLine from '../examples/CustomConnectionLine';
|
||||||
@@ -85,6 +86,11 @@ const routes: IRoute[] = [
|
|||||||
path: 'cancel-connection',
|
path: 'cancel-connection',
|
||||||
component: CancelConnection,
|
component: CancelConnection,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Click Distance',
|
||||||
|
path: 'click-distance',
|
||||||
|
component: ClickDistance,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Controlled/Uncontrolled',
|
name: 'Controlled/Uncontrolled',
|
||||||
path: 'controlled-uncontrolled',
|
path: 'controlled-uncontrolled',
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import { ReactFlow, addEdge, Node, Connection, Edge, useNodesState, useEdgesState, Panel } from '@xyflow/react';
|
||||||
|
|
||||||
|
const initNodes: Node[] = [
|
||||||
|
{
|
||||||
|
id: '1a',
|
||||||
|
type: 'input',
|
||||||
|
data: { label: 'Node 1' },
|
||||||
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
ariaLabel: 'Input Node 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2a',
|
||||||
|
data: { label: 'Node 2' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
ariaLabel: 'Default Node 2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3a',
|
||||||
|
data: { label: 'Node 3' },
|
||||||
|
position: { x: 400, y: 100 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4a',
|
||||||
|
data: { label: 'Node 4' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
className: 'light',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const initEdges: Edge[] = [
|
||||||
|
{ id: 'e1-2', source: '1a', target: '2a', ariaLabel: undefined },
|
||||||
|
{ id: 'e1-3', source: '1a', target: '3a' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const onPaneClick = () => console.log('pane click');
|
||||||
|
|
||||||
|
const BasicFlow = () => {
|
||||||
|
const [nodes, setNodes, onNodesChange] = useNodesState(initNodes);
|
||||||
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges);
|
||||||
|
const [paneClickDistance, setPaneClickDistance] = useState(0);
|
||||||
|
|
||||||
|
const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReactFlow
|
||||||
|
nodes={nodes}
|
||||||
|
edges={edges}
|
||||||
|
onNodesChange={onNodesChange}
|
||||||
|
onEdgesChange={onEdgesChange}
|
||||||
|
onConnect={onConnect}
|
||||||
|
paneClickDistance={paneClickDistance}
|
||||||
|
onPaneClick={onPaneClick}
|
||||||
|
>
|
||||||
|
<Panel position="top-right">
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
value={paneClickDistance}
|
||||||
|
onChange={(evt) => setPaneClickDistance(+evt.target.value)}
|
||||||
|
/>
|
||||||
|
click distance: {paneClickDistance}
|
||||||
|
</Panel>
|
||||||
|
</ReactFlow>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BasicFlow;
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
# @xyflow/react
|
# @xyflow/react
|
||||||
|
|
||||||
|
## 12.0.0-next.28
|
||||||
|
|
||||||
|
- add `paneDistanceClick` prop (max distance between mousedown/up that will trigger a click)
|
||||||
|
- returned nodes in `onNodeDragStop` are set to `dragging=false`
|
||||||
|
|
||||||
## 12.0.0-next.27
|
## 12.0.0-next.27
|
||||||
|
|
||||||
- return Promises for `setViewport`, `fitView`, `fitBounds` and `zoomTo` to be able to await viewport update
|
- return Promises for `setViewport`, `fitView`, `fitBounds` and `zoomTo` to be able to await viewport update
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xyflow/react",
|
"name": "@xyflow/react",
|
||||||
"version": "12.0.0-next.26",
|
"version": "12.0.0-next.27",
|
||||||
"description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.",
|
"description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ const reactFlowFieldsToTrack = [
|
|||||||
'onBeforeDelete',
|
'onBeforeDelete',
|
||||||
'debug',
|
'debug',
|
||||||
'autoPanSpeed',
|
'autoPanSpeed',
|
||||||
|
'paneClickDistance',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number];
|
type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number];
|
||||||
@@ -89,6 +90,7 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
setNodeExtent: s.setNodeExtent,
|
setNodeExtent: s.setNodeExtent,
|
||||||
reset: s.reset,
|
reset: s.reset,
|
||||||
setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
|
setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
|
||||||
|
setPaneClickDistance: s.setPaneClickDistance,
|
||||||
});
|
});
|
||||||
|
|
||||||
const initPrevValues = {
|
const initPrevValues = {
|
||||||
@@ -102,6 +104,7 @@ const initPrevValues = {
|
|||||||
elementsSelectable: true,
|
elementsSelectable: true,
|
||||||
noPanClassName: 'nopan',
|
noPanClassName: 'nopan',
|
||||||
rfId: '1',
|
rfId: '1',
|
||||||
|
paneClickDistance: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function StoreUpdater<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
export function StoreUpdater<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
||||||
@@ -116,6 +119,7 @@ export function StoreUpdater<NodeType extends Node = Node, EdgeType extends Edge
|
|||||||
setNodeExtent,
|
setNodeExtent,
|
||||||
reset,
|
reset,
|
||||||
setDefaultNodesAndEdges,
|
setDefaultNodesAndEdges,
|
||||||
|
setPaneClickDistance,
|
||||||
} = useStore(selector, shallow);
|
} = useStore(selector, shallow);
|
||||||
const store = useStoreApi<NodeType, EdgeType>();
|
const store = useStoreApi<NodeType, EdgeType>();
|
||||||
|
|
||||||
@@ -146,6 +150,7 @@ export function StoreUpdater<NodeType extends Node = Node, EdgeType extends Edge
|
|||||||
else if (fieldName === 'maxZoom') setMaxZoom(fieldValue as number);
|
else if (fieldName === 'maxZoom') setMaxZoom(fieldValue as number);
|
||||||
else if (fieldName === 'translateExtent') setTranslateExtent(fieldValue as CoordinateExtent);
|
else if (fieldName === 'translateExtent') setTranslateExtent(fieldValue as CoordinateExtent);
|
||||||
else if (fieldName === 'nodeExtent') setNodeExtent(fieldValue as CoordinateExtent);
|
else if (fieldName === 'nodeExtent') setNodeExtent(fieldValue as CoordinateExtent);
|
||||||
|
else if (fieldName === 'paneClickDistance') setPaneClickDistance(fieldValue as number);
|
||||||
// Renamed fields
|
// Renamed fields
|
||||||
else if (fieldName === 'fitView') store.setState({ fitViewOnInit: fieldValue as boolean });
|
else if (fieldName === 'fitView') store.setState({ fitViewOnInit: fieldValue as boolean });
|
||||||
else if (fieldName === 'fitViewOptions') store.setState({ fitViewOnInitOptions: fieldValue as FitViewOptions });
|
else if (fieldName === 'fitViewOptions') store.setState({ fitViewOnInitOptions: fieldValue as FitViewOptions });
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ function FlowRendererComponent<NodeType extends Node = Node>({
|
|||||||
onPaneMouseLeave,
|
onPaneMouseLeave,
|
||||||
onPaneContextMenu,
|
onPaneContextMenu,
|
||||||
onPaneScroll,
|
onPaneScroll,
|
||||||
|
paneClickDistance,
|
||||||
deleteKeyCode,
|
deleteKeyCode,
|
||||||
selectionKeyCode,
|
selectionKeyCode,
|
||||||
selectionOnDrag,
|
selectionOnDrag,
|
||||||
@@ -101,6 +102,7 @@ function FlowRendererComponent<NodeType extends Node = Node>({
|
|||||||
noPanClassName={noPanClassName}
|
noPanClassName={noPanClassName}
|
||||||
onViewportChange={onViewportChange}
|
onViewportChange={onViewportChange}
|
||||||
isControlledViewport={isControlledViewport}
|
isControlledViewport={isControlledViewport}
|
||||||
|
paneClickDistance={paneClickDistance}
|
||||||
>
|
>
|
||||||
<Pane
|
<Pane
|
||||||
onSelectionStart={onSelectionStart}
|
onSelectionStart={onSelectionStart}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export type GraphViewProps<NodeType extends Node = Node, EdgeType extends Edge =
|
|||||||
| 'noPanClassName'
|
| 'noPanClassName'
|
||||||
| 'defaultViewport'
|
| 'defaultViewport'
|
||||||
| 'disableKeyboardA11y'
|
| 'disableKeyboardA11y'
|
||||||
|
| 'paneClickDistance'
|
||||||
>
|
>
|
||||||
> & {
|
> & {
|
||||||
rfId: string;
|
rfId: string;
|
||||||
@@ -84,6 +85,7 @@ function GraphViewComponent<NodeType extends Node = Node, EdgeType extends Edge
|
|||||||
onPaneMouseLeave,
|
onPaneMouseLeave,
|
||||||
onPaneScroll,
|
onPaneScroll,
|
||||||
onPaneContextMenu,
|
onPaneContextMenu,
|
||||||
|
paneClickDistance,
|
||||||
onEdgeContextMenu,
|
onEdgeContextMenu,
|
||||||
onEdgeMouseEnter,
|
onEdgeMouseEnter,
|
||||||
onEdgeMouseMove,
|
onEdgeMouseMove,
|
||||||
@@ -116,6 +118,7 @@ function GraphViewComponent<NodeType extends Node = Node, EdgeType extends Edge
|
|||||||
onPaneMouseLeave={onPaneMouseLeave}
|
onPaneMouseLeave={onPaneMouseLeave}
|
||||||
onPaneContextMenu={onPaneContextMenu}
|
onPaneContextMenu={onPaneContextMenu}
|
||||||
onPaneScroll={onPaneScroll}
|
onPaneScroll={onPaneScroll}
|
||||||
|
paneClickDistance={paneClickDistance}
|
||||||
deleteKeyCode={deleteKeyCode}
|
deleteKeyCode={deleteKeyCode}
|
||||||
selectionKeyCode={selectionKeyCode}
|
selectionKeyCode={selectionKeyCode}
|
||||||
selectionOnDrag={selectionOnDrag}
|
selectionOnDrag={selectionOnDrag}
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
|||||||
onPaneMouseLeave,
|
onPaneMouseLeave,
|
||||||
onPaneScroll,
|
onPaneScroll,
|
||||||
onPaneContextMenu,
|
onPaneContextMenu,
|
||||||
|
paneClickDistance = 0,
|
||||||
children,
|
children,
|
||||||
onReconnect,
|
onReconnect,
|
||||||
onReconnectStart,
|
onReconnectStart,
|
||||||
@@ -200,6 +201,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
|||||||
onPaneMouseLeave={onPaneMouseLeave}
|
onPaneMouseLeave={onPaneMouseLeave}
|
||||||
onPaneScroll={onPaneScroll}
|
onPaneScroll={onPaneScroll}
|
||||||
onPaneContextMenu={onPaneContextMenu}
|
onPaneContextMenu={onPaneContextMenu}
|
||||||
|
paneClickDistance={paneClickDistance}
|
||||||
onSelectionContextMenu={onSelectionContextMenu}
|
onSelectionContextMenu={onSelectionContextMenu}
|
||||||
onSelectionStart={onSelectionStart}
|
onSelectionStart={onSelectionStart}
|
||||||
onSelectionEnd={onSelectionEnd}
|
onSelectionEnd={onSelectionEnd}
|
||||||
@@ -277,6 +279,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
|||||||
selectNodesOnDrag={selectNodesOnDrag}
|
selectNodesOnDrag={selectNodesOnDrag}
|
||||||
nodeDragThreshold={nodeDragThreshold}
|
nodeDragThreshold={nodeDragThreshold}
|
||||||
onBeforeDelete={onBeforeDelete}
|
onBeforeDelete={onBeforeDelete}
|
||||||
|
paneClickDistance={paneClickDistance}
|
||||||
debug={debug}
|
debug={debug}
|
||||||
/>
|
/>
|
||||||
<SelectionListener onSelectionChange={onSelectionChange} />
|
<SelectionListener onSelectionChange={onSelectionChange} />
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export function ZoomPane({
|
|||||||
noPanClassName,
|
noPanClassName,
|
||||||
onViewportChange,
|
onViewportChange,
|
||||||
isControlledViewport,
|
isControlledViewport,
|
||||||
|
paneClickDistance,
|
||||||
}: ZoomPaneProps) {
|
}: ZoomPaneProps) {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const zoomPane = useRef<HTMLDivElement>(null);
|
const zoomPane = useRef<HTMLDivElement>(null);
|
||||||
@@ -64,6 +65,7 @@ export function ZoomPane({
|
|||||||
maxZoom,
|
maxZoom,
|
||||||
translateExtent,
|
translateExtent,
|
||||||
viewport: defaultViewport,
|
viewport: defaultViewport,
|
||||||
|
paneClickDistance,
|
||||||
onTransformChange: (transform: Transform) => {
|
onTransformChange: (transform: Transform) => {
|
||||||
onViewportChange?.({ x: transform[0], y: transform[1], zoom: transform[2] });
|
onViewportChange?.({ x: transform[0], y: transform[1], zoom: transform[2] });
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ const createStore = ({
|
|||||||
const changes = [];
|
const changes = [];
|
||||||
|
|
||||||
for (const [id, dragItem] of nodeDragItems) {
|
for (const [id, dragItem] of nodeDragItems) {
|
||||||
// @todo add expandParent to drag item so that we can get rid of the look up here
|
|
||||||
const change: NodeChange = {
|
const change: NodeChange = {
|
||||||
id,
|
id,
|
||||||
type: 'position',
|
type: 'position',
|
||||||
@@ -255,6 +254,9 @@ const createStore = ({
|
|||||||
|
|
||||||
set({ translateExtent });
|
set({ translateExtent });
|
||||||
},
|
},
|
||||||
|
setPaneClickDistance: (clickDistance) => {
|
||||||
|
get().panZoom?.setClickDistance(clickDistance);
|
||||||
|
},
|
||||||
resetSelectedElements: () => {
|
resetSelectedElements: () => {
|
||||||
const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
|
const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
|
||||||
|
|
||||||
|
|||||||
@@ -223,6 +223,10 @@ export interface ReactFlowProps<NodeType extends Node = Node, EdgeType extends E
|
|||||||
onPaneMouseMove?: (event: ReactMouseEvent) => void;
|
onPaneMouseMove?: (event: ReactMouseEvent) => void;
|
||||||
/** This event handler gets called when mouse leaves the pane */
|
/** This event handler gets called when mouse leaves the pane */
|
||||||
onPaneMouseLeave?: (event: ReactMouseEvent) => void;
|
onPaneMouseLeave?: (event: ReactMouseEvent) => void;
|
||||||
|
/** Distance that the mouse can move between mousedown/up that will trigger a click
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
paneClickDistance?: number;
|
||||||
/** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */
|
/** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */
|
||||||
onBeforeDelete?: OnBeforeDelete<NodeType, EdgeType>;
|
onBeforeDelete?: OnBeforeDelete<NodeType, EdgeType>;
|
||||||
/** Custom node types to be available in a flow.
|
/** Custom node types to be available in a flow.
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ export type ReactFlowActions<NodeType extends Node, EdgeType extends Edge> = {
|
|||||||
panBy: PanBy;
|
panBy: PanBy;
|
||||||
fitView: (options?: FitViewOptions) => Promise<boolean>;
|
fitView: (options?: FitViewOptions) => Promise<boolean>;
|
||||||
fitViewSync: (options?: FitViewOptions) => boolean;
|
fitViewSync: (options?: FitViewOptions) => boolean;
|
||||||
|
setPaneClickDistance: (distance: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReactFlowState<NodeType extends Node = Node, EdgeType extends Edge = Edge> = ReactFlowStore<
|
export type ReactFlowState<NodeType extends Node = Node, EdgeType extends Edge = Edge> = ReactFlowStore<
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
# @xyflow/svelte
|
# @xyflow/svelte
|
||||||
|
|
||||||
|
## 0.1.10
|
||||||
|
|
||||||
|
- add `paneDistanceClick` prop (max distance between mousedown/up that will trigger a click)
|
||||||
|
- returned nodes in `on:nodedragstop` are set to `dragging=false`
|
||||||
|
|
||||||
## 0.1.9
|
## 0.1.9
|
||||||
|
|
||||||
- return Promises for `setViewport`, `fitView`, `fitBounds` and `zoomTo` to be able to await viewport update
|
- return Promises for `setViewport`, `fitView`, `fitBounds` and `zoomTo` to be able to await viewport update
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xyflow/svelte",
|
"name": "@xyflow/svelte",
|
||||||
"version": "0.1.8",
|
"version": "0.1.9",
|
||||||
"description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.",
|
"description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"svelte",
|
"svelte",
|
||||||
|
|||||||
@@ -35,11 +35,20 @@ type ZoomParams = {
|
|||||||
noWheelClassName: string;
|
noWheelClassName: string;
|
||||||
userSelectionActive: boolean;
|
userSelectionActive: boolean;
|
||||||
lib: string;
|
lib: string;
|
||||||
|
paneClickDistance: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function zoom(domNode: Element, params: ZoomParams) {
|
export default function zoom(domNode: Element, params: ZoomParams) {
|
||||||
const { panZoom, minZoom, maxZoom, initialViewport, viewport, dragging, translateExtent } =
|
const {
|
||||||
params;
|
panZoom,
|
||||||
|
minZoom,
|
||||||
|
maxZoom,
|
||||||
|
initialViewport,
|
||||||
|
viewport,
|
||||||
|
dragging,
|
||||||
|
translateExtent,
|
||||||
|
paneClickDistance
|
||||||
|
} = params;
|
||||||
|
|
||||||
const panZoomInstance = XYPanZoom({
|
const panZoomInstance = XYPanZoom({
|
||||||
domNode,
|
domNode,
|
||||||
@@ -47,6 +56,7 @@ export default function zoom(domNode: Element, params: ZoomParams) {
|
|||||||
maxZoom,
|
maxZoom,
|
||||||
translateExtent,
|
translateExtent,
|
||||||
viewport: initialViewport,
|
viewport: initialViewport,
|
||||||
|
paneClickDistance,
|
||||||
onTransformChange: (transform) =>
|
onTransformChange: (transform) =>
|
||||||
viewport.set({ x: transform[0], y: transform[1], zoom: transform[2] }),
|
viewport.set({ x: transform[0], y: transform[1], zoom: transform[2] }),
|
||||||
onDraggingChange: dragging.set
|
onDraggingChange: dragging.set
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
export let onbeforedelete: $$Props['onbeforedelete'] = undefined;
|
export let onbeforedelete: $$Props['onbeforedelete'] = undefined;
|
||||||
export let oninit: $$Props['oninit'] = undefined;
|
export let oninit: $$Props['oninit'] = undefined;
|
||||||
export let nodeOrigin: $$Props['nodeOrigin'] = undefined;
|
export let nodeOrigin: $$Props['nodeOrigin'] = undefined;
|
||||||
|
export let paneClickDistance: $$Props['paneClickDistance'] = 0;
|
||||||
|
|
||||||
export let defaultMarkerColor = '#b1b1b7';
|
export let defaultMarkerColor = '#b1b1b7';
|
||||||
|
|
||||||
@@ -125,7 +126,8 @@
|
|||||||
edgeTypes,
|
edgeTypes,
|
||||||
minZoom,
|
minZoom,
|
||||||
maxZoom,
|
maxZoom,
|
||||||
translateExtent
|
translateExtent,
|
||||||
|
paneClickDistance
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -188,7 +190,8 @@
|
|||||||
edgeTypes,
|
edgeTypes,
|
||||||
minZoom,
|
minZoom,
|
||||||
maxZoom,
|
maxZoom,
|
||||||
translateExtent
|
translateExtent,
|
||||||
|
paneClickDistance
|
||||||
});
|
});
|
||||||
|
|
||||||
$: colorModeClass = useColorModeClass(colorMode);
|
$: colorModeClass = useColorModeClass(colorMode);
|
||||||
@@ -225,6 +228,7 @@
|
|||||||
zoomOnPinch={zoomOnPinch === undefined ? true : zoomOnPinch}
|
zoomOnPinch={zoomOnPinch === undefined ? true : zoomOnPinch}
|
||||||
panOnScroll={panOnScroll === undefined ? false : panOnScroll}
|
panOnScroll={panOnScroll === undefined ? false : panOnScroll}
|
||||||
panOnDrag={panOnDrag === undefined ? true : panOnDrag}
|
panOnDrag={panOnDrag === undefined ? true : panOnDrag}
|
||||||
|
paneClickDistance={paneClickDistance === undefined ? 0 : paneClickDistance}
|
||||||
>
|
>
|
||||||
<Pane
|
<Pane
|
||||||
on:paneclick
|
on:paneclick
|
||||||
|
|||||||
@@ -134,6 +134,10 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
|
|||||||
* @default 1
|
* @default 1
|
||||||
*/
|
*/
|
||||||
nodeDragThreshold?: number;
|
nodeDragThreshold?: number;
|
||||||
|
/** Distance that the mouse can move between mousedown/up that will trigger a click
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
paneClickDistance?: number;
|
||||||
/** Minimum zoom level
|
/** Minimum zoom level
|
||||||
* @default 0.5
|
* @default 0.5
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import type { Writable } from 'svelte/store';
|
||||||
|
import type { CoordinateExtent } from '@xyflow/system';
|
||||||
|
|
||||||
import type { SvelteFlowStore } from '$lib/store/types';
|
import type { SvelteFlowStore } from '$lib/store/types';
|
||||||
import type { EdgeTypes, NodeTypes } from '$lib/types';
|
import type { EdgeTypes, NodeTypes } from '$lib/types';
|
||||||
import type { CoordinateExtent } from '@xyflow/system';
|
|
||||||
import type { Writable } from 'svelte/store';
|
|
||||||
|
|
||||||
// this is helper function for updating the store
|
// this is helper function for updating the store
|
||||||
// for props where we need to call a specific store action
|
// for props where we need to call a specific store action
|
||||||
@@ -12,13 +13,15 @@ export function updateStore(
|
|||||||
edgeTypes,
|
edgeTypes,
|
||||||
minZoom,
|
minZoom,
|
||||||
maxZoom,
|
maxZoom,
|
||||||
translateExtent
|
translateExtent,
|
||||||
|
paneClickDistance
|
||||||
}: {
|
}: {
|
||||||
nodeTypes?: NodeTypes;
|
nodeTypes?: NodeTypes;
|
||||||
edgeTypes?: EdgeTypes;
|
edgeTypes?: EdgeTypes;
|
||||||
minZoom?: number;
|
minZoom?: number;
|
||||||
maxZoom?: number;
|
maxZoom?: number;
|
||||||
translateExtent?: CoordinateExtent;
|
translateExtent?: CoordinateExtent;
|
||||||
|
paneClickDistance?: number;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (nodeTypes !== undefined) {
|
if (nodeTypes !== undefined) {
|
||||||
@@ -40,6 +43,10 @@ export function updateStore(
|
|||||||
if (translateExtent !== undefined) {
|
if (translateExtent !== undefined) {
|
||||||
store.setTranslateExtent(translateExtent);
|
store.setTranslateExtent(translateExtent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (paneClickDistance !== undefined) {
|
||||||
|
store.setPaneClickDistance(paneClickDistance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getKeys = <T extends object>(obj: T) => Object.keys(obj) as Array<keyof T>;
|
const getKeys = <T extends object>(obj: T) => Object.keys(obj) as Array<keyof T>;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
export let zoomOnPinch: $$Props['zoomOnPinch'];
|
export let zoomOnPinch: $$Props['zoomOnPinch'];
|
||||||
export let panOnDrag: $$Props['panOnDrag'];
|
export let panOnDrag: $$Props['panOnDrag'];
|
||||||
export let panOnScroll: $$Props['panOnScroll'];
|
export let panOnScroll: $$Props['panOnScroll'];
|
||||||
|
export let paneClickDistance: $$Props['paneClickDistance'];
|
||||||
|
|
||||||
const {
|
const {
|
||||||
viewport,
|
viewport,
|
||||||
@@ -68,7 +69,8 @@
|
|||||||
noWheelClassName: 'nowheel',
|
noWheelClassName: 'nowheel',
|
||||||
userSelectionActive: !!$selectionRect,
|
userSelectionActive: !!$selectionRect,
|
||||||
translateExtent: $translateExtent,
|
translateExtent: $translateExtent,
|
||||||
lib: $lib
|
lib: $lib,
|
||||||
|
paneClickDistance
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ export type ZoomProps = {
|
|||||||
zoomOnPinch: boolean;
|
zoomOnPinch: boolean;
|
||||||
panOnScroll: boolean;
|
panOnScroll: boolean;
|
||||||
panOnDrag: boolean | number[];
|
panOnDrag: boolean | number[];
|
||||||
|
paneClickDistance: number;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -248,6 +248,10 @@ export function createStore({
|
|||||||
return elementsChanged;
|
return elementsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setPaneClickDistance(distance: number) {
|
||||||
|
get(store.panZoom)?.setClickDistance(distance);
|
||||||
|
}
|
||||||
|
|
||||||
function unselectNodesAndEdges(params?: { nodes?: Node[]; edges?: Edge[] }) {
|
function unselectNodesAndEdges(params?: { nodes?: Node[]; edges?: Edge[] }) {
|
||||||
const resetNodes = resetSelectedElements(params?.nodes || get(store.nodes));
|
const resetNodes = resetSelectedElements(params?.nodes || get(store.nodes));
|
||||||
if (resetNodes) store.nodes.set(get(store.nodes));
|
if (resetNodes) store.nodes.set(get(store.nodes));
|
||||||
@@ -448,6 +452,7 @@ export function createStore({
|
|||||||
setMinZoom,
|
setMinZoom,
|
||||||
setMaxZoom,
|
setMaxZoom,
|
||||||
setTranslateExtent,
|
setTranslateExtent,
|
||||||
|
setPaneClickDistance,
|
||||||
unselectNodesAndEdges,
|
unselectNodesAndEdges,
|
||||||
addSelectedNodes,
|
addSelectedNodes,
|
||||||
addSelectedEdges,
|
addSelectedEdges,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export type SvelteFlowStoreActions = {
|
|||||||
setMinZoom: (minZoom: number) => void;
|
setMinZoom: (minZoom: number) => void;
|
||||||
setMaxZoom: (maxZoom: number) => void;
|
setMaxZoom: (maxZoom: number) => void;
|
||||||
setTranslateExtent: (extent: CoordinateExtent) => void;
|
setTranslateExtent: (extent: CoordinateExtent) => void;
|
||||||
|
setPaneClickDistance: (distance: number) => void;
|
||||||
fitView: (options?: FitViewOptions) => Promise<boolean>;
|
fitView: (options?: FitViewOptions) => Promise<boolean>;
|
||||||
updateNodePositions: UpdateNodePositions;
|
updateNodePositions: UpdateNodePositions;
|
||||||
updateNodeInternals: (updates: Map<string, InternalNodeUpdate>) => void;
|
updateNodeInternals: (updates: Map<string, InternalNodeUpdate>) => void;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xyflow/system",
|
"name": "@xyflow/system",
|
||||||
"version": "0.0.32",
|
"version": "0.0.33",
|
||||||
"description": "xyflow core system that powers React Flow and Svelte Flow.",
|
"description": "xyflow core system that powers React Flow and Svelte Flow.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"node-based UI",
|
"node-based UI",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export type PanZoomParams = {
|
|||||||
domNode: Element;
|
domNode: Element;
|
||||||
minZoom: number;
|
minZoom: number;
|
||||||
maxZoom: number;
|
maxZoom: number;
|
||||||
|
paneClickDistance: number;
|
||||||
viewport: Viewport;
|
viewport: Viewport;
|
||||||
translateExtent: CoordinateExtent;
|
translateExtent: CoordinateExtent;
|
||||||
onTransformChange: OnTransformChange;
|
onTransformChange: OnTransformChange;
|
||||||
@@ -56,4 +57,5 @@ export type PanZoomInstance = {
|
|||||||
scaleTo: (scale: number, options?: PanZoomTransformOptions) => Promise<boolean>;
|
scaleTo: (scale: number, options?: PanZoomTransformOptions) => Promise<boolean>;
|
||||||
scaleBy: (factor: number, options?: PanZoomTransformOptions) => Promise<boolean>;
|
scaleBy: (factor: number, options?: PanZoomTransformOptions) => Promise<boolean>;
|
||||||
syncViewport: (viewport: Viewport) => void;
|
syncViewport: (viewport: Viewport) => void;
|
||||||
|
setClickDistance: (distance: number) => void;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
nodeId,
|
nodeId,
|
||||||
dragItems,
|
dragItems,
|
||||||
nodeLookup,
|
nodeLookup,
|
||||||
|
dragging: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
onDragStop?.(event.sourceEvent as MouseEvent, dragItems, currentNode, currentNodes);
|
onDragStop?.(event.sourceEvent as MouseEvent, dragItems, currentNode, currentNodes);
|
||||||
|
|||||||
@@ -81,10 +81,12 @@ export function getEventHandlerParams<NodeType extends InternalNodeBase>({
|
|||||||
nodeId,
|
nodeId,
|
||||||
dragItems,
|
dragItems,
|
||||||
nodeLookup,
|
nodeLookup,
|
||||||
|
dragging = true,
|
||||||
}: {
|
}: {
|
||||||
nodeId?: string;
|
nodeId?: string;
|
||||||
dragItems: Map<string, NodeDragItem>;
|
dragItems: Map<string, NodeDragItem>;
|
||||||
nodeLookup: Map<string, NodeType>;
|
nodeLookup: Map<string, NodeType>;
|
||||||
|
dragging?: boolean;
|
||||||
}): [NodeBase, NodeBase[]] {
|
}): [NodeBase, NodeBase[]] {
|
||||||
const nodesFromDragItems: NodeBase[] = [];
|
const nodesFromDragItems: NodeBase[] = [];
|
||||||
|
|
||||||
@@ -95,6 +97,7 @@ export function getEventHandlerParams<NodeType extends InternalNodeBase>({
|
|||||||
nodesFromDragItems.push({
|
nodesFromDragItems.push({
|
||||||
...node,
|
...node,
|
||||||
position: dragItem.position,
|
position: dragItem.position,
|
||||||
|
dragging,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,6 +112,7 @@ export function getEventHandlerParams<NodeType extends InternalNodeBase>({
|
|||||||
{
|
{
|
||||||
...node,
|
...node,
|
||||||
position: dragItems.get(nodeId)?.position || node.position,
|
position: dragItems.get(nodeId)?.position || node.position,
|
||||||
|
dragging,
|
||||||
},
|
},
|
||||||
nodesFromDragItems,
|
nodesFromDragItems,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
PanZoomParams,
|
PanZoomParams,
|
||||||
PanZoomInstance,
|
PanZoomInstance,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { clamp } from '../utils';
|
import { clamp, isNumeric } from '../utils';
|
||||||
import { getD3Transition, viewportToTransform, wheelDelta } from './utils';
|
import { getD3Transition, viewportToTransform, wheelDelta } from './utils';
|
||||||
import {
|
import {
|
||||||
createPanOnScrollHandler,
|
createPanOnScrollHandler,
|
||||||
@@ -34,6 +34,7 @@ export function XYPanZoom({
|
|||||||
domNode,
|
domNode,
|
||||||
minZoom,
|
minZoom,
|
||||||
maxZoom,
|
maxZoom,
|
||||||
|
paneClickDistance,
|
||||||
translateExtent,
|
translateExtent,
|
||||||
viewport,
|
viewport,
|
||||||
onPanZoom,
|
onPanZoom,
|
||||||
@@ -52,7 +53,10 @@ export function XYPanZoom({
|
|||||||
isPanScrolling: false,
|
isPanScrolling: false,
|
||||||
};
|
};
|
||||||
const bbox = domNode.getBoundingClientRect();
|
const bbox = domNode.getBoundingClientRect();
|
||||||
const d3ZoomInstance = zoom().scaleExtent([minZoom, maxZoom]).translateExtent(translateExtent);
|
const d3ZoomInstance = zoom()
|
||||||
|
.clickDistance(!isNumeric(paneClickDistance) || paneClickDistance < 0 ? 0 : paneClickDistance)
|
||||||
|
.scaleExtent([minZoom, maxZoom])
|
||||||
|
.translateExtent(translateExtent);
|
||||||
const d3Selection = select(domNode).call(d3ZoomInstance);
|
const d3Selection = select(domNode).call(d3ZoomInstance);
|
||||||
|
|
||||||
setViewportConstrained(
|
setViewportConstrained(
|
||||||
@@ -267,6 +271,11 @@ export function XYPanZoom({
|
|||||||
d3ZoomInstance?.translateExtent(translateExtent);
|
d3ZoomInstance?.translateExtent(translateExtent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setClickDistance(distance: number) {
|
||||||
|
const validDistance = !isNumeric(distance) || distance < 0 ? 0 : distance;
|
||||||
|
d3ZoomInstance?.clickDistance(validDistance);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
update,
|
update,
|
||||||
destroy,
|
destroy,
|
||||||
@@ -278,5 +287,6 @@ export function XYPanZoom({
|
|||||||
setScaleExtent,
|
setScaleExtent,
|
||||||
setTranslateExtent,
|
setTranslateExtent,
|
||||||
syncViewport,
|
syncViewport,
|
||||||
|
setClickDistance,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user