chore(a11y): pass LabelConfig values through store SvelteFlow

This commit is contained in:
Abbey Yacoe
2025-05-21 14:03:50 +02:00
parent 54fc3c0717
commit 91ecfe73cc
9 changed files with 58 additions and 31 deletions
@@ -3,6 +3,7 @@
import { page } from '$app/stores';
const routes = [
'a11y',
'add-node-on-drop',
'color-mode',
'custom-connection-line',
@@ -0,0 +1,40 @@
<script lang="ts">
import {
SvelteFlow,
Controls,
Background,
MiniMap,
} from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css';
let nodes = $state.raw([
{
id: 'A',
position: { x: 0, y: 0 },
data: { label: 'A' },
},
{ id: 'B', position: { x: -100, y: 150 }, data: { label: 'B' } },
{ id: 'C', position: { x: 100, y: 150 }, data: { label: 'C' } },
{ id: 'D', position: { x: 0, y: 260 }, data: { label: 'D' } }
]);
let edges = $state.raw([
{ id: 'A-B', source: 'A', target: 'B' },
{ id: 'A-C', source: 'A', target: 'C' },
{ id: 'A-D', source: 'A', target: 'D' }
]);
</script>
<SvelteFlow bind:nodes bind:edges fitView labelConfig={{
'a11yDescription.node.default': 'Svelte Custom node description',
'a11yDescription.node.keyboardDisabled': 'Svelte Custom keyboard-disabled node description',
'a11yDescription.edge.default': 'Svelte Custom edge description',
}}>
<Controls />
<Background />
<MiniMap />
</SvelteFlow>
@@ -220,11 +220,6 @@
console.log('on selection changed via prop', { nodes, edges });
}}
selectNodesOnDrag
labelConfig={{
'a11yDescription.node.default': 'Svelte Custom Node Description.',
'a11yDescription.node.keyboardDisabled': 'Svelte Custom Keyboard Description',
'a11yDescription.edge.default': 'Svelte Custom Edge Desc.',
}}
>
<Controls orientation="horizontal" {fitViewOptions}>
{#snippet before()}
-1
View File
@@ -14,7 +14,6 @@ import {
NodeOrigin,
CoordinateExtent,
fitViewport,
LabelConfig,
} from '@xyflow/system';
import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
@@ -1,32 +1,22 @@
<script lang="ts" generics="NodeType extends Node = Node, EdgeType extends Edge = Edge">
import { derived } from 'svelte/store';
import type { SvelteFlowStore } from '$lib/store/types';
import type { descriptions as DescriptionsType } from '@xyflow/system'; // Rename the imported type
import type { Node, Edge } from '$lib/types';
import type { Node, Edge } from '$lib/types';
import { ARIA_EDGE_DESC_KEY, ARIA_LIVE_MESSAGE, ARIA_NODE_DESC_KEY } from '.';
const { store, descriptions = {} }: {
store: SvelteFlowStore<NodeType, EdgeType>;
descriptions?: Partial<DescriptionsType>;
} = $props();
let { store }: { store: SvelteFlowStore<NodeType, EdgeType> } = $props();
const defaultDescriptions = {
'a11yDescription.node.default':
'Press enter or space to select a node. Press delete to remove it and escape to cancel.',
'a11yDescription.node.keyboardDisabled':
'Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.',
'a11yDescription.edge.default':
'Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.',
};
</script>
<div id={`${ARIA_NODE_DESC_KEY}-${store.flowId}`} style="display: none;">
{store.disableKeyboardA11y
? descriptions['a11yDescription.node.default'] || defaultDescriptions['a11yDescription.node.default']
: descriptions['a11yDescription.node.keyboardDisabled'] || defaultDescriptions['a11yDescription.node.keyboardDisabled']}
{store.disableKeyboardA11y
? store.labelConfig['a11yDescription.node.default']
: store.labelConfig['a11yDescription.node.keyboardDisabled']}
</div>
<div id={`${ARIA_EDGE_DESC_KEY}-${store.flowId}`} style="display: none;">
{descriptions['a11yDescription.edge.default'] || defaultDescriptions['a11yDescription.edge.default']}
{store.labelConfig['a11yDescription.edge.default']}
</div>
{#if !store.disableKeyboardA11y}
@@ -38,4 +28,4 @@ const defaultDescriptions = {
>
{store.ariaLiveMessage}
</div>
{/if}
{/if}
@@ -70,7 +70,6 @@
nodes = $bindable([]),
edges = $bindable([]),
viewport = $bindable(undefined),
descriptions,
...props
}: SvelteFlowProps<NodeType, EdgeType> &
Omit<HTMLAttributes<HTMLDivElement>, 'onselectionchange'> = $props();
@@ -218,6 +217,6 @@
</Pane>
</Zoom>
<Attribution {proOptions} position={attributionPosition} />
<A11yDescriptions {store} descriptions={descriptions} />
<A11yDescriptions {store} />
{@render children?.()}
</Wrapper>
@@ -92,7 +92,7 @@
noDragClass,
noPanClass,
noWheelClass,
descriptions,
labelConfig,
...divAttributes
} = $derived(rest);
/* eslint-enable @typescript-eslint/no-unused-vars */
@@ -21,7 +21,7 @@ import type {
OnReconnect,
OnReconnectStart,
OnReconnectEnd,
descriptions
LabelConfig
} from '@xyflow/system';
import type {
@@ -476,5 +476,5 @@ export type SvelteFlowProps<
* Custom accessibility messages for screen readers and a11y features.
* Allows localization and customization of ARIA descriptions.
*/
descriptions?: descriptions;
labelConfig?: LabelConfig;
};
@@ -7,6 +7,7 @@ import {
getViewportForBounds,
updateConnectionLookup,
initialConnection,
defaultLabelConfig,
type SelectionRect,
type SnapGrid,
type MarkerProps,
@@ -32,7 +33,8 @@ import {
type Handle,
type OnReconnect,
type OnReconnectStart,
type OnReconnectEnd
type OnReconnectEnd,
type LabelConfig
} from '@xyflow/system';
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
@@ -289,6 +291,7 @@ export function getInitialStore<NodeType extends Node = Node, EdgeType extends E
noPanClass: string = $derived(signals.props.noPanClass ?? 'nopan');
noDragClass: string = $derived(signals.props.noDragClass ?? 'nodrag');
noWheelClass: string = $derived(signals.props.noWheelClass ?? 'nowheel');
labelConfig: LabelConfig = $derived(signals.props.labelConfig ?? defaultLabelConfig);
// _viewport is the internal viewport.
// when binding to viewport, we operate on signals.viewport instead