Merge branch 'next' into handle-connection-fixes
This commit is contained in:
@@ -81,6 +81,8 @@ const initialNodes: Node[] = [
|
|||||||
id: '4',
|
id: '4',
|
||||||
data: { label: 'Node 4' },
|
data: { label: 'Node 4' },
|
||||||
position: { x: 400, y: 200 },
|
position: { x: 400, y: 200 },
|
||||||
|
width: 200,
|
||||||
|
height: 50,
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { memo, useState } from 'react';
|
||||||
|
import { Handle, Position } from '@xyflow/react';
|
||||||
|
|
||||||
|
function CustomNode() {
|
||||||
|
const [text, setText] = useState('this is a pretty long text');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Handle type="target" position={Position.Top} />
|
||||||
|
<div style={{ background: '#eee', padding: 10 }}>
|
||||||
|
<div>
|
||||||
|
<input value={text} onChange={(e) => setText(e.target.value)} />
|
||||||
|
<div>text: {text}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Handle type="source" position={Position.Bottom} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(CustomNode);
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import {
|
||||||
|
ReactFlow,
|
||||||
|
addEdge,
|
||||||
|
useEdgesState,
|
||||||
|
useNodesState,
|
||||||
|
Background,
|
||||||
|
Controls,
|
||||||
|
type Connection,
|
||||||
|
type Edge,
|
||||||
|
type Node,
|
||||||
|
} from '@xyflow/react';
|
||||||
|
|
||||||
|
import CustomNode from './CustomNode';
|
||||||
|
|
||||||
|
import '@xyflow/react/dist/style.css';
|
||||||
|
|
||||||
|
const initialNodes: Node[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
data: {},
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
initialWidth: 200,
|
||||||
|
initialHeight: 50,
|
||||||
|
type: 'custom',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
data: {},
|
||||||
|
position: { x: 0, y: 200 },
|
||||||
|
width: 200,
|
||||||
|
initialHeight: 50,
|
||||||
|
type: 'custom',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const initialEdges: Edge[] = [{ id: 'e1-2', source: '1', target: '2' }];
|
||||||
|
|
||||||
|
const nodeTypes = {
|
||||||
|
custom: CustomNode,
|
||||||
|
};
|
||||||
|
|
||||||
|
function Flow() {
|
||||||
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ width: 700, height: 400 }}>
|
||||||
|
<ReactFlow
|
||||||
|
nodes={nodes}
|
||||||
|
onNodesChange={onNodesChange}
|
||||||
|
edges={edges}
|
||||||
|
onEdgesChange={onEdgesChange}
|
||||||
|
onConnect={onConnect}
|
||||||
|
nodeTypes={nodeTypes}
|
||||||
|
fitView
|
||||||
|
width={700}
|
||||||
|
height={400}
|
||||||
|
debug
|
||||||
|
>
|
||||||
|
<Background />
|
||||||
|
<Controls />
|
||||||
|
</ReactFlow>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Flow;
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
|
||||||
|
|
||||||
|
type $$Props = NodeProps;
|
||||||
|
|
||||||
|
let text = 'some default text';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Handle type="target" position={Position.Left} />
|
||||||
|
<div class="custom">
|
||||||
|
<div>
|
||||||
|
text: {text}
|
||||||
|
</div>
|
||||||
|
<input type="text" bind:value={text} />
|
||||||
|
</div>
|
||||||
|
<Handle type="source" position={Position.Right} />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.custom {
|
||||||
|
background-color: white;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #777;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import { SvelteFlow, Controls, Background, BackgroundVariant, type Node, type Edge } from '@xyflow/svelte';
|
||||||
|
|
||||||
|
import '@xyflow/svelte/dist/style.css';
|
||||||
|
import CustomNode from './CustomNode.svelte';
|
||||||
|
|
||||||
|
const nodes = writable<Node[]>([
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
data: {},
|
||||||
|
initialWidth: 100,
|
||||||
|
initialHeight: 40,
|
||||||
|
type: 'input-node',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
position: { x: 0, y: 150 },
|
||||||
|
data: {},
|
||||||
|
initialWidth: 100,
|
||||||
|
initialHeight: 40,
|
||||||
|
type: 'input-node',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const edges = writable<Edge[]>([{ id: '1-2', source: '1', target: '2' }]);
|
||||||
|
|
||||||
|
const nodeTypes = {
|
||||||
|
'input-node': CustomNode,
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div style="height: 400px; width: 700px;">
|
||||||
|
<SvelteFlow {nodes} {edges} {nodeTypes} fitView width={700} height={400}>
|
||||||
|
<Controls />
|
||||||
|
<Background variant={BackgroundVariant.Dots} />
|
||||||
|
</SvelteFlow>
|
||||||
|
</div>
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
---
|
---
|
||||||
import ReactFlowApp from '../components/ReactFlowExample'
|
import ReactFlowApp from '../components/ReactFlowExample';
|
||||||
import SvelteFlowApp from '../components/SvelteFlowExample/index.svelte'
|
import ReactFlowInitialApp from '../components/ReactFlowInitialExample';
|
||||||
|
import SvelteFlowApp from '../components/SvelteFlowExample/index.svelte';
|
||||||
|
import SvelteFlowInitialApp from '../components/SvelteFlowInitialExample/index.svelte';
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@@ -18,10 +20,24 @@ import SvelteFlowApp from '../components/SvelteFlowExample/index.svelte'
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<h2>React Flow</h2>
|
||||||
|
<p>no client hydration</p>
|
||||||
|
<ReactFlowApp />
|
||||||
|
|
||||||
|
<p>client hydration on load (client:load)</p>
|
||||||
|
<ReactFlowApp client:load />
|
||||||
|
|
||||||
|
<p>client hydration on load (client:load) and initialWidth / initialHeight</p>
|
||||||
|
<ReactFlowInitialApp client:load />
|
||||||
|
|
||||||
<h2>Svelte Flow</h2>
|
<h2>Svelte Flow</h2>
|
||||||
<SvelteFlowApp />
|
<SvelteFlowApp />
|
||||||
|
|
||||||
<h2>React Flow</h2>
|
<p>client hydration on load (client:load)</p>
|
||||||
<ReactFlowApp />
|
<SvelteFlowApp client:load />
|
||||||
|
|
||||||
|
<p>client hydration on load (client:load) and initialWidth / initialHeight</p>
|
||||||
|
<SvelteFlowInitialApp client:load />
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
## ⚠️ Breaking changes
|
## ⚠️ Breaking changes
|
||||||
|
|
||||||
- `useNodesData` not only returns data objects but also the type and the id of the node.
|
- `useNodesData` not only returns data objects but also the type and the id of the node
|
||||||
|
|
||||||
## Patch changes
|
## Patch changes
|
||||||
|
|
||||||
- better cursor defaults for the pane, nodes and edges
|
- better cursor defaults for the pane, nodes and edges
|
||||||
- `disableKeyboardA11y` now also disables Enter and Escape for selecting/deselecting nodes and edges
|
- `disableKeyboardA11y` now also disables Enter and Escape for selecting/deselecting nodes and edges
|
||||||
- fix bug where users couldn't drag a node after toggle nodes `hidden` attribute
|
- fix bug where users couldn't drag a node after toggle nodes `hidden` attribute
|
||||||
|
- add `initialWidth` and `initialHeight` node attributes for specifying initial dimensions for ssr
|
||||||
|
|
||||||
## 12.0.0-next.9
|
## 12.0.0-next.9
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { ComponentType, memo } from 'react';
|
import { ComponentType, memo } from 'react';
|
||||||
import { NodeOrigin, getNodePositionWithOrigin } from '@xyflow/system';
|
import { NodeOrigin, getNodeDimensions, getNodePositionWithOrigin, nodeHasDimensions } from '@xyflow/system';
|
||||||
import { shallow } from 'zustand/shallow';
|
import { shallow } from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore } from '../../hooks/useStore';
|
import { useStore } from '../../hooks/useStore';
|
||||||
@@ -94,16 +94,19 @@ function NodeComponentWrapperInner<NodeType extends Node>({
|
|||||||
y,
|
y,
|
||||||
};
|
};
|
||||||
}, shallow);
|
}, shallow);
|
||||||
if (!node || node.hidden || !(node.computed?.width || node.width) || !(node.computed?.height || node.height)) {
|
|
||||||
|
if (!node || node.hidden || !nodeHasDimensions(node)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { width, height } = getNodeDimensions(node);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeComponent
|
<NodeComponent
|
||||||
x={x}
|
x={x}
|
||||||
y={y}
|
y={y}
|
||||||
width={node.computed?.width ?? node.width ?? 0}
|
width={width}
|
||||||
height={node.computed?.height ?? node.height ?? 0}
|
height={height}
|
||||||
style={node.style}
|
style={node.style}
|
||||||
selected={!!node.selected}
|
selected={!!node.selected}
|
||||||
className={nodeClassNameFunc(node)}
|
className={nodeClassNameFunc(node)}
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ import {
|
|||||||
clampPosition,
|
clampPosition,
|
||||||
elementSelectionKeys,
|
elementSelectionKeys,
|
||||||
errorMessages,
|
errorMessages,
|
||||||
|
getNodeDimensions,
|
||||||
getPositionWithOrigin,
|
getPositionWithOrigin,
|
||||||
internalsSymbol,
|
internalsSymbol,
|
||||||
isInputDOMNode,
|
isInputDOMNode,
|
||||||
|
nodeHasDimensions,
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import { useStore, useStoreApi } from '../../hooks/useStore';
|
import { useStore, useStoreApi } from '../../hooks/useStore';
|
||||||
@@ -16,7 +18,7 @@ import { ARIA_NODE_DESC_KEY } from '../A11yDescriptions';
|
|||||||
import { useDrag } from '../../hooks/useDrag';
|
import { useDrag } from '../../hooks/useDrag';
|
||||||
import { useMoveSelectedNodes } from '../../hooks/useMoveSelectedNodes';
|
import { useMoveSelectedNodes } from '../../hooks/useMoveSelectedNodes';
|
||||||
import { handleNodeClick } from '../Nodes/utils';
|
import { handleNodeClick } from '../Nodes/utils';
|
||||||
import { arrowKeyDiffs, builtinNodeTypes } from './utils';
|
import { arrowKeyDiffs, builtinNodeTypes, getNodeInlineStyleDimensions } from './utils';
|
||||||
import type { Node, NodeWrapperProps } from '../../types';
|
import type { Node, NodeWrapperProps } from '../../types';
|
||||||
|
|
||||||
export function NodeWrapper<NodeType extends Node>({
|
export function NodeWrapper<NodeType extends Node>({
|
||||||
@@ -79,11 +81,9 @@ export function NodeWrapper<NodeType extends Node>({
|
|||||||
const prevTargetPosition = useRef(node.targetPosition);
|
const prevTargetPosition = useRef(node.targetPosition);
|
||||||
const prevType = useRef(nodeType);
|
const prevType = useRef(nodeType);
|
||||||
|
|
||||||
const width = node.width ?? undefined;
|
const nodeDimensions = getNodeDimensions(node);
|
||||||
const height = node.height ?? undefined;
|
const inlineDimensions = getNodeInlineStyleDimensions(node);
|
||||||
const computedWidth = node.computed?.width;
|
const initialized = nodeHasDimensions(node);
|
||||||
const computedHeight = node.computed?.height;
|
|
||||||
const initialized = (!!computedWidth && !!computedHeight) || (!!width && !!height);
|
|
||||||
const hasHandleBounds = !!node[internalsSymbol]?.handleBounds;
|
const hasHandleBounds = !!node[internalsSymbol]?.handleBounds;
|
||||||
|
|
||||||
const moveSelectedNodes = useMoveSelectedNodes();
|
const moveSelectedNodes = useMoveSelectedNodes();
|
||||||
@@ -143,8 +143,7 @@ export function NodeWrapper<NodeType extends Node>({
|
|||||||
const positionAbsoluteOrigin = getPositionWithOrigin({
|
const positionAbsoluteOrigin = getPositionWithOrigin({
|
||||||
x: positionAbsoluteX,
|
x: positionAbsoluteX,
|
||||||
y: positionAbsoluteY,
|
y: positionAbsoluteY,
|
||||||
width: computedWidth ?? width ?? 0,
|
...nodeDimensions,
|
||||||
height: computedHeight ?? height ?? 0,
|
|
||||||
origin: node.origin || nodeOrigin,
|
origin: node.origin || nodeOrigin,
|
||||||
});
|
});
|
||||||
const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave;
|
const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave;
|
||||||
@@ -226,8 +225,7 @@ export function NodeWrapper<NodeType extends Node>({
|
|||||||
pointerEvents: hasPointerEvents ? 'all' : 'none',
|
pointerEvents: hasPointerEvents ? 'all' : 'none',
|
||||||
visibility: initialized ? 'visible' : 'hidden',
|
visibility: initialized ? 'visible' : 'hidden',
|
||||||
...node.style,
|
...node.style,
|
||||||
width: width ?? node.style?.width,
|
...inlineDimensions,
|
||||||
height: height ?? node.style?.height,
|
|
||||||
}}
|
}}
|
||||||
data-id={id}
|
data-id={id}
|
||||||
data-testid={`rf__node-${id}`}
|
data-testid={`rf__node-${id}`}
|
||||||
@@ -248,8 +246,6 @@ export function NodeWrapper<NodeType extends Node>({
|
|||||||
id={id}
|
id={id}
|
||||||
data={node.data}
|
data={node.data}
|
||||||
type={nodeType}
|
type={nodeType}
|
||||||
width={computedWidth}
|
|
||||||
height={computedHeight}
|
|
||||||
positionAbsoluteX={positionAbsoluteX}
|
positionAbsoluteX={positionAbsoluteX}
|
||||||
positionAbsoluteY={positionAbsoluteY}
|
positionAbsoluteY={positionAbsoluteY}
|
||||||
selected={node.selected}
|
selected={node.selected}
|
||||||
@@ -259,6 +255,7 @@ export function NodeWrapper<NodeType extends Node>({
|
|||||||
dragging={dragging}
|
dragging={dragging}
|
||||||
dragHandle={node.dragHandle}
|
dragHandle={node.dragHandle}
|
||||||
zIndex={zIndex}
|
zIndex={zIndex}
|
||||||
|
{...nodeDimensions}
|
||||||
/>
|
/>
|
||||||
</Provider>
|
</Provider>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { InputNode } from '../Nodes/InputNode';
|
|||||||
import { DefaultNode } from '../Nodes/DefaultNode';
|
import { DefaultNode } from '../Nodes/DefaultNode';
|
||||||
import { GroupNode } from '../Nodes/GroupNode';
|
import { GroupNode } from '../Nodes/GroupNode';
|
||||||
import { OutputNode } from '../Nodes/OutputNode';
|
import { OutputNode } from '../Nodes/OutputNode';
|
||||||
import type { NodeTypes } from '../../types';
|
import type { Node, NodeTypes } from '../../types';
|
||||||
|
|
||||||
export const arrowKeyDiffs: Record<string, XYPosition> = {
|
export const arrowKeyDiffs: Record<string, XYPosition> = {
|
||||||
ArrowUp: { x: 0, y: -1 },
|
ArrowUp: { x: 0, y: -1 },
|
||||||
@@ -20,3 +20,22 @@ export const builtinNodeTypes: NodeTypes = {
|
|||||||
output: OutputNode as ComponentType<NodeProps>,
|
output: OutputNode as ComponentType<NodeProps>,
|
||||||
group: GroupNode as ComponentType<NodeProps>,
|
group: GroupNode as ComponentType<NodeProps>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getNodeInlineStyleDimensions<NodeType extends Node = Node>(
|
||||||
|
node: NodeType
|
||||||
|
): {
|
||||||
|
width: number | string | undefined;
|
||||||
|
height: number | string | undefined;
|
||||||
|
} {
|
||||||
|
if (!node.computed) {
|
||||||
|
return {
|
||||||
|
width: node.width ?? node.initialWidth ?? node.style?.width,
|
||||||
|
height: node.height ?? node.initialHeight ?? node.style?.height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: node.width ?? node.style?.width,
|
||||||
|
height: node.height ?? node.style?.height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ const reactFlowFieldsToTrack = [
|
|||||||
'selectNodesOnDrag',
|
'selectNodesOnDrag',
|
||||||
'nodeDragThreshold',
|
'nodeDragThreshold',
|
||||||
'onBeforeDelete',
|
'onBeforeDelete',
|
||||||
|
'debug',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number];
|
type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number];
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
colorMode = 'light',
|
colorMode = 'light',
|
||||||
|
debug,
|
||||||
...rest
|
...rest
|
||||||
}: ReactFlowProps<NodeType, EdgeType>,
|
}: ReactFlowProps<NodeType, EdgeType>,
|
||||||
ref: ForwardedRef<ReactFlowRefType>
|
ref: ForwardedRef<ReactFlowRefType>
|
||||||
@@ -274,6 +275,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
|||||||
selectNodesOnDrag={selectNodesOnDrag}
|
selectNodesOnDrag={selectNodesOnDrag}
|
||||||
nodeDragThreshold={nodeDragThreshold}
|
nodeDragThreshold={nodeDragThreshold}
|
||||||
onBeforeDelete={onBeforeDelete}
|
onBeforeDelete={onBeforeDelete}
|
||||||
|
debug={debug}
|
||||||
/>
|
/>
|
||||||
<SelectionListener onSelectionChange={onSelectionChange} />
|
<SelectionListener onSelectionChange={onSelectionChange} />
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ const createRFStore = ({
|
|||||||
fitViewOnInitOptions,
|
fitViewOnInitOptions,
|
||||||
domNode,
|
domNode,
|
||||||
nodeOrigin,
|
nodeOrigin,
|
||||||
|
debug,
|
||||||
} = get();
|
} = get();
|
||||||
const changes: NodeDimensionChange[] = [];
|
const changes: NodeDimensionChange[] = [];
|
||||||
|
|
||||||
@@ -130,6 +131,9 @@ const createRFStore = ({
|
|||||||
set({ nodes: nextNodes, fitViewDone: nextFitViewDone });
|
set({ nodes: nextNodes, fitViewDone: nextFitViewDone });
|
||||||
|
|
||||||
if (changes?.length > 0) {
|
if (changes?.length > 0) {
|
||||||
|
if (debug) {
|
||||||
|
console.log('React Flow: trigger node changes', changes);
|
||||||
|
}
|
||||||
onNodesChange?.(changes);
|
onNodesChange?.(changes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -149,7 +153,7 @@ const createRFStore = ({
|
|||||||
get().triggerNodeChanges(changes);
|
get().triggerNodeChanges(changes);
|
||||||
},
|
},
|
||||||
triggerNodeChanges: (changes) => {
|
triggerNodeChanges: (changes) => {
|
||||||
const { onNodesChange, setNodes, nodes, hasDefaultNodes } = get();
|
const { onNodesChange, setNodes, nodes, hasDefaultNodes, debug } = get();
|
||||||
|
|
||||||
if (changes?.length) {
|
if (changes?.length) {
|
||||||
if (hasDefaultNodes) {
|
if (hasDefaultNodes) {
|
||||||
@@ -157,11 +161,15 @@ const createRFStore = ({
|
|||||||
setNodes(updatedNodes);
|
setNodes(updatedNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
console.log('React Flow: trigger node changes', changes);
|
||||||
|
}
|
||||||
|
|
||||||
onNodesChange?.(changes);
|
onNodesChange?.(changes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
triggerEdgeChanges: (changes) => {
|
triggerEdgeChanges: (changes) => {
|
||||||
const { onEdgesChange, setEdges, edges, hasDefaultEdges } = get();
|
const { onEdgesChange, setEdges, edges, hasDefaultEdges, debug } = get();
|
||||||
|
|
||||||
if (changes?.length) {
|
if (changes?.length) {
|
||||||
if (hasDefaultEdges) {
|
if (hasDefaultEdges) {
|
||||||
@@ -169,6 +177,10 @@ const createRFStore = ({
|
|||||||
setEdges(updatedEdges);
|
setEdges(updatedEdges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
console.log('React Flow: trigger edge changes', changes);
|
||||||
|
}
|
||||||
|
|
||||||
onEdgesChange?.(changes);
|
onEdgesChange?.(changes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ const getInitialState = ({
|
|||||||
let transform: Transform = [0, 0, 1];
|
let transform: Transform = [0, 0, 1];
|
||||||
|
|
||||||
if (fitView && width && height) {
|
if (fitView && width && height) {
|
||||||
const nodesWithDimensions = nextNodes.filter((node) => node.width && node.height);
|
const nodesWithDimensions = nextNodes.filter(
|
||||||
|
(node) => (node.width || node.initialWidth) && (node.height || node.initialHeight)
|
||||||
|
);
|
||||||
// @todo users nodeOrigin should be used here
|
// @todo users nodeOrigin should be used here
|
||||||
const bounds = getNodesBounds(nodesWithDimensions, { nodeOrigin: [0, 0] });
|
const bounds = getNodesBounds(nodesWithDimensions, { nodeOrigin: [0, 0] });
|
||||||
const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
|
const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
|
||||||
@@ -113,6 +115,7 @@ const getInitialState = ({
|
|||||||
onSelectionChangeHandlers: [],
|
onSelectionChangeHandlers: [],
|
||||||
|
|
||||||
lib: 'react',
|
lib: 'react',
|
||||||
|
debug: false,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -503,6 +503,11 @@ export interface ReactFlowProps<NodeType extends Node = Node, EdgeType extends E
|
|||||||
* @example 'system' | 'light' | 'dark'
|
* @example 'system' | 'light' | 'dark'
|
||||||
*/
|
*/
|
||||||
colorMode?: ColorMode;
|
colorMode?: ColorMode;
|
||||||
|
/** If set true, some debug information will be logged to the console like which events are fired.
|
||||||
|
*
|
||||||
|
* @default undefined
|
||||||
|
*/
|
||||||
|
debug?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReactFlowRefType = HTMLDivElement;
|
export type ReactFlowRefType = HTMLDivElement;
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
|
|||||||
isValidConnection?: IsValidConnection<EdgeType>;
|
isValidConnection?: IsValidConnection<EdgeType>;
|
||||||
|
|
||||||
lib: string;
|
lib: string;
|
||||||
|
debug: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReactFlowActions<NodeType extends Node, EdgeType extends Edge> = {
|
export type ReactFlowActions<NodeType extends Node, EdgeType extends Edge> = {
|
||||||
|
|||||||
@@ -4,11 +4,12 @@
|
|||||||
|
|
||||||
## ⚠️ Breaking changes
|
## ⚠️ Breaking changes
|
||||||
|
|
||||||
- `useNodesData` not only returns data objects but also the type and the id of the node.
|
- `useNodesData` not only returns data objects but also the type and the id of the node
|
||||||
|
|
||||||
## Patch changes
|
## Patch changes
|
||||||
|
|
||||||
- better cursor defaults for the pane, nodes and edges.
|
- better cursor defaults for the pane, nodes and edges
|
||||||
|
- add `initialWidth` and `initialHeight` node attributes for specifying initial dimensions for ssr
|
||||||
|
|
||||||
## 0.0.36
|
## 0.0.36
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
||||||
import type { NodeWrapperProps } from './types';
|
import type { NodeWrapperProps } from './types';
|
||||||
import type { Node } from '$lib/types';
|
import type { Node } from '$lib/types';
|
||||||
|
import { getNodeInlineStyleDimensions } from './utils';
|
||||||
|
|
||||||
interface $$Props extends NodeWrapperProps {}
|
interface $$Props extends NodeWrapperProps {}
|
||||||
|
|
||||||
@@ -34,6 +35,10 @@
|
|||||||
export let sourcePosition: NodeWrapperProps['sourcePosition'] = undefined;
|
export let sourcePosition: NodeWrapperProps['sourcePosition'] = undefined;
|
||||||
export let targetPosition: NodeWrapperProps['targetPosition'] = undefined;
|
export let targetPosition: NodeWrapperProps['targetPosition'] = undefined;
|
||||||
export let zIndex: NodeWrapperProps['zIndex'];
|
export let zIndex: NodeWrapperProps['zIndex'];
|
||||||
|
export let computedWidth: NodeWrapperProps['computedWidth'] = undefined;
|
||||||
|
export let computedHeight: NodeWrapperProps['computedHeight'] = undefined;
|
||||||
|
export let initialWidth: NodeWrapperProps['initialWidth'] = undefined;
|
||||||
|
export let initialHeight: NodeWrapperProps['initialHeight'] = undefined;
|
||||||
export let width: NodeWrapperProps['width'] = undefined;
|
export let width: NodeWrapperProps['width'] = undefined;
|
||||||
export let height: NodeWrapperProps['height'] = undefined;
|
export let height: NodeWrapperProps['height'] = undefined;
|
||||||
export let dragHandle: NodeWrapperProps['dragHandle'] = undefined;
|
export let dragHandle: NodeWrapperProps['dragHandle'] = undefined;
|
||||||
@@ -77,6 +82,15 @@
|
|||||||
let prevSourcePosition: Position | undefined = undefined;
|
let prevSourcePosition: Position | undefined = undefined;
|
||||||
let prevTargetPosition: Position | undefined = undefined;
|
let prevTargetPosition: Position | undefined = undefined;
|
||||||
|
|
||||||
|
$: inlineStyleDimensions = getNodeInlineStyleDimensions({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
initialWidth,
|
||||||
|
initialHeight,
|
||||||
|
computedWidth,
|
||||||
|
computedHeight
|
||||||
|
});
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
connectableStore.set(!!connectable);
|
connectableStore.set(!!connectable);
|
||||||
}
|
}
|
||||||
@@ -170,9 +184,7 @@
|
|||||||
style:z-index={zIndex}
|
style:z-index={zIndex}
|
||||||
style:transform="translate({positionOriginX}px, {positionOriginY}px)"
|
style:transform="translate({positionOriginX}px, {positionOriginY}px)"
|
||||||
style:visibility={initialized ? 'visible' : 'hidden'}
|
style:visibility={initialized ? 'visible' : 'hidden'}
|
||||||
style="{style ?? ''}; {!width ? '' : `width:${width}px;`} {!height
|
style="{inlineStyleDimensions.width} {inlineStyleDimensions.height} {style ?? ''};"
|
||||||
? ''
|
|
||||||
: `height:${height}px;`}"
|
|
||||||
on:click={onSelectNodeHandler}
|
on:click={onSelectNodeHandler}
|
||||||
on:mouseenter={(event) => dispatch('nodemouseenter', { node, event })}
|
on:mouseenter={(event) => dispatch('nodemouseenter', { node, event })}
|
||||||
on:mouseleave={(event) => dispatch('nodemouseleave', { node, event })}
|
on:mouseleave={(event) => dispatch('nodemouseleave', { node, event })}
|
||||||
|
|||||||
@@ -16,9 +16,13 @@ export type NodeWrapperProps = Pick<
|
|||||||
| 'targetPosition'
|
| 'targetPosition'
|
||||||
| 'dragHandle'
|
| 'dragHandle'
|
||||||
| 'hidden'
|
| 'hidden'
|
||||||
|
| 'width'
|
||||||
|
| 'height'
|
||||||
|
| 'initialWidth'
|
||||||
|
| 'initialHeight'
|
||||||
> & {
|
> & {
|
||||||
width?: number;
|
computedWidth?: number;
|
||||||
height?: number;
|
computedHeight?: number;
|
||||||
type: string;
|
type: string;
|
||||||
positionX: number;
|
positionX: number;
|
||||||
positionY: number;
|
positionY: number;
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
export function getNodeInlineStyleDimensions({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
initialWidth,
|
||||||
|
initialHeight,
|
||||||
|
computedWidth,
|
||||||
|
computedHeight
|
||||||
|
}: {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
initialWidth?: number;
|
||||||
|
initialHeight?: number;
|
||||||
|
computedWidth?: number;
|
||||||
|
computedHeight?: number;
|
||||||
|
}): {
|
||||||
|
width: string | undefined;
|
||||||
|
height: string | undefined;
|
||||||
|
} {
|
||||||
|
if (computedWidth === undefined && computedHeight === undefined) {
|
||||||
|
const styleWidth = width ?? initialWidth;
|
||||||
|
const styleHeight = height ?? initialHeight;
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: styleWidth ? `width:${styleWidth}px;` : '',
|
||||||
|
height: styleHeight ? `height:${styleHeight}px;` : ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: width ? `width:${width}px;` : '',
|
||||||
|
height: height ? `height:${height}px;` : ''
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onDestroy } from 'svelte';
|
import { onDestroy } from 'svelte';
|
||||||
import { internalsSymbol, getPositionWithOrigin } from '@xyflow/system';
|
import {
|
||||||
|
internalsSymbol,
|
||||||
|
getPositionWithOrigin,
|
||||||
|
getNodeDimensions,
|
||||||
|
nodeHasDimensions
|
||||||
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import { NodeWrapper } from '$lib/components/NodeWrapper';
|
import { NodeWrapper } from '$lib/components/NodeWrapper';
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
@@ -39,11 +44,11 @@
|
|||||||
|
|
||||||
<div class="svelte-flow__nodes">
|
<div class="svelte-flow__nodes">
|
||||||
{#each $visibleNodes as node (node.id)}
|
{#each $visibleNodes as node (node.id)}
|
||||||
|
{@const nodeDimesions = getNodeDimensions(node)}
|
||||||
{@const posOrigin = getPositionWithOrigin({
|
{@const posOrigin = getPositionWithOrigin({
|
||||||
x: node.computed?.positionAbsolute?.x ?? 0,
|
x: node.computed?.positionAbsolute?.x ?? 0,
|
||||||
y: node.computed?.positionAbsolute?.y ?? 0,
|
y: node.computed?.positionAbsolute?.y ?? 0,
|
||||||
width: node.computed?.width ?? node.width ?? 0,
|
...nodeDimesions,
|
||||||
height: node.computed?.height ?? node.height ?? 0,
|
|
||||||
origin: node.origin
|
origin: node.origin
|
||||||
})}
|
})}
|
||||||
<NodeWrapper
|
<NodeWrapper
|
||||||
@@ -74,10 +79,13 @@
|
|||||||
dragging={node.dragging}
|
dragging={node.dragging}
|
||||||
zIndex={node[internalsSymbol]?.z ?? 0}
|
zIndex={node[internalsSymbol]?.z ?? 0}
|
||||||
dragHandle={node.dragHandle}
|
dragHandle={node.dragHandle}
|
||||||
width={node.width ?? undefined}
|
initialized={nodeHasDimensions(node)}
|
||||||
height={node.height ?? undefined}
|
width={node.width}
|
||||||
initialized={(!!node.computed?.width && !!node.computed?.height) ||
|
height={node.height}
|
||||||
(!!node.width && !!node.height)}
|
initialWidth={node.initialWidth}
|
||||||
|
initialHeight={node.initialHeight}
|
||||||
|
computedWidth={node.computed?.width}
|
||||||
|
computedHeight={node.computed?.height}
|
||||||
{resizeObserver}
|
{resizeObserver}
|
||||||
on:nodeclick
|
on:nodeclick
|
||||||
on:nodemouseenter
|
on:nodemouseenter
|
||||||
|
|||||||
@@ -7,7 +7,13 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
import { getBoundsOfRects, getNodePositionWithOrigin, getNodesBounds } from '@xyflow/system';
|
import {
|
||||||
|
getBoundsOfRects,
|
||||||
|
getNodeDimensions,
|
||||||
|
getNodePositionWithOrigin,
|
||||||
|
getNodesBounds,
|
||||||
|
nodeHasDimensions
|
||||||
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import { Panel } from '$lib/container/Panel';
|
import { Panel } from '$lib/container/Panel';
|
||||||
@@ -116,13 +122,13 @@
|
|||||||
{#if ariaLabel}<title id={labelledBy}>{ariaLabel}</title>{/if}
|
{#if ariaLabel}<title id={labelledBy}>{ariaLabel}</title>{/if}
|
||||||
|
|
||||||
{#each $nodes as node (node.id)}
|
{#each $nodes as node (node.id)}
|
||||||
{#if (node.computed?.width || node?.width) && (node.computed?.height || node.height)}
|
{#if nodeHasDimensions(node)}
|
||||||
{@const pos = getNodePositionWithOrigin(node).positionAbsolute}
|
{@const pos = getNodePositionWithOrigin(node).positionAbsolute}
|
||||||
|
{@const nodeDimesions = getNodeDimensions(node)}
|
||||||
<MinimapNode
|
<MinimapNode
|
||||||
x={pos.x}
|
x={pos.x}
|
||||||
y={pos.y}
|
y={pos.y}
|
||||||
width={node.computed?.width ?? node.width ?? 0}
|
{...nodeDimesions}
|
||||||
height={node.computed?.height ?? node.height ?? 0}
|
|
||||||
selected={node.selected}
|
selected={node.selected}
|
||||||
color={nodeColorFunc?.(node)}
|
color={nodeColorFunc?.(node)}
|
||||||
borderRadius={nodeBorderRadius}
|
borderRadius={nodeBorderRadius}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { getContext, setContext } from 'svelte';
|
import { getContext, setContext } from 'svelte';
|
||||||
import { derived, get, writable } from 'svelte/store';
|
import { derived, get, writable } from 'svelte/store';
|
||||||
import {
|
import {
|
||||||
internalsSymbol,
|
|
||||||
createMarkerIds,
|
createMarkerIds,
|
||||||
fitView as fitViewUtil,
|
fitView as fitViewUtil,
|
||||||
getElementsToRemove,
|
getElementsToRemove,
|
||||||
@@ -15,7 +14,6 @@ import {
|
|||||||
type XYPosition,
|
type XYPosition,
|
||||||
type CoordinateExtent,
|
type CoordinateExtent,
|
||||||
type UpdateConnection,
|
type UpdateConnection,
|
||||||
type NodeDragItem,
|
|
||||||
errorMessages
|
errorMessages
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ export const getInitialStore = ({
|
|||||||
let viewport: Viewport = { x: 0, y: 0, zoom: 1 };
|
let viewport: Viewport = { x: 0, y: 0, zoom: 1 };
|
||||||
|
|
||||||
if (fitView && width && height) {
|
if (fitView && width && height) {
|
||||||
const nodesWithDimensions = nextNodes.filter((node) => node.width && node.height);
|
const nodesWithDimensions = nextNodes.filter(
|
||||||
|
(node) => (node.width && node.height) || (node.initialWidth && node.initialHeight)
|
||||||
|
);
|
||||||
// @todo users nodeOrigin should be used here
|
// @todo users nodeOrigin should be used here
|
||||||
const bounds = getNodesBounds(nodesWithDimensions, { nodeOrigin: [0, 0] });
|
const bounds = getNodesBounds(nodesWithDimensions, { nodeOrigin: [0, 0] });
|
||||||
viewport = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
|
viewport = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
|
||||||
@@ -101,7 +103,7 @@ export const getInitialStore = ({
|
|||||||
flowId: writable<string | null>(null),
|
flowId: writable<string | null>(null),
|
||||||
nodes: createNodesStore(nextNodes, nodeLookup),
|
nodes: createNodesStore(nextNodes, nodeLookup),
|
||||||
nodeLookup: readable<NodeLookup<Node>>(nodeLookup),
|
nodeLookup: readable<NodeLookup<Node>>(nodeLookup),
|
||||||
edgeLookup: readable<EdgeLookup>(edgeLookup),
|
edgeLookup: readable<EdgeLookup<Edge>>(edgeLookup),
|
||||||
visibleNodes: readable<Node[]>([]),
|
visibleNodes: readable<Node[]>([]),
|
||||||
edges: createEdgesStore(edges, connectionLookup, edgeLookup),
|
edges: createEdgesStore(edges, connectionLookup, edgeLookup),
|
||||||
visibleEdges: readable<EdgeLayouted[]>([]),
|
visibleEdges: readable<EdgeLayouted[]>([]),
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ export type NodeBase<
|
|||||||
connectable?: boolean;
|
connectable?: boolean;
|
||||||
deletable?: boolean;
|
deletable?: boolean;
|
||||||
dragHandle?: string;
|
dragHandle?: string;
|
||||||
width?: number | null;
|
width?: number;
|
||||||
height?: number | null;
|
height?: number;
|
||||||
|
initialWidth?: number;
|
||||||
|
initialHeight?: number;
|
||||||
/** Parent node id, used for creating sub-flows */
|
/** Parent node id, used for creating sub-flows */
|
||||||
parentNode?: string;
|
parentNode?: string;
|
||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { NodeBase, NodeHandle } from '../../types/nodes';
|
|||||||
import { Position } from '../../types/utils';
|
import { Position } from '../../types/utils';
|
||||||
import { errorMessages, internalsSymbol } from '../../constants';
|
import { errorMessages, internalsSymbol } from '../../constants';
|
||||||
import { HandleElement } from '../../types';
|
import { HandleElement } from '../../types';
|
||||||
|
import { getNodeDimensions } from '../general';
|
||||||
|
|
||||||
export type GetEdgePositionParams = {
|
export type GetEdgePositionParams = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -16,7 +17,10 @@ export type GetEdgePositionParams = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function isNodeInitialized(node: NodeBase): boolean {
|
function isNodeInitialized(node: NodeBase): boolean {
|
||||||
return !!(node?.[internalsSymbol]?.handleBounds || node?.handles?.length) && !!(node?.computed?.width || node?.width);
|
return (
|
||||||
|
!!(node?.[internalsSymbol]?.handleBounds || node?.handles?.length) &&
|
||||||
|
!!(node?.computed?.width || node?.width || node?.initialWidth)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEdgePosition(params: GetEdgePositionParams): EdgePosition | null {
|
export function getEdgePosition(params: GetEdgePositionParams): EdgePosition | null {
|
||||||
@@ -75,8 +79,8 @@ function toHandleBounds(handles?: NodeHandle[]) {
|
|||||||
const target = [];
|
const target = [];
|
||||||
|
|
||||||
for (const handle of handles) {
|
for (const handle of handles) {
|
||||||
handle.width = handle.width || 1;
|
handle.width = handle.width ?? 1;
|
||||||
handle.height = handle.height || 1;
|
handle.height = handle.height ?? 1;
|
||||||
|
|
||||||
if (handle.type === 'source') {
|
if (handle.type === 'source') {
|
||||||
source.push(handle as HandleElement);
|
source.push(handle as HandleElement);
|
||||||
@@ -94,8 +98,7 @@ function toHandleBounds(handles?: NodeHandle[]) {
|
|||||||
function getHandlePosition(position: Position, node: NodeBase, handle: HandleElement | null = null): number[] {
|
function getHandlePosition(position: Position, node: NodeBase, handle: HandleElement | null = null): number[] {
|
||||||
const x = (handle?.x ?? 0) + (node.computed?.positionAbsolute?.x ?? 0);
|
const x = (handle?.x ?? 0) + (node.computed?.positionAbsolute?.x ?? 0);
|
||||||
const y = (handle?.y ?? 0) + (node.computed?.positionAbsolute?.y ?? 0);
|
const y = (handle?.y ?? 0) + (node.computed?.positionAbsolute?.y ?? 0);
|
||||||
const width = handle?.width || (node?.computed?.width ?? node?.width ?? 0);
|
const { width, height } = handle ?? getNodeDimensions(node);
|
||||||
const height = handle?.height || (node?.computed?.height ?? node?.height ?? 0);
|
|
||||||
|
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case Position.Top:
|
case Position.Top:
|
||||||
|
|||||||
@@ -202,3 +202,19 @@ export const isMacOs = () => typeof navigator !== 'undefined' && navigator?.user
|
|||||||
export function isCoordinateExtent(extent?: CoordinateExtent | 'parent'): extent is CoordinateExtent {
|
export function isCoordinateExtent(extent?: CoordinateExtent | 'parent'): extent is CoordinateExtent {
|
||||||
return extent !== undefined && extent !== 'parent';
|
return extent !== undefined && extent !== 'parent';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNodeDimensions<NodeType extends NodeBase = NodeBase>(
|
||||||
|
node: NodeType
|
||||||
|
): { width: number; height: number } {
|
||||||
|
return {
|
||||||
|
width: node.computed?.width ?? node.width ?? node.initialWidth ?? 0,
|
||||||
|
height: node.computed?.height ?? node.height ?? node.initialHeight ?? 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function nodeHasDimensions<NodeType extends NodeBase = NodeBase>(node: NodeType): boolean {
|
||||||
|
return (
|
||||||
|
(node.computed?.width ?? node.width ?? node.initialWidth) !== undefined &&
|
||||||
|
(node.computed?.height ?? node.height ?? node.initialHeight) !== undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
pointToRendererPoint,
|
pointToRendererPoint,
|
||||||
getViewportForBounds,
|
getViewportForBounds,
|
||||||
isCoordinateExtent,
|
isCoordinateExtent,
|
||||||
|
getNodeDimensions,
|
||||||
} from './general';
|
} from './general';
|
||||||
import {
|
import {
|
||||||
type Transform,
|
type Transform,
|
||||||
@@ -116,8 +117,9 @@ export const getNodePositionWithOrigin = (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const offsetX = (node.computed?.width ?? node.width ?? 0) * nodeOrigin[0];
|
const { width, height } = getNodeDimensions(node);
|
||||||
const offsetY = (node.computed?.height ?? node.height ?? 0) * nodeOrigin[1];
|
const offsetX = width * nodeOrigin[0];
|
||||||
|
const offsetY = height * nodeOrigin[1];
|
||||||
|
|
||||||
const position: XYPosition = {
|
const position: XYPosition = {
|
||||||
x: node.position.x - offsetX,
|
x: node.position.x - offsetX,
|
||||||
@@ -164,8 +166,7 @@ export const getNodesBounds = (
|
|||||||
currBox,
|
currBox,
|
||||||
rectToBox({
|
rectToBox({
|
||||||
...nodePos[params.useRelativePosition ? 'position' : 'positionAbsolute'],
|
...nodePos[params.useRelativePosition ? 'position' : 'positionAbsolute'],
|
||||||
width: node.computed?.width ?? node.width ?? 0,
|
...getNodeDimensions(node),
|
||||||
height: node.computed?.height ?? node.height ?? 0,
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -192,8 +193,8 @@ export const getNodesInside = <NodeType extends NodeBase>(
|
|||||||
|
|
||||||
const visibleNodes = nodes.reduce<NodeType[]>((res, node) => {
|
const visibleNodes = nodes.reduce<NodeType[]>((res, node) => {
|
||||||
const { computed, selectable = true, hidden = false } = node;
|
const { computed, selectable = true, hidden = false } = node;
|
||||||
const width = computed?.width ?? node.width ?? null;
|
const width = computed?.width ?? node.width ?? node.initialWidth ?? null;
|
||||||
const height = computed?.height ?? node.height ?? null;
|
const height = computed?.height ?? node.height ?? node.initialHeight ?? null;
|
||||||
|
|
||||||
if ((excludeNonSelectableNodes && !selectable) || hidden) {
|
if ((excludeNonSelectableNodes && !selectable) || hidden) {
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
Reference in New Issue
Block a user