chore(labelconfig): cleanup
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
|||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
OnNodeDrag,
|
OnNodeDrag,
|
||||||
|
LabelConfig,
|
||||||
} from '@xyflow/react';
|
} from '@xyflow/react';
|
||||||
|
|
||||||
const onNodeDrag: OnNodeDrag = (_, node: Node, nodes: Node[]) => console.log('drag', node, nodes);
|
const onNodeDrag: OnNodeDrag = (_, node: Node, nodes: Node[]) => console.log('drag', node, nodes);
|
||||||
@@ -43,6 +44,20 @@ const initialEdges: Edge[] = [
|
|||||||
{ id: 'e1-3', source: '1', target: '3' },
|
{ id: 'e1-3', source: '1', target: '3' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const labelConfig: Partial<LabelConfig> = {
|
||||||
|
'a11yDescription.node.default': 'Custom Node Desc.',
|
||||||
|
'a11yDescription.node.keyboardDisabled': 'Custom Keyboard Desc.',
|
||||||
|
'a11yDescription.edge.default': 'Custom Edge Desc.',
|
||||||
|
'a11yDescription.ariaLiveMessage': ({ direction, x, y }) =>
|
||||||
|
`Custom Moved selected node ${direction}. New position, x: ${x}, y: ${y}`,
|
||||||
|
'controls.ariaLabel': 'Custom Controls Aria Label',
|
||||||
|
'controls.zoomin.title': 'Custom Zoom in',
|
||||||
|
'controls.zoomout.title': 'Custom Zoom Out',
|
||||||
|
// 'controls.fitview.title': 'Custom Fit View',
|
||||||
|
'controls.interactive.title': 'Custom Toggle Interactivity',
|
||||||
|
'minimap.ariaLabel': 'Custom Aria Label',
|
||||||
|
};
|
||||||
|
|
||||||
const A11y = () => {
|
const A11y = () => {
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@@ -61,19 +76,7 @@ const A11y = () => {
|
|||||||
elevateEdgesOnSelect
|
elevateEdgesOnSelect
|
||||||
elevateNodesOnSelect={false}
|
elevateNodesOnSelect={false}
|
||||||
nodeDragThreshold={0}
|
nodeDragThreshold={0}
|
||||||
labelConfig={{
|
labelConfig={labelConfig}
|
||||||
'a11yDescription.node.default': 'Custom Node Desc.',
|
|
||||||
'a11yDescription.node.keyboardDisabled': 'Custom Keyboard Desc.',
|
|
||||||
'a11yDescription.edge.default': 'Custom Edge Desc.',
|
|
||||||
'a11yDescription.ariaLiveMessage': (node: string, x: number, y: number) =>
|
|
||||||
`Custom Moved selected node ${node}. New position, x: ${x}, y: ${y}`,
|
|
||||||
'controls.ariaLabel': 'Custom Controls Aria Label',
|
|
||||||
'controls.zoomin.title': 'Custom Zoom in',
|
|
||||||
'controls.zoomout.title': 'Custom Zoom Out',
|
|
||||||
// 'controls.fitview.title': 'Custom Fit View',
|
|
||||||
'controls.interactive.title': 'Custom Toggle Interactivity',
|
|
||||||
'minimap.ariaLabel': 'Custom Aria Label',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Background variant={BackgroundVariant.Dots} />
|
<Background variant={BackgroundVariant.Dots} />
|
||||||
<MiniMap />
|
<MiniMap />
|
||||||
|
|||||||
@@ -1,24 +1,17 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import { SvelteFlow, Controls, Background, MiniMap } from '@xyflow/svelte';
|
||||||
SvelteFlow,
|
|
||||||
Controls,
|
|
||||||
Background,
|
|
||||||
MiniMap,
|
|
||||||
} from '@xyflow/svelte';
|
|
||||||
|
|
||||||
import '@xyflow/svelte/dist/style.css';
|
import '@xyflow/svelte/dist/style.css';
|
||||||
|
|
||||||
|
|
||||||
let nodes = $state.raw([
|
let nodes = $state.raw([
|
||||||
{
|
{
|
||||||
id: 'A',
|
id: 'A',
|
||||||
position: { x: 0, y: 0 },
|
position: { x: 0, y: 0 },
|
||||||
data: { label: 'A' },
|
data: { label: 'A' }
|
||||||
|
|
||||||
},
|
},
|
||||||
{ id: 'B', position: { x: -100, y: 150 }, data: { label: 'B' } },
|
{ id: 'B', position: { x: -100, y: 150 }, data: { label: 'B' } },
|
||||||
{ id: 'C', position: { x: 100, y: 150 }, data: { label: 'C' } },
|
{ id: 'C', position: { x: 100, y: 150 }, data: { label: 'C' } },
|
||||||
{ id: 'D', position: { x: 0, y: 260 }, data: { label: 'D' } }
|
{ id: 'D', position: { x: 0, y: 260 }, data: { label: 'D' } }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let edges = $state.raw([
|
let edges = $state.raw([
|
||||||
@@ -26,25 +19,24 @@
|
|||||||
{ id: 'A-C', source: 'A', target: 'C' },
|
{ id: 'A-C', source: 'A', target: 'C' },
|
||||||
{ id: 'A-D', source: 'A', target: 'D' }
|
{ id: 'A-D', source: 'A', target: 'D' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SvelteFlow
|
<SvelteFlow
|
||||||
bind:nodes
|
bind:nodes
|
||||||
bind:edges
|
bind:edges
|
||||||
fitView
|
fitView
|
||||||
labelConfig={{
|
labelConfig={{
|
||||||
'a11yDescription.node.default': 'Svelte Custom Node Desc.',
|
'a11yDescription.node.default': 'Svelte Custom Node Desc.',
|
||||||
'a11yDescription.node.keyboardDisabled': 'Svelte Custom Keyboard Desc.',
|
'a11yDescription.node.keyboardDisabled': 'Svelte Custom Keyboard Desc.',
|
||||||
'a11yDescription.edge.default': 'Svelte Custom Edge Desc.',
|
'a11yDescription.edge.default': 'Svelte Custom Edge Desc.',
|
||||||
'a11yDescription.ariaLiveMessage': (node: string, x: number, y: number) =>
|
'a11yDescription.ariaLiveMessage': ({ direction, x, y }) =>
|
||||||
`Custom Moved selected node ${node}. New position, x: ${x}, y: ${y}`,
|
`Custom Moved selected node ${direction}. New position, x: ${x}, y: ${y}`,
|
||||||
'controls.ariaLabel': 'Svelte Custom Control Aria Label',
|
'controls.ariaLabel': 'Svelte Custom Control Aria Label',
|
||||||
'controls.zoomin.title': 'Svelte Custom Zoom in',
|
'controls.zoomin.title': 'Svelte Custom Zoom in',
|
||||||
'controls.zoomout.title': 'Svelte Custom Zoom Out',
|
'controls.zoomout.title': 'Svelte Custom Zoom Out',
|
||||||
// 'controls.fitview.title': 'Svelte Custom Fit View',
|
// 'controls.fitview.title': 'Svelte Custom Fit View',
|
||||||
'controls.interactive.title': 'Svelte Custom Toggle Interactivity',
|
'controls.interactive.title': 'Svelte Custom Toggle Interactivity',
|
||||||
'minimap.ariaLabel': 'Svelte Custom Minimap',
|
'minimap.ariaLabel': 'Svelte Custom Minimap'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Controls />
|
<Controls />
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ function ControlsComponent({
|
|||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const { isInteractive, minZoomReached, maxZoomReached, labelConfig } = useStore(selector, shallow);
|
const { isInteractive, minZoomReached, maxZoomReached, labelConfig } = useStore(selector, shallow);
|
||||||
const { zoomIn, zoomOut, fitView } = useReactFlow();
|
const { zoomIn, zoomOut, fitView } = useReactFlow();
|
||||||
const effectiveAriaLabel = ariaLabel ?? labelConfig['controls.ariaLabel'];
|
|
||||||
|
|
||||||
const onZoomInHandler = () => {
|
const onZoomInHandler = () => {
|
||||||
zoomIn();
|
zoomIn();
|
||||||
@@ -75,7 +74,7 @@ function ControlsComponent({
|
|||||||
position={position}
|
position={position}
|
||||||
style={style}
|
style={style}
|
||||||
data-testid="rf__controls"
|
data-testid="rf__controls"
|
||||||
aria-label={effectiveAriaLabel}
|
aria-label={ariaLabel ?? labelConfig['controls.ariaLabel']}
|
||||||
>
|
>
|
||||||
{showZoom && (
|
{showZoom && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ function MiniMapComponent<NodeType extends Node = Node>({
|
|||||||
}, [])
|
}, [])
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const effectiveAriaLabel = ariaLabel ?? labelConfig['minimap.ariaLabel'];
|
const _ariaLabel = ariaLabel ?? labelConfig['minimap.ariaLabel'];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Panel
|
<Panel
|
||||||
@@ -164,7 +164,7 @@ function MiniMapComponent<NodeType extends Node = Node>({
|
|||||||
ref={svg}
|
ref={svg}
|
||||||
onClick={onSvgClick}
|
onClick={onSvgClick}
|
||||||
>
|
>
|
||||||
{effectiveAriaLabel && <title id={labelledBy}>{effectiveAriaLabel}</title>}
|
{_ariaLabel && <title id={labelledBy}>{_ariaLabel}</title>}
|
||||||
|
|
||||||
<MiniMapNodes<NodeType>
|
<MiniMapNodes<NodeType>
|
||||||
onClick={onSvgNodeClick}
|
onClick={onSvgNodeClick}
|
||||||
|
|||||||
@@ -144,11 +144,11 @@ export function NodeWrapper<NodeType extends Node>({
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
store.setState({
|
store.setState({
|
||||||
ariaLiveMessage: labelConfig['a11yDescription.ariaLiveMessage'](
|
ariaLiveMessage: labelConfig['a11yDescription.ariaLiveMessage']({
|
||||||
event.key.replace('Arrow', '').toLowerCase(),
|
direction: event.key.replace('Arrow', '').toLowerCase(),
|
||||||
~~internals.positionAbsolute.x,
|
x: ~~internals.positionAbsolute.x,
|
||||||
~~internals.positionAbsolute.y
|
y: ~~internals.positionAbsolute.y,
|
||||||
),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
moveSelectedNodes({
|
moveSelectedNodes({
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ export {
|
|||||||
type NoConnection,
|
type NoConnection,
|
||||||
type NodeConnection,
|
type NodeConnection,
|
||||||
type OnReconnect,
|
type OnReconnect,
|
||||||
|
type LabelConfig,
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
// we need this workaround to prevent a duplicate identifier error
|
// we need this workaround to prevent a duplicate identifier error
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<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 { 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 '.';
|
||||||
@@ -8,12 +7,12 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id={`${ARIA_NODE_DESC_KEY}-${store.flowId}`} class="a11y-hidden">
|
<div id={`${ARIA_NODE_DESC_KEY}-${store.flowId}`} class="a11y-hidden">
|
||||||
{store.disableKeyboardA11y
|
{store.disableKeyboardA11y
|
||||||
? store.labelConfig['a11yDescription.node.default']
|
? store.labelConfig['a11yDescription.node.default']
|
||||||
: store.labelConfig['a11yDescription.node.keyboardDisabled']}
|
: store.labelConfig['a11yDescription.node.keyboardDisabled']}
|
||||||
</div>
|
</div>
|
||||||
<div id={`${ARIA_EDGE_DESC_KEY}-${store.flowId}`} class="a11y-hidden">
|
<div id={`${ARIA_EDGE_DESC_KEY}-${store.flowId}`} class="a11y-hidden">
|
||||||
{store.labelConfig['a11yDescription.edge.default']}
|
{store.labelConfig['a11yDescription.edge.default']}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if !store.disableKeyboardA11y}
|
{#if !store.disableKeyboardA11y}
|
||||||
|
|||||||
@@ -189,12 +189,11 @@
|
|||||||
) {
|
) {
|
||||||
// prevent default scrolling behavior on arrow key press when node is moved
|
// prevent default scrolling behavior on arrow key press when node is moved
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
store.ariaLiveMessage = labelConfig['a11yDescription.ariaLiveMessage'](
|
store.ariaLiveMessage = labelConfig['a11yDescription.ariaLiveMessage']({
|
||||||
event.key.replace('Arrow', '').toLowerCase(),
|
direction: event.key.replace('Arrow', '').toLowerCase(),
|
||||||
~~node.internals.positionAbsolute.x,
|
x: ~~node.internals.positionAbsolute.x,
|
||||||
~~node.internals.positionAbsolute.y
|
y: ~~node.internals.positionAbsolute.y
|
||||||
),
|
});
|
||||||
|
|
||||||
store.moveSelectedNodes(arrowKeyDiffs[event.key], event.shiftKey ? 4 : 1);
|
store.moveSelectedNodes(arrowKeyDiffs[event.key], event.shiftKey ? 4 : 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,5 +476,5 @@ export type SvelteFlowProps<
|
|||||||
* Configuration for customizable labels, descriptions, and UI text. Provided keys will override the corresponding defaults.
|
* Configuration for customizable labels, descriptions, and UI text. Provided keys will override the corresponding defaults.
|
||||||
* Allows localization, customization of ARIA descriptions, control labels, minimap labels, and other UI strings.
|
* Allows localization, customization of ARIA descriptions, control labels, minimap labels, and other UI strings.
|
||||||
*/
|
*/
|
||||||
labelConfig?: LabelConfig;
|
labelConfig?: Partial<LabelConfig>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ export {
|
|||||||
type ResizeParamsWithDirection,
|
type ResizeParamsWithDirection,
|
||||||
type ResizeDragEvent,
|
type ResizeDragEvent,
|
||||||
type IsValidConnection,
|
type IsValidConnection,
|
||||||
type NodeConnection
|
type NodeConnection,
|
||||||
|
type LabelConfig
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
// system utils
|
// system utils
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ export const defaultLabelConfig = {
|
|||||||
'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.',
|
'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':
|
'a11yDescription.edge.default':
|
||||||
'Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.',
|
'Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.',
|
||||||
'a11yDescription.ariaLiveMessage': (node: string, x: number, y: number) =>
|
'a11yDescription.ariaLiveMessage': ({ direction, x, y }: { direction: string; x: number; y: number }) =>
|
||||||
`Moved selected node ${node}. New position, x: ${x}, y: ${y}`,
|
`Moved selected node ${direction}. New position, x: ${x}, y: ${y}`,
|
||||||
|
|
||||||
// Control elements
|
// Control elements
|
||||||
'controls.ariaLabel': 'Control Panel',
|
'controls.ariaLabel': 'Control Panel',
|
||||||
@@ -61,4 +61,4 @@ export const defaultLabelConfig = {
|
|||||||
'handle.ariaLabel': 'Handle',
|
'handle.ariaLabel': 'Handle',
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LabelConfig = Required<typeof defaultLabelConfig>;
|
export type LabelConfig = typeof defaultLabelConfig;
|
||||||
|
|||||||
Reference in New Issue
Block a user