diff --git a/.changeset/flat-horses-smile.md b/.changeset/flat-horses-smile.md new file mode 100644 index 00000000..7d080484 --- /dev/null +++ b/.changeset/flat-horses-smile.md @@ -0,0 +1,7 @@ +--- +'@xyflow/system': patch +'@xyflow/react': patch +'@xyflow/svelte': patch +--- + +Let NodeResizer props change during ongoing resize diff --git a/examples/react/src/examples/NodeResizer/DefaultResizer.tsx b/examples/react/src/examples/NodeResizer/DefaultResizer.tsx index a3532a8f..d5d314ba 100644 --- a/examples/react/src/examples/NodeResizer/DefaultResizer.tsx +++ b/examples/react/src/examples/NodeResizer/DefaultResizer.tsx @@ -1,7 +1,9 @@ import { memo, FC } from 'react'; -import { Handle, Position, NodeProps, NodeResizer } from '@xyflow/react'; +import { Handle, Position, NodeProps, NodeResizer, useKeyPress } from '@xyflow/react'; const DefaultResizerNode: FC = ({ data, selected }) => { + const keepAspectRatio = useKeyPress('k'); + return ( <> = ({ data, selected }) => { onResizeStart={data.onResizeStart ?? undefined} onResize={data.onResize ?? undefined} onResizeEnd={data.onResizeEnd ?? undefined} - keepAspectRatio={data.keepAspectRatio ?? undefined} + keepAspectRatio={keepAspectRatio || (data.keepAspectRatio ?? undefined)} />
{data.label}
diff --git a/examples/svelte/src/routes/examples/node-resizer/+page.svelte b/examples/svelte/src/routes/examples/node-resizer/+page.svelte index c3311337..61f4ca22 100644 --- a/examples/svelte/src/routes/examples/node-resizer/+page.svelte +++ b/examples/svelte/src/routes/examples/node-resizer/+page.svelte @@ -9,6 +9,7 @@ import '@xyflow/svelte/dist/style.css'; import type { ResizeNode } from './types'; + import { store } from './store.svelte'; const nodeTypes = { defaultResizer: DefaultResizer, @@ -139,6 +140,15 @@ let snapToGrid = $state(false); + { + if (e.key === 'k') store.keepAspectRatio = true; + }} + on:keyup={(e) => { + if (e.key === 'k') store.keepAspectRatio = false; + }} +/> + import { Handle, Position, type NodeProps, NodeResizeControl, type Node } from '@xyflow/svelte'; import type { ResizeNode } from './types'; + import { store } from './store.svelte'; let { data }: NodeProps = $props(); @@ -14,7 +15,7 @@ onResizeStart={data.onResizeStart ?? undefined} onResize={data.onResize ?? undefined} onResizeEnd={data.onResizeEnd ?? undefined} - keepAspectRatio={data.keepAspectRatio ?? undefined} + keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)} style="background: transparent; border: none;" > = $props(); @@ -15,7 +17,7 @@ onResizeStart={data.onResizeStart ?? undefined} onResize={data.onResize ?? undefined} onResizeEnd={data.onResizeEnd ?? undefined} - keepAspectRatio={data.keepAspectRatio ?? undefined} + keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)} />
{data.label}
diff --git a/examples/svelte/src/routes/examples/node-resizer/HorizontalResizer.svelte b/examples/svelte/src/routes/examples/node-resizer/HorizontalResizer.svelte index d9ec28ff..2727e4c7 100644 --- a/examples/svelte/src/routes/examples/node-resizer/HorizontalResizer.svelte +++ b/examples/svelte/src/routes/examples/node-resizer/HorizontalResizer.svelte @@ -1,6 +1,7 @@ @@ -14,7 +15,7 @@ onResizeStart={data.onResizeStart ?? undefined} onResize={data.onResize ?? undefined} onResizeEnd={data.onResizeEnd ?? undefined} - keepAspectRatio={data.keepAspectRatio ?? undefined} + keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)} color="red" position={Position.Left} /> diff --git a/examples/svelte/src/routes/examples/node-resizer/VerticalResizer.svelte b/examples/svelte/src/routes/examples/node-resizer/VerticalResizer.svelte index fedfff50..eec2578b 100644 --- a/examples/svelte/src/routes/examples/node-resizer/VerticalResizer.svelte +++ b/examples/svelte/src/routes/examples/node-resizer/VerticalResizer.svelte @@ -1,6 +1,7 @@ @@ -14,7 +15,7 @@ onResizeStart={data.onResizeStart ?? undefined} onResize={data.onResize ?? undefined} onResizeEnd={data.onResizeEnd ?? undefined} - keepAspectRatio={data.keepAspectRatio ?? undefined} + keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)} color="red" position={Position.Top} /> diff --git a/examples/svelte/src/routes/examples/node-resizer/store.svelte.ts b/examples/svelte/src/routes/examples/node-resizer/store.svelte.ts new file mode 100644 index 00000000..076582b2 --- /dev/null +++ b/examples/svelte/src/routes/examples/node-resizer/store.svelte.ts @@ -0,0 +1,14 @@ +function createStore() { + let keepAspectRatio = $state(false); + + return { + get keepAspectRatio() { + return keepAspectRatio; + }, + set keepAspectRatio(value: boolean) { + keepAspectRatio = value; + } + }; +} + +export const store = createStore(); diff --git a/packages/system/src/xyresizer/XYResizer.ts b/packages/system/src/xyresizer/XYResizer.ts index 326a7007..713d14e3 100644 --- a/packages/system/src/xyresizer/XYResizer.ts +++ b/packages/system/src/xyresizer/XYResizer.ts @@ -104,6 +104,18 @@ function nodeToChildExtent(child: NodeBase, parent: NodeBase, nodeOrigin: NodeOr export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: XYResizerParams): XYResizerInstance { const selection = select(domNode); + let params = { + controlDirection: getControlDirection('bottom-right'), + boundaries: { + minWidth: 0, + minHeight: 0, + maxWidth: Number.MAX_VALUE, + maxHeight: Number.MAX_VALUE, + }, + resizeDirection: undefined as ResizeControlDirection | undefined, + keepAspectRatio: false, + }; + function update({ controlPosition, boundaries, @@ -117,7 +129,12 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X let prevValues = { ...initPrevValues }; let startValues = { ...initStartValues }; - const controlDirection = getControlDirection(controlPosition); + params = { + boundaries, + resizeDirection, + keepAspectRatio, + controlDirection: getControlDirection(controlPosition), + }; let node: InternalNodeBase | undefined = undefined; let containerBounds: DOMRect | null = null; @@ -212,16 +229,17 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X if (!node) { return; } + const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues; const change: XYResizerChange = {}; const nodeOrigin = node.origin ?? storeNodeOrigin; const { width, height, x, y } = getDimensionsAfterResize( startValues, - controlDirection, + params.controlDirection, pointerPosition, - boundaries, - keepAspectRatio, + params.boundaries, + params.keepAspectRatio, nodeOrigin, parentExtent, childExtent @@ -264,9 +282,13 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X if (isWidthChange || isHeightChange) { change.width = - isWidthChange && (!resizeDirection || resizeDirection === 'horizontal') ? width : prevValues.width; + isWidthChange && (!params.resizeDirection || params.resizeDirection === 'horizontal') + ? width + : prevValues.width; change.height = - isHeightChange && (!resizeDirection || resizeDirection === 'vertical') ? height : prevValues.height; + isHeightChange && (!params.resizeDirection || params.resizeDirection === 'vertical') + ? height + : prevValues.height; prevValues.width = change.width; prevValues.height = change.height; } @@ -291,8 +313,8 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X prevWidth, height: prevValues.height, prevHeight, - affectsX: controlDirection.affectsX, - affectsY: controlDirection.affectsY, + affectsX: params.controlDirection.affectsX, + affectsY: params.controlDirection.affectsY, }); const nextValues = { ...prevValues, direction };