diff --git a/examples/react/src/examples/A11y/index.tsx b/examples/react/src/examples/A11y/index.tsx index daf3ce47..344a20e4 100644 --- a/examples/react/src/examples/A11y/index.tsx +++ b/examples/react/src/examples/A11y/index.tsx @@ -78,8 +78,6 @@ const A11y = () => { ({ id, @@ -81,8 +80,6 @@ export function NodeWrapper({ nodeClickDistance, }); const moveSelectedNodes = useMoveSelectedNodes(); - const { fitView } = useReactFlow(); - const { getViewport } = useReactFlow(); if (node.hidden) { return null; @@ -165,26 +162,17 @@ export function NodeWrapper({ }; const onFocus = () => { - if (disableKeyboardA11y || !enablePanOnFocus) { + if (disableKeyboardA11y || !enablePanOnFocus || !nodeRef.current?.matches(':focus-visible')) { return; } - if (!nodeRef.current?.matches(':focus-visible')) { - return; - } + const { transform, width, height, setCenter } = store.getState(); + const withinViewport = + getNodesInside(new Map([[id, node]]), { x: 0, y: 0, width, height }, transform, true).length > 0; - const { transform, width, height } = store.getState(); - const visibleNodes = getNodesInside(new Map([[id, node]]), { x: 0, y: 0, width, height }, transform, true); - - const isNodeVisible = visibleNodes.length > 0; - - if (!isNodeVisible) { - const zoomLevel = transform[2]; - fitView({ - nodes: [{ id }], - duration: 100, - minZoom: zoomLevel, - maxZoom: zoomLevel, + if (!withinViewport) { + setCenter(node.position.x + nodeDimensions.width / 2, node.position.y + nodeDimensions.height / 2, { + zoom: transform[2], }); } }; diff --git a/packages/react/src/hooks/useViewportHelper.ts b/packages/react/src/hooks/useViewportHelper.ts index fc01a150..eee97484 100644 --- a/packages/react/src/hooks/useViewportHelper.ts +++ b/packages/react/src/hooks/useViewportHelper.ts @@ -63,25 +63,7 @@ const useViewportHelper = (): ViewportHelperFunctions => { return { x, y, zoom }; }, setCenter: async (x, y, options) => { - const { width, height, maxZoom, panZoom } = store.getState(); - const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom; - const centerX = width / 2 - x * nextZoom; - const centerY = height / 2 - y * nextZoom; - - if (!panZoom) { - return Promise.resolve(false); - } - - await panZoom.setViewport( - { - x: centerX, - y: centerY, - zoom: nextZoom, - }, - { duration: options?.duration, ease: options?.ease, interpolate: options?.interpolate } - ); - - return Promise.resolve(true); + return store.getState().setCenter(x, y, options); }, fitBounds: async (bounds, options) => { const { width, height, minZoom, maxZoom, panZoom } = store.getState(); diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 39702bd0..085f8b1e 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -360,6 +360,26 @@ const createStore = ({ return panBySystem({ delta, panZoom, transform, translateExtent, width, height }); }, + setCenter: async (x, y, options) => { + const { width, height, maxZoom, panZoom } = get(); + + if (!panZoom) { + return Promise.resolve(false); + } + + const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom; + + await panZoom.setViewport( + { + x: width / 2 - x * nextZoom, + y: height / 2 - y * nextZoom, + zoom: nextZoom, + }, + { duration: options?.duration, ease: options?.ease, interpolate: options?.interpolate } + ); + + return Promise.resolve(true); + }, cancelConnection: () => { set({ connection: { ...initialConnection }, diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index 25d8f42e..fd9eb91e 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -29,6 +29,7 @@ import { type EdgeChange, type ParentLookup, type AriaLabelConfig, + SetCenter, } from '@xyflow/system'; import type { @@ -172,6 +173,7 @@ export type ReactFlowActions = { triggerNodeChanges: (changes: NodeChange[]) => void; triggerEdgeChanges: (changes: EdgeChange[]) => void; panBy: PanBy; + setCenter: SetCenter; setPaneClickDistance: (distance: number) => void; }; diff --git a/tooling/eslint-config/src/index.js b/tooling/eslint-config/src/index.js index 60f82b0e..0a80797e 100644 --- a/tooling/eslint-config/src/index.js +++ b/tooling/eslint-config/src/index.js @@ -36,7 +36,6 @@ module.exports = { projectService: true, }, rules: { - '@typescript-eslint/no-deprecated': 'error', '@typescript-eslint/no-unnecessary-type-assertion': 'error', }, },