refactor(node-renderer): simplify selectors, remove reselect, cleanup
This commit is contained in:
@@ -64,7 +64,6 @@ const StressFlow = () => {
|
||||
minZoom={0.2}
|
||||
fitView
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
"d3-drag": "^3.0.0",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0",
|
||||
"reselect": "^4.1.8",
|
||||
"zustand": "^4.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,30 +1,18 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ComponentType, memo, MouseEvent } from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { ComponentType, memo } from 'react';
|
||||
import { NodeOrigin, getNodePositionWithOrigin } from '@xyflow/system';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { useStore } from '../../hooks/useStore';
|
||||
import type { ReactFlowState } from '../../types';
|
||||
import MiniMapNode from './MiniMapNode';
|
||||
import type { MiniMapNodes as MiniMapNodesProps, GetMiniMapNodeAttribute, MiniMapNodeProps } from './types';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
declare const window: any;
|
||||
|
||||
const selector = (s: ReactFlowState) => s.nodeOrigin;
|
||||
const selectorNodeIds = createSelector(
|
||||
[(s: ReactFlowState) => s.nodes],
|
||||
(nodes) =>
|
||||
nodes
|
||||
.filter((node) => !node.hidden && (node.computed?.width || node.width) && (node.computed?.height || node.height))
|
||||
.map((node) => node.id),
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: shallow,
|
||||
},
|
||||
}
|
||||
);
|
||||
const selectorNodeIds = (s: ReactFlowState) => s.nodes.map((node) => node.id);
|
||||
const getAttrFunction = (func: any): GetMiniMapNodeAttribute => (func instanceof Function ? func : () => func);
|
||||
|
||||
function MiniMapNodes({
|
||||
@@ -38,7 +26,7 @@ function MiniMapNodes({
|
||||
nodeComponent: NodeComponent = MiniMapNode,
|
||||
onClick,
|
||||
}: MiniMapNodesProps) {
|
||||
const nodes = useStore(selectorNodeIds);
|
||||
const nodeIds = useStore(selectorNodeIds, shallow);
|
||||
const nodeOrigin = useStore(selector);
|
||||
const nodeColorFunc = getAttrFunction(nodeColor);
|
||||
const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor);
|
||||
@@ -48,7 +36,7 @@ function MiniMapNodes({
|
||||
|
||||
return (
|
||||
<>
|
||||
{nodes.map((nodeId) => (
|
||||
{nodeIds.map((nodeId) => (
|
||||
// The split of responsibilities between MiniMapNodes and
|
||||
// NodeComponentWrapper may appear weird. However, it’s designed to
|
||||
// minimize the cost of updates when individual nodes change.
|
||||
@@ -96,16 +84,16 @@ const NodeComponentWrapper = memo(function NodeComponentWrapper({
|
||||
shapeRendering: string;
|
||||
}) {
|
||||
const node = useStore((s) => s.nodeLookup.get(id));
|
||||
if (!node) {
|
||||
if (!node || node.hidden || !(node.computed?.width || node.width) || !(node.computed?.height || node.height)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { x, y } = getNodePositionWithOrigin(node, node.origin || nodeOrigin).positionAbsolute;
|
||||
const positionOrigin = getNodePositionWithOrigin(node, node.origin || nodeOrigin).positionAbsolute;
|
||||
|
||||
return (
|
||||
<NodeComponent
|
||||
x={x}
|
||||
y={y}
|
||||
x={positionOrigin.x}
|
||||
y={positionOrigin.y}
|
||||
width={node.computed?.width ?? node.width ?? 0}
|
||||
height={node.computed?.height ?? node.height ?? 0}
|
||||
style={node.style}
|
||||
|
||||
@@ -22,10 +22,10 @@ export default (NodeComponent: ComponentType<NodeProps>) => {
|
||||
id,
|
||||
type,
|
||||
data,
|
||||
xPos,
|
||||
yPos,
|
||||
xPosOrigin,
|
||||
yPosOrigin,
|
||||
positionAbsoluteX,
|
||||
positionAbsoluteY,
|
||||
selected,
|
||||
onClick,
|
||||
onMouseEnter,
|
||||
@@ -52,7 +52,6 @@ export default (NodeComponent: ComponentType<NodeProps>) => {
|
||||
disableKeyboardA11y,
|
||||
ariaLabel,
|
||||
rfId,
|
||||
positionAbsolute,
|
||||
width,
|
||||
height,
|
||||
}: WrapNodeProps) => {
|
||||
@@ -111,7 +110,7 @@ export default (NodeComponent: ComponentType<NodeProps>) => {
|
||||
store.setState({
|
||||
ariaLiveMessage: `Moved selected node ${event.key
|
||||
.replace('Arrow', '')
|
||||
.toLowerCase()}. New position, x: ${~~xPos}, y: ${~~yPos}`,
|
||||
.toLowerCase()}. New position, x: ${~~positionAbsoluteX}, y: ${~~positionAbsoluteY}`,
|
||||
});
|
||||
|
||||
updatePositions({
|
||||
@@ -212,7 +211,8 @@ export default (NodeComponent: ComponentType<NodeProps>) => {
|
||||
type={type}
|
||||
width={width}
|
||||
height={height}
|
||||
positionAbsolute={positionAbsolute}
|
||||
positionAbsoluteX={positionAbsoluteX}
|
||||
positionAbsoluteY={positionAbsoluteY}
|
||||
selected={selected}
|
||||
isConnectable={isConnectable}
|
||||
sourcePosition={sourcePosition}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import { memo, type ComponentType } from 'react';
|
||||
import { internalsSymbol, errorMessages, Position, clampPosition, getPositionWithOrigin } from '@xyflow/system';
|
||||
|
||||
import { useStore } from '../../hooks/useStore';
|
||||
import type { ReactFlowState, WrapNodeProps } from '../../types';
|
||||
import { NodeRendererProps } from '.';
|
||||
|
||||
function NodeComponentWrapper(props: {
|
||||
id: string;
|
||||
nodeExtent: NodeRendererProps['nodeExtent'];
|
||||
nodeTypes: NodeRendererProps['nodeTypes'];
|
||||
nodeOrigin: NodeRendererProps['nodeOrigin'];
|
||||
onNodeClick: NodeRendererProps['onNodeClick'];
|
||||
onNodeMouseEnter: NodeRendererProps['onNodeMouseEnter'];
|
||||
onNodeMouseMove: NodeRendererProps['onNodeMouseMove'];
|
||||
onNodeMouseLeave: NodeRendererProps['onNodeMouseLeave'];
|
||||
onNodeContextMenu: NodeRendererProps['onNodeContextMenu'];
|
||||
onNodeDoubleClick: NodeRendererProps['onNodeDoubleClick'];
|
||||
noDragClassName: NodeRendererProps['noDragClassName'];
|
||||
noPanClassName: NodeRendererProps['noPanClassName'];
|
||||
rfId: NodeRendererProps['rfId'];
|
||||
disableKeyboardA11y: NodeRendererProps['disableKeyboardA11y'];
|
||||
resizeObserver: ResizeObserver | null;
|
||||
nodesDraggable: boolean;
|
||||
nodesConnectable: boolean;
|
||||
nodesFocusable: boolean;
|
||||
elementsSelectable: boolean;
|
||||
onError: ReactFlowState['onError'];
|
||||
}) {
|
||||
const node = useStore((s) => s.nodeLookup.get(props.id));
|
||||
if (!node) return null;
|
||||
|
||||
let nodeType = node.type || 'default';
|
||||
|
||||
if (!props.nodeTypes[nodeType]) {
|
||||
props.onError?.('003', errorMessages['error003'](nodeType));
|
||||
|
||||
nodeType = 'default';
|
||||
}
|
||||
|
||||
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<WrapNodeProps>;
|
||||
const isDraggable = !!(node.draggable || (props.nodesDraggable && typeof node.draggable === 'undefined'));
|
||||
const isSelectable = !!(node.selectable || (props.elementsSelectable && typeof node.selectable === 'undefined'));
|
||||
const isConnectable = !!(node.connectable || (props.nodesConnectable && typeof node.connectable === 'undefined'));
|
||||
const isFocusable = !!(node.focusable || (props.nodesFocusable && typeof node.focusable === 'undefined'));
|
||||
|
||||
const absolutePositionClamped = props.nodeExtent
|
||||
? clampPosition(node.computed?.positionAbsolute, props.nodeExtent)
|
||||
: node.computed?.positionAbsolute || { x: 0, y: 0 };
|
||||
|
||||
const posOrigin = getPositionWithOrigin({
|
||||
x: absolutePositionClamped.x,
|
||||
y: absolutePositionClamped.y,
|
||||
width: node.computed?.width ?? node.width ?? 0,
|
||||
height: node.computed?.height ?? node.height ?? 0,
|
||||
origin: node.origin || props.nodeOrigin,
|
||||
});
|
||||
const initialized = (!!node.computed?.width && !!node.computed?.height) || (!!node.width && !!node.height);
|
||||
|
||||
return (
|
||||
<NodeComponent
|
||||
key={node.id}
|
||||
id={node.id}
|
||||
className={node.className}
|
||||
style={node.style}
|
||||
width={node.width ?? undefined}
|
||||
height={node.height ?? undefined}
|
||||
type={nodeType}
|
||||
data={node.data}
|
||||
sourcePosition={node.sourcePosition || Position.Bottom}
|
||||
targetPosition={node.targetPosition || Position.Top}
|
||||
hidden={node.hidden}
|
||||
xPosOrigin={posOrigin.x}
|
||||
yPosOrigin={posOrigin.y}
|
||||
positionAbsoluteX={absolutePositionClamped.x}
|
||||
positionAbsoluteY={absolutePositionClamped.y}
|
||||
onClick={props.onNodeClick}
|
||||
onMouseEnter={props.onNodeMouseEnter}
|
||||
onMouseMove={props.onNodeMouseMove}
|
||||
onMouseLeave={props.onNodeMouseLeave}
|
||||
onContextMenu={props.onNodeContextMenu}
|
||||
onDoubleClick={props.onNodeDoubleClick}
|
||||
selected={!!node.selected}
|
||||
isDraggable={isDraggable}
|
||||
isSelectable={isSelectable}
|
||||
isConnectable={isConnectable}
|
||||
isFocusable={isFocusable}
|
||||
resizeObserver={props.resizeObserver}
|
||||
dragHandle={node.dragHandle}
|
||||
zIndex={node[internalsSymbol]?.z ?? 0}
|
||||
isParent={!!node[internalsSymbol]?.isParent}
|
||||
noDragClassName={props.noDragClassName}
|
||||
noPanClassName={props.noPanClassName}
|
||||
initialized={initialized}
|
||||
rfId={props.rfId}
|
||||
disableKeyboardA11y={props.disableKeyboardA11y}
|
||||
ariaLabel={node.ariaLabel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
NodeComponentWrapper.displayName = 'NodeComponentWrapper';
|
||||
|
||||
export default memo(NodeComponentWrapper);
|
||||
@@ -1,14 +1,15 @@
|
||||
import { memo, useMemo, useEffect, useRef, type ComponentType } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { internalsSymbol, errorMessages, Position, clampPosition, getPositionWithOrigin } from '@xyflow/system';
|
||||
|
||||
import useVisibleNodesIds from '../../hooks/useVisibleNodes';
|
||||
import { useStore } from '../../hooks/useStore';
|
||||
import { containerStyle } from '../../styles/utils';
|
||||
import { GraphViewProps } from '../GraphView';
|
||||
import type { NodeTypesWrapped, ReactFlowState, WrapNodeProps } from '../../types';
|
||||
import type { NodeTypesWrapped, ReactFlowState } from '../../types';
|
||||
import NodeComponentWrapper from './NodeComponentWrapper';
|
||||
import useResizeObserver from './useResizeObserver';
|
||||
|
||||
type NodeRendererProps = Pick<
|
||||
export type NodeRendererProps = Pick<
|
||||
GraphViewProps,
|
||||
| 'onNodeClick'
|
||||
| 'onNodeDoubleClick'
|
||||
@@ -32,46 +33,13 @@ const selector = (s: ReactFlowState) => ({
|
||||
nodesConnectable: s.nodesConnectable,
|
||||
nodesFocusable: s.nodesFocusable,
|
||||
elementsSelectable: s.elementsSelectable,
|
||||
updateNodeDimensions: s.updateNodeDimensions,
|
||||
onError: s.onError,
|
||||
});
|
||||
|
||||
const NodeRenderer = (props: NodeRendererProps) => {
|
||||
const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, updateNodeDimensions, onError } =
|
||||
useStore(selector, shallow);
|
||||
const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector, shallow);
|
||||
const nodeIds = useVisibleNodesIds(props.onlyRenderVisibleElements);
|
||||
const resizeObserverRef = useRef<ResizeObserver>();
|
||||
|
||||
const resizeObserver = useMemo(() => {
|
||||
if (typeof ResizeObserver === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
|
||||
const updates = new Map();
|
||||
|
||||
entries.forEach((entry: ResizeObserverEntry) => {
|
||||
const id = entry.target.getAttribute('data-id') as string;
|
||||
updates.set(id, {
|
||||
id,
|
||||
nodeElement: entry.target as HTMLDivElement,
|
||||
forceUpdate: true,
|
||||
});
|
||||
});
|
||||
|
||||
updateNodeDimensions(updates);
|
||||
});
|
||||
|
||||
resizeObserverRef.current = observer;
|
||||
|
||||
return observer;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
resizeObserverRef?.current?.disconnect();
|
||||
};
|
||||
}, []);
|
||||
const resizeObserver = useResizeObserver();
|
||||
|
||||
return (
|
||||
<div className="react-flow__nodes" style={containerStyle}>
|
||||
@@ -129,103 +97,6 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const NodeComponentWrapper = memo(function NodeComponentWrapper(props: {
|
||||
id: string;
|
||||
nodeExtent: NodeRendererProps['nodeExtent'];
|
||||
nodeTypes: NodeRendererProps['nodeTypes'];
|
||||
nodeOrigin: NodeRendererProps['nodeOrigin'];
|
||||
onNodeClick: NodeRendererProps['onNodeClick'];
|
||||
onNodeMouseEnter: NodeRendererProps['onNodeMouseEnter'];
|
||||
onNodeMouseMove: NodeRendererProps['onNodeMouseMove'];
|
||||
onNodeMouseLeave: NodeRendererProps['onNodeMouseLeave'];
|
||||
onNodeContextMenu: NodeRendererProps['onNodeContextMenu'];
|
||||
onNodeDoubleClick: NodeRendererProps['onNodeDoubleClick'];
|
||||
noDragClassName: NodeRendererProps['noDragClassName'];
|
||||
noPanClassName: NodeRendererProps['noPanClassName'];
|
||||
rfId: NodeRendererProps['rfId'];
|
||||
disableKeyboardA11y: NodeRendererProps['disableKeyboardA11y'];
|
||||
resizeObserver: ResizeObserver | null;
|
||||
nodesDraggable: boolean;
|
||||
nodesConnectable: boolean;
|
||||
nodesFocusable: boolean;
|
||||
elementsSelectable: boolean;
|
||||
onError: ReactFlowState['onError'];
|
||||
}) {
|
||||
const node = useStore((s) => s.nodeLookup.get(props.id));
|
||||
if (!node) return null;
|
||||
|
||||
let nodeType = node.type || 'default';
|
||||
|
||||
if (!props.nodeTypes[nodeType]) {
|
||||
props.onError?.('003', errorMessages['error003'](nodeType));
|
||||
|
||||
nodeType = 'default';
|
||||
}
|
||||
|
||||
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<WrapNodeProps>;
|
||||
const isDraggable = !!(node.draggable || (props.nodesDraggable && typeof node.draggable === 'undefined'));
|
||||
const isSelectable = !!(node.selectable || (props.elementsSelectable && typeof node.selectable === 'undefined'));
|
||||
const isConnectable = !!(node.connectable || (props.nodesConnectable && typeof node.connectable === 'undefined'));
|
||||
const isFocusable = !!(node.focusable || (props.nodesFocusable && typeof node.focusable === 'undefined'));
|
||||
|
||||
const clampedPosition = props.nodeExtent
|
||||
? clampPosition(node.computed?.positionAbsolute, props.nodeExtent)
|
||||
: node.computed?.positionAbsolute;
|
||||
|
||||
const posX = clampedPosition?.x ?? 0;
|
||||
const posY = clampedPosition?.y ?? 0;
|
||||
const posOrigin = getPositionWithOrigin({
|
||||
x: posX,
|
||||
y: posY,
|
||||
width: node.computed?.width ?? node.width ?? 0,
|
||||
height: node.computed?.height ?? node.height ?? 0,
|
||||
origin: node.origin || props.nodeOrigin,
|
||||
});
|
||||
const initialized = (!!node.computed?.width && !!node.computed?.height) || (!!node.width && !!node.height);
|
||||
|
||||
return (
|
||||
<NodeComponent
|
||||
key={node.id}
|
||||
id={node.id}
|
||||
className={node.className}
|
||||
style={node.style}
|
||||
width={node.width ?? undefined}
|
||||
height={node.height ?? undefined}
|
||||
type={nodeType}
|
||||
data={node.data}
|
||||
sourcePosition={node.sourcePosition || Position.Bottom}
|
||||
targetPosition={node.targetPosition || Position.Top}
|
||||
hidden={node.hidden}
|
||||
xPos={posX}
|
||||
yPos={posY}
|
||||
xPosOrigin={posOrigin.x}
|
||||
yPosOrigin={posOrigin.y}
|
||||
positionAbsolute={clampedPosition || { x: 0, y: 0 }}
|
||||
onClick={props.onNodeClick}
|
||||
onMouseEnter={props.onNodeMouseEnter}
|
||||
onMouseMove={props.onNodeMouseMove}
|
||||
onMouseLeave={props.onNodeMouseLeave}
|
||||
onContextMenu={props.onNodeContextMenu}
|
||||
onDoubleClick={props.onNodeDoubleClick}
|
||||
selected={!!node.selected}
|
||||
isDraggable={isDraggable}
|
||||
isSelectable={isSelectable}
|
||||
isConnectable={isConnectable}
|
||||
isFocusable={isFocusable}
|
||||
resizeObserver={props.resizeObserver}
|
||||
dragHandle={node.dragHandle}
|
||||
zIndex={node[internalsSymbol]?.z ?? 0}
|
||||
isParent={!!node[internalsSymbol]?.isParent}
|
||||
noDragClassName={props.noDragClassName}
|
||||
noPanClassName={props.noPanClassName}
|
||||
initialized={initialized}
|
||||
rfId={props.rfId}
|
||||
disableKeyboardA11y={props.disableKeyboardA11y}
|
||||
ariaLabel={node.ariaLabel}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
NodeRenderer.displayName = 'NodeRenderer';
|
||||
|
||||
export default memo(NodeRenderer);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
import { ReactFlowState } from '../../types';
|
||||
import { useStore } from '../../hooks/useStore';
|
||||
|
||||
const selector = (s: ReactFlowState) => s.updateNodeDimensions;
|
||||
|
||||
export default function useResizeObserver() {
|
||||
const updateNodeDimensions = useStore(selector);
|
||||
const resizeObserverRef = useRef<ResizeObserver>();
|
||||
|
||||
const resizeObserver = useMemo(() => {
|
||||
if (typeof ResizeObserver === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
|
||||
const updates = new Map();
|
||||
|
||||
entries.forEach((entry: ResizeObserverEntry) => {
|
||||
const id = entry.target.getAttribute('data-id') as string;
|
||||
updates.set(id, {
|
||||
id,
|
||||
nodeElement: entry.target as HTMLDivElement,
|
||||
forceUpdate: true,
|
||||
});
|
||||
});
|
||||
|
||||
updateNodeDimensions(updates);
|
||||
});
|
||||
|
||||
resizeObserverRef.current = observer;
|
||||
|
||||
return observer;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
resizeObserverRef?.current?.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return resizeObserver;
|
||||
}
|
||||
@@ -1,31 +1,20 @@
|
||||
import { getNodesInside } from '@xyflow/system';
|
||||
import { createSelector } from 'reselect';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { useStore } from '../hooks/useStore';
|
||||
import type { Node, ReactFlowState } from '../types';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const visibleNodeIdsSelector = createSelector(
|
||||
[
|
||||
(s: ReactFlowState) => s.nodes,
|
||||
(s: ReactFlowState) => s.width,
|
||||
(s: ReactFlowState) => s.height,
|
||||
(s: ReactFlowState) => s.transform,
|
||||
(_s: ReactFlowState, onlyRenderVisibleNodes: boolean) => onlyRenderVisibleNodes,
|
||||
],
|
||||
(nodes, width, height, transform, onlyRenderVisible) =>
|
||||
onlyRenderVisible
|
||||
? getNodesInside<Node>(nodes, { x: 0, y: 0, width, height }, transform, true).map((node) => node.id)
|
||||
: nodes.map((node) => node.id),
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: shallow,
|
||||
},
|
||||
}
|
||||
);
|
||||
const selector = (onlyRenderVisible: boolean) => (s: ReactFlowState) => {
|
||||
return onlyRenderVisible
|
||||
? getNodesInside<Node>(s.nodes, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map(
|
||||
(node) => node.id
|
||||
)
|
||||
: Array.from(s.nodeLookup.keys());
|
||||
};
|
||||
|
||||
function useVisibleNodeIds(onlyRenderVisible: boolean) {
|
||||
const nodeIds = useStore((s: ReactFlowState) => visibleNodeIdsSelector(s, onlyRenderVisible));
|
||||
const nodeIds = useStore(useCallback(selector(onlyRenderVisible), [onlyRenderVisible]), shallow);
|
||||
|
||||
return nodeIds;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
|
||||
import type { NodeBase, XYPosition } from '@xyflow/system';
|
||||
import type { NodeBase } from '@xyflow/system';
|
||||
|
||||
export type Node<NodeData = any, NodeType extends string | undefined = string | undefined> = NodeBase<
|
||||
NodeData,
|
||||
@@ -20,11 +20,10 @@ export type WrapNodeProps<NodeData = any> = Pick<
|
||||
> &
|
||||
Required<Pick<Node<NodeData>, 'selected' | 'type' | 'zIndex'>> & {
|
||||
isConnectable: boolean;
|
||||
xPos: number;
|
||||
yPos: number;
|
||||
xPosOrigin: number;
|
||||
yPosOrigin: number;
|
||||
positionAbsolute: XYPosition;
|
||||
positionAbsoluteX: number;
|
||||
positionAbsoluteY: number;
|
||||
initialized: boolean;
|
||||
isSelectable: boolean;
|
||||
isDraggable: boolean;
|
||||
|
||||
@@ -191,7 +191,8 @@
|
||||
{dragging}
|
||||
{dragHandle}
|
||||
isConnectable={connectable}
|
||||
positionAbsolute={{ x: positionX, y: positionY }}
|
||||
positionAbsoluteX={positionX}
|
||||
positionAbsoluteY={positionY}
|
||||
{width}
|
||||
{height}
|
||||
/>
|
||||
|
||||
@@ -56,7 +56,8 @@ export type NodeProps<T = any> = {
|
||||
selected: NodeBase['selected'];
|
||||
isConnectable: NodeBase['connectable'];
|
||||
zIndex: NodeBase['zIndex'];
|
||||
positionAbsolute: XYPosition;
|
||||
positionAbsoluteX: number;
|
||||
positionAbsoluteY: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
dragging: boolean;
|
||||
|
||||
Generated
-9
@@ -235,9 +235,6 @@ importers:
|
||||
react-dom:
|
||||
specifier: '>=17'
|
||||
version: registry.npmjs.org/react-dom@18.2.0(react@18.2.0)
|
||||
reselect:
|
||||
specifier: ^4.1.8
|
||||
version: registry.npmjs.org/reselect@4.1.8
|
||||
zustand:
|
||||
specifier: ^4.4.0
|
||||
version: registry.npmjs.org/zustand@4.4.1(@types/react@18.2.24)(react@18.2.0)
|
||||
@@ -10036,12 +10033,6 @@ packages:
|
||||
version: 1.0.0
|
||||
dev: true
|
||||
|
||||
registry.npmjs.org/reselect@4.1.8:
|
||||
resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz}
|
||||
name: reselect
|
||||
version: 4.1.8
|
||||
dev: false
|
||||
|
||||
registry.npmjs.org/resolve-from@4.0.0:
|
||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz}
|
||||
name: resolve-from
|
||||
|
||||
Reference in New Issue
Block a user