diff --git a/packages/core/src/components/A11yDescriptions/index.tsx b/packages/core/src/components/A11yDescriptions/index.tsx
index 5f6f420d..5b019009 100644
--- a/packages/core/src/components/A11yDescriptions/index.tsx
+++ b/packages/core/src/components/A11yDescriptions/index.tsx
@@ -1,12 +1,28 @@
-const style = { display: 'none' };
+import { CSSProperties } from 'react';
+import { useStore } from '../../hooks/useStore';
+import { ReactFlowState } from '../../types';
+
+const style: CSSProperties = { display: 'none' };
+const ariaLiveStyle: CSSProperties = {
+ position: 'absolute',
+ width: 1,
+ height: 1,
+ margin: -1,
+ border: 0,
+ padding: 0,
+ overflow: 'hidden',
+ clip: 'rect(0px, 0px, 0px, 0px)',
+ clipPath: 'inset(100%)',
+};
export const ARIA_NODE_DESC_KEY = 'react-flow__node-desc';
export const ARIA_EDGE_DESC_KEY = 'react-flow__edge-desc';
+export const ARIA_LIVE_MESSAGE = 'react-flow__arai-live';
-function A11yDescriptions({ rfId, disableKeyboardA11y }: { rfId: string; disableKeyboardA11y: boolean }) {
- if (disableKeyboardA11y) {
- return null;
- }
+const selector = (s: ReactFlowState) => s.ariaLiveMessage;
+
+function A11yDescriptions({ rfId }: { rfId: string }) {
+ const ariaLiveMessage = useStore(selector);
return (
<>
@@ -17,6 +33,9 @@ function A11yDescriptions({ rfId, disableKeyboardA11y }: { rfId: string; disable
Press enter or space to select an edge. You can then press delete to remove it or press escape to cancel.
+
+ {ariaLiveMessage}
+
>
);
}
diff --git a/packages/core/src/components/Nodes/wrapNode.tsx b/packages/core/src/components/Nodes/wrapNode.tsx
index 108a3ceb..bdca639b 100644
--- a/packages/core/src/components/Nodes/wrapNode.tsx
+++ b/packages/core/src/components/Nodes/wrapNode.tsx
@@ -91,6 +91,12 @@ export default (NodeComponent: ComponentType) => {
unselect,
});
} else if (selected && Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
+ store.setState({
+ ariaLiveMessage: `Move selected node ten pixels to the ${event.key
+ .replace('Arrow', '')
+ .toLowerCase()}. New position, x: ${xPos}, y: ${yPos}`,
+ });
+
updatePositions(arrowKeyDiffs[event.key]);
}
};
diff --git a/packages/core/src/container/ReactFlow/index.tsx b/packages/core/src/container/ReactFlow/index.tsx
index 4af5484f..224debc3 100644
--- a/packages/core/src/container/ReactFlow/index.tsx
+++ b/packages/core/src/container/ReactFlow/index.tsx
@@ -258,7 +258,7 @@ const ReactFlow = forwardRef(
{onSelectionChange && }
{children}
-
+ {!disableKeyboardA11y && }
);
diff --git a/packages/core/src/hooks/useGlobalKeyHandler.ts b/packages/core/src/hooks/useGlobalKeyHandler.ts
index 01474a5d..151c9786 100644
--- a/packages/core/src/hooks/useGlobalKeyHandler.ts
+++ b/packages/core/src/hooks/useGlobalKeyHandler.ts
@@ -12,7 +12,6 @@ interface HookParams {
export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => {
const store = useStoreApi();
-
const deleteKeyPressed = useKeyPress(deleteKeyCode);
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
diff --git a/packages/core/src/hooks/useOnInitHandler.ts b/packages/core/src/hooks/useOnInitHandler.ts
index 551ed107..8a3a119c 100644
--- a/packages/core/src/hooks/useOnInitHandler.ts
+++ b/packages/core/src/hooks/useOnInitHandler.ts
@@ -4,15 +4,15 @@ import useReactFlow from './useReactFlow';
import { OnInit } from '../types';
function useOnInitHandler(onInit: OnInit | undefined) {
- const ReactFlowInstance = useReactFlow();
+ const rfInstance = useReactFlow();
const isInitialized = useRef(false);
useEffect(() => {
- if (!isInitialized.current && ReactFlowInstance.viewportInitialized && onInit) {
- setTimeout(() => onInit(ReactFlowInstance), 1);
+ if (!isInitialized.current && rfInstance.viewportInitialized && onInit) {
+ setTimeout(() => onInit(rfInstance), 1);
isInitialized.current = true;
}
- }, [onInit, ReactFlowInstance.viewportInitialized]);
+ }, [onInit, rfInstance.viewportInitialized]);
}
export default useOnInitHandler;
diff --git a/packages/core/src/hooks/useUpdateNodeInternals.ts b/packages/core/src/hooks/useUpdateNodeInternals.ts
index bca6b416..dbd1a84d 100644
--- a/packages/core/src/hooks/useUpdateNodeInternals.ts
+++ b/packages/core/src/hooks/useUpdateNodeInternals.ts
@@ -1,16 +1,14 @@
import { useCallback } from 'react';
-import { useStore, useStoreApi } from '../hooks/useStore';
-import { UpdateNodeInternals, ReactFlowState } from '../types';
-
-const selector = (state: ReactFlowState) => state.updateNodeDimensions;
+import { useStoreApi } from '../hooks/useStore';
+import { UpdateNodeInternals } from '../types';
function useUpdateNodeInternals(): UpdateNodeInternals {
const store = useStoreApi();
- const updateNodeDimensions = useStore(selector);
return useCallback((id: string) => {
- const nodeElement = store.getState().domNode?.querySelector(`.react-flow__node[data-id="${id}"]`) as HTMLDivElement;
+ const { domNode, updateNodeDimensions } = store.getState();
+ const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${id}"]`) as HTMLDivElement;
if (nodeElement) {
requestAnimationFrame(() => updateNodeDimensions([{ id, nodeElement, forceUpdate: true }]));
diff --git a/packages/core/src/store/initialState.ts b/packages/core/src/store/initialState.ts
index a40093de..50e52f26 100644
--- a/packages/core/src/store/initialState.ts
+++ b/packages/core/src/store/initialState.ts
@@ -48,6 +48,8 @@ const initialState: ReactFlowStore = {
connectionStartHandle: null,
connectOnClick: true,
+
+ ariaLiveMessage: '',
};
export default initialState;
diff --git a/packages/core/src/types/general.ts b/packages/core/src/types/general.ts
index 44097968..b84e71c4 100644
--- a/packages/core/src/types/general.ts
+++ b/packages/core/src/types/general.ts
@@ -202,6 +202,8 @@ export type ReactFlowStore = {
onViewportChangeEnd?: OnViewportChange;
onSelectionChange?: OnSelectionChangeFunc;
+
+ ariaLiveMessage: string;
};
export type ReactFlowActions = {