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'; import { page } from '$app/stores';
const routes = [ const routes = [
'a11y',
'add-node-on-drop', 'add-node-on-drop',
'color-mode', 'color-mode',
'custom-connection-line', '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 }); console.log('on selection changed via prop', { nodes, edges });
}} }}
selectNodesOnDrag 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}> <Controls orientation="horizontal" {fitViewOptions}>
{#snippet before()} {#snippet before()}
-1
View File
@@ -14,7 +14,6 @@ import {
NodeOrigin, NodeOrigin,
CoordinateExtent, CoordinateExtent,
fitViewport, fitViewport,
LabelConfig,
} from '@xyflow/system'; } from '@xyflow/system';
import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes'; import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
@@ -1,32 +1,22 @@
<script lang="ts" generics="NodeType extends Node = Node, EdgeType extends Edge = Edge"> <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 { 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 '.'; import { ARIA_EDGE_DESC_KEY, ARIA_LIVE_MESSAGE, ARIA_NODE_DESC_KEY } from '.';
const { store, descriptions = {} }: { let { store }: { store: SvelteFlowStore<NodeType, EdgeType> } = $props();
store: SvelteFlowStore<NodeType, EdgeType>;
descriptions?: Partial<DescriptionsType>;
} = $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> </script>
<div id={`${ARIA_NODE_DESC_KEY}-${store.flowId}`} style="display: none;"> <div id={`${ARIA_NODE_DESC_KEY}-${store.flowId}`} style="display: none;">
{store.disableKeyboardA11y {store.disableKeyboardA11y
? descriptions['a11yDescription.node.default'] || defaultDescriptions['a11yDescription.node.default'] ? store.labelConfig['a11yDescription.node.default']
: descriptions['a11yDescription.node.keyboardDisabled'] || defaultDescriptions['a11yDescription.node.keyboardDisabled']} : store.labelConfig['a11yDescription.node.keyboardDisabled']}
</div> </div>
<div id={`${ARIA_EDGE_DESC_KEY}-${store.flowId}`} style="display: none;"> <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> </div>
{#if !store.disableKeyboardA11y} {#if !store.disableKeyboardA11y}
@@ -38,4 +28,4 @@ const defaultDescriptions = {
> >
{store.ariaLiveMessage} {store.ariaLiveMessage}
</div> </div>
{/if} {/if}
@@ -70,7 +70,6 @@
nodes = $bindable([]), nodes = $bindable([]),
edges = $bindable([]), edges = $bindable([]),
viewport = $bindable(undefined), viewport = $bindable(undefined),
descriptions,
...props ...props
}: SvelteFlowProps<NodeType, EdgeType> & }: SvelteFlowProps<NodeType, EdgeType> &
Omit<HTMLAttributes<HTMLDivElement>, 'onselectionchange'> = $props(); Omit<HTMLAttributes<HTMLDivElement>, 'onselectionchange'> = $props();
@@ -218,6 +217,6 @@
</Pane> </Pane>
</Zoom> </Zoom>
<Attribution {proOptions} position={attributionPosition} /> <Attribution {proOptions} position={attributionPosition} />
<A11yDescriptions {store} descriptions={descriptions} /> <A11yDescriptions {store} />
{@render children?.()} {@render children?.()}
</Wrapper> </Wrapper>
@@ -92,7 +92,7 @@
noDragClass, noDragClass,
noPanClass, noPanClass,
noWheelClass, noWheelClass,
descriptions, labelConfig,
...divAttributes ...divAttributes
} = $derived(rest); } = $derived(rest);
/* eslint-enable @typescript-eslint/no-unused-vars */ /* eslint-enable @typescript-eslint/no-unused-vars */
@@ -21,7 +21,7 @@ import type {
OnReconnect, OnReconnect,
OnReconnectStart, OnReconnectStart,
OnReconnectEnd, OnReconnectEnd,
descriptions LabelConfig
} from '@xyflow/system'; } from '@xyflow/system';
import type { import type {
@@ -476,5 +476,5 @@ export type SvelteFlowProps<
* Custom accessibility messages for screen readers and a11y features. * Custom accessibility messages for screen readers and a11y features.
* Allows localization and customization of ARIA descriptions. * Allows localization and customization of ARIA descriptions.
*/ */
descriptions?: descriptions; labelConfig?: LabelConfig;
}; };
@@ -7,6 +7,7 @@ import {
getViewportForBounds, getViewportForBounds,
updateConnectionLookup, updateConnectionLookup,
initialConnection, initialConnection,
defaultLabelConfig,
type SelectionRect, type SelectionRect,
type SnapGrid, type SnapGrid,
type MarkerProps, type MarkerProps,
@@ -32,7 +33,8 @@ import {
type Handle, type Handle,
type OnReconnect, type OnReconnect,
type OnReconnectStart, type OnReconnectStart,
type OnReconnectEnd type OnReconnectEnd,
type LabelConfig
} from '@xyflow/system'; } from '@xyflow/system';
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte'; 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'); noPanClass: string = $derived(signals.props.noPanClass ?? 'nopan');
noDragClass: string = $derived(signals.props.noDragClass ?? 'nodrag'); noDragClass: string = $derived(signals.props.noDragClass ?? 'nodrag');
noWheelClass: string = $derived(signals.props.noWheelClass ?? 'nowheel'); noWheelClass: string = $derived(signals.props.noWheelClass ?? 'nowheel');
labelConfig: LabelConfig = $derived(signals.props.labelConfig ?? defaultLabelConfig);
// _viewport is the internal viewport. // _viewport is the internal viewport.
// when binding to viewport, we operate on signals.viewport instead // when binding to viewport, we operate on signals.viewport instead