diff --git a/.changeset/pretty-spoons-punch.md b/.changeset/pretty-spoons-punch.md new file mode 100644 index 00000000..0b661034 --- /dev/null +++ b/.changeset/pretty-spoons-punch.md @@ -0,0 +1,5 @@ +--- +'@reactflow/node-resizer': major +--- + +Add shouldresize, cleanup types diff --git a/examples/vite-app/src/examples/NodeResizer/CustomResizer.tsx b/examples/vite-app/src/examples/NodeResizer/CustomResizer.tsx index 996e24c5..6cf58fd9 100644 --- a/examples/vite-app/src/examples/NodeResizer/CustomResizer.tsx +++ b/examples/vite-app/src/examples/NodeResizer/CustomResizer.tsx @@ -1,7 +1,7 @@ -import { memo, FC, CSSProperties } from 'react'; +import { memo, FC } from 'react'; 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 ResizeIcon from './ResizeIcon'; diff --git a/examples/vite-app/src/examples/NodeResizer/CustomResizer2.tsx b/examples/vite-app/src/examples/NodeResizer/CustomResizer2.tsx index 27833556..63ff061b 100644 --- a/examples/vite-app/src/examples/NodeResizer/CustomResizer2.tsx +++ b/examples/vite-app/src/examples/NodeResizer/CustomResizer2.tsx @@ -1,14 +1,14 @@ import { memo, FC } from 'react'; 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'; const CustomNode: FC = ({ id, data }) => { return ( <> - - + +
{data.label}
diff --git a/examples/vite-app/src/examples/NodeResizer/CustomResizer3.tsx b/examples/vite-app/src/examples/NodeResizer/CustomResizer3.tsx new file mode 100644 index 00000000..422f2982 --- /dev/null +++ b/examples/vite-app/src/examples/NodeResizer/CustomResizer3.tsx @@ -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 = ({ id, data }) => { + return ( + <> + + + +
{data.label}
+ + + ); +}; + +export default memo(CustomNode); diff --git a/examples/vite-app/src/examples/NodeResizer/NodeResizerNode.tsx b/examples/vite-app/src/examples/NodeResizer/NodeResizerNode.tsx index a8f76eca..03e4960f 100644 --- a/examples/vite-app/src/examples/NodeResizer/NodeResizerNode.tsx +++ b/examples/vite-app/src/examples/NodeResizer/NodeResizerNode.tsx @@ -1,21 +1,27 @@ import { memo, FC } from 'react'; 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'; -const onResizeStart = (_: ResizeDragEvent, params: ResizeEventParams) => { +const onResizeStart: OnResizeStart = (_, params) => { console.log('resize start', params); }; -const onResize = (_: ResizeDragEvent, params: ResizeEventParams) => { +const onResize: OnResize = (_, params) => { console.log('resize', params); }; -const onResizeEnd = (_: ResizeDragEvent, params: ResizeEventParams) => { +const onResizeEnd: OnResizeEnd = (_, params) => { console.log('resize end', params); }; +const shouldResize: ShouldResize = (_, params) => { + console.log('should resize', params); + + return true; +}; + const CustomNode: FC = ({ data, selected }) => { return ( <> @@ -23,6 +29,7 @@ const CustomNode: FC = ({ data, selected }) => { minWidth={100} minHeight={100} isVisible={selected} + shouldResize={shouldResize} onResizeStart={onResizeStart} onResize={onResize} onResizeEnd={onResizeEnd} diff --git a/examples/vite-app/src/examples/NodeResizer/index.tsx b/examples/vite-app/src/examples/NodeResizer/index.tsx index 68afe5df..01bb0851 100644 --- a/examples/vite-app/src/examples/NodeResizer/index.tsx +++ b/examples/vite-app/src/examples/NodeResizer/index.tsx @@ -4,11 +4,13 @@ import ReactFlow, { Controls, addEdge, Position, Connection, useNodesState, useE import NodeResizerNode from './NodeResizerNode'; import CustomResizer from './CustomResizer'; import CustomResizer2 from './CustomResizer2'; +import CustomResizer3 from './CustomResizer3'; const nodeTypes = { resizer: NodeResizerNode, customResizer: CustomResizer, customResizer2: CustomResizer2, + customResizer3: CustomResizer3, }; const initialEdges = [ @@ -60,6 +62,13 @@ const initialNodes = [ position: { x: 250, y: 250 }, 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 = () => { @@ -87,7 +96,7 @@ const CustomNodeFlow = () => { > - + ); diff --git a/packages/node-resizer/package.json b/packages/node-resizer/package.json index 6bed1b65..a570caaf 100644 --- a/packages/node-resizer/package.json +++ b/packages/node-resizer/package.json @@ -38,7 +38,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@reactflow/core": "workspace:*", + "@reactflow/core": "workspace:^11.3.3", "classcat": "^5.0.4", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", diff --git a/packages/node-resizer/src/NodeResizer.tsx b/packages/node-resizer/src/NodeResizer.tsx index f676e79a..c7a3b8a6 100644 --- a/packages/node-resizer/src/NodeResizer.tsx +++ b/packages/node-resizer/src/NodeResizer.tsx @@ -14,6 +14,7 @@ export default function NodeResizer({ color, minWidth = 10, minHeight = 10, + shouldResize, onResizeStart, onResize, onResizeEnd, @@ -36,6 +37,7 @@ export default function NodeResizer({ minWidth={minWidth} minHeight={minHeight} onResizeStart={onResizeStart} + shouldResize={shouldResize} onResize={onResize} onResizeEnd={onResizeEnd} /> @@ -51,6 +53,7 @@ export default function NodeResizer({ minWidth={minWidth} minHeight={minHeight} onResizeStart={onResizeStart} + shouldResize={shouldResize} onResize={onResize} onResizeEnd={onResizeEnd} /> diff --git a/packages/node-resizer/src/ResizeControl.tsx b/packages/node-resizer/src/ResizeControl.tsx index 654b3249..3397537d 100644 --- a/packages/node-resizer/src/ResizeControl.tsx +++ b/packages/node-resizer/src/ResizeControl.tsx @@ -12,6 +12,7 @@ import { } from '@reactflow/core'; import { ResizeDragEvent, ResizeControlProps, ResizeControlLineProps, ResizeControlVariant } from './types'; +import { getDirection } from './utils'; const initPrevValues = { width: 0, height: 0, x: 0, y: 0 }; @@ -31,6 +32,7 @@ function ResizeControl({ color, minWidth = 10, minHeight = 10, + shouldResize, onResizeStart, onResize, onResizeEnd, @@ -140,7 +142,28 @@ function ResizeControl({ 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); } }) diff --git a/packages/node-resizer/src/types.ts b/packages/node-resizer/src/types.ts index 9dc808f6..75d40ace 100644 --- a/packages/node-resizer/src/types.ts +++ b/packages/node-resizer/src/types.ts @@ -1,13 +1,24 @@ import type { CSSProperties, ReactNode } from 'react'; import type { D3DragEvent, SubjectPosition } from 'd3-drag'; -export type ResizeEventParams = { +export type ResizeParams = { x: number; y: number; width: number; height: number; }; +export type ResizeParamsWithDirection = ResizeParams & { + direction: number[]; +}; + +type OnResizeHandler = (event: ResizeDragEvent, params: Params) => Result; + +export type ShouldResize = OnResizeHandler; +export type OnResizeStart = OnResizeHandler; +export type OnResize = OnResizeHandler; +export type OnResizeEnd = OnResizeHandler; + export type NodeResizerProps = { nodeId?: string; color?: string; @@ -18,9 +29,10 @@ export type NodeResizerProps = { isVisible?: boolean; minWidth?: number; minHeight?: number; - onResizeStart?: (event: ResizeDragEvent, params: ResizeEventParams) => void; - onResize?: (event: ResizeDragEvent, params: ResizeEventParams) => void; - onResizeEnd?: (event: ResizeDragEvent, params: ResizeEventParams) => void; + shouldResize?: ShouldResize; + onResizeStart?: OnResizeStart; + onResize?: OnResize; + onResizeEnd?: OnResizeEnd; }; export type ControlLinePosition = 'top' | 'bottom' | 'left' | 'right'; @@ -34,7 +46,7 @@ export enum ResizeControlVariant { export type ResizeControlProps = Pick< NodeResizerProps, - 'nodeId' | 'color' | 'minWidth' | 'minHeight' | 'onResizeStart' | 'onResize' | 'onResizeEnd' + 'nodeId' | 'color' | 'minWidth' | 'minHeight' | 'shouldResize' | 'onResizeStart' | 'onResize' | 'onResizeEnd' > & { position?: ControlPosition; variant?: ResizeControlVariant; diff --git a/packages/node-resizer/src/utils.ts b/packages/node-resizer/src/utils.ts new file mode 100644 index 00000000..00d81d81 --- /dev/null +++ b/packages/node-resizer/src/utils.ts @@ -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; +} diff --git a/packages/node-toolbar/package.json b/packages/node-toolbar/package.json index b719ceb8..7ef50f38 100644 --- a/packages/node-toolbar/package.json +++ b/packages/node-toolbar/package.json @@ -36,7 +36,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@reactflow/core": "workspace:*", + "@reactflow/core": "workspace:^11.3.3", "classcat": "^5.0.3", "zustand": "^4.3.1" },