Merge pull request #4328 from xyflow/next

React Flow 12.0.0-next.19 and Svelte Flow 0.1.4
This commit is contained in:
Moritz Klack
2024-06-05 13:08:46 +02:00
committed by GitHub
40 changed files with 625 additions and 831 deletions
@@ -60,12 +60,13 @@ const ControlledUncontrolled = () => {
const updateNodePositions = () => { const updateNodePositions = () => {
instance.setNodes((nodes) => instance.setNodes((nodes) =>
nodes.map((node) => { nodes.map((node) => {
node.position = { return {
x: Math.random() * 400, ...node,
y: Math.random() * 400, position: {
x: Math.random() * 400,
y: Math.random() * 400,
},
}; };
return node;
}) })
); );
}; };
@@ -73,11 +74,12 @@ const ControlledUncontrolled = () => {
const updateEdgeColors = () => { const updateEdgeColors = () => {
instance.setEdges((edges) => instance.setEdges((edges) =>
edges.map((edge) => { edges.map((edge) => {
edge.style = { return {
stroke: '#ff5050', ...edge,
style: {
stroke: '#ff5050',
},
}; };
return edge;
}) })
); );
}; };
@@ -73,6 +73,8 @@ const HiddenFlow = () => {
setEdges(setHidden(isHidden)); setEdges(setHidden(isHidden));
}, [isHidden, setEdges, setNodes]); }, [isHidden, setEdges, setNodes]);
console.log(nodes);
return ( return (
<ReactFlow <ReactFlow
nodes={nodes} nodes={nodes}
+4 -4
View File
@@ -12,8 +12,8 @@
"format": "prettier --plugin-search-dir . --write ." "format": "prettier --plugin-search-dir . --write ."
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-auto": "^3.1.1", "@sveltejs/adapter-auto": "^3.2.1",
"@sveltejs/kit": "^2.5.2", "@sveltejs/kit": "^2.5.10",
"@typescript-eslint/eslint-plugin": "^6.10.0", "@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0", "@typescript-eslint/parser": "^6.10.0",
"eslint": "^8.53.0", "eslint": "^8.53.0",
@@ -25,12 +25,12 @@
"svelte-check": "^3.6.6", "svelte-check": "^3.6.6",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vite": "^4.5.0" "vite": "^5.2.12"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@dagrejs/dagre": "^1.0.4", "@dagrejs/dagre": "^1.0.4",
"@sveltejs/vite-plugin-svelte": "^3.0.2", "@sveltejs/vite-plugin-svelte": "^3.1.1",
"@xyflow/svelte": "workspace:^" "@xyflow/svelte": "workspace:^"
} }
} }
@@ -159,6 +159,8 @@
on:nodemouseenter={(event) => console.log('on node enter', event)} on:nodemouseenter={(event) => console.log('on node enter', event)}
on:nodemouseleave={(event) => console.log('on node leave', event)} on:nodemouseleave={(event) => console.log('on node leave', event)}
on:edgeclick={(event) => console.log('edge click', event)} on:edgeclick={(event) => console.log('edge click', event)}
on:edgemouseenter={(event) => console.log('edge enter', event)}
on:edgemouseleave={(event) => console.log('edge leave', event)}
onconnectstart={(event) => console.log('on connect start', event)} onconnectstart={(event) => console.log('on connect start', event)}
onconnect={(event) => console.log('on connect', event)} onconnect={(event) => console.log('on connect', event)}
onconnectend={(event) => console.log('on connect end', event)} onconnectend={(event) => console.log('on connect end', event)}
@@ -21,7 +21,7 @@
{ id: 'B', position: { x: 0, y: 100 }, data: { label: 'B' } } { id: 'B', position: { x: 0, y: 100 }, data: { label: 'B' } }
]); ]);
const edges = writable([{ id: 'ab', source: 'A', target: 'B' }]); const edges = writable([{ id: 'ab', source: 'A', target: 'B' }]);
const viewport = writable<Viewport>({ x: 0, y: 10, zoom: 1.25 }); const viewport = writable<Viewport>({ x: 100, y: 100, zoom: 1.25 });
const { fitView } = useSvelteFlow(); const { fitView } = useSvelteFlow();
@@ -35,7 +35,7 @@
}); });
</script> </script>
<SvelteFlow {nodes} {edges} fitView {viewport}> <SvelteFlow {nodes} {edges} {viewport}>
<Controls /> <Controls />
<Background variant={BackgroundVariant.Dots} /> <Background variant={BackgroundVariant.Dots} />
+8
View File
@@ -1,5 +1,13 @@
# @xyflow/react # @xyflow/react
## 12.0.0-next.19
- update internals on node resizer updates
- re-observe node when `node.hidden` is toggled
- update `updateNodeData` argument type - thanks @ogroppo
- add `selectable`, `deletable` and `draggable` to node and edge props
- add `parentId` to node props
## 12.0.0-next.18 ## 12.0.0-next.18
- don't show nodeTypes warning if not necessary you've created a new nodeTypes or edgeTypes - don't show nodeTypes warning if not necessary you've created a new nodeTypes or edgeTypes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/react", "name": "@xyflow/react",
"version": "12.0.0-next.18", "version": "12.0.0-next.19",
"description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.",
"keywords": [ "keywords": [
"react", "react",
@@ -215,6 +215,8 @@ export function EdgeWrapper<EdgeType extends Edge = Edge>({
type={edge.type} type={edge.type}
selected={edge.selected} selected={edge.selected}
animated={edge.animated} animated={edge.animated}
selectable={isSelectable}
deletable={edge.deletable ?? true}
label={edge.label} label={edge.label}
labelStyle={edge.labelStyle} labelStyle={edge.labelStyle}
labelShowBg={edge.labelShowBg} labelShowBg={edge.labelShowBg}
@@ -209,12 +209,16 @@ export function NodeWrapper<NodeType extends Node>({
positionAbsoluteX={clampedPosition.x} positionAbsoluteX={clampedPosition.x}
positionAbsoluteY={clampedPosition.y} positionAbsoluteY={clampedPosition.y}
selected={node.selected} selected={node.selected}
selectable={isSelectable}
draggable={isDraggable}
deletable={node.deletable ?? true}
isConnectable={isConnectable} isConnectable={isConnectable}
sourcePosition={node.sourcePosition} sourcePosition={node.sourcePosition}
targetPosition={node.targetPosition} targetPosition={node.targetPosition}
dragging={dragging} dragging={dragging}
dragHandle={node.dragHandle} dragHandle={node.dragHandle}
zIndex={internals.z} zIndex={internals.z}
parentId={node.parentId}
{...nodeDimensions} {...nodeDimensions}
/> />
</Provider> </Provider>
@@ -26,17 +26,17 @@ export function useNodeObserver({
const prevSourcePosition = useRef(node.sourcePosition); const prevSourcePosition = useRef(node.sourcePosition);
const prevTargetPosition = useRef(node.targetPosition); const prevTargetPosition = useRef(node.targetPosition);
const prevType = useRef(nodeType); const prevType = useRef(nodeType);
const isInitialized = hasDimensions && !!node.internals.handleBounds && !node.hidden; const isInitialized = hasDimensions && !!node.internals.handleBounds;
useEffect(() => { useEffect(() => {
if (nodeRef.current && (!isInitialized || observedNode.current !== nodeRef.current)) { if (nodeRef.current && !node.hidden && (!isInitialized || observedNode.current !== nodeRef.current)) {
if (observedNode.current) { if (observedNode.current) {
resizeObserver?.unobserve(observedNode.current); resizeObserver?.unobserve(observedNode.current);
} }
resizeObserver?.observe(nodeRef.current); resizeObserver?.observe(nodeRef.current);
observedNode.current = nodeRef.current; observedNode.current = nodeRef.current;
} }
}, [isInitialized]); }, [isInitialized, node.hidden]);
useEffect(() => { useEffect(() => {
return () => { return () => {
@@ -20,6 +20,7 @@ export function useResizeObserver() {
updates.set(id, { updates.set(id, {
id, id,
nodeElement: entry.target as HTMLDivElement, nodeElement: entry.target as HTMLDivElement,
force: true,
}); });
}); });
+1 -1
View File
@@ -100,7 +100,7 @@ export type EdgeTextProps = HTMLAttributes<SVGElement> &
*/ */
export type EdgeProps<EdgeType extends Edge = Edge> = Pick< export type EdgeProps<EdgeType extends Edge = Edge> = Pick<
EdgeType, EdgeType,
'id' | 'animated' | 'data' | 'style' | 'selected' | 'source' | 'target' 'id' | 'animated' | 'data' | 'style' | 'selected' | 'source' | 'target' | 'selectable' | 'deletable'
> & > &
EdgePosition & EdgePosition &
EdgeLabelOptions & { EdgeLabelOptions & {
+1 -1
View File
@@ -140,7 +140,7 @@ export type GeneralHelpers<NodeType extends Node = Node, EdgeType extends Edge =
*/ */
updateNodeData: ( updateNodeData: (
id: string, id: string,
dataUpdate: object | ((node: NodeType) => object), dataUpdate: Partial<NodeType['data']> | ((node: NodeType) => Partial<NodeType['data']>),
options?: { replace: boolean } options?: { replace: boolean }
) => void; ) => void;
}; };
+9
View File
@@ -1,5 +1,14 @@
# @xyflow/svelte # @xyflow/svelte
## 0.1.4
- add `selectable`, `deletable` and `draggable` to node and edge props
- add `parentId` to node props
- add `on:edgemouseenter` and `on:edgemouseleave` event handler
- fix deselection of edges
- remove pointer events from panel when user selection is active
- fix viewport initialization with user viewport
## 0.1.3 ## 0.1.3
- fix `NodeToolbar` for subflows - fix `NodeToolbar` for subflows
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/svelte", "name": "@xyflow/svelte",
"version": "0.1.3", "version": "0.1.4",
"description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.", "description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.",
"keywords": [ "keywords": [
"svelte", "svelte",
@@ -23,6 +23,7 @@
export let animated: $$Props['animated'] = false; export let animated: $$Props['animated'] = false;
export let selected: $$Props['selected'] = false; export let selected: $$Props['selected'] = false;
export let selectable: $$Props['selectable'] = undefined; export let selectable: $$Props['selectable'] = undefined;
export let deletable: $$Props['deletable'] = undefined;
export let hidden: $$Props['hidden'] = false; export let hidden: $$Props['hidden'] = false;
export let label: $$Props['label'] = undefined; export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined; export let labelStyle: $$Props['labelStyle'] = undefined;
@@ -49,13 +50,15 @@
const dispatch = createEventDispatcher<{ const dispatch = createEventDispatcher<{
edgeclick: { edge: Edge; event: MouseEvent | TouchEvent }; edgeclick: { edge: Edge; event: MouseEvent | TouchEvent };
edgecontextmenu: { edge: Edge; event: MouseEvent }; edgecontextmenu: { edge: Edge; event: MouseEvent };
edgemouseenter: { edge: Edge; event: MouseEvent };
edgemouseleave: { edge: Edge; event: MouseEvent };
}>(); }>();
$: edgeType = type || 'default'; $: edgeType = type || 'default';
$: edgeComponent = $edgeTypes[edgeType] || BezierEdgeInternal; $: edgeComponent = $edgeTypes[edgeType] || BezierEdgeInternal;
$: markerStartUrl = markerStart ? `url('#${getMarkerId(markerStart, $flowId)}')` : undefined; $: markerStartUrl = markerStart ? `url('#${getMarkerId(markerStart, $flowId)}')` : undefined;
$: markerEndUrl = markerEnd ? `url('#${getMarkerId(markerEnd, $flowId)}')` : undefined; $: markerEndUrl = markerEnd ? `url('#${getMarkerId(markerEnd, $flowId)}')` : undefined;
$: isSelectable = selectable || ($elementsSelectable && typeof selectable === 'undefined'); $: isSelectable = selectable ?? $elementsSelectable;
const handleEdgeSelect = useHandleEdgeSelect(); const handleEdgeSelect = useHandleEdgeSelect();
@@ -68,11 +71,12 @@
} }
} }
function onContextMenu(event: MouseEvent) { type EdgeMouseEvent = 'edgecontextmenu' | 'edgemouseenter' | 'edgemouseleave';
function onMouseEvent(event: MouseEvent, type: EdgeMouseEvent) {
const edge = $edgeLookup.get(id); const edge = $edgeLookup.get(id);
if (edge) { if (edge) {
dispatch('edgecontextmenu', { event, edge }); dispatch(type, { event, edge });
} }
} }
</script> </script>
@@ -88,7 +92,15 @@
class:selectable={isSelectable} class:selectable={isSelectable}
data-id={id} data-id={id}
on:click={onClick} on:click={onClick}
on:contextmenu={onContextMenu} on:contextmenu={(e) => {
onMouseEvent(e, 'edgecontextmenu');
}}
on:mouseenter={(e) => {
onMouseEvent(e, 'edgemouseenter');
}}
on:mouseleave={(e) => {
onMouseEvent(e, 'edgemouseleave');
}}
aria-label={ariaLabel === null aria-label={ariaLabel === null
? undefined ? undefined
: ariaLabel : ariaLabel
@@ -114,6 +126,8 @@
{data} {data}
{style} {style}
{interactionWidth} {interactionWidth}
selectable={isSelectable}
deletable={deletable ?? true}
type={edgeType} type={edgeType}
sourceHandleId={sourceHandle} sourceHandleId={sourceHandle}
targetHandleId={targetHandle} targetHandleId={targetHandle}
@@ -22,6 +22,7 @@
export let draggable: $$Props['draggable'] = undefined; export let draggable: $$Props['draggable'] = undefined;
export let selectable: $$Props['selectable'] = undefined; export let selectable: $$Props['selectable'] = undefined;
export let connectable: $$Props['connectable'] = true; export let connectable: $$Props['connectable'] = true;
export let deletable: $$Props['deletable'] = true;
export let hidden: $$Props['hidden'] = false; export let hidden: $$Props['hidden'] = false;
export let dragging: boolean = false; export let dragging: boolean = false;
export let resizeObserver: $$Props['resizeObserver'] = null; export let resizeObserver: $$Props['resizeObserver'] = null;
@@ -43,6 +44,8 @@
export let height: $$Props['height'] = undefined; export let height: $$Props['height'] = undefined;
export let dragHandle: $$Props['dragHandle'] = undefined; export let dragHandle: $$Props['dragHandle'] = undefined;
export let initialized: $$Props['initialized'] = false; export let initialized: $$Props['initialized'] = false;
export let parentId: $$Props['parentId'] = undefined;
let className: string = ''; let className: string = '';
export { className as class }; export { className as class };
@@ -192,11 +195,15 @@
{data} {data}
{id} {id}
{selected} {selected}
{selectable}
{deletable}
{sourcePosition} {sourcePosition}
{targetPosition} {targetPosition}
{zIndex} {zIndex}
{dragging} {dragging}
{draggable}
{dragHandle} {dragHandle}
{parentId}
type={nodeType} type={nodeType}
isConnectable={$connectableStore} isConnectable={$connectableStore}
positionAbsoluteX={positionX} positionAbsoluteX={positionX}
@@ -10,6 +10,7 @@ export type NodeWrapperProps = Pick<
| 'dragging' | 'dragging'
| 'selected' | 'selected'
| 'selectable' | 'selectable'
| 'deletable'
| 'style' | 'style'
| 'type' | 'type'
| 'sourcePosition' | 'sourcePosition'
@@ -20,6 +21,7 @@ export type NodeWrapperProps = Pick<
| 'height' | 'height'
| 'initialWidth' | 'initialWidth'
| 'initialHeight' | 'initialHeight'
| 'parentId'
> & { > & {
measuredWidth?: number; measuredWidth?: number;
measuredHeight?: number; measuredHeight?: number;
@@ -6,16 +6,8 @@
type $$Props = EdgeProps; type $$Props = EdgeProps;
// these props are not used in this edge, but passed to every custom edge component
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let type: $$Props['type'] = 'default';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined; export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined; export let labelStyle: $$Props['labelStyle'] = undefined;
export let data: $$Props['data'] = undefined;
export let style: $$Props['style'] = undefined; export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined; export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined; export let markerEnd: $$Props['markerEnd'] = undefined;
@@ -24,12 +16,10 @@
export let sourceX: $$Props['sourceX']; export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY']; export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition']; export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX']; export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY']; export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition']; export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [path, labelX, labelY] = getBezierPath({ $: [path, labelX, labelY] = getBezierPath({
sourceX, sourceX,
@@ -40,16 +30,8 @@
targetPosition targetPosition
}); });
// hopefully with Svelte5, we don't need this kind of workaround anymore // this is a workaround for suppressing the warning about unused props
id; $$restProps;
source;
target;
type;
animated;
selected;
data;
sourceHandleId;
targetHandleId;
</script> </script>
<BaseEdge <BaseEdge
@@ -6,17 +6,8 @@
type $$Props = EdgeProps; type $$Props = EdgeProps;
// these props are not used in this edge, but passed to every custom edge component
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let type: $$Props['type'] = 'smoothstep';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined; export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined; export let labelStyle: $$Props['labelStyle'] = undefined;
export let data: $$Props['data'] = undefined;
export let style: $$Props['style'] = undefined; export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined; export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined; export let markerEnd: $$Props['markerEnd'] = undefined;
@@ -25,12 +16,10 @@
export let sourceX: $$Props['sourceX']; export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY']; export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition']; export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX']; export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY']; export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition']; export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [path, labelX, labelY] = getSmoothStepPath({ $: [path, labelX, labelY] = getSmoothStepPath({
sourceX, sourceX,
@@ -41,15 +30,8 @@
targetPosition targetPosition
}); });
id; // this is a workaround for suppressing the warning about unused props
source; $$restProps;
target;
type;
animated;
selected;
data;
sourceHandleId;
targetHandleId;
</script> </script>
<BaseEdge <BaseEdge
@@ -6,16 +6,7 @@
type $$Props = EdgeProps; type $$Props = EdgeProps;
// these props are not used in this edge, but passed to every custom edge component
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let type: $$Props['type'] = 'step';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined; export let label: $$Props['label'] = undefined;
export let data: $$Props['data'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined; export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined; export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined; export let markerStart: $$Props['markerStart'] = undefined;
@@ -25,12 +16,10 @@
export let sourceX: $$Props['sourceX']; export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY']; export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition']; export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX']; export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY']; export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition']; export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [path, labelX, labelY] = getSmoothStepPath({ $: [path, labelX, labelY] = getSmoothStepPath({
sourceX, sourceX,
@@ -42,15 +31,8 @@
borderRadius: 0 borderRadius: 0
}); });
id; // this is a workaround for suppressing the warning about unused props
source; $$restProps;
target;
type;
animated;
selected;
data;
sourceHandleId;
targetHandleId;
</script> </script>
<BaseEdge <BaseEdge
@@ -6,17 +6,8 @@
type $$Props = EdgeProps; type $$Props = EdgeProps;
// these props are not used in this edge, but passed to every custom edge component
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let type: $$Props['type'] = 'straight';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined; export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined; export let labelStyle: $$Props['labelStyle'] = undefined;
export let data: $$Props['data'] = undefined;
export let style: $$Props['style'] = undefined; export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined; export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined; export let markerEnd: $$Props['markerEnd'] = undefined;
@@ -24,13 +15,9 @@
export let sourceX: $$Props['sourceX']; export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY']; export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX']; export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY']; export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [path, labelX, labelY] = getStraightPath({ $: [path, labelX, labelY] = getStraightPath({
sourceX, sourceX,
@@ -39,17 +26,8 @@
targetY targetY
}); });
id; // this is a workaround for suppressing the warning about unused props
source; $$restProps;
target;
type;
animated;
selected;
data;
sourcePosition;
targetPosition;
sourceHandleId;
targetHandleId;
</script> </script>
<BaseEdge <BaseEdge
@@ -7,36 +7,13 @@
interface $$Props extends NodeProps {} interface $$Props extends NodeProps {}
export let data: $$Props['data'] = { label: 'Node' }; export let data: $$Props['data'] = { label: 'Node' };
export let targetPosition: $$Props['targetPosition'] = Position.Top; export let targetPosition: $$Props['targetPosition'] = undefined;
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom; export let sourcePosition: $$Props['sourcePosition'] = undefined;
// unused props - we need to list them here in order to prevent warnings // this is a workaround for suppressing the warning about unused props
export let id: $$Props['id'] = ''; $$restProps;
export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let type: $$Props['type'] = undefined;
export let dragging: $$Props['dragging'] = false;
export let dragHandle: $$Props['dragHandle'] = undefined;
export let positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
export let isConnectable: $$Props['isConnectable'];
export let zIndex: $$Props['zIndex'];
// @todo: there must be a better way to do this
id;
width;
height;
selected;
type;
zIndex;
dragging;
dragHandle;
positionAbsoluteX;
positionAbsoluteY;
isConnectable;
</script> </script>
<Handle type="target" position={targetPosition} /> <Handle type="target" position={targetPosition ?? Position.Top} />
{data?.label} {data?.label}
<Handle type="source" position={sourcePosition} /> <Handle type="source" position={sourcePosition ?? Position.Bottom} />
@@ -3,35 +3,6 @@
interface $$Props extends NodeProps {} interface $$Props extends NodeProps {}
// unused props - we need to list them here in order to prevent warnings // this is a workaround for suppressing the warning about unused props
export let id: $$Props['id'] = ''; $$restProps;
export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = undefined;
export let data: $$Props['data'] = {};
export let selected: $$Props['selected'] = undefined;
export let sourcePosition: $$Props['sourcePosition'] = undefined;
export let targetPosition: $$Props['targetPosition'] = undefined;
export let type: $$Props['type'] = undefined;
export let dragging: $$Props['dragging'] = false;
export let dragHandle: $$Props['dragHandle'] = undefined;
export let positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
export let isConnectable: $$Props['isConnectable'];
export let zIndex: $$Props['zIndex'];
// @todo: there must be a better way to do this
id;
width;
height;
data;
selected;
sourcePosition;
targetPosition;
type;
zIndex;
dragging;
dragHandle;
positionAbsoluteX;
positionAbsoluteY;
isConnectable;
</script> </script>
@@ -7,36 +7,11 @@
interface $$Props extends NodeProps {} interface $$Props extends NodeProps {}
export let data: $$Props['data'] = { label: 'Node' }; export let data: $$Props['data'] = { label: 'Node' };
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom; export let sourcePosition: $$Props['sourcePosition'] = undefined;
// unused props - we need to list them here in order to prevent warnings // this is a workaround for suppressing the warning about unused props
export let id: $$Props['id'] = ''; $$restProps;
export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let targetPosition: $$Props['targetPosition'] = undefined;
export let type: $$Props['type'] = undefined;
export let dragging: $$Props['dragging'] = false;
export let dragHandle: $$Props['dragHandle'] = undefined;
export let positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
export let isConnectable: $$Props['isConnectable'];
export let zIndex: $$Props['zIndex'];
// @todo: there must be a better way to do this
id;
width;
height;
selected;
targetPosition;
type;
zIndex;
dragging;
dragHandle;
positionAbsoluteX;
positionAbsoluteY;
isConnectable;
</script> </script>
{data?.label} {data?.label}
<Handle type="source" position={sourcePosition} /> <Handle type="source" position={sourcePosition ?? Position.Bottom} />
@@ -7,36 +7,11 @@
interface $$Props extends NodeProps {} interface $$Props extends NodeProps {}
export let data: $$Props['data'] = { label: 'Node' }; export let data: $$Props['data'] = { label: 'Node' };
export let targetPosition: $$Props['targetPosition'] = Position.Top; export let targetPosition: $$Props['targetPosition'] = undefined;
// unused props - we need to list them here in order to prevent warnings // this is a workaround for suppressing the warning about unused props
export let id: $$Props['id'] = ''; $$restProps;
export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let sourcePosition: $$Props['sourcePosition'] = undefined;
export let type: $$Props['type'] = undefined;
export let dragging: $$Props['dragging'] = false;
export let dragHandle: $$Props['dragHandle'] = undefined;
export let positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
export let isConnectable: $$Props['isConnectable'];
export let zIndex: $$Props['zIndex'];
// @todo: there must be a better way to do this
id;
width;
height;
selected;
sourcePosition;
type;
zIndex;
dragging;
dragHandle;
positionAbsoluteX;
positionAbsoluteY;
isConnectable;
</script> </script>
{data?.label} {data?.label}
<Handle type="target" position={targetPosition} /> <Handle type="target" position={targetPosition ?? Position.Top} />
@@ -11,7 +11,8 @@
const { const {
visibleEdges, visibleEdges,
edgesInitialized, edgesInitialized,
edges: { setDefaultOptions } edges: { setDefaultOptions },
elementsSelectable
} = useStore(); } = useStore();
onMount(() => { onMount(() => {
@@ -33,7 +34,8 @@
style={edge.style} style={edge.style}
animated={edge.animated} animated={edge.animated}
selected={edge.selected} selected={edge.selected}
selectable={edge.selectable} selectable={edge.selectable ?? $elementsSelectable}
deletable={edge.deletable}
hidden={edge.hidden} hidden={edge.hidden}
label={edge.label} label={edge.label}
labelStyle={edge.labelStyle} labelStyle={edge.labelStyle}
@@ -54,6 +56,8 @@
zIndex={edge.zIndex} zIndex={edge.zIndex}
on:edgeclick on:edgeclick
on:edgecontextmenu on:edgecontextmenu
on:edgemouseenter
on:edgemouseleave
/> />
{/each} {/each}
@@ -62,6 +62,7 @@
node.connectable || node.connectable ||
($nodesConnectable && typeof node.connectable === 'undefined') ($nodesConnectable && typeof node.connectable === 'undefined')
)} )}
deletable={node.deletable ?? true}
positionX={node.internals.positionAbsolute.x} positionX={node.internals.positionAbsolute.x}
positionY={node.internals.positionAbsolute.y} positionY={node.internals.positionAbsolute.y}
positionOriginX={posOrigin.x ?? 0} positionOriginX={posOrigin.x ?? 0}
@@ -82,6 +83,7 @@
initialHeight={node.initialHeight} initialHeight={node.initialHeight}
measuredWidth={node.measured.width} measuredWidth={node.measured.width}
measuredHeight={node.measured.height} measuredHeight={node.measured.height}
parentId={node.parentId}
{resizeObserver} {resizeObserver}
on:nodeclick on:nodeclick
on:nodemouseenter on:nodemouseenter
@@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import cc from 'classcat'; import cc from 'classcat';
import type { PanelProps } from './types'; import type { PanelProps } from './types';
import { useStore } from '$lib/store';
type $$Props = PanelProps; type $$Props = PanelProps;
@@ -10,9 +11,16 @@
let className: $$Props['class'] = undefined; let className: $$Props['class'] = undefined;
export { className as class }; export { className as class };
const { selectionRectMode } = useStore();
$: positionClasses = `${position}`.split('-'); $: positionClasses = `${position}`.split('-');
</script> </script>
<div class={cc(['svelte-flow__panel', className, ...positionClasses])} {style} {...$$restProps}> <div
class={cc(['svelte-flow__panel', className, ...positionClasses])}
{style}
style:pointer-events={$selectionRectMode ? 'none' : undefined}
{...$$restProps}
>
<slot /> <slot />
</div> </div>
@@ -2,7 +2,7 @@
import { onMount, hasContext } from 'svelte'; import { onMount, hasContext } from 'svelte';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import cc from 'classcat'; import cc from 'classcat';
import { ConnectionMode, PanOnScrollMode, type Viewport } from '@xyflow/system'; import { ConnectionMode, PanOnScrollMode } from '@xyflow/system';
import { Zoom } from '$lib/container/Zoom'; import { Zoom } from '$lib/container/Zoom';
import { Pane } from '$lib/container/Pane'; import { Pane } from '$lib/container/Pane';
@@ -28,7 +28,7 @@
export let fitViewOptions: $$Props['fitViewOptions'] = undefined; export let fitViewOptions: $$Props['fitViewOptions'] = undefined;
export let minZoom: $$Props['minZoom'] = undefined; export let minZoom: $$Props['minZoom'] = undefined;
export let maxZoom: $$Props['maxZoom'] = undefined; export let maxZoom: $$Props['maxZoom'] = undefined;
export let initialViewport: Viewport = { x: 0, y: 0, zoom: 1 }; export let initialViewport: $$Props['initialViewport'] = undefined;
export let viewport: $$Props['viewport'] = undefined; export let viewport: $$Props['viewport'] = undefined;
export let nodeTypes: $$Props['nodeTypes'] = undefined; export let nodeTypes: $$Props['nodeTypes'] = undefined;
export let edgeTypes: $$Props['edgeTypes'] = undefined; export let edgeTypes: $$Props['edgeTypes'] = undefined;
@@ -89,6 +89,8 @@
let clientWidth: number; let clientWidth: number;
let clientHeight: number; let clientHeight: number;
const initViewport = $viewport || initialViewport;
const store = hasContext(key) const store = hasContext(key)
? useStore() ? useStore()
: createStoreContext({ nodes: get(nodes), edges: get(edges), width, height, fitView }); : createStoreContext({ nodes: get(nodes), edges: get(edges), width, height, fitView });
@@ -203,7 +205,7 @@
{zoomActivationKey} {zoomActivationKey}
/> />
<Zoom <Zoom
{initialViewport} initialViewport={initViewport}
{onMoveStart} {onMoveStart}
{onMove} {onMove}
{onMoveEnd} {onMoveEnd}
@@ -222,7 +224,13 @@
{selectionOnDrag} {selectionOnDrag}
> >
<ViewportComponent> <ViewportComponent>
<EdgeRenderer on:edgeclick on:edgecontextmenu {defaultEdgeOptions} /> <EdgeRenderer
on:edgeclick
on:edgecontextmenu
on:edgemouseenter
on:edgemouseleave
{defaultEdgeOptions}
/>
<ConnectionLine <ConnectionLine
containerStyle={connectionLineContainerStyle} containerStyle={connectionLineContainerStyle}
style={connectionLineStyle} style={connectionLineStyle}
@@ -8,7 +8,7 @@
type $$Props = ZoomProps; type $$Props = ZoomProps;
export let initialViewport: $$Props['initialViewport']; export let initialViewport: $$Props['initialViewport'] = undefined;
export let onMoveStart: $$Props['onMoveStart'] = undefined; export let onMoveStart: $$Props['onMoveStart'] = undefined;
export let onMove: $$Props['onMove'] = undefined; export let onMove: $$Props['onMove'] = undefined;
export let onMoveEnd: $$Props['onMoveEnd'] = undefined; export let onMoveEnd: $$Props['onMoveEnd'] = undefined;
@@ -1,7 +1,7 @@
import type { OnMoveStart, OnMove, OnMoveEnd, PanOnScrollMode, Viewport } from '@xyflow/system'; import type { OnMoveStart, OnMove, OnMoveEnd, PanOnScrollMode, Viewport } from '@xyflow/system';
export type ZoomProps = { export type ZoomProps = {
initialViewport: Viewport; initialViewport?: Viewport;
panOnScrollMode: PanOnScrollMode; panOnScrollMode: PanOnScrollMode;
onMove?: OnMove; onMove?: OnMove;
onMoveStart?: OnMoveStart; onMoveStart?: OnMoveStart;
+2 -2
View File
@@ -210,10 +210,10 @@ export function createStore({
function unselectNodesAndEdges(params?: { nodes?: Node[]; edges?: Edge[] }) { function unselectNodesAndEdges(params?: { nodes?: Node[]; edges?: Edge[] }) {
const resetNodes = resetSelectedElements(params?.nodes || get(store.nodes)); const resetNodes = resetSelectedElements(params?.nodes || get(store.nodes));
if (resetNodes) store.nodes.update((nds) => nds); if (resetNodes) store.nodes.set(get(store.nodes));
const resetEdges = resetSelectedElements(params?.edges || get(store.edges)); const resetEdges = resetSelectedElements(params?.edges || get(store.edges));
if (resetEdges) store.edges.update((nds) => nds); if (resetEdges) store.edges.set(get(store.edges));
} }
store.deleteKeyPressed.subscribe(async (deleteKeyPressed) => { store.deleteKeyPressed.subscribe(async (deleteKeyPressed) => {
+1
View File
@@ -133,6 +133,7 @@ export type EdgeLayouted = Pick<
| 'animated' | 'animated'
| 'selected' | 'selected'
| 'selectable' | 'selectable'
| 'deletable'
| 'label' | 'label'
| 'labelStyle' | 'labelStyle'
| 'interactionWidth' | 'interactionWidth'
+5 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/system", "name": "@xyflow/system",
"version": "0.0.26", "version": "0.0.27",
"description": "xyflow core system that powers React Flow and Svelte Flow.", "description": "xyflow core system that powers React Flow and Svelte Flow.",
"keywords": [ "keywords": [
"node-based UI", "node-based UI",
@@ -42,10 +42,10 @@
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@types/d3": "^7.4.0", "@types/d3-drag": "^3.0.7",
"@types/d3-drag": "^3.0.1", "@types/d3-selection": "^3.0.10",
"@types/d3-selection": "^3.0.3", "@types/d3-transition": "^3.0.8",
"@types/d3-zoom": "^3.0.1", "@types/d3-zoom": "^3.0.8",
"d3-drag": "^3.0.0", "d3-drag": "^3.0.0",
"d3-selection": "^3.0.0", "d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0" "d3-zoom": "^3.0.0"
+6 -1
View File
@@ -1,5 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { D3DragEvent, Selection as D3Selection, SubjectPosition, ZoomBehavior } from 'd3'; import type { Selection as D3Selection } from 'd3-selection';
import type { D3DragEvent, SubjectPosition } from 'd3-drag';
import type { ZoomBehavior } from 'd3-zoom';
// this is needed for the Selection type to include the transition function :/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { Transition } from 'd3-transition';
import type { XYPosition, Rect } from './utils'; import type { XYPosition, Rect } from './utils';
import type { InternalNodeBase, NodeBase, NodeDragItem, NodeOrigin } from './nodes'; import type { InternalNodeBase, NodeBase, NodeDragItem, NodeOrigin } from './nodes';
+12 -1
View File
@@ -87,7 +87,18 @@ export type InternalNodeBase<NodeType extends NodeBase = NodeBase> = NodeType &
*/ */
export type NodeProps<NodeType extends NodeBase> = Pick< export type NodeProps<NodeType extends NodeBase> = Pick<
NodeType, NodeType,
'id' | 'data' | 'width' | 'height' | 'sourcePosition' | 'targetPosition' | 'selected' | 'dragHandle' | 'id'
| 'data'
| 'width'
| 'height'
| 'sourcePosition'
| 'targetPosition'
| 'selected'
| 'dragHandle'
| 'selectable'
| 'deletable'
| 'draggable'
| 'parentId'
> & > &
Required<Pick<NodeType, 'type' | 'dragging' | 'zIndex'>> & { Required<Pick<NodeType, 'type' | 'dragging' | 'zIndex'>> & {
/** whether a node is connectable or not */ /** whether a node is connectable or not */
+1 -1
View File
@@ -247,7 +247,7 @@ export function evaluateAbsolutePosition(
const positionAbsolute = { ...position }; const positionAbsolute = { ...position };
while (nextParentId) { while (nextParentId) {
const parent = nodeLookup.get(parentId); const parent = nodeLookup.get(nextParentId);
nextParentId = parent?.parentId; nextParentId = parent?.parentId;
if (parent) { if (parent) {
+458 -578
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -7,12 +7,12 @@
"main": "src/index.js", "main": "src/index.js",
"module": "src/index.js", "module": "src/index.js",
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-commonjs": "^25.0.8",
"@rollup/plugin-node-resolve": "^15.1.0", "@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-replace": "^5.0.6",
"@rollup/plugin-terser": "^0.4.3", "@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "11.0.0", "@rollup/plugin-typescript": "11.1.6",
"rollup": "^3.23.0", "rollup": "^4.18.0",
"rollup-plugin-peer-deps-external": "^2.2.4", "rollup-plugin-peer-deps-external": "^2.2.4",
"typescript": "^5.1.3" "typescript": "^5.1.3"
} }