Merge pull request #5317 from xyflow/feat/nodes-html-attributes
feat(nodes-edges): add domAttributes
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
'@xyflow/react': minor
|
||||||
|
'@xyflow/svelte': minor
|
||||||
|
'@xyflow/system': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Add `domAttributes` option for nodes and edges
|
||||||
@@ -18,6 +18,11 @@ const initialNodes: Node[] = [
|
|||||||
type: 'input',
|
type: 'input',
|
||||||
data: { label: 'A11y Node 1' },
|
data: { label: 'A11y Node 1' },
|
||||||
position: { x: 250, y: 5 },
|
position: { x: 250, y: 5 },
|
||||||
|
className: 'light',
|
||||||
|
domAttributes: {
|
||||||
|
tabIndex: 10,
|
||||||
|
'aria-roledescription': 'A11y Node',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ export function EdgeWrapper<EdgeType extends Edge = Edge>({
|
|||||||
onKeyDown={isFocusable ? onKeyDown : undefined}
|
onKeyDown={isFocusable ? onKeyDown : undefined}
|
||||||
tabIndex={isFocusable ? 0 : undefined}
|
tabIndex={isFocusable ? 0 : undefined}
|
||||||
role={edge.ariaRole ?? (isFocusable ? 'group' : 'img')}
|
role={edge.ariaRole ?? (isFocusable ? 'group' : 'img')}
|
||||||
aria-roledescription={edge.ariaRoleDescription || 'edge'}
|
aria-roledescription="edge"
|
||||||
data-id={id}
|
data-id={id}
|
||||||
data-testid={`rf__edge-${id}`}
|
data-testid={`rf__edge-${id}`}
|
||||||
aria-label={
|
aria-label={
|
||||||
@@ -207,6 +207,7 @@ export function EdgeWrapper<EdgeType extends Edge = Edge>({
|
|||||||
}
|
}
|
||||||
aria-describedby={isFocusable ? `${ARIA_EDGE_DESC_KEY}-${rfId}` : undefined}
|
aria-describedby={isFocusable ? `${ARIA_EDGE_DESC_KEY}-${rfId}` : undefined}
|
||||||
ref={edgeRef}
|
ref={edgeRef}
|
||||||
|
{...edge.domAttributes}
|
||||||
>
|
>
|
||||||
{!reconnecting && (
|
{!reconnecting && (
|
||||||
<EdgeComponent
|
<EdgeComponent
|
||||||
|
|||||||
@@ -220,9 +220,10 @@ export function NodeWrapper<NodeType extends Node>({
|
|||||||
tabIndex={isFocusable ? 0 : undefined}
|
tabIndex={isFocusable ? 0 : undefined}
|
||||||
onFocus={isFocusable ? onFocus : undefined}
|
onFocus={isFocusable ? onFocus : undefined}
|
||||||
role={node.ariaRole ?? (isFocusable ? 'group' : undefined)}
|
role={node.ariaRole ?? (isFocusable ? 'group' : undefined)}
|
||||||
aria-roledescription={node.ariaRoleDescription || 'node'}
|
aria-roledescription="node"
|
||||||
aria-describedby={disableKeyboardA11y ? undefined : `${ARIA_NODE_DESC_KEY}-${rfId}`}
|
aria-describedby={disableKeyboardA11y ? undefined : `${ARIA_NODE_DESC_KEY}-${rfId}`}
|
||||||
aria-label={node.ariaLabel}
|
aria-label={node.ariaLabel}
|
||||||
|
{...node.domAttributes}
|
||||||
>
|
>
|
||||||
<Provider value={id}>
|
<Provider value={id}>
|
||||||
<NodeComponent
|
<NodeComponent
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ export type Edge<
|
|||||||
* @default "group"
|
* @default "group"
|
||||||
*/
|
*/
|
||||||
ariaRole?: AriaRole;
|
ariaRole?: AriaRole;
|
||||||
|
/**
|
||||||
|
* General escape hatch for adding custom attributes to the edge's DOM element.
|
||||||
|
*/
|
||||||
|
domAttributes?: Omit<SVGAttributes<SVGGElement>, 'id' | 'style' | 'className' | 'role' | 'aria-label'>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SmoothStepEdge<EdgeData extends Record<string, unknown> = Record<string, unknown>> = Edge<
|
type SmoothStepEdge<EdgeData extends Record<string, unknown> = Record<string, unknown>> = Edge<
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { CSSProperties, MouseEvent as ReactMouseEvent, AriaRole } from 'react';
|
import type { CSSProperties, MouseEvent as ReactMouseEvent, AriaRole, HTMLAttributes, DOMAttributes } from 'react';
|
||||||
import type { CoordinateExtent, NodeBase, OnError, NodeProps as NodePropsBase, InternalNodeBase } from '@xyflow/system';
|
import type { CoordinateExtent, NodeBase, OnError, NodeProps as NodePropsBase, InternalNodeBase } from '@xyflow/system';
|
||||||
|
|
||||||
import { NodeTypes } from './general';
|
import { NodeTypes } from './general';
|
||||||
@@ -22,8 +22,15 @@ export type Node<
|
|||||||
* The ARIA role attribute for the node element, used for accessibility.
|
* The ARIA role attribute for the node element, used for accessibility.
|
||||||
* @default "group"
|
* @default "group"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ariaRole?: AriaRole;
|
ariaRole?: AriaRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General escape hatch for adding custom attributes to the node's DOM element.
|
||||||
|
*/
|
||||||
|
domAttributes?: Omit<
|
||||||
|
HTMLAttributes<HTMLDivElement>,
|
||||||
|
'id' | 'style' | 'className' | 'draggable' | 'role' | 'aria-label' | keyof DOMAttributes<HTMLDivElement>
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -138,9 +138,10 @@
|
|||||||
: `Edge from ${source} to ${target}`}
|
: `Edge from ${source} to ${target}`}
|
||||||
aria-describedby={focusable ? `${ARIA_EDGE_DESC_KEY}-${store.flowId}` : undefined}
|
aria-describedby={focusable ? `${ARIA_EDGE_DESC_KEY}-${store.flowId}` : undefined}
|
||||||
role={edge.ariaRole ?? (focusable ? 'group' : 'img')}
|
role={edge.ariaRole ?? (focusable ? 'group' : 'img')}
|
||||||
aria-roledescription={edge.ariaRoleDescription || 'edge'}
|
aria-roledescription="edge"
|
||||||
onkeydown={focusable ? onkeydown : undefined}
|
onkeydown={focusable ? onkeydown : undefined}
|
||||||
tabindex={focusable ? 0 : undefined}
|
tabindex={focusable ? 0 : undefined}
|
||||||
|
{...edge.domAttributes}
|
||||||
>
|
>
|
||||||
<EdgeComponent
|
<EdgeComponent
|
||||||
{id}
|
{id}
|
||||||
|
|||||||
@@ -284,10 +284,11 @@
|
|||||||
onfocus={focusable ? onFocus : undefined}
|
onfocus={focusable ? onFocus : undefined}
|
||||||
tabIndex={focusable ? 0 : undefined}
|
tabIndex={focusable ? 0 : undefined}
|
||||||
role={node.ariaRole ?? (focusable ? 'group' : undefined)}
|
role={node.ariaRole ?? (focusable ? 'group' : undefined)}
|
||||||
aria-roledescription={node.ariaRoleDescription || 'node'}
|
aria-roledescription="node"
|
||||||
aria-describedby={store.disableKeyboardA11y
|
aria-describedby={store.disableKeyboardA11y
|
||||||
? undefined
|
? undefined
|
||||||
: `${ARIA_NODE_DESC_KEY}-${store.flowId}`}
|
: `${ARIA_NODE_DESC_KEY}-${store.flowId}`}
|
||||||
|
{...node.domAttributes}
|
||||||
>
|
>
|
||||||
<NodeComponent
|
<NodeComponent
|
||||||
{data}
|
{data}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { Component } from 'svelte';
|
import type { Component } from 'svelte';
|
||||||
|
import type { ClassValue, HTMLAttributes, SVGAttributes } from 'svelte/elements';
|
||||||
import type {
|
import type {
|
||||||
EdgeBase,
|
EdgeBase,
|
||||||
BezierPathOptions,
|
BezierPathOptions,
|
||||||
@@ -9,7 +10,6 @@ import type {
|
|||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import type { Node } from '$lib/types';
|
import type { Node } from '$lib/types';
|
||||||
import type { ClassValue, HTMLAttributes } from 'svelte/elements';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `Edge` is the complete description with everything Svelte Flow needs to know in order to
|
* An `Edge` is the complete description with everything Svelte Flow needs to know in order to
|
||||||
@@ -30,6 +30,13 @@ export type Edge<
|
|||||||
* @default "group"
|
* @default "group"
|
||||||
*/
|
*/
|
||||||
ariaRole?: HTMLAttributes<HTMLElement>['role'];
|
ariaRole?: HTMLAttributes<HTMLElement>['role'];
|
||||||
|
/**
|
||||||
|
* General escape hatch for adding custom attributes to the edge's DOM element.
|
||||||
|
*/
|
||||||
|
domAttributes?: Omit<
|
||||||
|
SVGAttributes<SVGGElement>,
|
||||||
|
'id' | 'style' | 'class' | 'role' | 'aria-label'
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BaseEdgeProps = Pick<
|
export type BaseEdgeProps = Pick<
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Component } from 'svelte';
|
import type { Component } from 'svelte';
|
||||||
import type { ClassValue, HTMLAttributes } from 'svelte/elements';
|
import type { ClassValue, HTMLAttributes, DOMAttributes } from 'svelte/elements';
|
||||||
import type { InternalNodeBase, NodeBase, NodeProps as NodePropsBase } from '@xyflow/system';
|
import type { InternalNodeBase, NodeBase, NodeProps as NodePropsBase } from '@xyflow/system';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +25,21 @@ export type Node<
|
|||||||
* The ARIA role attribute for the node element, used for accessibility.
|
* The ARIA role attribute for the node element, used for accessibility.
|
||||||
* @default "group"
|
* @default "group"
|
||||||
*/
|
*/
|
||||||
ariaRole?: HTMLAttributes<HTMLElement>['role'];
|
ariaRole?: HTMLAttributes<HTMLDivElement>['role'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General escape hatch for adding custom attributes to the node's DOM element.
|
||||||
|
*/
|
||||||
|
domAttributes?: Omit<
|
||||||
|
HTMLAttributes<HTMLDivElement>,
|
||||||
|
| 'id'
|
||||||
|
| 'style'
|
||||||
|
| 'class'
|
||||||
|
| 'draggable'
|
||||||
|
| 'role'
|
||||||
|
| 'aria-label'
|
||||||
|
| keyof DOMAttributes<HTMLDivElement>
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// @todo: currently generics for nodes are not really supported
|
// @todo: currently generics for nodes are not really supported
|
||||||
|
|||||||
@@ -40,11 +40,6 @@ export type EdgeBase<
|
|||||||
* This property sets the width of that invisible path.
|
* This property sets the width of that invisible path.
|
||||||
*/
|
*/
|
||||||
interactionWidth?: number;
|
interactionWidth?: number;
|
||||||
/**
|
|
||||||
* A description of the edge's, used for accessibility.
|
|
||||||
* @default "edge"
|
|
||||||
*/
|
|
||||||
ariaRoleDescription?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SmoothStepPathOptions = {
|
export type SmoothStepPathOptions = {
|
||||||
|
|||||||
@@ -73,11 +73,6 @@ export type NodeBase<
|
|||||||
*/
|
*/
|
||||||
origin?: NodeOrigin;
|
origin?: NodeOrigin;
|
||||||
handles?: NodeHandle[];
|
handles?: NodeHandle[];
|
||||||
/**
|
|
||||||
* A description of the node's role, used for accessibility.
|
|
||||||
* @default "node"
|
|
||||||
*/
|
|
||||||
ariaRoleDescription?: string;
|
|
||||||
measured?: {
|
measured?: {
|
||||||
width?: number;
|
width?: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user