Merge pull request #2749 from wbkd/node-resizer/before-resize
Node-resizer: add shouldResize handler
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@reactflow/node-resizer': major
|
||||||
|
---
|
||||||
|
|
||||||
|
Add shouldresize, cleanup types
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { memo, FC, CSSProperties } from 'react';
|
import { memo, FC } from 'react';
|
||||||
import { Handle, Position, NodeProps } from 'reactflow';
|
import { Handle, Position, NodeProps } from 'reactflow';
|
||||||
|
|
||||||
import { NodeResizer, NodeResizeControl } from '@reactflow/node-resizer';
|
import { NodeResizeControl } from '@reactflow/node-resizer';
|
||||||
import '@reactflow/node-resizer/dist/style.css';
|
import '@reactflow/node-resizer/dist/style.css';
|
||||||
import ResizeIcon from './ResizeIcon';
|
import ResizeIcon from './ResizeIcon';
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { memo, FC } from 'react';
|
import { memo, FC } from 'react';
|
||||||
import { Handle, Position, NodeProps } from 'reactflow';
|
import { Handle, Position, NodeProps } from 'reactflow';
|
||||||
|
|
||||||
import { NodeResizer, NodeResizeControl } from '@reactflow/node-resizer';
|
import { NodeResizeControl } from '@reactflow/node-resizer';
|
||||||
import '@reactflow/node-resizer/dist/style.css';
|
import '@reactflow/node-resizer/dist/style.css';
|
||||||
|
|
||||||
const CustomNode: FC<NodeProps> = ({ id, data }) => {
|
const CustomNode: FC<NodeProps> = ({ id, data }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NodeResizeControl color="red" position="top" />
|
<NodeResizeControl color="red" position={Position.Top} />
|
||||||
<NodeResizeControl color="red" position="bottom" />
|
<NodeResizeControl color="red" position={Position.Bottom} />
|
||||||
<Handle type="target" position={Position.Left} />
|
<Handle type="target" position={Position.Left} />
|
||||||
<div style={{ padding: 10 }}>{data.label}</div>
|
<div style={{ padding: 10 }}>{data.label}</div>
|
||||||
<Handle type="source" position={Position.Right} />
|
<Handle type="source" position={Position.Right} />
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { memo, FC } from 'react';
|
||||||
|
import { Handle, Position, NodeProps } from 'reactflow';
|
||||||
|
|
||||||
|
import { NodeResizeControl, OnResize, ShouldResize } from '@reactflow/node-resizer';
|
||||||
|
import '@reactflow/node-resizer/dist/style.css';
|
||||||
|
|
||||||
|
const shouldResize: ShouldResize = (event, params) => {
|
||||||
|
console.log('before resize', params);
|
||||||
|
|
||||||
|
if (params.width > 100) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onResize: OnResize = (event, params) => {
|
||||||
|
console.log('resize', params.direction);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomNode: FC<NodeProps> = ({ id, data }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<NodeResizeControl color="red" position={Position.Left} />
|
||||||
|
<NodeResizeControl color="red" position={Position.Right} shouldResize={shouldResize} onResize={onResize} />
|
||||||
|
<Handle type="target" position={Position.Top} />
|
||||||
|
<div style={{ padding: 10 }}>{data.label}</div>
|
||||||
|
<Handle type="source" position={Position.Bottom} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(CustomNode);
|
||||||
@@ -1,21 +1,27 @@
|
|||||||
import { memo, FC } from 'react';
|
import { memo, FC } from 'react';
|
||||||
import { Handle, Position, NodeProps } from 'reactflow';
|
import { Handle, Position, NodeProps } from 'reactflow';
|
||||||
|
|
||||||
import { NodeResizer, ResizeDragEvent, ResizeEventParams } from '@reactflow/node-resizer';
|
import { NodeResizer, ShouldResize, OnResize, OnResizeEnd, OnResizeStart } from '@reactflow/node-resizer';
|
||||||
import '@reactflow/node-resizer/dist/style.css';
|
import '@reactflow/node-resizer/dist/style.css';
|
||||||
|
|
||||||
const onResizeStart = (_: ResizeDragEvent, params: ResizeEventParams) => {
|
const onResizeStart: OnResizeStart = (_, params) => {
|
||||||
console.log('resize start', params);
|
console.log('resize start', params);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onResize = (_: ResizeDragEvent, params: ResizeEventParams) => {
|
const onResize: OnResize = (_, params) => {
|
||||||
console.log('resize', params);
|
console.log('resize', params);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onResizeEnd = (_: ResizeDragEvent, params: ResizeEventParams) => {
|
const onResizeEnd: OnResizeEnd = (_, params) => {
|
||||||
console.log('resize end', params);
|
console.log('resize end', params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const shouldResize: ShouldResize = (_, params) => {
|
||||||
|
console.log('should resize', params);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
const CustomNode: FC<NodeProps> = ({ data, selected }) => {
|
const CustomNode: FC<NodeProps> = ({ data, selected }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -23,6 +29,7 @@ const CustomNode: FC<NodeProps> = ({ data, selected }) => {
|
|||||||
minWidth={100}
|
minWidth={100}
|
||||||
minHeight={100}
|
minHeight={100}
|
||||||
isVisible={selected}
|
isVisible={selected}
|
||||||
|
shouldResize={shouldResize}
|
||||||
onResizeStart={onResizeStart}
|
onResizeStart={onResizeStart}
|
||||||
onResize={onResize}
|
onResize={onResize}
|
||||||
onResizeEnd={onResizeEnd}
|
onResizeEnd={onResizeEnd}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import ReactFlow, { Controls, addEdge, Position, Connection, useNodesState, useE
|
|||||||
import NodeResizerNode from './NodeResizerNode';
|
import NodeResizerNode from './NodeResizerNode';
|
||||||
import CustomResizer from './CustomResizer';
|
import CustomResizer from './CustomResizer';
|
||||||
import CustomResizer2 from './CustomResizer2';
|
import CustomResizer2 from './CustomResizer2';
|
||||||
|
import CustomResizer3 from './CustomResizer3';
|
||||||
|
|
||||||
const nodeTypes = {
|
const nodeTypes = {
|
||||||
resizer: NodeResizerNode,
|
resizer: NodeResizerNode,
|
||||||
customResizer: CustomResizer,
|
customResizer: CustomResizer,
|
||||||
customResizer2: CustomResizer2,
|
customResizer2: CustomResizer2,
|
||||||
|
customResizer3: CustomResizer3,
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialEdges = [
|
const initialEdges = [
|
||||||
@@ -60,6 +62,13 @@ const initialNodes = [
|
|||||||
position: { x: 250, y: 250 },
|
position: { x: 250, y: 250 },
|
||||||
style: { border: '1px solid #222', fontSize: 10 },
|
style: { border: '1px solid #222', fontSize: 10 },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: '6',
|
||||||
|
type: 'customResizer3',
|
||||||
|
data: { label: 'resize controls' },
|
||||||
|
position: { x: 400, y: 200 },
|
||||||
|
style: { border: '1px solid #222', fontSize: 10 },
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const CustomNodeFlow = () => {
|
const CustomNodeFlow = () => {
|
||||||
@@ -87,7 +96,7 @@ const CustomNodeFlow = () => {
|
|||||||
>
|
>
|
||||||
<Controls />
|
<Controls />
|
||||||
<Panel position="bottom-right">
|
<Panel position="bottom-right">
|
||||||
<button onClick={() => setSnapToGrid(!snapToGrid)}>snapToGrid: {snapToGrid ? 'on' : 'off'}</button>
|
<button onClick={() => setSnapToGrid((s) => !s)}>snapToGrid: {snapToGrid ? 'on' : 'off'}</button>
|
||||||
</Panel>
|
</Panel>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reactflow/core": "workspace:*",
|
"@reactflow/core": "workspace:^11.3.3",
|
||||||
"classcat": "^5.0.4",
|
"classcat": "^5.0.4",
|
||||||
"d3-drag": "^3.0.0",
|
"d3-drag": "^3.0.0",
|
||||||
"d3-selection": "^3.0.0",
|
"d3-selection": "^3.0.0",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export default function NodeResizer({
|
|||||||
color,
|
color,
|
||||||
minWidth = 10,
|
minWidth = 10,
|
||||||
minHeight = 10,
|
minHeight = 10,
|
||||||
|
shouldResize,
|
||||||
onResizeStart,
|
onResizeStart,
|
||||||
onResize,
|
onResize,
|
||||||
onResizeEnd,
|
onResizeEnd,
|
||||||
@@ -36,6 +37,7 @@ export default function NodeResizer({
|
|||||||
minWidth={minWidth}
|
minWidth={minWidth}
|
||||||
minHeight={minHeight}
|
minHeight={minHeight}
|
||||||
onResizeStart={onResizeStart}
|
onResizeStart={onResizeStart}
|
||||||
|
shouldResize={shouldResize}
|
||||||
onResize={onResize}
|
onResize={onResize}
|
||||||
onResizeEnd={onResizeEnd}
|
onResizeEnd={onResizeEnd}
|
||||||
/>
|
/>
|
||||||
@@ -51,6 +53,7 @@ export default function NodeResizer({
|
|||||||
minWidth={minWidth}
|
minWidth={minWidth}
|
||||||
minHeight={minHeight}
|
minHeight={minHeight}
|
||||||
onResizeStart={onResizeStart}
|
onResizeStart={onResizeStart}
|
||||||
|
shouldResize={shouldResize}
|
||||||
onResize={onResize}
|
onResize={onResize}
|
||||||
onResizeEnd={onResizeEnd}
|
onResizeEnd={onResizeEnd}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
} from '@reactflow/core';
|
} from '@reactflow/core';
|
||||||
|
|
||||||
import { ResizeDragEvent, ResizeControlProps, ResizeControlLineProps, ResizeControlVariant } from './types';
|
import { ResizeDragEvent, ResizeControlProps, ResizeControlLineProps, ResizeControlVariant } from './types';
|
||||||
|
import { getDirection } from './utils';
|
||||||
|
|
||||||
const initPrevValues = { width: 0, height: 0, x: 0, y: 0 };
|
const initPrevValues = { width: 0, height: 0, x: 0, y: 0 };
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ function ResizeControl({
|
|||||||
color,
|
color,
|
||||||
minWidth = 10,
|
minWidth = 10,
|
||||||
minHeight = 10,
|
minHeight = 10,
|
||||||
|
shouldResize,
|
||||||
onResizeStart,
|
onResizeStart,
|
||||||
onResize,
|
onResize,
|
||||||
onResizeEnd,
|
onResizeEnd,
|
||||||
@@ -140,7 +142,28 @@ function ResizeControl({
|
|||||||
prevValues.current.height = height;
|
prevValues.current.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
onResize?.(event, { ...prevValues.current });
|
if (changes.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const direction = getDirection({
|
||||||
|
width: prevValues.current.width,
|
||||||
|
prevWidth,
|
||||||
|
height: prevValues.current.height,
|
||||||
|
prevHeight,
|
||||||
|
invertX,
|
||||||
|
invertY,
|
||||||
|
});
|
||||||
|
|
||||||
|
const nextValues = { ...prevValues.current, direction };
|
||||||
|
|
||||||
|
const callResize = shouldResize?.(event, nextValues);
|
||||||
|
|
||||||
|
if (callResize === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onResize?.(event, nextValues);
|
||||||
triggerNodeChanges(changes);
|
triggerNodeChanges(changes);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
import type { CSSProperties, ReactNode } from 'react';
|
import type { CSSProperties, ReactNode } from 'react';
|
||||||
import type { D3DragEvent, SubjectPosition } from 'd3-drag';
|
import type { D3DragEvent, SubjectPosition } from 'd3-drag';
|
||||||
|
|
||||||
export type ResizeEventParams = {
|
export type ResizeParams = {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ResizeParamsWithDirection = ResizeParams & {
|
||||||
|
direction: number[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type OnResizeHandler<Params = ResizeParams, Result = void> = (event: ResizeDragEvent, params: Params) => Result;
|
||||||
|
|
||||||
|
export type ShouldResize = OnResizeHandler<ResizeParamsWithDirection, boolean>;
|
||||||
|
export type OnResizeStart = OnResizeHandler;
|
||||||
|
export type OnResize = OnResizeHandler<ResizeParamsWithDirection>;
|
||||||
|
export type OnResizeEnd = OnResizeHandler;
|
||||||
|
|
||||||
export type NodeResizerProps = {
|
export type NodeResizerProps = {
|
||||||
nodeId?: string;
|
nodeId?: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
@@ -18,9 +29,10 @@ export type NodeResizerProps = {
|
|||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
minWidth?: number;
|
minWidth?: number;
|
||||||
minHeight?: number;
|
minHeight?: number;
|
||||||
onResizeStart?: (event: ResizeDragEvent, params: ResizeEventParams) => void;
|
shouldResize?: ShouldResize;
|
||||||
onResize?: (event: ResizeDragEvent, params: ResizeEventParams) => void;
|
onResizeStart?: OnResizeStart;
|
||||||
onResizeEnd?: (event: ResizeDragEvent, params: ResizeEventParams) => void;
|
onResize?: OnResize;
|
||||||
|
onResizeEnd?: OnResizeEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ControlLinePosition = 'top' | 'bottom' | 'left' | 'right';
|
export type ControlLinePosition = 'top' | 'bottom' | 'left' | 'right';
|
||||||
@@ -34,7 +46,7 @@ export enum ResizeControlVariant {
|
|||||||
|
|
||||||
export type ResizeControlProps = Pick<
|
export type ResizeControlProps = Pick<
|
||||||
NodeResizerProps,
|
NodeResizerProps,
|
||||||
'nodeId' | 'color' | 'minWidth' | 'minHeight' | 'onResizeStart' | 'onResize' | 'onResizeEnd'
|
'nodeId' | 'color' | 'minWidth' | 'minHeight' | 'shouldResize' | 'onResizeStart' | 'onResize' | 'onResizeEnd'
|
||||||
> & {
|
> & {
|
||||||
position?: ControlPosition;
|
position?: ControlPosition;
|
||||||
variant?: ResizeControlVariant;
|
variant?: ResizeControlVariant;
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
type GetDirectionParams = {
|
||||||
|
width: number;
|
||||||
|
prevWidth: number;
|
||||||
|
height: number;
|
||||||
|
prevHeight: number;
|
||||||
|
invertX: boolean;
|
||||||
|
invertY: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns an array of two numbers (0, 1 or -1) representing the direction of the resize
|
||||||
|
// 0 = no change, 1 = increase, -1 = decrease
|
||||||
|
export function getDirection({ width, prevWidth, height, prevHeight, invertX, invertY }: GetDirectionParams) {
|
||||||
|
const deltaWidth = width - prevWidth;
|
||||||
|
const deltaHeight = height - prevHeight;
|
||||||
|
|
||||||
|
const direction = [deltaWidth > 0 ? 1 : deltaWidth < 0 ? -1 : 0, deltaHeight > 0 ? 1 : deltaHeight < 0 ? -1 : 0];
|
||||||
|
|
||||||
|
if (deltaWidth && invertX) {
|
||||||
|
direction[0] = direction[0] * -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deltaHeight && invertY) {
|
||||||
|
direction[1] = direction[1] * -1;
|
||||||
|
}
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reactflow/core": "workspace:*",
|
"@reactflow/core": "workspace:^11.3.3",
|
||||||
"classcat": "^5.0.3",
|
"classcat": "^5.0.3",
|
||||||
"zustand": "^4.3.1"
|
"zustand": "^4.3.1"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user