Skip to content

chore: release 2.0.0#717

Draft
bcakmakoglu wants to merge 203 commits into
masterfrom
release/2.0.0
Draft

chore: release 2.0.0#717
bcakmakoglu wants to merge 203 commits into
masterfrom
release/2.0.0

Conversation

@bcakmakoglu

@bcakmakoglu bcakmakoglu commented Feb 24, 2023

Copy link
Copy Markdown
Owner

🚀 What's changed?

  • Change 1
  • Change 2
  • ...

🐛 Fixes

  • #Issue1
  • #Issue2
  • ...

@bcakmakoglu bcakmakoglu added the release Related to a release label Feb 24, 2023
@bcakmakoglu bcakmakoglu added this to the Release: 2.0.0 milestone Feb 24, 2023
@bcakmakoglu bcakmakoglu self-assigned this Feb 24, 2023
@changeset-bot

changeset-bot Bot commented Feb 24, 2023

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bf267a4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@vue-flow/core Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Feb 24, 2023

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
vue-flow-docs Ready Ready Preview Comment Dec 12, 2025 8:42pm
vue-flow-typedoc Ready Ready Preview Comment Dec 12, 2025 8:42pm

@bcakmakoglu bcakmakoglu changed the title refactor(core)!: update handle styles chore: release 2.0.0 Feb 24, 2023
@vercel
vercel Bot temporarily deployed to Preview – vue-flow-typedoc February 24, 2023 19:39 Inactive
@vercel
vercel Bot temporarily deployed to Preview – vue-flow-typedoc March 17, 2023 19:11 Inactive
@vercel
vercel Bot temporarily deployed to Preview – vue-flow-typedoc March 18, 2023 10:35 Inactive
@bcakmakoglu bcakmakoglu changed the title chore: release 2.0.0 chore: release 2.0.0 Mar 22, 2023
@vercel
vercel Bot temporarily deployed to Preview – vue-flow-typedoc March 22, 2023 22:43 Inactive
@vercel
vercel Bot temporarily deployed to Preview – vue-flow-typedoc March 22, 2023 22:50 Inactive
@vercel
vercel Bot temporarily deployed to Preview – vue-flow-typedoc March 22, 2023 23:18 Inactive
@vercel
vercel Bot temporarily deployed to Preview – vue-flow-typedoc March 24, 2023 20:51 Inactive
bcakmakoglu and others added 30 commits June 17, 2026 14:57
xyflow/react #4594 fixed reconnecting edges in connectionMode 'loose': system's
getHandle now searches both source+target handle bounds in loose mode, so the
fixed (opposite) end of a reconnect is found even when its handle is registered
under the other type. vue-flow already has it — system 0.0.77 carries the fix,
useHandle threads connectionMode to XYHandle.onPointerDown, and EdgeWrapper's
handleReconnect computes the opposite handle (nodeId/handleId/type) correctly.
Add a regression guard reproducing the exact case (single source-type handles).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#2136)

xyflow/react #5384 fixes the unknown-type fallback to honor a user's custom
`default` registered via nodeTypes/edgeTypes (it previously used the built-in).
vue-flow already does this: NodeWrapper/EdgeWrapper resolve the fallback through
the merged getNodeTypes/getEdgeTypes (`{ ...builtin, ...userTypes }`), so a
custom `default` wins. Add a regression guard for both nodes and edges.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#2135)

