From ffbbc35fe97858950d60aaf9237b26fceb34feb3 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Sun, 18 Dec 2022 21:11:47 +0100 Subject: [PATCH] feat(core,edges): add a11y to edge wrapper Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .../core/src/components/Edges/EdgeWrapper.ts | 41 ++++++++++++++++--- .../container/EdgeRenderer/EdgeRenderer.vue | 3 ++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/packages/core/src/components/Edges/EdgeWrapper.ts b/packages/core/src/components/Edges/EdgeWrapper.ts index 1a7eed61..c81e8a79 100644 --- a/packages/core/src/components/Edges/EdgeWrapper.ts +++ b/packages/core/src/components/Edges/EdgeWrapper.ts @@ -7,6 +7,7 @@ interface Props { type: EdgeComponent | Function | Object | false name: string selectable?: boolean + focusable?: boolean updatable?: EdgeUpdatable edge: GraphEdge sourceNode: GraphNode @@ -14,10 +15,20 @@ interface Props { } const EdgeWrapper = defineComponent({ - props: ['name', 'type', 'id', 'updatable', 'selectable', 'edge', 'sourceNode', 'targetNode'], + props: ['name', 'type', 'id', 'updatable', 'selectable', 'focusable', 'edge', 'sourceNode', 'targetNode'], setup(props: Props) { - const { addSelectedEdges, connectionMode, edgeUpdaterRadius, emits, nodesSelectionActive, getEdges, getEdgeTypes } = - useVueFlow() + const { + id: vueFlowId, + addSelectedEdges, + connectionMode, + edgeUpdaterRadius, + emits, + nodesSelectionActive, + getEdges, + getEdgeTypes, + removeSelectedEdges, + findEdge, + } = useVueFlow() const hooks = useEdgeHooks(props.edge, emits) @@ -32,7 +43,7 @@ const EdgeWrapper = defineComponent({ const elementEdgeUpdaterType = ref('source') const mouseEvent = ref() - const edgeEl = ref() + const edgeEl = ref() provide(EdgeId, props.id) provide(EdgeRef, edgeEl) @@ -103,6 +114,19 @@ const EdgeWrapper = defineComponent({ handleEdgeUpdater(event, false) } + const onKeyDown = (event: KeyboardEvent) => { + if (elementSelectionKeys.includes(event.key) && props.selectable) { + const unselect = event.key === 'Escape' + + if (unselect) { + edgeEl.value?.blur() + removeSelectedEdges([findEdge(props.id)!]) + } else { + addSelectedEdges([findEdge(props.id)!]) + } + } + } + return () => { if (!props.sourceNode || !props.targetNode) return null @@ -162,6 +186,11 @@ const EdgeWrapper = defineComponent({ 'onMouseenter': onEdgeMouseEnter, 'onMousemove': onEdgeMouseMove, 'onMouseleave': onEdgeMouseLeave, + 'onKeyDown': props.focusable ? onKeyDown : undefined, + 'tabIndex': props.focusable ? 0 : undefined, + 'aria-label': edge.ariaLabel === null ? undefined : edge.ariaLabel || `Edge from ${edge.source} to ${edge.target}`, + 'aria-describedby': props.focusable ? `${ARIA_EDGE_DESC_KEY}-${vueFlowId}` : undefined, + 'role': props.focusable ? 'button' : undefined, }, [ updating @@ -185,8 +214,8 @@ const EdgeWrapper = defineComponent({ data: edge.data, events: { ...edge.events, ...hooks.on }, style: edgeStyle, - markerStart: `url(#${getMarkerId(edge.markerStart)})`, - markerEnd: `url(#${getMarkerId(edge.markerEnd)})`, + markerStart: `url(#${getMarkerId(edge.markerStart, vueFlowId)})`, + markerEnd: `url(#${getMarkerId(edge.markerEnd, vueFlowId)})`, sourcePosition, targetPosition, sourceX, diff --git a/packages/core/src/container/EdgeRenderer/EdgeRenderer.vue b/packages/core/src/container/EdgeRenderer/EdgeRenderer.vue index 1557bf02..4768a49c 100644 --- a/packages/core/src/container/EdgeRenderer/EdgeRenderer.vue +++ b/packages/core/src/container/EdgeRenderer/EdgeRenderer.vue @@ -15,6 +15,7 @@ const { connectionStartHandle, nodesConnectable, edgesUpdatable, + edgesFocusable, elementsSelectable, getSelectedNodes, getSelectedEdges, @@ -32,6 +33,8 @@ const selectable = (s?: boolean) => (typeof s === 'undefined' ? elementsSelectab const updatable = (u?: EdgeUpdatable) => (typeof u === 'undefined' ? edgesUpdatable : u) +const focusable = (f?: boolean) => (typeof f === 'undefined' ? edgesFocusable : f) + const sourceNode = $( controlledComputed( () => connectionStartHandle?.nodeId,