Merge branch 'main' into middlewares

This commit is contained in:
Moritz Klack
2025-12-02 16:34:21 +01:00
committed by GitHub
115 changed files with 2360 additions and 426 deletions

View File

@@ -17,9 +17,9 @@
"@types/react-dom": "^18.2.8",
"@xyflow/react": "workspace:^",
"@xyflow/svelte": "workspace:^",
"astro": "^5.9.2",
"astro": "^5.13.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"svelte": "^5.33.18"
"svelte": "^5.38.7"
}
}

View File

@@ -60,7 +60,7 @@ const initialNodes: Node[] = [
{
id: '3',
data: { label: 'Node 3' },
position: { x: 400, y: 100 },
position: { x: 900, y: 100 },
...nodeSize,
handles: [
{
@@ -110,9 +110,10 @@ function Flow() {
onEdgesChange={onEdgesChange}
onConnect={onConnect}
nodeTypes={nodeTypes}
fitView
// fitView
width={700}
height={400}
onlyRenderVisibleElements
>
<Background />
<Controls />

View File

@@ -54,7 +54,7 @@
},
{
id: 'C',
position: { x: 250, y: 300 },
position: { x: 950, y: 300 },
data: { label: 'C' },
sourcePosition: Position.Right,
targetPosition: Position.Left,
@@ -79,7 +79,7 @@
</script>
<div style="height: 400px; width: 700px;">
<SvelteFlow bind:nodes bind:edges fitView {defaultEdgeOptions} width={700} height={400}>
<SvelteFlow bind:nodes bind:edges onlyRenderVisibleElements {defaultEdgeOptions} width={700} height={400}>
<Controls />
<Background variant={BackgroundVariant.Dots} />
<ViewportPortal target="front">

View File

@@ -50,6 +50,7 @@ import CancelConnection from '../examples/CancelConnection';
import InteractiveMinimap from '../examples/InteractiveMinimap';
import UseOnSelectionChange from '../examples/UseOnSelectionChange';
import NodeToolbar from '../examples/NodeToolbar';
import EdgeToolbar from '../examples/EdgeToolbar';
import UseConnection from '../examples/UseConnection';
import UseNodesInitialized from '../examples/UseNodesInit';
import UseNodesData from '../examples/UseNodesData';
@@ -193,6 +194,11 @@ const routes: IRoute[] = [
path: 'edge-routing',
component: EdgeRouting,
},
{
name: 'Edge Toolbar',
path: 'edge-toolbar',
component: EdgeToolbar,
},
{
name: 'Empty',
path: 'empty',

View File

@@ -1,4 +1,4 @@
import { MouseEvent, useCallback } from 'react';
import { MouseEvent, useCallback, useState } from 'react';
import {
ReactFlow,
MiniMap,
@@ -134,47 +134,57 @@ const BasicFlow = () => {
});
fitView();
};
const [isHidden, setIsHidden] = useState(false);
const toggleVisibility = () => {
setIsHidden(!isHidden);
};
return (
<ReactFlow
defaultNodes={initialNodes}
defaultEdges={initialEdges}
onNodesChange={console.log}
onNodeClick={onNodeClick}
onNodeDragStop={onNodeDragStop}
onNodeDragStart={onNodeDragStart}
onNodeDrag={onNodeDrag}
onSelectionDragStart={printSelectionEvent('selection drag start')}
onSelectionDrag={printSelectionEvent('selection drag')}
onSelectionDragStop={printSelectionEvent('selection drag stop')}
className="react-flow-basic-example"
minZoom={0.2}
maxZoom={4}
fitView
fitViewOptions={fitViewOptions}
defaultEdgeOptions={defaultEdgeOptions}
selectNodesOnDrag={false}
elevateEdgesOnSelect
elevateNodesOnSelect={false}
nodeDragThreshold={0}
>
<Background variant={BackgroundVariant.Dots} />
<MiniMap />
<Controls />
<>
<ReactFlow
defaultNodes={initialNodes}
defaultEdges={initialEdges}
onNodesChange={console.log}
onNodeClick={onNodeClick}
onNodeDragStop={onNodeDragStop}
onNodeDragStart={onNodeDragStart}
onNodeDrag={onNodeDrag}
onSelectionDragStart={printSelectionEvent('selection drag start')}
onSelectionDrag={printSelectionEvent('selection drag')}
onSelectionDragStop={printSelectionEvent('selection drag stop')}
className="react-flow-basic-example"
style={{ display: isHidden ? 'none' : 'block' }}
minZoom={0.2}
maxZoom={4}
fitView
fitViewOptions={fitViewOptions}
defaultEdgeOptions={defaultEdgeOptions}
selectNodesOnDrag={false}
elevateEdgesOnSelect
elevateNodesOnSelect={false}
nodeDragThreshold={0}
>
<Background variant={BackgroundVariant.Dots} />
<MiniMap />
<Controls />
<Panel position="top-right">
<button onClick={resetTransform}>reset transform</button>
<button onClick={updatePos}>change pos</button>
<button onClick={toggleClassnames}>toggle classnames</button>
<button onClick={logToObject}>toObject</button>
<Panel position="top-right">
<button onClick={resetTransform}>reset transform</button>
<button onClick={updatePos}>change pos</button>
<button onClick={toggleClassnames}>toggle classnames</button>
<button onClick={logToObject}>toObject</button>
<button onClick={deleteSelectedElements}>deleteSelectedElements</button>
<button onClick={deleteSomeElements}>deleteSomeElements</button>
<button onClick={onSetNodes}>setNodes</button>
<button onClick={onUpdateNode}>updateNode</button>
<button onClick={addNode}>addNode</button>
</Panel>
</ReactFlow>
<button onClick={deleteSelectedElements}>deleteSelectedElements</button>
<button onClick={deleteSomeElements}>deleteSomeElements</button>
<button onClick={onSetNodes}>setNodes</button>
<button onClick={onUpdateNode}>updateNode</button>
<button onClick={addNode}>addNode</button>
</Panel>
</ReactFlow>
<button onClick={toggleVisibility} style={{ position: 'absolute', zIndex: 10, right: 10, top: 100 }}>
{isHidden ? 'Show' : 'Hide'} Flow
</button>
</>
);
};

View File

@@ -1,6 +1,7 @@
import { ConnectionLineComponentProps } from '@xyflow/react';
function ConnectionLine({ fromX, fromY, toX, toY }: ConnectionLineComponentProps) {
function ConnectionLine({ fromX, fromY, toX, toY, pointer }: ConnectionLineComponentProps) {
console.log('pointer', pointer);
return (
<>
<path

View File

@@ -1,4 +1,4 @@
import { MouseEvent, CSSProperties, useCallback } from 'react';
import { MouseEvent, CSSProperties, useCallback, useState } from 'react';
import {
ReactFlow,
@@ -14,19 +14,13 @@ import {
ReactFlowInstance,
useEdgesState,
useNodesState,
Panel,
} from '@xyflow/react';
const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const buttonStyle: CSSProperties = {
position: 'absolute',
left: 10,
top: 10,
zIndex: 4,
};
const CustomMiniMapNode = ({ x, y, width, height }: MiniMapNodeProps) => {
return <circle cx={x} cy={y} r={Math.max(width, height) / 2} fill="#ffcc00" />;
};
@@ -34,6 +28,7 @@ const CustomMiniMapNode = ({ x, y, width, height }: MiniMapNodeProps) => {
const CustomMiniMapNodeFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState<Node>([]);
const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([]);
const [hideAllNodes, setHideAllNodes] = useState(false);
const onConnect = useCallback((params: Connection | Edge) => setEdges((els) => addEdge(params, els)), [setEdges]);
const addRandomNode = () => {
@@ -45,10 +40,20 @@ const CustomMiniMapNodeFlow = () => {
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
},
hidden: hideAllNodes,
};
setNodes((nds) => nds.concat(newNode));
};
const toggleHideAllNodes = () => {
setHideAllNodes(prev => {
const next = !prev;
setNodes(nds => nds.map(n => ({ ...n, hidden: next })));
setEdges(eds => eds.map(e => ({ ...e, hidden: next })));
return next;
});
};
return (
<ReactFlow
nodes={nodes}
@@ -65,9 +70,14 @@ const CustomMiniMapNodeFlow = () => {
<Background variant={BackgroundVariant.Lines} />
<MiniMap nodeComponent={CustomMiniMapNode} />
<button type="button" onClick={addRandomNode} style={buttonStyle}>
add node
</button>
<Panel position="top-left">
<button type="button" onClick={addRandomNode}>
add node
</button>
<button type="button" onClick={toggleHideAllNodes}>
{hideAllNodes ? 'show all nodes' : 'hide all nodes'}
</button>
</Panel>
</ReactFlow>
);
};

View File

@@ -30,7 +30,7 @@ function ColorSelectorNode({ data, isConnectable }: NodeProps<ColorSelectorNode>
<div>
Custom Color Picker Node: <strong>{data.color}</strong>
</div>
<input className="nodrag" type="color" onChange={data.onChange} defaultValue={data.color} />
<input className="nodrag nokey" type="color" onChange={data.onChange} defaultValue={data.color} />
<Handle
type="source"
position={Position.Right}

View File

@@ -0,0 +1,40 @@
import { getBezierPath, BaseEdge, EdgeProps, useReactFlow, getStraightPath, getSmoothStepPath } from '@xyflow/react';
import { EdgeToolbar } from '@xyflow/react';
const getPath = (props: EdgeProps) => {
switch (props.data!.type) {
case 'smoothstep':
return getSmoothStepPath(props);
case 'straight':
return getStraightPath(props);
default:
return getBezierPath(props);
}
};
export function CustomEdge(props: EdgeProps) {
const [edgePath, centerX, centerY] = getPath(props);
const { setEdges } = useReactFlow();
const deleteEdge = () => {
setEdges((edges) => edges.filter((edge) => edge.id !== props.id));
};
return (
<>
<BaseEdge id={props.id} path={edgePath} />
<EdgeToolbar
edgeId={props.id}
x={centerX + 0}
y={centerY + 0}
alignX={props.data?.align?.[0] ?? 'center'}
alignY={props.data?.align?.[1] ?? 'center'}
isVisible
>
<button style={{}} onClick={deleteEdge}>
Delete
</button>
</EdgeToolbar>
</>
);
}

View File

@@ -0,0 +1,80 @@
import {
Background,
BackgroundVariant,
Controls,
Edge,
EdgeTypes,
MiniMap,
Node,
Position,
ReactFlow,
} from '@xyflow/react';
import { CustomEdge } from './CustomEdge';
const edgeTypes: EdgeTypes = {
custom: CustomEdge,
};
const initialNodes: Node[] = [
{
id: '1',
data: { label: 'Node 1', toolbarPosition: Position.Top },
position: { x: 0, y: 0 },
className: 'react-flow__node-default',
},
{
id: '2',
data: { label: 'Node 2', toolbarPosition: Position.Top },
position: { x: 100, y: 150 },
className: 'react-flow__node-default',
},
{
id: '3',
data: { label: 'Node 3', toolbarPosition: Position.Top },
position: { x: 200, y: 0 },
className: 'react-flow__node-default',
},
];
const initialEdges: Edge[] = [
{
id: 'e1-2',
source: '1',
target: '2',
type: 'custom',
data: { type: 'smoothstep', align: ['left', 'bottom'] },
},
{
id: 'e3-2',
source: '3',
target: '2',
type: 'custom',
data: { type: 'bezier', align: ['right', 'bottom'] },
},
{
id: 'e1-3',
source: '1',
target: '3',
type: 'custom',
data: { type: 'straight', align: ['center', 'center'] },
},
];
export default function EdgeToolbarExample() {
return (
<ReactFlow
defaultNodes={initialNodes}
defaultEdges={initialEdges}
className="react-flow-edge-toolbar-example"
minZoom={0.2}
maxZoom={4}
fitView
edgeTypes={edgeTypes}
>
<Background variant={BackgroundVariant.Dots} />
<MiniMap />
<Controls />
</ReactFlow>
);
}

View File

@@ -30,10 +30,11 @@ const BasicFlow = () => {
<ReactFlow
defaultNodes={initialNodes}
defaultEdges={initialEdges}
selectionOnDrag
selectionOnDrag={true}
selectionMode={SelectionMode.Partial}
panOnDrag={panOnDrag}
panOnScroll
paneClickDistance={100}
zoomActivationKeyCode="Meta"
multiSelectionKeyCode={MULTI_SELECT_KEY}
onPaneContextMenu={onPaneContextMenu}
@@ -43,6 +44,12 @@ const BasicFlow = () => {
onMoveStart={onMoveStart}
onMove={onMove}
onMoveEnd={onMoveEnd}
onPaneClick={(e) => console.log('pane click', e)}
onSelectionStart={(e) => console.log('on selection start', e)}
onSelectionEnd={(e) => console.log('on selection end', e)}
onPointerDown={(e) => console.log('pointer down', e)}
onPointerUp={(e) => console.log('pointer up', e)}
onClick={(e) => console.log('click', e)}
>
<Background variant={BackgroundVariant.Cross} />
<Controls />

View File

@@ -1,7 +1,9 @@
import { memo, FC } from 'react';
import { Handle, Position, NodeProps, NodeResizer } from '@xyflow/react';
import { Handle, Position, NodeProps, NodeResizer, useKeyPress } from '@xyflow/react';
const DefaultResizerNode: FC<NodeProps> = ({ data, selected }) => {
const keepAspectRatio = useKeyPress('k');
return (
<>
<NodeResizer
@@ -14,7 +16,7 @@ const DefaultResizerNode: FC<NodeProps> = ({ data, selected }) => {
onResizeStart={data.onResizeStart ?? undefined}
onResize={data.onResize ?? undefined}
onResizeEnd={data.onResizeEnd ?? undefined}
keepAspectRatio={data.keepAspectRatio ?? undefined}
keepAspectRatio={keepAspectRatio || (data.keepAspectRatio ?? undefined)}
/>
<Handle type="target" position={Position.Left} />
<div>{data.label}</div>

View File

@@ -239,6 +239,16 @@ const StressFlow = () => {
<button onClick={remount}>re-mount</button>
<button onClick={updatePos}>change pos</button>
<button onClick={updateElements}>update elements</button>
<button
onClick={() => {
setNodes((nds) => [
...nds,
{ id: (nds.length + 1).toString(), position: { x: 0, y: 0 }, data: { label: `Node ${nds.length + 1}` } },
]);
}}
>
Add element
</button>
</Panel>
</ReactFlow>
);

View File

@@ -27,15 +27,15 @@ const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
const defaultViewport = { x: 0, y: 0, zoom: 1.5 };
const initialNodes: Node[] = [
{
id: 'extent',
position: { x: 0, y: 0 },
width: 1000,
height: 1000,
data: { label: 'Extent' },
origin: [0, 0],
zIndex: -1,
},
// {
// id: 'extent',
// position: { x: 0, y: 0 },
// width: 1000,
// height: 1000,
// data: { label: 'Extent' },
// origin: [0, 0],
// zIndex: -1,
// },
{
id: '1',
type: 'input',
@@ -96,12 +96,12 @@ const initialNodes: Node[] = [
},
{
id: '5',
type: 'group',
// type: 'group',
data: { label: 'Node 5' },
position: { x: 650, y: 250 },
className: 'light',
style: { width: 100, height: 100 },
zIndex: 1000,
// zIndex: 1000,
},
{
id: '5a',

View File

@@ -7,11 +7,13 @@
'add-node-on-drop',
'color-mode',
'custom-connection-line',
'custom-minimap',
'customnode',
'dagre',
'detached-handle',
'drag-n-drop',
'edges',
'edge-toolbar',
'figma',
'handle-connect',
'interaction',

View File

@@ -19,6 +19,8 @@
}
return null;
});
$inspect(connection.current.pointer);
</script>
{#if connection.current.inProgress}

View File

@@ -0,0 +1,55 @@
<script lang="ts">
import {
SvelteFlow,
Background,
Controls,
MiniMap,
Panel,
type Node,
type Edge
} from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css';
import CustomMiniMapNode from './CustomMiniMapNode.svelte';
let nodes = $state.raw<Node[]>([]);
let edges = $state.raw<Edge[]>([]);
let hideAllNodes = $state(false);
function addRandomNode() {
const nodeId = (nodes.length + 1).toString();
const newNode: Node = {
id: nodeId,
data: { label: `Node: ${nodeId}` },
position: {
x: Math.random() * (typeof window !== 'undefined' ? window.innerWidth : 800),
y: Math.random() * (typeof window !== 'undefined' ? window.innerHeight : 600)
},
type: 'default',
hidden: hideAllNodes
};
nodes = [...nodes, newNode];
}
function toggleHideAllNodes() {
hideAllNodes = !hideAllNodes;
nodes = nodes.map((node) => ({
...node,
hidden: hideAllNodes
}));
}
</script>
<SvelteFlow bind:nodes bind:edges onlyRenderVisibleElements={true}>
<Controls />
<Background />
<MiniMap nodeComponent={CustomMiniMapNode} />
<Panel position="top-left">
<button type="button" onclick={addRandomNode}> add node </button>
<button type="button" onclick={toggleHideAllNodes}>
{hideAllNodes ? 'show all nodes' : 'hide all nodes'}
</button>
</Panel>
</SvelteFlow>

View File

@@ -0,0 +1,25 @@
<script lang="ts">
import type { MiniMapNodeProps } from '@xyflow/svelte';
let { id, x, y, width, height, selected }: MiniMapNodeProps = $props();
</script>
<circle
cx={x + width / 2}
cy={y + height / 2}
r={Math.min(width, height) - 2}
fill={selected ? '#ff6b6b' : '#ffcc00'}
/>
<text
x={x + width / 2}
y={y + height / 2}
text-anchor="middle"
dominant-baseline="middle"
fill="blue"
stroke-width="0.5"
font-size="100"
font-family="Arial, sans-serif"
font-weight="bold"
>
{id}
</text>

View File

@@ -13,7 +13,7 @@
Custom Color Picker Node: <strong>{bg.color}</strong>
</div>
<input
class="nodrag"
class="nodrag nokey"
type="color"
oninput={(evt) => (bg.color = evt.currentTarget.value)}
value={bg.color}

View File

@@ -0,0 +1,60 @@
<script lang="ts">
import { Background, Position, SvelteFlow, type Edge, type Node } from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css';
import CustomEdge from './CustomEdge.svelte';
const edgeTypes = {
custom: CustomEdge
};
const initialNodes: Node[] = [
{
id: '1',
data: { label: 'Node 1', toolbarPosition: Position.Top },
position: { x: 0, y: 0 },
class: 'svelte-flow__node-default'
},
{
id: '2',
data: { label: 'Node 2', toolbarPosition: Position.Top },
position: { x: 100, y: 150 },
class: 'svelte-flow__node-default'
},
{
id: '3',
data: { label: 'Node 3', toolbarPosition: Position.Top },
position: { x: 200, y: 0 },
class: 'svelte-flow__node-default'
}
];
const initialEdges: Edge[] = [
{
id: 'e1-2',
source: '1',
target: '2',
type: 'custom'
},
{
id: 'e3-2',
source: '3',
target: '2',
type: 'custom'
},
{
id: 'e1-3',
source: '1',
target: '3',
type: 'custom'
}
];
let nodes = $state.raw<Node[]>(initialNodes);
let edges = $state.raw<Edge[]>(initialEdges);
</script>
<SvelteFlow bind:nodes bind:edges {edgeTypes} fitView>
<Background />
</SvelteFlow>

View File

@@ -0,0 +1,26 @@
<script lang="ts">
import { getBezierPath, BaseEdge, type EdgeProps, useSvelteFlow } from '@xyflow/svelte';
import { EdgeToolbar } from '@xyflow/svelte';
const { deleteElements } = useSvelteFlow();
let { id, sourceX, sourceY, targetX, targetY }: EdgeProps = $props();
let [edgePath, labelX, labelY] = $derived(
getBezierPath({
sourceX,
sourceY,
targetX,
targetY
})
);
const deleteEdge = () => {
deleteElements({ edges: [{ id }] });
};
</script>
<BaseEdge {id} path={edgePath} />
<EdgeToolbar edgeId={id} x={labelX} y={labelY} isVisible>
<button onclick={deleteEdge}>Delete</button>
</EdgeToolbar>

View File

@@ -9,11 +9,6 @@
import '@xyflow/svelte/dist/style.css';
const onPaneContextMenu = (e: any) => {
e.preventDefault();
console.log('context menu');
};
const panOnDrag = [1, 2];
const onmovestart = (e: any) => console.log('move start', e);
@@ -44,12 +39,17 @@
bind:edges
fitView
selectionMode={SelectionMode.Partial}
multiSelectionKey={['Meta', 'Shift']}
selectionOnDrag
panOnScroll
paneClickDistance={100}
{panOnDrag}
{onmovestart}
{onmove}
{onmoveend}
onpaneclick={(e) => console.log('on pane click', e)}
onselectionend={(e) => console.log('on selection end', e)}
onselectionstart={(e) => console.log('on selection start', e)}
>
<Controls />
<Background variant={BackgroundVariant.Dots} />

View File

@@ -5,15 +5,18 @@
import CustomResizer from './CustomResizer.svelte';
import VerticalResizer from './VerticalResizer.svelte';
import HorizontalResizer from './HorizontalResizer.svelte';
import BottomRightResizer from './BottomRightResizer.svelte';
import '@xyflow/svelte/dist/style.css';
import type { ResizeNode } from './types';
import { store } from './store.svelte';
const nodeTypes = {
defaultResizer: DefaultResizer,
customResizer: CustomResizer,
verticalResizer: VerticalResizer,
horizontalResizer: HorizontalResizer
horizontalResizer: HorizontalResizer,
bottomRightResizer: BottomRightResizer
};
const nodeStyle = 'border: 1px solid #222; font-size: 10px; background-color: #ddd;';
@@ -124,12 +127,28 @@
position: { x: 100, y: 100 },
parentId: '5',
style: nodeStyle
},
{
id: '6',
type: 'bottomRightResizer',
data: { label: 'bottom-right horizontal resizer' },
position: { x: 500, y: 0 },
style: nodeStyle
}
]);
let snapToGrid = $state(false);
</script>
<svelte:window
on:keydown={(e) => {
if (e.key === 'k') store.keepAspectRatio = true;
}}
on:keyup={(e) => {
if (e.key === 'k') store.keepAspectRatio = false;
}}
/>
<SvelteFlow
bind:nodes
bind:edges

View File

@@ -0,0 +1,25 @@
<script lang="ts">
import {
Handle,
Position,
type NodeProps,
NodeResizeControl,
ResizeControlVariant
} from '@xyflow/svelte';
import type { ResizeNode } from './types';
let { data }: NodeProps<ResizeNode> = $props();
</script>
<NodeResizeControl
variant={ResizeControlVariant.Handle}
position="bottom-right"
resizeDirection="horizontal"
minWidth={100}
maxWidth={500}
color="orange"
autoScale={false}
/>
<Handle type="target" position={Position.Left} />
<div>{data.label}</div>
<Handle type="source" position={Position.Right} />

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { Handle, Position, type NodeProps, NodeResizeControl, type Node } from '@xyflow/svelte';
import type { ResizeNode } from './types';
import { store } from './store.svelte';
let { data }: NodeProps<ResizeNode> = $props();
</script>
@@ -14,7 +15,7 @@
onResizeStart={data.onResizeStart ?? undefined}
onResize={data.onResize ?? undefined}
onResizeEnd={data.onResizeEnd ?? undefined}
keepAspectRatio={data.keepAspectRatio ?? undefined}
keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)}
style="background: transparent; border: none;"
>
<svg

View File

@@ -2,6 +2,8 @@
import { Handle, NodeResizer, Position, type NodeProps } from '@xyflow/svelte';
import type { ResizeNode } from './types';
import { store } from './store.svelte';
let { data, selected }: NodeProps<ResizeNode> = $props();
</script>
@@ -15,7 +17,7 @@
onResizeStart={data.onResizeStart ?? undefined}
onResize={data.onResize ?? undefined}
onResizeEnd={data.onResizeEnd ?? undefined}
keepAspectRatio={data.keepAspectRatio ?? undefined}
keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)}
/>
<Handle type="target" position={Position.Left} />
<div>{data.label}</div>

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { Handle, NodeResizeControl, Position, type NodeProps } from '@xyflow/svelte';
import type { ResizeNode } from './types';
import { store } from './store.svelte';
let { data }: NodeProps<ResizeNode> = $props();
</script>
@@ -14,7 +15,7 @@
onResizeStart={data.onResizeStart ?? undefined}
onResize={data.onResize ?? undefined}
onResizeEnd={data.onResizeEnd ?? undefined}
keepAspectRatio={data.keepAspectRatio ?? undefined}
keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)}
color="red"
position={Position.Left}
/>

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { Handle, NodeResizeControl, Position, type NodeProps } from '@xyflow/svelte';
import type { ResizeNode } from './types';
import { store } from './store.svelte';
let { data }: NodeProps<ResizeNode> = $props();
</script>
@@ -14,7 +15,7 @@
onResizeStart={data.onResizeStart ?? undefined}
onResize={data.onResize ?? undefined}
onResizeEnd={data.onResizeEnd ?? undefined}
keepAspectRatio={data.keepAspectRatio ?? undefined}
keepAspectRatio={store.keepAspectRatio || (data.keepAspectRatio ?? undefined)}
color="red"
position={Position.Top}
/>

View File

@@ -0,0 +1,14 @@
function createStore() {
let keepAspectRatio = $state(false);
return {
get keepAspectRatio() {
return keepAspectRatio;
},
set keepAspectRatio(value: boolean) {
keepAspectRatio = value;
}
};
}
export const store = createStore();

View File

@@ -155,6 +155,8 @@
// console.log(edges.map((edge) => ({ id: edge.id, selected: edge.selected })));
edges.forEach((edge) => console.log({ id: edge.id, selected: edge.selected }));
});
let hidden = $state(false);
</script>
<!-- oninit={() => console.log('on init')}
@@ -197,6 +199,7 @@
}} -->
<SvelteFlow
style="display:{hidden ? 'none' : 'block'}"
bind:nodes
bind:edges
{nodeTypes}
@@ -247,7 +250,20 @@
<InitTracker />
</SvelteFlow>
<button
class="hide"
onclick={() => {
hidden = !hidden;
}}>Hide/Unhide</button
>
<style>
.hide {
position: absolute;
top: 80px;
right: 15px;
}
:root {
/* --background-color: #ffffdd; */
--background-pattern-color: #5050ff;