From a488322c551c2990a40c6faa4485282ec656d2f3 Mon Sep 17 00:00:00 2001 From: Abbey Yacoe Date: Mon, 2 Jun 2025 16:00:42 +0200 Subject: [PATCH] feat(onFocus): pan nodes into the viewport on tab --- .../src/components/NodeWrapper/index.tsx | 14 ++++++++++++ .../components/NodeWrapper/NodeWrapper.svelte | 22 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/packages/react/src/components/NodeWrapper/index.tsx b/packages/react/src/components/NodeWrapper/index.tsx index 5c0ce08b..e507a02c 100644 --- a/packages/react/src/components/NodeWrapper/index.tsx +++ b/packages/react/src/components/NodeWrapper/index.tsx @@ -155,6 +155,19 @@ export function NodeWrapper({ } }; + const onFocus = () => { + const { panZoom } = store.getState(); + const zoom = panZoom?.getViewport().zoom ?? 1; + panZoom?.setViewport( + { + x: -(internals.positionAbsolute.x + nodeDimensions.width / 2) * zoom + window.innerWidth / 2, + y: -(internals.positionAbsolute.y + nodeDimensions.height / 2) * zoom + window.innerHeight / 2, + zoom: zoom, + }, + { duration: 100 } + ); + }; + return (
({ onDoubleClick={onDoubleClickHandler} onKeyDown={isFocusable ? onKeyDown : undefined} tabIndex={isFocusable ? 0 : undefined} + onFocus={isFocusable ? onFocus : undefined} role={isFocusable ? 'button' : undefined} aria-describedby={disableKeyboardA11y ? undefined : `${ARIA_NODE_DESC_KEY}-${rfId}`} aria-label={node.ariaLabel} diff --git a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte index f053cd82..24556d42 100644 --- a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte +++ b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte @@ -196,6 +196,27 @@ store.moveSelectedNodes(arrowKeyDiffs[event.key], event.shiftKey ? 4 : 1); } } + + function onFocus() { + if (store.disableKeyboardA11y) { + return; + } + + const zoom = store.panZoom?.getViewport().zoom ?? 1; + + // Get node dimensions + const nodeWidth = nodeRef?.offsetWidth || 0; + const nodeHeight = nodeRef?.offsetHeight || 0; + + store.panZoom?.setViewport( + { + x: -(positionX + nodeWidth / 2) * zoom + window.innerWidth / 2, + y: -(positionY + nodeHeight / 2) * zoom + window.innerHeight / 2, + zoom: zoom, + }, + { duration: 100 } + ); + } {#if !hidden} @@ -251,6 +272,7 @@ ? (event) => onnodecontextmenu({ node: userNode, event }) : undefined} onkeydown={focusable ? onKeyDown : undefined} + onfocus={focusable ? onFocus : undefined} tabIndex={focusable ? 0 : undefined} role={focusable ? 'button' : undefined} aria-describedby={store.disableKeyboardA11y