From 8f934d7793f97a6cf6a45f159c8caf1fa3dffbc7 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Mon, 29 Sep 2025 18:02:18 +0200 Subject: [PATCH 1/3] switch keep aspect on shortcut --- .../src/routes/examples/node-resizer/+page.svelte | 10 ++++++++++ .../examples/node-resizer/CustomResizer.svelte | 3 ++- .../examples/node-resizer/DefaultResizer.svelte | 4 +++- .../examples/node-resizer/HorizontalResizer.svelte | 3 ++- .../examples/node-resizer/VerticalResizer.svelte | 3 ++- .../routes/examples/node-resizer/store.svelte.ts | 14 ++++++++++++++ 6 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 examples/svelte/src/routes/examples/node-resizer/store.svelte.ts diff --git a/examples/svelte/src/routes/examples/node-resizer/+page.svelte b/examples/svelte/src/routes/examples/node-resizer/+page.svelte index 8a5ec2ae..008f76c7 100644 --- a/examples/svelte/src/routes/examples/node-resizer/+page.svelte +++ b/examples/svelte/src/routes/examples/node-resizer/+page.svelte @@ -8,6 +8,7 @@ import '@xyflow/svelte/dist/style.css'; import type { ResizeNode } from './types'; + import { store } from './store.svelte'; const nodeTypes = { defaultResizer: DefaultResizer, @@ -130,6 +131,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(); From f29593072c7fbf54216693345b2cfaa447169cb9 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 30 Sep 2025 10:40:57 +0200 Subject: [PATCH 2/3] let resizer params be updated dynamically --- .../examples/NodeResizer/DefaultResizer.tsx | 6 ++- packages/system/src/xyresizer/XYResizer.ts | 38 +++++++++++++++---- 2 files changed, 34 insertions(+), 10 deletions(-) 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/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 }; From d50a963cd0f00cd31236d760dcd7995218d80553 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 30 Sep 2025 10:42:32 +0200 Subject: [PATCH 3/3] chore(changeset) --- .changeset/flat-horses-smile.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/flat-horses-smile.md 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