xyflow/react #5362 moved the panel's "no pointer events while a selection is
dragged" from a JS store-subscription to a `.pane.selection .panel` CSS rule.
That CSS approach can't be ported to vue-flow: panels render via the default
slot, a sibling of `.vue-flow__pane`, not a descendant — so the descendant
selector would match nothing. vue-flow keeps the existing reactive
`userSelectionActive` inline style in Panel.vue, which already prevents a panel
from intercepting a selection drag. Add a regression guard for it.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ring a connection (#2145)

`<Handle>` stopped emitting the per-handle connection-state classes, so
connection-validation styling (e.g. red/green target handles) no longer worked.
Re-derive and toggle `connectingfrom` (drag source), `connectingto` (hovered
handle) and `valid` (hovered + valid target) from the store's connection
handles + status, matching xyflow/react + xyflow/svelte. Coloring stays in user
CSS; the validation examples are updated to the new class names.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…line slot props (#2146)

The custom `#connection-line` slot exposes `fromX`/`fromY`/`fromPosition` and
`toX`/`toY`/`toPosition` (xyflow/react + svelte parity), not `source*`/`target*`.
The example still destructured the old names, so it rendered against `undefined`
coordinates. The edge path helpers (`getBezierPath` etc.) keep their
`source*`/`target*` params, so the slot's `from*`/`to*` are mapped onto them.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
`@xyflow/system`'s `parseHandles` resets `handleBounds` to `undefined` when a
re-committed user node has no `measured`, and the node-rep split keeps both off
the user node — so a layout pass, a `sourcePosition`/`targetPosition` change, or
any `nodes.value.map(...)` re-commit wiped handle bounds and edges fell back to
the node's default handle sides. `adoptNodes` now carries prior `handleBounds`
forward alongside `measured` (the same adapter #2143 added for `measured`); a
real re-measure still overwrites it, and that result survives the next re-commit.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
- connection-line `#connection-line` slot: `source*/target*` → `from*/to*`
  (CustomConnectionLine, EasyConnect, FloatingEdges, SnapHandle), with the
  `getStraightPath`/`getBezierPath`/`getEdgeParams` calls remapped (their own
  `source*/target*` param names are unchanged)
- Layouting: `getNode(id).measured` → `getInternalNode(id).measured` for dagre
  sizing (`getNode` returns the user node, which has no `measured`)
- RGBFlow: the edge label is an RGB channel value (a number) — type `EdgeData.text`
  as `number` so the `:data` binding typechecks

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`ref<Node[]>` makes `.value` an `UnwrapRef<Node[]>`, and Vue's `UnwrapRef`
recursively walks the whole `Node` type — including `style`'s `CSSProperties`.
A single `nodes.value.map((n) => ({ ...n, position }))` therefore costs ~426k
type instantiations (verified via `tsc --generateTrace`: the bulk is
`structuredTypeRelatedTo` against `Styles`/`CSSProperties`), sitting on TS's
instantiation-depth limit and intermittently throwing TS2589 in long-running
editor type-checkers.

Nodes/edges hold no refs, so unwrapping is pure overhead. Opt them out via
Vue's `RefUnwrapBailTypes` (the hook Vue itself uses for DOM `Node`/`Window`),
using minimal `Pick` shapes that match every node/edge — incl. custom `data`
generics — and avoid the `label` self-reference the full `Edge` type triggers.
Drops the same operation to ~1k instantiations. Type-only; no runtime change.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… ConnectionLineProps/Actions (#2152)

* feat(core): discriminate #node-/#edge- slot props by type

`NodeSlots`/`EdgeSlots` typed every `#node-<type>`/`#edge-<type>` slot as the whole
`NodeProps<NodeType>`/`EdgeProps<EdgeType>`, so a per-type custom component that
narrows `data` couldn't `v-bind` the slot props without a cast. Map each slot key
to the matching union variant via a distributive conditional (`type` is optional on
Node/Edge, so `Extract<…, {type:T}>` would be `never`), with a broad
`node-/edge-${string}` fallback to keep arbitrary slot names + generic `Node[]`/
`Edge[]` flows working. Type-only; no runtime change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(core): thread NodeType/EdgeType through ConnectionLineProps + Actions

- ConnectionLineProps<NodeType>: the only FlowSlots slot not carrying the flow's
  NodeType. `fromNode`/`toNode` are now InternalNode<NodeType>, inferred from
  `:nodes` via the `#connection-line` slot.
- RemoveNodes<NodeType> / RemoveEdges<EdgeType>: the functional-updater arg now
  carries the flow's type, matching SetNodes/AddNodes.
- IsNodeIntersecting<NodeType>: mirrors its sibling GetIntersectingNodes<NodeType>.

Left getConnectedEdges' input as `Node[]` (it's a query matched by id — tightening
its input is contravariant and broke a caller for no benefit; output stays EdgeType[]).
All generics default to Node/Edge → non-breaking. Type-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- NodeTypeChange: "change type" was a no-op — it mutated `el.type` in place on
  `nodes.value`, which never re-commits in 2.0 (user nodes are markRaw'd). Re-map
  immutably instead, matching how the other examples update state.
- Overview: `@pane-contex-menu` typo (missing "t") left the pane context-menu
  handler dead → `@pane-context-menu`.
- NodeResizer: node 3 used `type: 'custom-resizable'` with no matching slot, so it
  rendered as a plain default node (+ "Node type is missing" warning). Add a
  CustomResizableNode (NodeResizer with a custom handle style) and register the slot.
- FloatingEdges: `edgePath` fell back to `''` (a string), so `edgePath[0]` was
  undefined before nodes are measured → BaseEdge `path` prop warning x8 on load.
  Fall back to `['']` so the path is always a string.
- SaveRestore: `onRestore` defaulted `zoom` to 0 (invisible viewport) → default 1.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
@vue-flow/core's source imports no d3 package directly — the d3 zoom/transition/
interpolate logic now lives inside @xyflow/system. Removes the d3-interpolate
runtime dep and the @types/d3-interpolate / @types/d3-transition / @types/d3-zoom
devDeps. The own postcss pipeline (postcss-import/nested/autoprefixer) is untouched.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(core): align two element class names with xyflow

Rename the structural element classes to match @xyflow/react/@xyflow/svelte:
- .vue-flow__transformationpane → .vue-flow__renderer
- .vue-flow__edge-labels → .vue-flow__edgelabel-renderer

Renders sites, the querySelector/getElementsByClassName lookups, and the copied
CSS are all updated. Breaking for consumers targeting either class in custom CSS
(or JS); documented in the migration guide. Only these two `vue-flow__*` suffixes
change. (The full system-sourced CSS build can't carry from the fork — the
published @xyflow/system ships no CSS — so @vue-flow/core keeps its copied CSS.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(core)!: align internal DOM with xyflow (viewport = transformed, renderer = outer)

The earlier rename mapped vue-flow's transformed layer to `renderer`, but in
@xyflow/react/@xyflow/svelte the transformed layer is `viewport` and the outer
pan/zoom container is `renderer`. Swap them so the DOM nests and is named exactly
like xyflow: renderer (outer) › pane (drag/selection) › viewport (transformed).

- ZoomPane renders `.vue-flow__renderer`; Viewport renders `.vue-flow__viewport`
- _necessary.css: `viewport` carries transform-origin/z-index:2/pointer-events:none;
  `renderer` is the outer z-index:4 (root `.vue-flow` keeps overflow:hidden)
- Handle.vue + actions.ts querySelector the transformed `.vue-flow__viewport`
- Cypress viewPort/transformationPane helpers point at the right elements
- migration guide (3-way rename table), theming guide, changeset updated

Net renames vs 1.x: transformationpane → viewport, viewport → renderer,
edge-labels → edgelabel-renderer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
The per-element v-for re-ran on every commit because each position/data
update replaces the whole nodes/edges array, re-diffing all N children
every frame. Iterating a value-stable id list keeps the renderer's render
effect firing only on membership changes; a moved node/edge re-renders
only through its own lookup-backed wrapper. Membership changes stay
O(changed) via the existing per-item v-memo.

Also fixes the edgeZIndex spec selector (the per-edge svg, not the new
shared .vue-flow__edges wrapper) and adds a dynamic runtime-selection
elevation test.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ement composables (#2156)

* perf(core): read store directly in node/edge/handle wrappers, not per-instance storeToRefs

`storeToRefs(useStore())` runs `toRefs` over the whole state (a ref per state key) on every call. In
`NodeWrapper`/`EdgeWrapper`/`Handle` that runs once per node, edge and handle — N + E + 2N times on a
large graph (~28.7 ms/1000 nodes for NodeWrapper alone, measured). Inside a component's computeds/render,
`store.x` already tracks reactively, so the refs aren't needed: read the reactive store directly.

The few values handed to helpers that write them back (`nodesSelectionActive`) or read them as a ref
(`isValidConnection`) stay as a single `toRef`. `useStore`/`storeToRefs` are unchanged; `storeToRefs`
remains the public destructure-and-carry helper. Updated the EasyConnect custom-node example + the
migration/composables guides to recommend direct `store.x` reads in custom nodes/edges.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* perf(core): read store directly in the per-element composables too

Follow-up to the wrapper conversion: the per-element composables those wrappers call still ran
`storeToRefs(useStore())` per element — `useNode` (per node + per handle), `useHandle` (per handle/edge),
`useDrag` + `useUpdateNodePositions` (per node), and `useNodeConnections` (consumer-facing). Each read its
store values inside event handlers / lazy `getStoreItems`/`getTransform` callbacks / computeds / a
`watchEffect`, where `store.x` gives the current value with the same reactivity — so no per-element ref
projection is needed. `useNodeConnections` was also `storeToRefs`-ing a lookup, which is now read raw.

17 interaction specs (drag, connect, reconnect, valid-connection, strict-mode, drag-threshold, selection,
basic) pass; build is type-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…re (#2158)

perf(core): drop the per-frame id-array allocation in the stable-id compare

nodeIds/edgeIds mapped the whole array to ids on every commit just to diff
it against the previous list. Compare the live array against the previous id
list in place with an indexed loop, allocating a new id array only when
membership actually changes — the unchanged path (every drag frame) now
allocates nothing and skips the per-element `.every` callback.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The edge `<g>` never carried a `selectable` class, so the CSS papered over
it with an unconditional `cursor: pointer` and ungated `:focus` rules. Emit
`selectable` (the edge's own flag, or `elementsSelectable` when unset) and
gate `cursor: pointer` + the focus edge-path stroke behind `.selectable`,
matching @xyflow/system. Non-selectable edges no longer show the pointer
cursor.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(core): drop the per-wrapper useNodeHooks/useEdgeHooks

These internal composables created a second set of 9 ExtendedEventHooks per
node and per edge whose only listener forwarded to the global `emits` hooks.
NodeWrapper/EdgeWrapper now call emits.node*/emits.edge* directly — identical
dispatch (the global hooks in store/hooks.ts back both the on* subscriptions
and the Vue @event emitter), minus 9 hook instances + 9 forwarding closures
of setup cost and memory per element. Drops the now-unused NodeEventsEmit/
EdgeEventsEmit types.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(core): resolve NodeWrapper's node via a direct computed

NodeWrapper used the public `useNode` composable but only ever read its
`node`. Resolve the InternalNode with `computed(() => getInternalNode(id))`
directly — identical to useNode's `node` — dropping the unused
parentNode/connectedEdges computeds, the nodeEl inject, and a redundant
useVueFlow/useStore resolution that useNode allocated per node. `useNode`
stays unchanged for custom-node use.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: cleanup

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>

---------

Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…able (#2161)

`useGetPointerPosition` was an @internal helper with no callers in core,
the examples, or the docs — the drag/connection paths derive pointer
positions inline via @xyflow/system. Remove the composable and its public
re-export.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ling it (#2162)

refactor(core): render the zoom-pane slot in Viewport, not drilled

The `zoom-pane` slot was drilled VueFlow → ZoomPane → Pane → Viewport via a
forwarded `<slot />`, which made Pane's and Viewport's slots dynamic — forcing
them to re-render whenever ZoomPane/Pane re-render. It now renders inside
Viewport (the transformed layer it belongs to) from the provided `Slots`,
through a small propless `ZoomPaneSlot` component:

- ZoomPane's slot to Viewport is now static → Pane/Viewport bail out of
  ZoomPane/Pane re-renders;
- the slot content bails out of Viewport's per-frame transform re-renders —
  invoked once and riding the CSS transform, not rebuilt each pan/zoom frame.

Mirrors the existing provide(Slots) pattern used for node/edge/minimap slots.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Handle is the highest-multiplicity element (~2 per node). It created ~13
reactive refs/computeds per instance — 7 of them connection-state `toRef`s
derived from the same global `connection*` store state and used only in the
class binding. Consolidate those into one `connectionClasses` computed, and
drop the redundant isConnectableStart/isConnectableEnd refs (their props
already default to true). ~13 → ~5 reactive effects per handle, identical
rendered classes, no API change.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…2165)

`updateNodeDimensions`' guard skipped measuring whenever the incoming
dimensions matched `node.measured` and the update wasn't forced — even
when the node still had no `handleBounds`. xyflow/system's guard carries
a `!node.internals.handleBounds` term for exactly this case; add it so a
node can't be left without handle bounds if it reaches the guard
un-forced with already-matching dimensions.

Inert in the normal flow (the ResizeObserver's forced update fires
first), so there's no behavior change today — this is parity hardening
against any future un-forced measurement path.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…enders (#2166)

`connectionClasses` returned a fresh object on every recompute, so Vue's
reference-identity gate re-ran the class binding's render effect each time.
During a connection drag `connectionEndHandle` invalidates every handle's
computed on each intermediate target change, even though only the two
endpoints' classes actually change — so every visible handle re-rendered
repeatedly, scaling with on-screen handle count.

Reuse the previous object when all class flags are unchanged (via the
computed's `prev` getter arg — the Vue equivalent of React's `useShallow`).
Measured on a 12-node / 24-handle connection drag: 312 -> 48 handle
re-renders (~6.5x), with no change to the emitted classes.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment