diff --git a/.changeset/fifty-rockets-report.md b/.changeset/fifty-rockets-report.md new file mode 100644 index 000000000..7ab72fa33 --- /dev/null +++ b/.changeset/fifty-rockets-report.md @@ -0,0 +1,5 @@ +--- +"@vue-flow/minimap": patch +--- + +Update import of `getBoundsOfRects` diff --git a/.changeset/fluffy-tables-wash.md b/.changeset/fluffy-tables-wash.md new file mode 100644 index 000000000..df7f5a246 --- /dev/null +++ b/.changeset/fluffy-tables-wash.md @@ -0,0 +1,26 @@ +--- +"@vue-flow/core": minor +--- + +Replace existing graph utils exports with those already provided by `@xyflow/system`: + +- Replace utils + - `clamp` + - `clampPosition` + - `getDimensions` + - `getHostForElement` + - `getOverlappingArea` + - `rectToBox` + - `boxToRect` + - `getBoundsofRects` + - `getBoundsOfBoxes` + - `rendererPointToPoint` + - `getMarkerId` + - `isRect` + - `isNumeric` + - `calcAutoPan` + - `isMouseEvent` + - `getEventPosition` + +-Remove utils +- `isMacOS` diff --git a/.changeset/seven-ads-wait.md b/.changeset/seven-ads-wait.md new file mode 100644 index 000000000..6d7a11e61 --- /dev/null +++ b/.changeset/seven-ads-wait.md @@ -0,0 +1,5 @@ +--- +"@vue-flow/minimap": minor +--- + +Replace d3 with xyflow minimap instance diff --git a/.changeset/tame-books-cross.md b/.changeset/tame-books-cross.md new file mode 100644 index 000000000..49a3225fd --- /dev/null +++ b/.changeset/tame-books-cross.md @@ -0,0 +1,5 @@ +--- +"@vue-flow/core": major +--- + +Replace d3 zoom and pan with panzoom instance diff --git a/.changeset/ten-snails-flash.md b/.changeset/ten-snails-flash.md new file mode 100644 index 000000000..e92f8f092 --- /dev/null +++ b/.changeset/ten-snails-flash.md @@ -0,0 +1,5 @@ +--- +"@vue-flow/core": minor +--- + +Replace existing edge utils with ones that are already provided by `@xyflow/system` and re-export them diff --git a/docs/src/guide/vue-flow/config.md b/docs/src/guide/vue-flow/config.md index 54712824d..8ad8d48cd 100644 --- a/docs/src/guide/vue-flow/config.md +++ b/docs/src/guide/vue-flow/config.md @@ -500,7 +500,7 @@ const edges = ref([ ### default-viewport (optional) -- Type: [`ViewportTransform`](/typedocs/interfaces/ViewportTransform) +- Type: `Viewport` - Default: `{ zoom: 1, position: { x: 0, y: 0 } }` diff --git a/examples/vite/src/Basic/Basic.vue b/examples/vite/src/Basic/Basic.vue index 04f7684a4..e0ae58d34 100644 --- a/examples/vite/src/Basic/Basic.vue +++ b/examples/vite/src/Basic/Basic.vue @@ -18,10 +18,7 @@ const edges = ref([ { id: 'e1-3', source: '1', target: '3' }, ]) -const { onConnect, addEdges, setViewport, toObject } = useVueFlow({ - minZoom: 0.2, - maxZoom: 4, -}) +const { onConnect, addEdges, setViewport, toObject } = useVueFlow() onConnect(addEdges) diff --git a/packages/core/package.json b/packages/core/package.json index 311965cb8..9411a55db 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -75,7 +75,7 @@ "d3-drag": "^3.0.0", "d3-interpolate": "^3.0.1", "d3-selection": "^3.0.0", - "d3-zoom": "^3.0.0" + "@xyflow/system": "^0.0.73" }, "devDependencies": { "@rollup/plugin-replace": "^5.0.3", diff --git a/packages/core/src/components/ConnectionLine/index.ts b/packages/core/src/components/ConnectionLine/index.ts index 854335a88..342d925c0 100644 --- a/packages/core/src/components/ConnectionLine/index.ts +++ b/packages/core/src/components/ConnectionLine/index.ts @@ -1,10 +1,11 @@ import { computed, defineComponent, h, inject } from 'vue' +import { getBezierPath, getMarkerId, getSmoothStepPath } from '@xyflow/system' import type { HandleElement } from '../../types' import { ConnectionLineType, ConnectionMode, Position } from '../../types' -import { getHandlePosition, getMarkerId, oppositePosition } from '../../utils' +import { getHandlePosition, oppositePosition } from '../../utils' import { useVueFlow } from '../../composables' import { Slots } from '../../context' -import { getBezierPath, getSimpleBezierPath, getSmoothStepPath } from '../Edges/utils' +import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge' const ConnectionLine = defineComponent({ name: 'ConnectionLine', diff --git a/packages/core/src/components/Edges/BezierEdge.ts b/packages/core/src/components/Edges/BezierEdge.ts index 7dc0751f2..4ed7dd82a 100644 --- a/packages/core/src/components/Edges/BezierEdge.ts +++ b/packages/core/src/components/Edges/BezierEdge.ts @@ -1,8 +1,8 @@ import { defineComponent, h } from 'vue' +import { getBezierPath } from '@xyflow/system' import type { BezierEdgeProps } from '../../types' import { Position } from '../../types' import BaseEdge from './BaseEdge.vue' -import { getBezierPath } from './utils' const BezierEdge = defineComponent({ name: 'BezierEdge', diff --git a/packages/core/src/components/Edges/EdgeWrapper.ts b/packages/core/src/components/Edges/EdgeWrapper.ts index b5825ead7..9abdec209 100644 --- a/packages/core/src/components/Edges/EdgeWrapper.ts +++ b/packages/core/src/components/Edges/EdgeWrapper.ts @@ -1,17 +1,10 @@ import { computed, defineComponent, getCurrentInstance, h, inject, provide, ref, resolveComponent, toRef } from 'vue' +import { getMarkerId } from '@xyflow/system' import type { Connection, EdgeComponent, HandleType, MouseTouchEvent } from '../../types' import { ConnectionMode, Position } from '../../types' import { useEdgeHooks, useHandle, useVueFlow } from '../../composables' import { EdgeId, EdgeRef, Slots } from '../../context' -import { - ARIA_EDGE_DESC_KEY, - ErrorCode, - VueFlowError, - elementSelectionKeys, - getEdgeHandle, - getHandlePosition, - getMarkerId, -} from '../../utils' +import { ARIA_EDGE_DESC_KEY, ErrorCode, VueFlowError, elementSelectionKeys, getEdgeHandle, getHandlePosition } from '../../utils' import EdgeAnchor from './EdgeAnchor' interface Props { @@ -46,7 +39,7 @@ const EdgeWrapper = defineComponent({ const edge = computed(() => findEdge(props.id)!) - const { emit, on } = useEdgeHooks(edge.value, emits) + const { emit, on } = useEdgeHooks(emits) const slots = inject(Slots) @@ -229,7 +222,6 @@ const EdgeWrapper = defineComponent({ labelBgPadding: edge.value.labelBgPadding, labelBgBorderRadius: edge.value.labelBgBorderRadius, data: edge.value.data, - events: { ...edge.value.events, ...on }, style: edgeStyle.value, markerStart: `url('#${getMarkerId(edge.value.markerStart, vueFlowId)}')`, markerEnd: `url('#${getMarkerId(edge.value.markerEnd, vueFlowId)}')`, diff --git a/packages/core/src/components/Edges/SimpleBezierEdge.ts b/packages/core/src/components/Edges/SimpleBezierEdge.ts index a33e7c76f..019c9fb8f 100644 --- a/packages/core/src/components/Edges/SimpleBezierEdge.ts +++ b/packages/core/src/components/Edges/SimpleBezierEdge.ts @@ -1,8 +1,99 @@ import { defineComponent, h } from 'vue' +import { getBezierEdgeCenter } from '@xyflow/system' import type { SimpleBezierEdgeProps } from '../../types' import { Position } from '../../types' import BaseEdge from './BaseEdge.vue' -import { getSimpleBezierPath } from './utils' + +export interface GetSimpleBezierPathParams { + sourceX: number + sourceY: number + sourcePosition?: Position + targetX: number + targetY: number + targetPosition?: Position +} + +interface GetControlParams { + pos: Position + x1: number + y1: number + x2: number + y2: number +} + +function getControl({ pos, x1, y1, x2, y2 }: GetControlParams): [number, number] { + let ctX: number, ctY: number + switch (pos) { + case Position.Left: + case Position.Right: + ctX = 0.5 * (x1 + x2) + ctY = y1 + break + case Position.Top: + case Position.Bottom: + ctX = x1 + ctY = 0.5 * (y1 + y2) + break + } + return [ctX, ctY] +} + +/** + * Get a simple bezier path from source to target handle (no curvature) + * @public + * + * @param simpleBezierPathParams + * @param simpleBezierPathParams.sourceX - The x position of the source handle + * @param simpleBezierPathParams.sourceY - The y position of the source handle + * @param simpleBezierPathParams.sourcePosition - The position of the source handle (default: Position.Bottom) + * @param simpleBezierPathParams.targetX - The x position of the target handle + * @param simpleBezierPathParams.targetY - The y position of the target handle + * @param simpleBezierPathParams.targetPosition - The position of the target handle (default: Position.Top) + * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label + */ +export function getSimpleBezierPath({ + sourceX, + sourceY, + sourcePosition = Position.Bottom, + targetX, + targetY, + targetPosition = Position.Top, +}: GetSimpleBezierPathParams): [path: string, labelX: number, labelY: number, offsetX: number, offsetY: number] { + const [sourceControlX, sourceControlY] = getControl({ + pos: sourcePosition, + x1: sourceX, + y1: sourceY, + x2: targetX, + y2: targetY, + }) + + const [targetControlX, targetControlY] = getControl({ + pos: targetPosition, + x1: targetX, + y1: targetY, + x2: sourceX, + y2: sourceY, + }) + + const [labelX, labelY, offsetX, offsetY] = getBezierEdgeCenter({ + sourceX, + sourceY, + targetX, + targetY, + sourceControlX, + sourceControlY, + targetControlX, + targetControlY, + }) + + return [ + `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`, + labelX, + labelY, + offsetX, + offsetY, + ] +} const SimpleBezierEdge = defineComponent({ name: 'SimpleBezierEdge', diff --git a/packages/core/src/components/Edges/SmoothStepEdge.ts b/packages/core/src/components/Edges/SmoothStepEdge.ts index 88fd824d6..f43b49cd8 100644 --- a/packages/core/src/components/Edges/SmoothStepEdge.ts +++ b/packages/core/src/components/Edges/SmoothStepEdge.ts @@ -1,8 +1,8 @@ import { defineComponent, h } from 'vue' +import { getSmoothStepPath } from '@xyflow/system' import type { SmoothStepEdgeProps } from '../../types' import { Position } from '../../types' import BaseEdge from './BaseEdge.vue' -import { getSmoothStepPath } from './utils' const SmoothStepEdge = defineComponent({ name: 'SmoothStepEdge', diff --git a/packages/core/src/components/Edges/StraightEdge.ts b/packages/core/src/components/Edges/StraightEdge.ts index 38752a902..6d5b6b84d 100644 --- a/packages/core/src/components/Edges/StraightEdge.ts +++ b/packages/core/src/components/Edges/StraightEdge.ts @@ -1,7 +1,7 @@ import { defineComponent, h } from 'vue' +import { getStraightPath } from '@xyflow/system' import type { StraightEdgeProps } from '../../types' import BaseEdge from './BaseEdge.vue' -import { getStraightPath } from './utils' const StraightEdge = defineComponent({ name: 'StraightEdge', diff --git a/packages/core/src/components/Edges/utils/bezier.ts b/packages/core/src/components/Edges/utils/bezier.ts deleted file mode 100644 index 5ddca603c..000000000 --- a/packages/core/src/components/Edges/utils/bezier.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Position } from '../../../types' -import type { EdgePathParams } from './general' -import { getBezierEdgeCenter } from './general' - -export interface GetBezierPathParams { - sourceX: number - sourceY: number - sourcePosition?: Position - targetX: number - targetY: number - targetPosition?: Position - curvature?: number -} - -interface GetControlWithCurvatureParams { - pos: Position - x1: number - y1: number - x2: number - y2: number - c: number -} - -function calculateControlOffset(distance: number, curvature: number) { - if (distance >= 0) { - return 0.5 * distance - } else { - return curvature * 25 * Math.sqrt(-distance) - } -} - -function getControlWithCurvature({ pos, x1, y1, x2, y2, c }: GetControlWithCurvatureParams): [number, number] { - let ctX: number, ctY: number - switch (pos) { - case Position.Left: - ctX = x1 - calculateControlOffset(x1 - x2, c) - ctY = y1 - break - case Position.Right: - ctX = x1 + calculateControlOffset(x2 - x1, c) - ctY = y1 - break - case Position.Top: - ctX = x1 - ctY = y1 - calculateControlOffset(y1 - y2, c) - break - case Position.Bottom: - ctX = x1 - ctY = y1 + calculateControlOffset(y2 - y1, c) - break - } - return [ctX, ctY] -} - -/** - * Get a bezier path from source to target handle - * @public - * - * @param bezierPathParams - * @param bezierPathParams.sourceX - The x position of the source handle - * @param bezierPathParams.sourceY - The y position of the source handle - * @param bezierPathParams.sourcePosition - The position of the source handle (default: Position.Bottom) - * @param bezierPathParams.targetX - The x position of the target handle - * @param bezierPathParams.targetY - The y position of the target handle - * @param bezierPathParams.targetPosition - The position of the target handle (default: Position.Top) - * @param bezierPathParams.curvature - The curvature of the edge (default: 0.25) - * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label - */ -export function getBezierPath(bezierPathParams: GetBezierPathParams): EdgePathParams { - const { - sourceX, - sourceY, - sourcePosition = Position.Bottom, - targetX, - targetY, - targetPosition = Position.Top, - curvature = 0.25, - } = bezierPathParams - - const [sourceControlX, sourceControlY] = getControlWithCurvature({ - pos: sourcePosition, - x1: sourceX, - y1: sourceY, - x2: targetX, - y2: targetY, - c: curvature, - }) - const [targetControlX, targetControlY] = getControlWithCurvature({ - pos: targetPosition, - x1: targetX, - y1: targetY, - x2: sourceX, - y2: sourceY, - c: curvature, - }) - const [labelX, labelY, offsetX, offsetY] = getBezierEdgeCenter({ - sourceX, - sourceY, - targetX, - targetY, - sourceControlX, - sourceControlY, - targetControlX, - targetControlY, - }) - - return [ - `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`, - labelX, - labelY, - offsetX, - offsetY, - ] -} diff --git a/packages/core/src/components/Edges/utils/general.ts b/packages/core/src/components/Edges/utils/general.ts deleted file mode 100644 index 1b7bfab9c..000000000 --- a/packages/core/src/components/Edges/utils/general.ts +++ /dev/null @@ -1,51 +0,0 @@ -export type EdgePathParams = [path: string, labelX: number, labelY: number, offsetX: number, offsetY: number] - -// this is used for straight edges and simple smoothstep edges (LTR, RTL, BTT, TTB) -export function getSimpleEdgeCenter({ - sourceX, - sourceY, - targetX, - targetY, -}: { - sourceX: number - sourceY: number - targetX: number - targetY: number -}): [number, number, number, number] { - const xOffset = Math.abs(targetX - sourceX) / 2 - const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset - - const yOffset = Math.abs(targetY - sourceY) / 2 - const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset - - return [centerX, centerY, xOffset, yOffset] -} - -export function getBezierEdgeCenter({ - sourceX, - sourceY, - targetX, - targetY, - sourceControlX, - sourceControlY, - targetControlX, - targetControlY, -}: { - sourceX: number - sourceY: number - targetX: number - targetY: number - sourceControlX: number - sourceControlY: number - targetControlX: number - targetControlY: number -}): [number, number, number, number] { - // cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate - // https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve - const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125 - const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125 - const offsetX = Math.abs(centerX - sourceX) - const offsetY = Math.abs(centerY - sourceY) - - return [centerX, centerY, offsetX, offsetY] -} diff --git a/packages/core/src/components/Edges/utils/index.ts b/packages/core/src/components/Edges/utils/index.ts deleted file mode 100644 index 5993032ad..000000000 --- a/packages/core/src/components/Edges/utils/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './bezier' -export * from './general' -export * from './simple-bezier' -export * from './smoothstep' -export * from './straight' diff --git a/packages/core/src/components/Edges/utils/simple-bezier.ts b/packages/core/src/components/Edges/utils/simple-bezier.ts deleted file mode 100644 index 6f9c5f411..000000000 --- a/packages/core/src/components/Edges/utils/simple-bezier.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Position } from '../../../types' -import type { EdgePathParams } from './general' -import { getBezierEdgeCenter } from './general' - -export interface GetSimpleBezierPathParams { - sourceX: number - sourceY: number - sourcePosition?: Position - targetX: number - targetY: number - targetPosition?: Position -} - -interface GetControlParams { - pos: Position - x1: number - y1: number - x2: number - y2: number -} - -function getControl({ pos, x1, y1, x2, y2 }: GetControlParams): [number, number] { - let ctX: number, ctY: number - switch (pos) { - case Position.Left: - case Position.Right: - ctX = 0.5 * (x1 + x2) - ctY = y1 - break - case Position.Top: - case Position.Bottom: - ctX = x1 - ctY = 0.5 * (y1 + y2) - break - } - return [ctX, ctY] -} - -/** - * Get a simple bezier path from source to target handle (no curvature) - * @public - * - * @param simpleBezierPathParams - * @param simpleBezierPathParams.sourceX - The x position of the source handle - * @param simpleBezierPathParams.sourceY - The y position of the source handle - * @param simpleBezierPathParams.sourcePosition - The position of the source handle (default: Position.Bottom) - * @param simpleBezierPathParams.targetX - The x position of the target handle - * @param simpleBezierPathParams.targetY - The y position of the target handle - * @param simpleBezierPathParams.targetPosition - The position of the target handle (default: Position.Top) - * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label - */ -export function getSimpleBezierPath(simpleBezierPathParams: GetSimpleBezierPathParams): EdgePathParams { - const { - sourceX, - sourceY, - sourcePosition = Position.Bottom, - targetX, - targetY, - targetPosition = Position.Top, - } = simpleBezierPathParams - - const [sourceControlX, sourceControlY] = getControl({ - pos: sourcePosition, - x1: sourceX, - y1: sourceY, - x2: targetX, - y2: targetY, - }) - const [targetControlX, targetControlY] = getControl({ - pos: targetPosition, - x1: targetX, - y1: targetY, - x2: sourceX, - y2: sourceY, - }) - - const [centerX, centerY, offsetX, offsetY] = getBezierEdgeCenter({ - sourceX, - sourceY, - targetX, - targetY, - sourceControlX, - sourceControlY, - targetControlX, - targetControlY, - }) - - return [ - `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`, - centerX, - centerY, - offsetX, - offsetY, - ] -} diff --git a/packages/core/src/components/Edges/utils/smoothstep.ts b/packages/core/src/components/Edges/utils/smoothstep.ts deleted file mode 100644 index cc6477440..000000000 --- a/packages/core/src/components/Edges/utils/smoothstep.ts +++ /dev/null @@ -1,250 +0,0 @@ -import type { XYPosition } from '../../../types' -import { Position } from '../../../types' -import type { EdgePathParams } from './general' -import { getSimpleEdgeCenter } from './general' - -export interface GetSmoothStepPathParams { - sourceX: number - sourceY: number - sourcePosition?: Position - targetX: number - targetY: number - targetPosition?: Position - borderRadius?: number - centerX?: number - centerY?: number - offset?: number -} - -const handleDirections = { - [Position.Left]: { x: -1, y: 0 }, - [Position.Right]: { x: 1, y: 0 }, - [Position.Top]: { x: 0, y: -1 }, - [Position.Bottom]: { x: 0, y: 1 }, -} - -function getDirection({ - source, - sourcePosition = Position.Bottom, - target, -}: { - source: XYPosition - sourcePosition: Position - target: XYPosition -}): XYPosition { - if (sourcePosition === Position.Left || sourcePosition === Position.Right) { - return source.x < target.x ? { x: 1, y: 0 } : { x: -1, y: 0 } - } - return source.y < target.y ? { x: 0, y: 1 } : { x: 0, y: -1 } -} - -function distance(a: XYPosition, b: XYPosition) { - return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2) -} - -// With this function we try to mimic an orthogonal edge routing behaviour -// It's not as good as a real orthogonal edge routing, but it's faster and good enough as a default for step and smooth step edges -function getPoints({ - source, - sourcePosition = Position.Bottom, - target, - targetPosition = Position.Top, - center, - offset, -}: { - source: XYPosition - sourcePosition: Position - target: XYPosition - targetPosition: Position - center: Partial - offset: number -}): [XYPosition[], number, number, number, number] { - const sourceDir = handleDirections[sourcePosition] - const targetDir = handleDirections[targetPosition] - const sourceGapped: XYPosition = { x: source.x + sourceDir.x * offset, y: source.y + sourceDir.y * offset } - const targetGapped: XYPosition = { x: target.x + targetDir.x * offset, y: target.y + targetDir.y * offset } - const dir = getDirection({ - source: sourceGapped, - sourcePosition, - target: targetGapped, - }) - const dirAccessor = dir.x !== 0 ? 'x' : 'y' - const currDir = dir[dirAccessor] - - let points: XYPosition[] - let centerX, centerY - - const sourceGapOffset = { x: 0, y: 0 } - const targetGapOffset = { x: 0, y: 0 } - - const [defaultCenterX, defaultCenterY, defaultOffsetX, defaultOffsetY] = getSimpleEdgeCenter({ - sourceX: source.x, - sourceY: source.y, - targetX: target.x, - targetY: target.y, - }) - - // opposite handle positions, default case - if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) { - centerX = center.x ?? defaultCenterX - centerY = center.y ?? defaultCenterY - // ---> - // | - // >--- - const verticalSplit: XYPosition[] = [ - { x: centerX, y: sourceGapped.y }, - { x: centerX, y: targetGapped.y }, - ] - // | - // --- - // | - const horizontalSplit: XYPosition[] = [ - { x: sourceGapped.x, y: centerY }, - { x: targetGapped.x, y: centerY }, - ] - - if (sourceDir[dirAccessor] === currDir) { - points = dirAccessor === 'x' ? verticalSplit : horizontalSplit - } else { - points = dirAccessor === 'x' ? horizontalSplit : verticalSplit - } - } else { - // sourceTarget means we take x from source and y from target, targetSource is the opposite - const sourceTarget: XYPosition[] = [{ x: sourceGapped.x, y: targetGapped.y }] - const targetSource: XYPosition[] = [{ x: targetGapped.x, y: sourceGapped.y }] - // this handles edges with same handle positions - if (dirAccessor === 'x') { - points = sourceDir.x === currDir ? targetSource : sourceTarget - } else { - points = sourceDir.y === currDir ? sourceTarget : targetSource - } - - if (sourcePosition === targetPosition) { - const diff = Math.abs(source[dirAccessor] - target[dirAccessor]) - - // if an edge goes from right to right for example (sourcePosition === targetPosition) and the distance between source.x and target.x is less than the offset, the added point and the gapped source/target will overlap. This leads to a weird edge path. To avoid this we add a gapOffset to the source/target - if (diff <= offset) { - const gapOffset = Math.min(offset - 1, offset - diff) - if (sourceDir[dirAccessor] === currDir) { - sourceGapOffset[dirAccessor] = (sourceGapped[dirAccessor] > source[dirAccessor] ? -1 : 1) * gapOffset - } else { - targetGapOffset[dirAccessor] = (targetGapped[dirAccessor] > target[dirAccessor] ? -1 : 1) * gapOffset - } - } - } - - // these are conditions for handling mixed handle positions like Right -> Bottom for example - if (sourcePosition !== targetPosition) { - const dirAccessorOpposite = dirAccessor === 'x' ? 'y' : 'x' - const isSameDir = sourceDir[dirAccessor] === targetDir[dirAccessorOpposite] - const sourceGtTargetOppo = sourceGapped[dirAccessorOpposite] > targetGapped[dirAccessorOpposite] - const sourceLtTargetOppo = sourceGapped[dirAccessorOpposite] < targetGapped[dirAccessorOpposite] - const flipSourceTarget = - (sourceDir[dirAccessor] === 1 && ((!isSameDir && sourceGtTargetOppo) || (isSameDir && sourceLtTargetOppo))) || - (sourceDir[dirAccessor] !== 1 && ((!isSameDir && sourceLtTargetOppo) || (isSameDir && sourceGtTargetOppo))) - - if (flipSourceTarget) { - points = dirAccessor === 'x' ? sourceTarget : targetSource - } - } - - const sourceGapPoint = { x: sourceGapped.x + sourceGapOffset.x, y: sourceGapped.y + sourceGapOffset.y } - const targetGapPoint = { x: targetGapped.x + targetGapOffset.x, y: targetGapped.y + targetGapOffset.y } - const maxXDistance = Math.max(Math.abs(sourceGapPoint.x - points[0].x), Math.abs(targetGapPoint.x - points[0].x)) - const maxYDistance = Math.max(Math.abs(sourceGapPoint.y - points[0].y), Math.abs(targetGapPoint.y - points[0].y)) - - // we want to place the label on the longest segment of the edge - if (maxXDistance >= maxYDistance) { - centerX = (sourceGapPoint.x + targetGapPoint.x) / 2 - centerY = points[0].y - } else { - centerX = points[0].x - centerY = (sourceGapPoint.y + targetGapPoint.y) / 2 - } - } - - const pathPoints = [ - source, - { x: sourceGapped.x + sourceGapOffset.x, y: sourceGapped.y + sourceGapOffset.y }, - ...points, - { x: targetGapped.x + targetGapOffset.x, y: targetGapped.y + targetGapOffset.y }, - target, - ] - - return [pathPoints, centerX, centerY, defaultOffsetX, defaultOffsetY] -} - -function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): string { - const bendSize = Math.min(distance(a, b) / 2, distance(b, c) / 2, size) - const { x, y } = b - - // no bend - if ((a.x === x && x === c.x) || (a.y === y && y === c.y)) { - return `L${x} ${y}` - } - - // first segment is horizontal - if (a.y === y) { - const xDir = a.x < c.x ? -1 : 1 - const yDir = a.y < c.y ? 1 : -1 - return `L ${x + bendSize * xDir},${y}Q ${x},${y} ${x},${y + bendSize * yDir}` - } - - const xDir = a.x < c.x ? 1 : -1 - const yDir = a.y < c.y ? -1 : 1 - return `L ${x},${y + bendSize * yDir}Q ${x},${y} ${x + bendSize * xDir},${y}` -} - -/** - * Get a smooth step path from source to target handle - * @public - * - * @param smoothStepPathParams - * @param smoothStepPathParams.sourceX - The x position of the source handle - * @param smoothStepPathParams.sourceY - The y position of the source handle - * @param smoothStepPathParams.sourcePosition - The position of the source handle (default: Position.Bottom) - * @param smoothStepPathParams.targetX - The x position of the target handle - * @param smoothStepPathParams.targetY - The y position of the target handle - * @param smoothStepPathParams.targetPosition - The position of the target handle (default: Position.Top) - * @param smoothStepPathParams.borderRadius - The border radius of the edge (default: 5) - * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label - */ -export function getSmoothStepPath(smoothStepPathParams: GetSmoothStepPathParams): EdgePathParams { - const { - sourceX, - sourceY, - sourcePosition = Position.Bottom, - targetX, - targetY, - targetPosition = Position.Top, - borderRadius = 5, - centerX, - centerY, - offset = 20, - } = smoothStepPathParams - - const [points, labelX, labelY, offsetX, offsetY] = getPoints({ - source: { x: sourceX, y: sourceY }, - sourcePosition, - target: { x: targetX, y: targetY }, - targetPosition, - center: { x: centerX, y: centerY }, - offset, - }) - - const path = points.reduce((res, p, i) => { - let segment - - if (i > 0 && i < points.length - 1) { - segment = getBend(points[i - 1], p, points[i + 1], borderRadius) - } else { - segment = `${i === 0 ? 'M' : 'L'}${p.x} ${p.y}` - } - - res += segment - - return res - }, '') - - return [path, labelX, labelY, offsetX, offsetY] -} diff --git a/packages/core/src/components/Edges/utils/straight.ts b/packages/core/src/components/Edges/utils/straight.ts deleted file mode 100644 index f8dba4a93..000000000 --- a/packages/core/src/components/Edges/utils/straight.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { EdgePathParams } from './general' -import { getSimpleEdgeCenter } from './general' - -export interface GetStraightPathParams { - sourceX: number - sourceY: number - targetX: number - targetY: number -} - -/** - * Get a straight path from source to target handle - * @public - * - * @param straightEdgeParams - * @param straightEdgeParams.sourceX - The x position of the source handle - * @param straightEdgeParams.sourceY - The y position of the source handle - * @param straightEdgeParams.targetX - The x position of the target handle - * @param straightEdgeParams.targetY - The y position of the target handle - * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label - */ -export function getStraightPath(straightEdgeParams: GetStraightPathParams): EdgePathParams { - const { sourceX, sourceY, targetX, targetY } = straightEdgeParams - - const [centerX, centerY, offsetX, offsetY] = getSimpleEdgeCenter({ - sourceX, - sourceY, - targetX, - targetY, - }) - - return [`M ${sourceX},${sourceY}L ${targetX},${targetY}`, centerX, centerY, offsetX, offsetY] -} diff --git a/packages/core/src/components/Handle/Handle.vue b/packages/core/src/components/Handle/Handle.vue index 2aebb3754..4e1f13689 100644 --- a/packages/core/src/components/Handle/Handle.vue +++ b/packages/core/src/components/Handle/Handle.vue @@ -1,13 +1,14 @@ - - - - diff --git a/packages/core/src/container/Viewport/Viewport.vue b/packages/core/src/container/Viewport/Viewport.vue index 78e48dabf..6bed770bc 100644 --- a/packages/core/src/container/Viewport/Viewport.vue +++ b/packages/core/src/container/Viewport/Viewport.vue @@ -1,412 +1,18 @@ diff --git a/packages/core/src/container/VueFlow/VueFlow.vue b/packages/core/src/container/VueFlow/VueFlow.vue index 4f69763a2..eaf50fd0a 100644 --- a/packages/core/src/container/VueFlow/VueFlow.vue +++ b/packages/core/src/container/VueFlow/VueFlow.vue @@ -1,19 +1,17 @@ - + + + + diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 20a2c08a9..cb75e6840 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -18,33 +18,24 @@ export { default as BaseEdge } from './components/Edges/BaseEdge.vue' export { default as EdgeText } from './components/Edges/EdgeText.vue' export { default as EdgeLabelRenderer } from './components/Edges/EdgeLabelRenderer.vue' -export { - getBezierPath, - getSimpleBezierPath, - getSmoothStepPath, - getStraightPath, - getSimpleEdgeCenter, - getBezierEdgeCenter, -} from './components/Edges/utils' +// re-export these utils from system +export { getBezierPath, getSmoothStepPath, getStraightPath, getBezierEdgeCenter } from '@xyflow/system' +export { getSimpleBezierPath } from './components/Edges/SimpleBezierEdge' + +// re-export graph utils +export { clamp, getBoundsOfRects, getBoundsOfBoxes, rendererPointToPoint, getMarkerId, wheelDelta } from '@xyflow/system' export { isNode, isEdge, isGraphNode, isGraphEdge, - getOutgoers, - getIncomers, getConnectedEdges, getTransformForBounds, getRectOfNodes, pointToRendererPoint, - rendererPointToPoint, getNodesInside, - getMarkerId, - getBoundsofRects, connectionExists, - clamp, - wheelDelta, } from './utils/graph' export { isMacOs } from './utils/general' @@ -77,3 +68,6 @@ export { useKeyPress } from './composables/useKeyPress' export { VueFlowError, ErrorCode, isErrorOfType } from './utils/errors' export * from './types' + +// todo: add more re-exports +export { type Viewport, PanOnScrollMode } from '@xyflow/system' diff --git a/packages/core/src/store/actions.ts b/packages/core/src/store/actions.ts index 5160c40ed..b3f0f0537 100644 --- a/packages/core/src/store/actions.ts +++ b/packages/core/src/store/actions.ts @@ -1,15 +1,13 @@ -import { zoomIdentity } from 'd3-zoom' import type { ComputedRef } from 'vue' import { until } from '@vueuse/core' +import { getDimensions, getOverlappingArea, isRectObject, panBy as panBySystem } from '@xyflow/system' import type { Actions, - CoordinateExtent, Edge, EdgeAddChange, EdgeLookup, EdgeRemoveChange, EdgeSelectionChange, - Elements, FlowExportObject, GraphEdge, GraphNode, @@ -19,14 +17,12 @@ import type { NodeLookup, NodePositionChange, NodeRemoveChange, - NodeSelectionChange, Rect, State, } from '../types' import { useViewportHelper } from '../composables' import { applyChanges, - clamp, createAdditionChange, createEdgeRemoveChange, createGraphEdges, @@ -34,41 +30,31 @@ import { createNodeRemoveChange, createSelectionChange, getConnectedEdges as getConnectedEdgesBase, - getDimensions, getHandleBounds, - getIncomers as getIncomersBase, - getOutgoers as getOutgoersBase, - getOverlappingArea, getSelectionChanges, isDef, - isEdge, isGraphNode, - isNode, - isRect, nodeToRect, + parseNode, updateConnectionLookup, updateEdgeAction, } from '../utils' import { storeOptionsToSkip, useState } from './state' -export function useActions(state: State, nodeLookup: ComputedRef, edgeLookup: ComputedRef): Actions { +export function useActions( + state: State, + nodeLookup: ComputedRef>, + edgeLookup: ComputedRef, +): Actions { const viewportHelper = useViewportHelper(state) - const updateNodeInternals: Actions['updateNodeInternals'] = (ids) => { + const updateNodeInternals: Actions['updateNodeInternals'] = (ids) => { const updateIds = ids ?? [] state.hooks.updateNodeInternals.trigger(updateIds) } - const getIncomers: Actions['getIncomers'] = (nodeOrId) => { - return getIncomersBase(nodeOrId, state.nodes, state.edges) - } - - const getOutgoers: Actions['getOutgoers'] = (nodeOrId) => { - return getOutgoersBase(nodeOrId, state.nodes, state.edges) - } - - const getConnectedEdges: Actions['getConnectedEdges'] = (nodesOrId) => { + const getConnectedEdges: Actions['getConnectedEdges'] = (nodesOrId) => { return getConnectedEdgesBase(nodesOrId, state.edges) } @@ -77,7 +63,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed return Array.from(state.connectionLookup.get(`${nodeId}${handleSuffix}`)?.values() ?? []) } - const findNode: Actions['findNode'] = (id) => { + const findNode: Actions['findNode'] = (id) => { if (!id) { return } @@ -85,7 +71,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed return nodeLookup.value.get(id) } - const findEdge: Actions['findEdge'] = (id) => { + const findEdge: Actions['findEdge'] = (id) => { if (!id) { return } @@ -93,7 +79,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed return edgeLookup.value.get(id) } - const updateNodePositions: Actions['updateNodePositions'] = (dragItems, changed, dragging) => { + const updateNodePositions: Actions['updateNodePositions'] = (dragItems, changed, dragging) => { const changes: NodePositionChange[] = [] for (const node of dragItems) { @@ -125,7 +111,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - const updateNodeDimensions: Actions['updateNodeDimensions'] = (updates) => { + const updateNodeDimensions: Actions['updateNodeDimensions'] = (updates) => { if (!state.vueFlowRef) { return } @@ -181,41 +167,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - const elementSelectionHandler = (elements: Elements, selected: boolean) => { - const nodeIds = new Set() - const edgeIds = new Set() - - for (const element of elements) { - if (isNode(element)) { - nodeIds.add(element.id) - } else if (isEdge(element)) { - edgeIds.add(element.id) - } - } - - const changedNodes = getSelectionChanges(nodeLookup.value, nodeIds, true) - const changedEdges = getSelectionChanges(edgeLookup.value, edgeIds) - - if (state.multiSelectionActive) { - for (const nodeId of nodeIds) { - changedNodes.push(createSelectionChange(nodeId, selected)) - } - - for (const edgeId of edgeIds) { - changedEdges.push(createSelectionChange(edgeId, selected)) - } - } - - if (changedNodes.length) { - state.hooks.nodesChange.trigger(changedNodes) - } - - if (changedEdges.length) { - state.hooks.edgesChange.trigger(changedEdges) - } - } - - const addSelectedNodes: Actions['addSelectedNodes'] = (nodes) => { + const addSelectedNodes: Actions['addSelectedNodes'] = (nodes) => { if (state.multiSelectionActive) { const nodeChanges = nodes.map((node) => createSelectionChange(node.id, true)) state.hooks.nodesChange.trigger(nodeChanges) @@ -226,7 +178,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed state.hooks.edgesChange.trigger(getSelectionChanges(edgeLookup.value)) } - const addSelectedEdges: Actions['addSelectedEdges'] = (edges) => { + const addSelectedEdges: Actions['addSelectedEdges'] = (edges) => { if (state.multiSelectionActive) { const changedEdges = edges.map((edge) => createSelectionChange(edge.id, true)) state.hooks.edgesChange.trigger(changedEdges as EdgeSelectionChange[]) @@ -237,11 +189,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed state.hooks.nodesChange.trigger(getSelectionChanges(nodeLookup.value, new Set(), true)) } - const addSelectedElements: Actions['addSelectedElements'] = (elements) => { - elementSelectionHandler(elements, true) - } - - const removeSelectedNodes: Actions['removeSelectedNodes'] = (nodes) => { + const removeSelectedNodes: Actions['removeSelectedNodes'] = (nodes) => { const nodesToUnselect = nodes || state.nodes const nodeChanges = nodesToUnselect.map((n) => { @@ -252,7 +200,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed state.hooks.nodesChange.trigger(nodeChanges) } - const removeSelectedEdges: Actions['removeSelectedEdges'] = (edges) => { + const removeSelectedEdges: Actions['removeSelectedEdges'] = (edges) => { const edgesToUnselect = edges || state.edges const edgeChanges = edgesToUnselect.map((e) => { @@ -263,76 +211,47 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed state.hooks.edgesChange.trigger(edgeChanges) } - const removeSelectedElements: Actions['removeSelectedElements'] = (elements) => { - if (!elements || !elements.length) { - return elementSelectionHandler([], false) - } - - const changes = elements.reduce( - (changes, curr) => { - const selectionChange = createSelectionChange(curr.id, false) - - if (isNode(curr)) { - changes.nodes.push(selectionChange) - } else { - changes.edges.push(selectionChange) - } - - return changes - }, - { nodes: [] as NodeSelectionChange[], edges: [] as EdgeSelectionChange[] }, - ) - - if (changes.nodes.length) { - state.hooks.nodesChange.trigger(changes.nodes) - } - - if (changes.edges.length) { - state.hooks.edgesChange.trigger(changes.edges) - } - } - - const setMinZoom: Actions['setMinZoom'] = (minZoom) => { - state.d3Zoom?.scaleExtent([minZoom, state.maxZoom]) + const setMinZoom: Actions['setMinZoom'] = (minZoom) => { + state.panZoom?.setScaleExtent([minZoom, state.maxZoom]) state.minZoom = minZoom } - const setMaxZoom: Actions['setMaxZoom'] = (maxZoom) => { - state.d3Zoom?.scaleExtent([state.minZoom, maxZoom]) + const setMaxZoom: Actions['setMaxZoom'] = (maxZoom) => { + state.panZoom?.setScaleExtent([state.minZoom, maxZoom]) state.maxZoom = maxZoom } - const setTranslateExtent: Actions['setTranslateExtent'] = (translateExtent) => { - state.d3Zoom?.translateExtent(translateExtent) + const setTranslateExtent: Actions['setTranslateExtent'] = (translateExtent) => { + state.panZoom?.setTranslateExtent(translateExtent) state.translateExtent = translateExtent } - const setNodeExtent: Actions['setNodeExtent'] = (nodeExtent) => { + const setNodeExtent: Actions['setNodeExtent'] = (nodeExtent) => { state.nodeExtent = nodeExtent updateNodeInternals() } - const setPaneClickDistance: Actions['setPaneClickDistance'] = (clickDistance) => { - state.d3Zoom?.clickDistance(clickDistance) + const setPaneClickDistance: Actions['setPaneClickDistance'] = (clickDistance) => { + state.panZoom?.setClickDistance(clickDistance) } - const setInteractive: Actions['setInteractive'] = (isInteractive) => { + const setInteractive: Actions['setInteractive'] = (isInteractive) => { state.nodesDraggable = isInteractive state.nodesConnectable = isInteractive state.elementsSelectable = isInteractive } - const setNodes: Actions['setNodes'] = (nodes) => { + const setNodes: Actions['setNodes'] = (nodes) => { const nextNodes = nodes instanceof Function ? nodes(state.nodes) : nodes if (!state.initialized && !nextNodes.length) { return } - state.nodes = createGraphNodes(nextNodes, findNode, state.hooks.error.trigger) + state.nodes = createGraphNodes(nextNodes, findNode, state.hooks.error.trigger) as GraphNode[] } - const setEdges: Actions['setEdges'] = (edges) => { + const setEdges: Actions['setEdges'] = (edges) => { const nextEdges = edges instanceof Function ? edges(state.edges) : edges if (!state.initialized && !nextEdges.length) { @@ -355,18 +274,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed state.edges = validEdges } - const setElements: Actions['setElements'] = (elements) => { - const nextElements = elements instanceof Function ? elements([...state.nodes, ...state.edges]) : elements - - if (!state.initialized && !nextElements.length) { - return - } - - setNodes(nextElements.filter(isNode)) - setEdges(nextElements.filter(isEdge)) - } - - const addNodes: Actions['addNodes'] = (nodes) => { + const addNodes: Actions['addNodes'] = (nodes) => { let nextNodes = nodes instanceof Function ? nodes(state.nodes) : nodes nextNodes = Array.isArray(nextNodes) ? nextNodes : [nextNodes] @@ -382,7 +290,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - const addEdges: Actions['addEdges'] = (params) => { + const addEdges: Actions['addEdges'] = (params) => { let nextEdges = params instanceof Function ? params(state.edges) : params nextEdges = Array.isArray(nextEdges) ? nextEdges : [nextEdges] @@ -407,7 +315,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - const removeNodes: Actions['removeNodes'] = (nodes, removeConnectedEdges = true, removeChildren = false) => { + const removeNodes: Actions['removeNodes'] = (nodes, removeConnectedEdges = true, removeChildren = false) => { const nextNodes = nodes instanceof Function ? nodes(state.nodes) : nodes const nodesToRemove = Array.isArray(nextNodes) ? nextNodes : [nextNodes] @@ -478,7 +386,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - const removeEdges: Actions['removeEdges'] = (edges) => { + const removeEdges: Actions['removeEdges'] = (edges) => { const nextEdges = edges instanceof Function ? edges(state.edges) : edges const edgesToRemove = Array.isArray(nextEdges) ? nextEdges : [nextEdges] @@ -509,7 +417,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed state.hooks.edgesChange.trigger(changes) } - const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection, shouldReplaceId = true) => { + const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection, shouldReplaceId = true) => { const prevEdge = findEdge(oldEdge.id) if (!prevEdge) { @@ -542,7 +450,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed return false } - const updateEdgeData: Actions['updateEdgeData'] = (id, dataUpdate, options = { replace: false }) => { + const updateEdgeData: Actions['updateEdgeData'] = (id, dataUpdate, options = { replace: false }) => { const edge = findEdge(id) if (!edge) { @@ -554,11 +462,11 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed edge.data = options.replace ? nextData : { ...edge.data, ...nextData } } - const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => { + const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => { return applyChanges(changes, state.nodes) } - const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => { + const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => { const changedEdges = applyChanges(changes, state.edges) updateConnectionLookup(state.connectionLookup, edgeLookup.value, changedEdges) @@ -567,7 +475,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } // todo: maybe we should use a more immutable approach, this is a bit too much mutation and hard to maintain - const updateNode: Actions['updateNode'] = (id, nodeUpdate, options = { replace: false }) => { + const updateNode: Actions['updateNode'] = (id, nodeUpdate, options = { replace: false }) => { const node = findNode(id) if (!node) { @@ -577,13 +485,13 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node) : nodeUpdate if (options.replace) { - state.nodes.splice(state.nodes.indexOf(node), 1, nextNode as GraphNode) + state.nodes.splice(state.nodes.indexOf(node), 1, parseNode(nextNode as NodeType)) } else { Object.assign(node, nextNode) } } - const updateNodeData: Actions['updateNodeData'] = (id, dataUpdate, options = { replace: false }) => { + const updateNodeData: Actions['updateNodeData'] = (id, dataUpdate, options = { replace: false }) => { const node = findNode(id) if (!node) { @@ -595,7 +503,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed node.data = options.replace ? nextData : { ...node.data, ...nextData } } - const startConnection: Actions['startConnection'] = (startHandle, position, isClick = false) => { + const startConnection: Actions['startConnection'] = (startHandle, position, isClick = false) => { if (isClick) { state.connectionClickStartHandle = startHandle } else { @@ -610,7 +518,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - const updateConnection: Actions['updateConnection'] = (position, result = null, status = null) => { + const updateConnection: Actions['updateConnection'] = (position, result = null, status = null) => { if (state.connectionStartHandle) { state.connectionPosition = position state.connectionEndHandle = result @@ -618,7 +526,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - const endConnection: Actions['endConnection'] = (event, isClick) => { + const endConnection: Actions['endConnection'] = (event, isClick) => { state.connectionPosition = { x: Number.NaN, y: Number.NaN } state.connectionEndHandle = null state.connectionStatus = null @@ -633,7 +541,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed const getNodeRect = ( nodeOrRect: (Partial & { id: Node['id'] }) | Rect, ): [Rect | null, Node | null | undefined, boolean] => { - const isRectObj = isRect(nodeOrRect) + const isRectObj = isRectObject(nodeOrRect) const node = isRectObj ? null : isGraphNode(nodeOrRect as GraphNode) ? (nodeOrRect as GraphNode) : findNode(nodeOrRect.id) if (!isRectObj && !node) { @@ -645,14 +553,14 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed return [nodeRect, node, isRectObj] } - const getIntersectingNodes: Actions['getIntersectingNodes'] = (nodeOrRect, partially = true, nodes = state.nodes) => { + const getIntersectingNodes: Actions['getIntersectingNodes'] = (nodeOrRect, partially = true, nodes = state.nodes) => { const [nodeRect, node, isRect] = getNodeRect(nodeOrRect) if (!nodeRect) { return [] } - const intersections: GraphNode[] = [] + const intersections: GraphNode[] = [] for (const n of nodes || state.nodes) { if (!isRect && (n.id === node!.id || !n.computedPosition)) { continue @@ -674,7 +582,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed return intersections } - const isNodeIntersecting: Actions['isNodeIntersecting'] = (nodeOrRect, area, partially = true) => { + const isNodeIntersecting: Actions['isNodeIntersecting'] = (nodeOrRect, area, partially = true) => { const [nodeRect] = getNodeRect(nodeOrRect) if (!nodeRect) { @@ -687,69 +595,23 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed return partiallyVisible || overlappingArea >= Number(nodeRect.width) * Number(nodeRect.height) } - const panBy: Actions['panBy'] = (delta) => { - const { viewport, dimensions, d3Zoom, d3Selection, translateExtent } = state - - if (!d3Zoom || !d3Selection || (!delta.x && !delta.y)) { - return false - } - - const nextTransform = zoomIdentity.translate(viewport.x + delta.x, viewport.y + delta.y).scale(viewport.zoom) - - const extent: CoordinateExtent = [ - [0, 0], - [dimensions.width, dimensions.height], - ] - - const constrainedTransform = d3Zoom.constrain()(nextTransform, extent, translateExtent) + const panBy: Actions['panBy'] = (delta) => { + const { viewport, dimensions, translateExtent, panZoom } = state - const transformChanged = - state.viewport.x !== constrainedTransform.x || - state.viewport.y !== constrainedTransform.y || - state.viewport.zoom !== constrainedTransform.k - - d3Zoom.transform(d3Selection, constrainedTransform) - - return transformChanged + return panBySystem({ delta, panZoom, transform: [viewport.x, viewport.y, viewport.zoom], translateExtent, ...dimensions }) } - const setState: Actions['setState'] = (options) => { + const setState: Actions['setState'] = (options) => { const opts = options instanceof Function ? options(state) : options // these options cannot be set after initialization - const exclude: (keyof typeof opts)[] = [ - 'd3Zoom', - 'd3Selection', - 'd3ZoomHandler', - 'viewportRef', - 'vueFlowRef', - 'dimensions', - 'hooks', - ] + const exclude: (keyof typeof opts)[] = ['viewportRef', 'vueFlowRef', 'dimensions', 'hooks'] // we need to set the default opts before setting any elements so the options are applied to the elements on first render if (isDef(opts.defaultEdgeOptions)) { state.defaultEdgeOptions = opts.defaultEdgeOptions } - const elements = opts.modelValue || opts.nodes || opts.edges ? ([] as Elements) : undefined - - if (elements) { - if (opts.modelValue) { - elements.push(...opts.modelValue) - } - - if (opts.nodes) { - elements.push(...opts.nodes) - } - - if (opts.edges) { - elements.push(...opts.edges) - } - - setElements(elements) - } - const setSkippedOptions = () => { if (isDef(opts.maxZoom)) { setMaxZoom(opts.maxZoom) @@ -771,7 +633,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - until(() => state.d3Zoom) + until(() => state.panZoom) .not.toBeNull() .then(setSkippedOptions) @@ -780,7 +642,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed } } - const toObject: Actions['toObject'] = () => { + const toObject: Actions['toObject'] = () => { const nodes: Node[] = [] const edges: Edge[] = [] @@ -793,7 +655,6 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed isParent: _____, resizing: ______, dragging: _______, - events: _________, ...rest } = node @@ -818,12 +679,12 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed ) } - const fromObject: Actions['fromObject'] = (obj) => { + const fromObject: Actions['fromObject'] = (obj) => { return new Promise((resolve) => { const { nodes, edges, position, zoom, viewport } = obj if (nodes) { - setNodes(nodes) + setNodes(nodes as NodeType[]) } if (edges) { @@ -854,27 +715,18 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed }) } - const $reset: Actions['$reset'] = () => { - const resetState = useState() + const $reset: Actions['$reset'] = () => { + const { nodes: _nodes, edges: _edges, ...resetState } = useState() state.edges = [] state.nodes = [] - // reset the zoom state - if (state.d3Zoom && state.d3Selection) { - const updatedTransform = zoomIdentity - .translate(resetState.defaultViewport.x ?? 0, resetState.defaultViewport.y ?? 0) - .scale(clamp(resetState.defaultViewport.zoom ?? 1, resetState.minZoom, resetState.maxZoom)) - - const bbox = state.viewportRef!.getBoundingClientRect() - - const extent: CoordinateExtent = [ - [0, 0], - [bbox.width, bbox.height], - ] - - const constrainedTransform = state.d3Zoom.constrain()(updatedTransform, extent, resetState.translateExtent) - state.d3Zoom.transform(state.d3Selection, constrainedTransform) + if (state.panZoom) { + state.panZoom.setViewport({ + x: state.defaultViewport.x ?? 0, + y: state.defaultViewport.y ?? 0, + zoom: state.defaultViewport.zoom ?? 1, + }) } setState(resetState) @@ -883,7 +735,6 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed return { updateNodePositions, updateNodeDimensions, - setElements, setNodes, setEdges, addNodes, @@ -898,7 +749,6 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed updateNodeData, applyEdgeChanges, applyNodeChanges, - addSelectedElements, addSelectedNodes, addSelectedEdges, setMinZoom, @@ -906,7 +756,6 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed setTranslateExtent, setNodeExtent, setPaneClickDistance, - removeSelectedElements, removeSelectedNodes, removeSelectedEdges, startConnection, @@ -915,8 +764,6 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed setInteractive, setState, getIntersectingNodes, - getIncomers, - getOutgoers, getConnectedEdges, getHandleConnections, isNodeIntersecting, @@ -926,9 +773,7 @@ export function useActions(state: State, nodeLookup: ComputedRef, ed zoomOut: (transitionOpts) => viewportHelper.value.zoomOut(transitionOpts), zoomTo: (zoomLevel, transitionOpts) => viewportHelper.value.zoomTo(zoomLevel, transitionOpts), setViewport: (params, transitionOpts) => viewportHelper.value.setViewport(params, transitionOpts), - setTransform: (params, transitionOpts) => viewportHelper.value.setTransform(params, transitionOpts), getViewport: () => viewportHelper.value.getViewport(), - getTransform: () => viewportHelper.value.getTransform(), setCenter: (x, y, opts) => viewportHelper.value.setCenter(x, y, opts), fitBounds: (params, opts) => viewportHelper.value.fitBounds(params, opts), project: (params) => viewportHelper.value.project(params), diff --git a/packages/core/src/store/getters.ts b/packages/core/src/store/getters.ts index 4c5341058..19f83452d 100644 --- a/packages/core/src/store/getters.ts +++ b/packages/core/src/store/getters.ts @@ -1,25 +1,25 @@ import type { ComputedRef } from 'vue' import { computed } from 'vue' -import type { ComputedGetters, EdgeLookup, GraphEdge, GraphNode, NodeLookup, State } from '../types' +import type { ComputedGetters, EdgeLookup, GraphEdge, GraphNode, Node, NodeLookup, State } from '../types' import { getNodesInside, isEdgeVisible } from '../utils' import { defaultEdgeTypes, defaultNodeTypes } from '../utils/defaultNodesEdges' -export function useGetters( - state: State, - nodeLookup: ComputedRef, +export function useGetters( + state: State, + nodeLookup: ComputedRef>, edgeLookup: ComputedRef, -): ComputedGetters { +): ComputedGetters { /** * @deprecated will be removed in next major version; use findNode instead */ - const getNode: ComputedGetters['getNode'] = computed(() => (id) => nodeLookup.value.get(id)) + const getNode: ComputedGetters['getNode'] = computed(() => (id) => nodeLookup.value.get(id)) /** * @deprecated will be removed in next major version; use findEdge instead */ - const getEdge: ComputedGetters['getEdge'] = computed(() => (id) => edgeLookup.value.get(id)) + const getEdge: ComputedGetters['getEdge'] = computed(() => (id) => edgeLookup.value.get(id)) - const getEdgeTypes: ComputedGetters['getEdgeTypes'] = computed(() => { + const getEdgeTypes: ComputedGetters['getEdgeTypes'] = computed(() => { const edgeTypes: Record = { ...defaultEdgeTypes, ...state.edgeTypes, @@ -34,7 +34,7 @@ export function useGetters( return edgeTypes }) - const getNodeTypes: ComputedGetters['getNodeTypes'] = computed(() => { + const getNodeTypes: ComputedGetters['getNodeTypes'] = computed(() => { const nodeTypes: Record = { ...defaultNodeTypes, ...state.nodeTypes, @@ -49,7 +49,7 @@ export function useGetters( return nodeTypes }) - const getNodes: ComputedGetters['getNodes'] = computed(() => { + const getNodes: ComputedGetters['getNodes'] = computed(() => { if (state.onlyRenderVisibleElements) { return getNodesInside( state.nodes, @@ -67,7 +67,7 @@ export function useGetters( return state.nodes }) - const getEdges: ComputedGetters['getEdges'] = computed(() => { + const getEdges: ComputedGetters['getEdges'] = computed(() => { if (state.onlyRenderVisibleElements) { const visibleEdges: GraphEdge[] = [] @@ -98,10 +98,8 @@ export function useGetters( return state.edges }) - const getElements: ComputedGetters['getElements'] = computed(() => [...getNodes.value, ...getEdges.value]) - - const getSelectedNodes: ComputedGetters['getSelectedNodes'] = computed(() => { - const selectedNodes: GraphNode[] = [] + const getSelectedNodes: ComputedGetters['getSelectedNodes'] = computed(() => { + const selectedNodes: GraphNode[] = [] for (const node of state.nodes) { if (node.selected) { selectedNodes.push(node) @@ -111,7 +109,7 @@ export function useGetters( return selectedNodes }) - const getSelectedEdges: ComputedGetters['getSelectedEdges'] = computed(() => { + const getSelectedEdges: ComputedGetters['getSelectedEdges'] = computed(() => { const selectedEdges: GraphEdge[] = [] for (const edge of state.edges) { if (edge.selected) { @@ -122,45 +120,14 @@ export function useGetters( return selectedEdges }) - const getSelectedElements: ComputedGetters['getSelectedElements'] = computed(() => [ - ...getSelectedNodes.value, - ...getSelectedEdges.value, - ]) - - /** - * @deprecated will be removed in next major version; use `useNodesInitialized` instead - */ - const getNodesInitialized: ComputedGetters['getNodesInitialized'] = computed(() => { - const initializedNodes: GraphNode[] = [] - - for (const node of state.nodes) { - if (!!node.dimensions.width && !!node.dimensions.height && node.handleBounds !== undefined) { - initializedNodes.push(node) - } - } - - return initializedNodes - }) - - /** - * @deprecated will be removed in next major version; use `useNodesInitialized` instead - */ - const areNodesInitialized: ComputedGetters['areNodesInitialized'] = computed( - () => getNodes.value.length > 0 && getNodesInitialized.value.length === getNodes.value.length, - ) - return { getNode, getEdge, - getElements, getEdgeTypes, getNodeTypes, getEdges, getNodes, - getSelectedElements, getSelectedNodes, getSelectedEdges, - getNodesInitialized, - areNodesInitialized, } } diff --git a/packages/core/src/store/hooks.ts b/packages/core/src/store/hooks.ts index 4bb2449a1..4d6fbdacb 100644 --- a/packages/core/src/store/hooks.ts +++ b/packages/core/src/store/hooks.ts @@ -1,10 +1,10 @@ import { tryOnScopeDispose } from '@vueuse/core' import type { Ref } from 'vue' import { getCurrentInstance, onBeforeMount } from 'vue' -import type { FlowEvents, FlowHooks } from '../types' +import type { FlowEvents, FlowHooks, Node } from '../types' import { createExtendedEventHook, warn } from '../utils' -export function createHooks(): FlowHooks { +export function createHooks(): FlowHooks { return { edgesChange: createExtendedEventHook(), nodesChange: createExtendedEventHook(), @@ -62,9 +62,8 @@ export function createHooks(): FlowHooks { } } -export function useHooks(emit: (...args: any[]) => void, hooks: Ref) { +export function useHooks(emit: (...args: any[]) => void, hooks: Ref>) { const inst = getCurrentInstance() - onBeforeMount(() => { for (const [key, value] of Object.entries(hooks.value)) { const listener = (data: unknown) => { diff --git a/packages/core/src/store/state.ts b/packages/core/src/store/state.ts index 2198b9465..17e3c8506 100644 --- a/packages/core/src/store/state.ts +++ b/packages/core/src/store/state.ts @@ -1,10 +1,10 @@ -import type { FlowOptions, State } from '../types' -import { ConnectionLineType, ConnectionMode, PanOnScrollMode, SelectionMode } from '../types' +import { PanOnScrollMode, isMacOs } from '@xyflow/system' +import type { FlowProps, Node, State } from '../types' +import { ConnectionLineType, ConnectionMode, SelectionMode } from '../types' -import { isMacOs } from '../utils' import { createHooks } from './hooks' -export function useState(): State { +export function useState(): State { return { vueFlowRef: null, viewportRef: null, @@ -22,9 +22,7 @@ export function useState(): State { }, viewport: { x: 0, y: 0, zoom: 1 }, - d3Zoom: null, - d3Selection: null, - d3ZoomHandler: null, + panZoom: null, minZoom: 0.5, maxZoom: 2, @@ -118,12 +116,11 @@ export function useState(): State { } // these options will be set using the appropriate methods -export const storeOptionsToSkip: (keyof Partial>)[] = [ +export const storeOptionsToSkip: (keyof Partial>)[] = [ 'id', 'vueFlowRef', 'viewportRef', 'initialized', - 'modelValue', 'nodes', 'edges', 'maxZoom', diff --git a/packages/core/src/types/changes.ts b/packages/core/src/types/changes.ts index 051aac95d..10b09a0fd 100644 --- a/packages/core/src/types/changes.ts +++ b/packages/core/src/types/changes.ts @@ -43,12 +43,17 @@ export interface NodeRemoveChange { type: 'remove' } -export interface NodeAddChange { - item: GraphNode +export interface NodeAddChange { + item: GraphNode type: 'add' } -export type NodeChange = NodeDimensionChange | NodePositionChange | NodeSelectionChange | NodeRemoveChange | NodeAddChange +export type NodeChange = + | NodeDimensionChange + | NodePositionChange + | NodeSelectionChange + | NodeRemoveChange + | NodeAddChange export type EdgeSelectionChange = NodeSelectionChange diff --git a/packages/core/src/types/components.ts b/packages/core/src/types/components.ts index 257df6de8..ad7cb33f6 100644 --- a/packages/core/src/types/components.ts +++ b/packages/core/src/types/components.ts @@ -1,15 +1,20 @@ import type { CSSProperties, Component, DefineComponent, VNode } from 'vue' import type { BezierEdge, SimpleBezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '../components' -import type { NodeProps } from './node' +import type { BuiltInNode, Node, NodeProps } from './node' import type { EdgeProps } from './edge' /** Global component names are components registered to the vue instance and are "autoloaded" by their string name */ type GlobalComponentName = string /** Node Components can either be a component definition or a string name */ -export type NodeComponent = Component | DefineComponent | GlobalComponentName +export type NodeComponent = + | Component> + | DefineComponent, any, any, any, any> + | GlobalComponentName -export type NodeTypesObject = { [key in keyof DefaultNodeTypes]?: NodeComponent } & Record +export type NodeTypesObject = { + [key in keyof DefaultNodeTypes]?: NodeComponent +} & Record> export type EdgeTypesObject = { [key in keyof DefaultEdgeTypes]?: EdgeComponent } & Record @@ -24,7 +29,7 @@ export interface DefaultEdgeTypes { smoothstep: typeof SmoothStepEdge } -export type DefaultNodeTypes = { [key in 'input' | 'output' | 'default']: NodeComponent } +export type DefaultNodeTypes = { [key in 'input' | 'output' | 'default']: NodeComponent } /** these props are passed to edge texts */ export interface EdgeTextProps { diff --git a/packages/core/src/types/edge.ts b/packages/core/src/types/edge.ts index 1842f666e..694875a36 100644 --- a/packages/core/src/types/edge.ts +++ b/packages/core/src/types/edge.ts @@ -1,8 +1,8 @@ import type { CSSProperties, Component, SVGAttributes, VNode } from 'vue' -import type { ClassFunc, ElementData, Position, StyleFunc, Styles } from './flow' +import type { ElementData, Position, Styles } from './flow' import type { GraphNode } from './node' import type { EdgeComponent, EdgeTextProps } from './components' -import type { CustomEvent, EdgeEventsHandler, EdgeEventsOn } from './hooks' +import type { EdgeEventsHandler } from './hooks' /** Edge markers */ export enum MarkerType { @@ -58,11 +58,7 @@ export interface EdgeLabelOptions { labelBgBorderRadius?: number } -export interface DefaultEdge< - Data = ElementData, - CustomEvents extends Record = any, - Type extends string = string, -> extends EdgeLabelOptions { +export interface DefaultEdge extends EdgeLabelOptions { /** Unique edge id */ id: string /** An edge label */ @@ -92,9 +88,9 @@ export interface DefaultEdge< /** Disable/enable deleting edge */ deletable?: boolean /** Additional class names, can be a string or a callback returning a string (receives current flow element) */ - class?: string | string[] | Record | ClassFunc> + class?: string | string[] | Record /** Additional styles, can be an object or a callback returning an object (receives current flow element) */ - style?: Styles | StyleFunc> + style?: Styles /** Is edge hidden */ hidden?: boolean /** Radius of mouse event triggers (to ease selecting edges), defaults to 2 */ @@ -103,8 +99,6 @@ export interface DefaultEdge< template?: EdgeComponent /** Additional data that is passed to your custom components */ data?: Data - /** @deprecated will be removed in the next major version */ - events?: Partial> /** Aria label for edge (a11y) */ zIndex?: number ariaLabel?: string | null @@ -133,10 +127,7 @@ export interface SmoothStepPathOptions { borderRadius?: number } -export type SmoothStepEdgeType = any> = DefaultEdge< - Data, - CustomEvents -> & { +export type SmoothStepEdgeType = DefaultEdge & { type: 'smoothstep' pathOptions?: SmoothStepPathOptions } @@ -145,18 +136,15 @@ export interface BezierPathOptions { curvature?: number } -export type BezierEdgeType = any> = DefaultEdge< - Data, - CustomEvents -> & { +export type BezierEdgeType = DefaultEdge & { type: 'default' pathOptions?: BezierPathOptions } -export type Edge = any, Type extends string = string> = - | DefaultEdge - | SmoothStepEdgeType - | BezierEdgeType +export type Edge = + | DefaultEdge + | SmoothStepEdgeType + | BezierEdgeType export type DefaultEdgeOptions = Omit @@ -168,24 +156,18 @@ export interface EdgePositions { } /** Internal edge type */ -export type GraphEdge< - Data = ElementData, - CustomEvents extends Record = any, - Type extends string = string, -> = Edge & { +export type GraphEdge = Edge & { selected: boolean sourceNode: GraphNode targetNode: GraphNode data: Data /** @deprecated will be removed in the next major version */ - events: Partial> + events: Partial type: Type } & EdgePositions /** these props are passed to edge components */ -export interface EdgeProps - extends EdgeLabelOptions, - EdgePositions { +export interface EdgeProps extends EdgeLabelOptions, EdgePositions { id: string sourceNode: GraphNode targetNode: GraphNode @@ -206,8 +188,6 @@ export interface EdgeProps } export interface BaseEdgeProps extends EdgeLabelOptions { @@ -240,9 +220,3 @@ export type SmoothStepEdgeProps = EdgePositions & Omit & Pick & SmoothStepPathOptions - -export type ToGraphEdge = GraphEdge< - T extends Edge ? Data : never, - T extends Edge ? CustomEvents : never, - T extends Edge ? Type : never -> diff --git a/packages/core/src/types/flow.ts b/packages/core/src/types/flow.ts index 7590d50e4..d68b48bb7 100644 --- a/packages/core/src/types/flow.ts +++ b/packages/core/src/types/flow.ts @@ -1,6 +1,6 @@ import type { CSSProperties } from 'vue' import type { KeyFilter } from '@vueuse/core' -import type { D3ZoomEvent } from 'd3-zoom' +import type { PanOnScrollMode, Viewport } from '@xyflow/system' import type { VueFlowError } from '../utils' import type { DefaultEdgeOptions, Edge, EdgeProps, EdgeUpdatable, GraphEdge } from './edge' import type { CoordinateExtent, CoordinateExtentRange, GraphNode, Node, NodeProps } from './node' @@ -13,9 +13,8 @@ import type { Connector, OnConnectStartParams, } from './connection' -import type { PanOnScrollMode, ViewportTransform } from './zoom' import type { EdgeTypesObject, NodeTypesObject } from './components' -import type { CustomEvent, EdgeMouseEvent, EdgeUpdateEvent, NodeDragEvent, NodeMouseEvent } from './hooks' +import type { EdgeMouseEvent, EdgeUpdateEvent, MouseTouchEvent, NodeDragEvent, NodeMouseEvent } from './hooks' import type { ValidConnectionFunc } from './handle' import type { EdgeChange, NodeChange } from './changes' import type { VueFlowStore } from './store' @@ -23,44 +22,7 @@ import type { VueFlowStore } from './store' // todo: should be object type export type ElementData = any -/** - * @deprecated - will be removed in the next major version - * A flow element (after parsing into state) - */ -export type FlowElement< - NodeData = ElementData, - EdgeData = ElementData, - NodeEvents extends Record = any, - EdgeEvents extends Record = any, -> = GraphNode | GraphEdge - -/** - * @deprecated - will be removed in the next major version - * An array of flow elements (after parsing into state) - */ -export type FlowElements< - NodeData = ElementData, - EdgeData = ElementData, - NodeEvents extends Record = any, - EdgeEvents extends Record = any, -> = FlowElement[] - -/** Initial elements (before parsing into state) */ -export type Element< - NodeData = ElementData, - EdgeData = ElementData, - NodeEvents extends Record = any, - EdgeEvents extends Record = any, -> = Node | Edge - -export type Elements< - NodeData = ElementData, - EdgeData = ElementData, - NodeEvents extends Record = any, - EdgeEvents extends Record = any, -> = Element[] - -export type MaybeElement = Node | Edge | Connection | FlowElement | Element +export type MaybeElement = Node | Edge | Connection | Element export interface CustomThemeVars { [key: string]: string | number | undefined @@ -76,11 +38,6 @@ export type CSSVars = export type ThemeVars = { [key in CSSVars]?: CSSProperties['color'] } export type Styles = CSSProperties & ThemeVars & CustomThemeVars -/** @deprecated will be removed in the next major version */ -export type ClassFunc = (element: ElementType) => string | void - -/** @deprecated will be removed in the next major version */ -export type StyleFunc = (element: ElementType) => Styles | void /** Handle Positions */ export enum Position { @@ -137,24 +94,19 @@ export interface FlowExportObject { */ zoom: number /** exported viewport (position + zoom) */ - viewport: ViewportTransform + viewport: Viewport } export type FlowImportObject = { [key in keyof FlowExportObject]?: FlowExportObject[key] } -export interface FlowProps { +export interface FlowProps { id?: string - /** - * all elements (nodes + edges) - * @deprecated use {@link FlowProps.nodes} & {@link FlowProps.nodes} instead - */ - modelValue?: Elements - nodes?: Node[] + nodes?: NodeType[] edges?: Edge[] /** either use the edgeTypes prop to define your edge-types or use slots (