refactor(svelte): cleanup types
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
# @reactflow/core
|
# @reactflow/edge-utils
|
||||||
|
|
||||||
Core components and util functions of React Flow.
|
Edge util functions of React Flow.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install @reactflow/core
|
npm install @reactflow/edge-utils
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,6 @@
|
|||||||
# create-svelte
|
# SvelteFlow
|
||||||
|
|
||||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
|
A highly customizable Svelte component for building interactive graphs and node-based editors.
|
||||||
|
|
||||||
## Creating a project
|
|
||||||
|
|
||||||
If you're seeing this, you've probably already done this step. Congrats!
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# create a new project in the current directory
|
|
||||||
npm create svelte@latest
|
|
||||||
|
|
||||||
# create a new project in my-app
|
|
||||||
npm create svelte@latest my-app
|
|
||||||
```
|
|
||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { get, type Writable } from 'svelte/store';
|
import { get, type Writable } from 'svelte/store';
|
||||||
import { drag as d3Drag, type D3DragEvent, type SubjectPosition } from 'd3-drag';
|
import { drag as d3Drag, type D3DragEvent, type SubjectPosition } from 'd3-drag';
|
||||||
import { select } from 'd3-selection';
|
import { select } from 'd3-selection';
|
||||||
import type { XYPosition, CoordinateExtent, Node, Transform } from '@reactflow/system';
|
import type { XYPosition, CoordinateExtent, Transform, Node as RFNode } from '@reactflow/system';
|
||||||
|
|
||||||
import { getDragItems, hasSelector, calcNextPosition } from './utils';
|
import { getDragItems, hasSelector, calcNextPosition } from './utils';
|
||||||
|
import type { Node } from '$lib/types';
|
||||||
|
|
||||||
export type UseDragData = { dx: number; dy: number };
|
export type UseDragData = { dx: number; dy: number };
|
||||||
export type UseDragEvent = D3DragEvent<HTMLDivElement, null, SubjectPosition>;
|
export type UseDragEvent = D3DragEvent<HTMLDivElement, null, SubjectPosition>;
|
||||||
@@ -69,7 +70,7 @@ export default function drag(
|
|||||||
|
|
||||||
dragItems = dragItems.map((n) => {
|
dragItems = dragItems.map((n) => {
|
||||||
const nextPosition = { x: x - n.distance.x, y: y - n.distance.y };
|
const nextPosition = { x: x - n.distance.x, y: y - n.distance.y };
|
||||||
const updatedPos = calcNextPosition(n, nextPosition, get(nodesStore));
|
const updatedPos = calcNextPosition(n, nextPosition, get(nodesStore) as RFNode[]);
|
||||||
|
|
||||||
// we want to make sure that we only fire a change event when there is a changes
|
// we want to make sure that we only fire a change event when there is a changes
|
||||||
hasChange =
|
hasChange =
|
||||||
@@ -96,7 +97,7 @@ export default function drag(
|
|||||||
const pointerPos = getPointerPosition(event);
|
const pointerPos = getPointerPosition(event);
|
||||||
console.log(pointerPos);
|
console.log(pointerPos);
|
||||||
lastPos = pointerPos;
|
lastPos = pointerPos;
|
||||||
dragItems = getDragItems(get(nodesStore), pointerPos, nodeId);
|
dragItems = getDragItems(get(nodesStore) as RFNode[], pointerPos, nodeId);
|
||||||
})
|
})
|
||||||
.on('drag', (event: UseDragEvent) => {
|
.on('drag', (event: UseDragEvent) => {
|
||||||
const pointerPos = getPointerPosition(event);
|
const pointerPos = getPointerPosition(event);
|
||||||
|
|||||||
@@ -1,25 +1,31 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, setContext, SvelteComponentTyped } from 'svelte';
|
import { onMount, setContext, SvelteComponentTyped } from 'svelte';
|
||||||
|
import cc from 'classcat';
|
||||||
import { type XYPosition, Position } from '@reactflow/system';
|
import { type XYPosition, Position } from '@reactflow/system';
|
||||||
|
|
||||||
import drag from '$lib/actions/drag'
|
import drag from '$lib/actions/drag'
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import DefaultNode from './DefaultNode.svelte';
|
import DefaultNode from './DefaultNode.svelte';
|
||||||
import type { NodeProps } from '$lib/types';
|
import type { WrapNodeProps, NodeProps } from '$lib/types';
|
||||||
|
|
||||||
export let id: NodeProps['id'];
|
interface $$Props extends WrapNodeProps {}
|
||||||
export let data: NodeProps['data'] = {};
|
|
||||||
export let selected: NodeProps['selected'] = false;
|
export let id: WrapNodeProps['id'];
|
||||||
|
export let data: WrapNodeProps['data'] = {};
|
||||||
|
export let selected: WrapNodeProps['selected'] = false;
|
||||||
export let positionAbsolute: XYPosition = { x: 0, y: 0 };
|
export let positionAbsolute: XYPosition = { x: 0, y: 0 };
|
||||||
export let position: XYPosition = { x: 0, y: 0 };
|
export let position: XYPosition = { x: 0, y: 0 };
|
||||||
export let dragging: boolean = false;
|
export let dragging: boolean = false;
|
||||||
export let resizeObserver: ResizeObserver | null = null;
|
export let resizeObserver: WrapNodeProps['resizeObserver'] = undefined;
|
||||||
export let style: any = {};
|
export let style: WrapNodeProps['style'] = undefined;
|
||||||
export let width: number = 0;
|
export let width: WrapNodeProps['width'] = undefined;
|
||||||
export let height: number = 0;
|
export let height: WrapNodeProps['height'] = undefined;
|
||||||
export let type: string = 'default';
|
export let type: WrapNodeProps['type'] = 'default';
|
||||||
export let sourcePosition: Position = Position.Bottom;
|
export let sourcePosition: WrapNodeProps['sourcePosition'] = Position.Bottom;
|
||||||
export let targetPosition: Position = Position.Top;
|
export let targetPosition: WrapNodeProps['targetPosition'] = Position.Top;
|
||||||
|
|
||||||
|
let className: string = '';
|
||||||
|
export { className as class };
|
||||||
|
|
||||||
let nodeRef: HTMLDivElement;
|
let nodeRef: HTMLDivElement;
|
||||||
|
|
||||||
@@ -39,7 +45,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
use:drag={{ nodeId: id, nodesStore, transformStore, updateNodePositions }}
|
use:drag={{ nodeId: id, nodesStore, transformStore, updateNodePositions }}
|
||||||
class="react-flow__node"
|
class={cc(['react-flow__node', `react-flow__node-${type}`, className])}
|
||||||
class:initializing={!width && !height}
|
class:initializing={!width && !height}
|
||||||
class:dragging={dragging}
|
class:dragging={dragging}
|
||||||
bind:this={nodeRef}
|
bind:this={nodeRef}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom;
|
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom;
|
||||||
export let xPos: $$Props['xPos'];
|
export let xPos: $$Props['xPos'];
|
||||||
export let yPos: $$Props['yPos'];
|
export let yPos: $$Props['yPos'];
|
||||||
export let selected: $$Props['selected'];
|
export let selected: $$Props['selected'] = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Handle type="target" position={targetPosition} />
|
<Handle type="target" position={targetPosition} />
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { setContext, onMount, SvelteComponent } from 'svelte'
|
import { setContext, onMount } from 'svelte'
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
import type { Node, Edge } from '@reactflow/system';
|
|
||||||
|
|
||||||
import { key, createStore } from '$lib/store';
|
import { key, createStore } from '$lib/store';
|
||||||
import Zoom from '$lib/container/Zoom/index.svelte';
|
import Zoom from '$lib/container/Zoom/index.svelte';
|
||||||
import Pane from '$lib/container/Pane/index.svelte';
|
import Pane from '$lib/container/Pane/index.svelte';
|
||||||
import Viewport from '$lib/container/Viewport.svelte';
|
import Viewport from '$lib/container/Viewport.svelte';
|
||||||
import NodeRenderer from '$lib/container/NodeRenderer.svelte';
|
import NodeRenderer from '$lib/container/NodeRenderer/index.svelte';
|
||||||
import EdgeRenderer from '$lib/container/EdgeRenderer/index.svelte';
|
import EdgeRenderer from '$lib/container/EdgeRenderer/index.svelte';
|
||||||
import UserSelection from '$lib/components/UserSelection/index.svelte';
|
import UserSelection from '$lib/components/UserSelection/index.svelte';
|
||||||
import NodeSelection from '$lib/components/NodeSelection/index.svelte';
|
import NodeSelection from '$lib/components/NodeSelection/index.svelte';
|
||||||
import KeyHandler from '$lib/components/KeyHandler/index.svelte';
|
import KeyHandler from '$lib/components/KeyHandler/index.svelte';
|
||||||
|
import type { NodeTypes, Node, Edge } from '$lib/types';
|
||||||
|
|
||||||
export let id: string = '1';
|
export let id: string = '1';
|
||||||
export let nodes: Node[] = [];
|
export let nodes: Node[] = [];
|
||||||
export let edges: Edge[] = [];
|
export let edges: Edge[] = [];
|
||||||
export let fitView: boolean = false;
|
export let fitView: boolean = false;
|
||||||
export let nodeTypes: Record<string, SvelteComponent>
|
export let nodeTypes: NodeTypes;
|
||||||
|
|
||||||
let className: string = '';
|
let className: string = '';
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
||||||
@@ -71,4 +70,10 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.react-flow :global(.react-flow__node-default),
|
||||||
|
.react-flow :global(.react-flow__node-input),
|
||||||
|
.react-flow :global(.react-flow__node-output) {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -3,5 +3,6 @@ export { Controls, ControlButton } from '$lib/plugins/Controls';
|
|||||||
export { Background, BackgroundVariant } from '$lib/plugins/Background';
|
export { Background, BackgroundVariant } from '$lib/plugins/Background';
|
||||||
export { Minimap } from '$lib/plugins/Minimap';
|
export { Minimap } from '$lib/plugins/Minimap';
|
||||||
export { default as Panel } from '$lib/container/Panel/index.svelte';
|
export { default as Panel } from '$lib/container/Panel/index.svelte';
|
||||||
|
export * from '$lib/types';
|
||||||
|
|
||||||
export default SvelteFlow;
|
export default SvelteFlow;
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { derived, get, writable, type Readable, type Writable } from 'svelte/store';
|
import { derived, get, writable, type Readable, type Writable } from 'svelte/store';
|
||||||
import {
|
import {
|
||||||
type Node,
|
|
||||||
type Transform,
|
type Transform,
|
||||||
type NodeDragItem,
|
type NodeDragItem,
|
||||||
type NodeDimensionUpdate,
|
type NodeDimensionUpdate,
|
||||||
type Edge,
|
|
||||||
Position,
|
Position,
|
||||||
internalsSymbol,
|
internalsSymbol,
|
||||||
type NodeOrigin,
|
type NodeOrigin,
|
||||||
type D3ZoomInstance,
|
type D3ZoomInstance,
|
||||||
type D3SelectionInstance,
|
type D3SelectionInstance,
|
||||||
type ViewportHelperFunctionOptions,
|
type ViewportHelperFunctionOptions,
|
||||||
type SelectionRect
|
type SelectionRect,
|
||||||
|
type Node as RFNode
|
||||||
} from '@reactflow/system';
|
} from '@reactflow/system';
|
||||||
import { fitView, getD3Transition, getDimensions } from '@reactflow/utils';
|
import { fitView, getD3Transition, getDimensions } from '@reactflow/utils';
|
||||||
|
|
||||||
@@ -27,7 +26,7 @@ import { SelectionMode } from 'reactflow';
|
|||||||
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
||||||
import InputNode from '$lib/components/nodes/InputNode.svelte';
|
import InputNode from '$lib/components/nodes/InputNode.svelte';
|
||||||
import OutputNode from '$lib/components/nodes/OutputNode.svelte';
|
import OutputNode from '$lib/components/nodes/OutputNode.svelte';
|
||||||
import type { EdgeTypes, NodeTypes } from '$lib/types';
|
import type { EdgeTypes, NodeTypes, Node, Edge } from '$lib/types';
|
||||||
import BezierEdge from '$lib/components/edges/BezierEdge.svelte';
|
import BezierEdge from '$lib/components/edges/BezierEdge.svelte';
|
||||||
import StraightEdge from '$lib/components/edges/StraightEdge.svelte';
|
import StraightEdge from '$lib/components/edges/StraightEdge.svelte';
|
||||||
import SmoothStepEdge from '$lib/components/edges/SmoothStepEdge.svelte';
|
import SmoothStepEdge from '$lib/components/edges/SmoothStepEdge.svelte';
|
||||||
@@ -128,8 +127,12 @@ export function createStore({
|
|||||||
.map((edge) => {
|
.map((edge) => {
|
||||||
const sourceNode = $nodes.find((node) => node.id === edge.source);
|
const sourceNode = $nodes.find((node) => node.id === edge.source);
|
||||||
const targetNode = $nodes.find((node) => node.id === edge.target);
|
const targetNode = $nodes.find((node) => node.id === edge.target);
|
||||||
const [sourceNodeRect, sourceHandleBounds, sourceIsValid] = getNodeData(sourceNode);
|
const [sourceNodeRect, sourceHandleBounds, sourceIsValid] = getNodeData(
|
||||||
const [targetNodeRect, targetHandleBounds, targetIsValid] = getNodeData(targetNode);
|
sourceNode as RFNode
|
||||||
|
);
|
||||||
|
const [targetNodeRect, targetHandleBounds, targetIsValid] = getNodeData(
|
||||||
|
targetNode as RFNode
|
||||||
|
);
|
||||||
|
|
||||||
if (!sourceIsValid || !targetIsValid) {
|
if (!sourceIsValid || !targetIsValid) {
|
||||||
return null;
|
return null;
|
||||||
@@ -261,7 +264,7 @@ export function createStore({
|
|||||||
|
|
||||||
return fitView(
|
return fitView(
|
||||||
{
|
{
|
||||||
nodes: get(nodesStore),
|
nodes: get(nodesStore) as RFNode[],
|
||||||
width: get(widthStore),
|
width: get(widthStore),
|
||||||
height: get(heightStore),
|
height: get(heightStore),
|
||||||
minZoom: 0.2,
|
minZoom: 0.2,
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import type { SvelteComponentTyped } from 'svelte';
|
||||||
|
import type { Position } from '@reactflow/system';
|
||||||
|
|
||||||
|
export type Edge = {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
source: string;
|
||||||
|
target: string;
|
||||||
|
sourceHandle?: string;
|
||||||
|
targetHandle?: string;
|
||||||
|
selected?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EdgeProps = {
|
||||||
|
id: string;
|
||||||
|
sourceX: number;
|
||||||
|
sourceY: number;
|
||||||
|
targetX: number;
|
||||||
|
targetY: number;
|
||||||
|
sourcePosition?: Position;
|
||||||
|
targetPosition?: Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EdgeTypes = Record<string, typeof SvelteComponentTyped<EdgeProps>>;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import type { Node, NodeTypes } from './nodes';
|
||||||
|
import type { Edge } from './edges';
|
||||||
|
|
||||||
|
export type SvelteFlowProps = {
|
||||||
|
nodes: Node[];
|
||||||
|
edges: Edge[];
|
||||||
|
nodeTypes?: NodeTypes;
|
||||||
|
fitView?: boolean;
|
||||||
|
class?: string;
|
||||||
|
style?: string;
|
||||||
|
};
|
||||||
@@ -1,27 +1,5 @@
|
|||||||
import type { SvelteComponentTyped } from 'svelte';
|
export type { Position, XYPosition } from '@reactflow/system';
|
||||||
import type { Position } from '@reactflow/system';
|
|
||||||
|
|
||||||
export type NodeProps<NodeData extends Record<string, unknown> = Record<string, never>> = {
|
export * from './nodes';
|
||||||
id: string;
|
export * from './edges';
|
||||||
data: NodeData;
|
export * from './general';
|
||||||
xPos: number;
|
|
||||||
yPos: number;
|
|
||||||
selected: boolean;
|
|
||||||
isConnectable: boolean;
|
|
||||||
sourcePosition: Position;
|
|
||||||
targetPosition: Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NodeTypes = Record<string, typeof SvelteComponentTyped<NodeProps>>;
|
|
||||||
|
|
||||||
export type EdgeProps = {
|
|
||||||
id: string;
|
|
||||||
sourceX: number;
|
|
||||||
sourceY: number;
|
|
||||||
targetX: number;
|
|
||||||
targetY: number;
|
|
||||||
sourcePosition?: Position;
|
|
||||||
targetPosition?: Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type EdgeTypes = Record<string, typeof SvelteComponentTyped<EdgeProps>>;
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import type { SvelteComponentTyped } from 'svelte';
|
||||||
|
import type { internalsSymbol, NodeHandleBounds, Position, XYPosition } from '@reactflow/system';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export type Node<NodeData = any> = {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
data: NodeData;
|
||||||
|
position: XYPosition;
|
||||||
|
sourcePosition?: Position;
|
||||||
|
targetPosition?: Position;
|
||||||
|
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
selected?: boolean;
|
||||||
|
class?: string;
|
||||||
|
style?: string;
|
||||||
|
|
||||||
|
// only used internally
|
||||||
|
[internalsSymbol]?: {
|
||||||
|
z?: number;
|
||||||
|
handleBounds?: NodeHandleBounds;
|
||||||
|
isParent?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export type NodeProps<NodeData = any> = Pick<
|
||||||
|
Node<NodeData>,
|
||||||
|
'id' | 'data' | 'selected' | 'sourcePosition' | 'targetPosition'
|
||||||
|
> & {
|
||||||
|
xPos: number;
|
||||||
|
yPos: number;
|
||||||
|
isConnectable?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WrapNodeProps = Node & {
|
||||||
|
resizeObserver?: ResizeObserver;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NodeTypes = Record<string, typeof SvelteComponentTyped<NodeProps>>;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Node, Edge } from '@reactflow/system';
|
import type { Node, Edge } from '../lib/types';
|
||||||
|
|
||||||
import SvelteFlow, { Controls, Background, BackgroundVariant, Minimap } from '../lib/index';
|
import SvelteFlow, { Controls, Background, BackgroundVariant, Minimap } from '../lib/index';
|
||||||
import CustomNode from '../customnodes/Custom.svelte';
|
import CustomNode from '../customnodes/Custom.svelte';
|
||||||
|
|
||||||
@@ -44,7 +43,7 @@
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const nodes: Node[] = [{
|
const nodes: Node<{ label: string }>[] = [{
|
||||||
id: '1',
|
id: '1',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
data: { label: 'Input Node' },
|
data: { label: 'Input Node' },
|
||||||
@@ -54,12 +53,26 @@
|
|||||||
type: 'default',
|
type: 'default',
|
||||||
data: { label: 'Node' },
|
data: { label: 'Node' },
|
||||||
position: { x: 0, y: 150 },
|
position: { x: 0, y: 150 },
|
||||||
|
}, {
|
||||||
|
id: 'A',
|
||||||
|
type: 'default',
|
||||||
|
data: { label: 'Styled with class' },
|
||||||
|
class: 'custom-style',
|
||||||
|
position: { x: 150, y: 150 },
|
||||||
}, {
|
}, {
|
||||||
id: '3',
|
id: '3',
|
||||||
type: 'output',
|
type: 'output',
|
||||||
data: { label: 'Output Node' },
|
data: { label: 'Output Node' },
|
||||||
position: { x: 300, y: 150 },
|
position: { x: 300, y: 150 },
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
|
id: 'B',
|
||||||
|
type: 'default',
|
||||||
|
data: { label: 'Styled with style' },
|
||||||
|
style: 'border: 2px solid #ff5050;',
|
||||||
|
position: { x: 450, y: 150 },
|
||||||
|
},
|
||||||
|
{
|
||||||
id: '4',
|
id: '4',
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
data: { label: 'Custom Node' },
|
data: { label: 'Custom Node' },
|
||||||
@@ -94,4 +107,9 @@
|
|||||||
:root {
|
:root {
|
||||||
--node-width: 50;
|
--node-width: 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.react-flow .custom-style) {
|
||||||
|
background: #ff5050;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# @reactflow/core
|
# @reactflow/system
|
||||||
|
|
||||||
Core components and util functions of React Flow.
|
Types for React Flow.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install @reactflow/core
|
npm install @reactflow/system
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# @reactflow/core
|
# @reactflow/utils
|
||||||
|
|
||||||
Core components and util functions of React Flow.
|
Util functions of React Flow.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install @reactflow/core
|
npm install @reactflow/utils
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user