feat(nodes-edges): add zIndexMode

This commit is contained in:
moklick
2025-11-13 10:28:56 +01:00
parent 57a2134b52
commit d59707f4f2
10 changed files with 80 additions and 23 deletions

View File

@@ -4,7 +4,7 @@ import { Provider } from '../../contexts/StoreContext';
import { createStore } from '../../store';
import { BatchProvider } from '../BatchProvider';
import type { Node, Edge, FitViewOptions } from '../../types';
import { CoordinateExtent, NodeOrigin } from '@xyflow/system';
import { CoordinateExtent, NodeOrigin, ZIndexMode } from '@xyflow/system';
export type ReactFlowProviderProps = {
/** These nodes are used to initialize the flow. They are not dynamic. */
@@ -48,6 +48,7 @@ export type ReactFlowProviderProps = {
*/
nodeExtent?: CoordinateExtent;
children: ReactNode;
zIndexMode?: ZIndexMode;
};
/**
@@ -97,6 +98,7 @@ export function ReactFlowProvider({
fitView,
nodeOrigin,
nodeExtent,
zIndexMode,
children,
}: ReactFlowProviderProps) {
const [store] = useState(() =>
@@ -113,6 +115,7 @@ export function ReactFlowProvider({
fitViewOptions,
nodeOrigin,
nodeExtent,
zIndexMode,
})
);

View File

@@ -70,6 +70,7 @@ const reactFlowFieldsToTrack = [
'debug',
'autoPanSpeed',
'ariaLabelConfig',
'zIndexMode',
] as const;
type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number];

View File

@@ -3,7 +3,7 @@ import { useContext, type ReactNode } from 'react';
import StoreContext from '../../contexts/StoreContext';
import { ReactFlowProvider } from '../../components/ReactFlowProvider';
import type { Node, Edge, FitViewOptions } from '../../types';
import { CoordinateExtent, NodeOrigin } from '@xyflow/system';
import { CoordinateExtent, NodeOrigin, ZIndexMode } from '@xyflow/system';
export function Wrapper({
children,
@@ -19,6 +19,7 @@ export function Wrapper({
maxZoom,
nodeOrigin,
nodeExtent,
zIndexMode,
}: {
children: ReactNode;
nodes?: Node[];
@@ -33,6 +34,7 @@ export function Wrapper({
maxZoom?: number;
nodeOrigin?: NodeOrigin;
nodeExtent?: CoordinateExtent;
zIndexMode?: ZIndexMode;
}) {
const isWrapped = useContext(StoreContext);
@@ -58,6 +60,7 @@ export function Wrapper({
initialMaxZoom={maxZoom}
nodeOrigin={nodeOrigin}
nodeExtent={nodeExtent}
zIndexMode={zIndexMode}
>
{children}
</ReactFlowProvider>

View File

@@ -148,6 +148,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
debug,
onScroll,
ariaLabelConfig,
zIndexMode,
...rest
}: ReactFlowProps<NodeType, EdgeType>,
ref: ForwardedRef<HTMLDivElement>
@@ -186,6 +187,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
maxZoom={maxZoom}
nodeOrigin={nodeOrigin}
nodeExtent={nodeExtent}
zIndexMode={zIndexMode}
>
<GraphView<NodeType, EdgeType>
onInit={onInit}
@@ -311,6 +313,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
onBeforeDelete={onBeforeDelete}
debug={debug}
ariaLabelConfig={ariaLabelConfig}
zIndexMode={zIndexMode}
/>
<SelectionListener<NodeType, EdgeType> onSelectionChange={onSelectionChange} />
{children}

View File

@@ -14,6 +14,7 @@ import {
NodeOrigin,
CoordinateExtent,
fitViewport,
ZIndexMode,
} from '@xyflow/system';
import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
@@ -33,6 +34,7 @@ const createStore = ({
maxZoom,
nodeOrigin,
nodeExtent,
zIndexMode,
}: {
nodes?: Node[];
edges?: Edge[];
@@ -46,6 +48,7 @@ const createStore = ({
maxZoom?: number;
nodeOrigin?: NodeOrigin;
nodeExtent?: CoordinateExtent;
zIndexMode?: ZIndexMode;
}) =>
createWithEqualityFn<ReactFlowState>((set, get) => {
async function resolveFitView() {
@@ -89,9 +92,10 @@ const createStore = ({
nodeExtent,
defaultNodes,
defaultEdges,
zIndexMode,
}),
setNodes: (nodes: Node[]) => {
const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued } = get();
const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued, zIndexMode } = get();
/*
* setNodes() is called exclusively in response to user actions:
* - either when the `<ReactFlow nodes>` prop is updated in the controlled ReactFlow setup,
@@ -106,6 +110,7 @@ const createStore = ({
nodeExtent,
elevateNodesOnSelect,
checkEquality: true,
zIndexMode,
});
if (fitViewQueued && nodesInitialized) {
@@ -140,8 +145,17 @@ const createStore = ({
* new dimensions and update the nodes.
*/
updateNodeInternals: (updates) => {
const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug, fitViewQueued } =
get();
const {
triggerNodeChanges,
nodeLookup,
parentLookup,
domNode,
nodeOrigin,
nodeExtent,
debug,
fitViewQueued,
zIndexMode,
} = get();
const { changes, updatedInternals } = updateNodeInternalsSystem(
updates,
@@ -149,14 +163,15 @@ const createStore = ({
parentLookup,
domNode,
nodeOrigin,
nodeExtent
nodeExtent,
zIndexMode
);
if (!updatedInternals) {
return;
}
updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent });
updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent, zIndexMode });
if (fitViewQueued) {
resolveFitView();
@@ -332,7 +347,7 @@ const createStore = ({
triggerEdgeChanges(edgeChanges);
},
setNodeExtent: (nextNodeExtent) => {
const { nodes, nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, nodeExtent } = get();
const { nodes, nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, nodeExtent, zIndexMode } = get();
if (
nextNodeExtent[0][0] === nodeExtent[0][0] &&
@@ -348,6 +363,7 @@ const createStore = ({
nodeExtent: nextNodeExtent,
elevateNodesOnSelect,
checkEquality: false,
zIndexMode,
});
set({ nodeExtent: nextNodeExtent });

View File

@@ -11,6 +11,7 @@ import {
initialConnection,
CoordinateExtent,
defaultAriaLabelConfig,
ZIndexMode,
} from '@xyflow/system';
import type { Edge, FitViewOptions, InternalNode, Node, ReactFlowStore } from '../types';
@@ -28,6 +29,7 @@ const getInitialState = ({
maxZoom = 2,
nodeOrigin,
nodeExtent,
zIndexMode = 'auto',
}: {
nodes?: Node[];
edges?: Edge[];
@@ -41,6 +43,7 @@ const getInitialState = ({
maxZoom?: number;
nodeOrigin?: NodeOrigin;
nodeExtent?: CoordinateExtent;
zIndexMode?: ZIndexMode;
} = {}): ReactFlowStore => {
const nodeLookup = new Map<string, InternalNode>();
const parentLookup = new Map();
@@ -146,6 +149,7 @@ const getInitialState = ({
lib: 'react',
debug: false,
ariaLabelConfig: defaultAriaLabelConfig,
zIndexMode,
};
};

View File

@@ -23,6 +23,7 @@ import type {
OnReconnect,
AriaLabelConfig,
FinalConnectionState,
ZIndexMode,
} from '@xyflow/system';
import type {
@@ -691,4 +692,5 @@ export interface ReactFlowProps<NodeType extends Node = Node, EdgeType extends E
* Allows localization, customization of ARIA descriptions, control labels, minimap labels, and other UI strings.
*/
ariaLabelConfig?: Partial<AriaLabelConfig>;
zIndexMode?: ZIndexMode;
}

View File

@@ -30,6 +30,7 @@ import {
type ParentLookup,
type AriaLabelConfig,
SetCenter,
ZIndexMode,
} from '@xyflow/system';
import type {
@@ -152,6 +153,8 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
lib: string;
debug: boolean;
ariaLabelConfig: AriaLabelConfig;
zIndexMode: ZIndexMode;
};
export type ReactFlowActions<NodeType extends Node, EdgeType extends Edge> = {