Merge branch 'main' of https://github.com/xyflow/xyflow into 5030-focus-nodes-when-user-selects-via-tab

This commit is contained in:
Abbey Yacoe
2025-06-04 12:00:34 +02:00
41 changed files with 360 additions and 84 deletions
@@ -7,15 +7,12 @@
</script>
<div id={`${ARIA_NODE_DESC_KEY}-${store.flowId}`} class="a11y-hidden">
Press enter or space to select a node.
{#if !store.disableKeyboardA11y}
You can then use the arrow keys to move the node around.
{/if}
Press delete to remove it and escape to cancel.
{store.disableKeyboardA11y
? store.ariaLabelConfig['node.a11yDescription.default']
: store.ariaLabelConfig['node.a11yDescription.keyboardDisabled']}
</div>
<div id={`${ARIA_EDGE_DESC_KEY}-${store.flowId}`} class="a11y-hidden">
Press enter or space to select an edge. You can then press delete to remove it or escape to
cancel.
{store.ariaLabelConfig['edge.a11yDescription.default']}
</div>
{#if !store.disableKeyboardA11y}
@@ -36,7 +36,6 @@
style:width={toPxString(width)}
style:height={toPxString(height)}
style:z-index={z}
role="button"
tabindex="-1"
onclick={() => {
if (selectEdgeOnClick && id) store.handleEdgeSelection(id);
@@ -137,7 +137,8 @@
? ariaLabel
: `Edge from ${source} to ${target}`}
aria-describedby={focusable ? `${ARIA_EDGE_DESC_KEY}-${store.flowId}` : undefined}
role={focusable ? 'button' : 'img'}
role={edge.ariaRole ?? (focusable ? 'group' : 'img')}
aria-roledescription={edge.ariaRoleDescription || 'edge'}
onkeydown={focusable ? onkeydown : undefined}
tabindex={focusable ? 0 : undefined}
>
@@ -44,6 +44,8 @@
);
let store = useStore();
let ariaLabelConfig = $derived(store.ariaLabelConfig);
let prevConnections: Map<string, HandleConnection> | null = null;
$effect.pre(() => {
@@ -227,6 +229,7 @@ The Handle component is the part of a node that can be used to connect nodes.
onkeypress={() => {}}
{style}
role="button"
aria-label={ariaLabelConfig[`handle.ariaLabel`]}
tabindex="-1"
{...rest}
>
@@ -85,6 +85,7 @@
let prevTargetPosition: Position | undefined = targetPosition;
let NodeComponent = $derived(store.nodeTypes[type] ?? DefaultNode);
let ariaLabelConfig = $derived(store.ariaLabelConfig);
let connectableContext: ConnectableContext = {
get value() {
@@ -188,11 +189,11 @@
) {
// prevent default scrolling behavior on arrow key press when node is moved
event.preventDefault();
store.ariaLiveMessage = `Moved selected node ${event.key
.replace('Arrow', '')
.toLowerCase()}. New position, x: ${node.internals.positionAbsolute.x}, y: ${node.internals.positionAbsolute.y}`;
store.ariaLiveMessage = ariaLabelConfig['node.a11yDescription.ariaLiveMessage']({
direction: event.key.replace('Arrow', '').toLowerCase(),
x: ~~node.internals.positionAbsolute.x,
y: ~~node.internals.positionAbsolute.y
});
store.moveSelectedNodes(arrowKeyDiffs[event.key], event.shiftKey ? 4 : 1);
}
}
@@ -274,7 +275,8 @@
onkeydown={focusable ? onKeyDown : undefined}
onfocus={focusable ? onFocus : undefined}
tabIndex={focusable ? 0 : undefined}
role={focusable ? 'button' : undefined}
role={node.ariaRole ?? (focusable ? 'group' : undefined)}
aria-roledescription={node.ariaRoleDescription || 'node'}
aria-describedby={store.disableKeyboardA11y
? undefined
: `${ARIA_NODE_DESC_KEY}-${store.flowId}`}