chore: release 2.0.0#717
Draft
bcakmakoglu wants to merge 203 commits into
Draft
Conversation
🦋 Changeset detectedLatest commit: bf267a4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
1 task
bcakmakoglu
force-pushed
the
release/2.0.0
branch
from
March 17, 2023 19:00
127dfcc to
c95c229
Compare
bcakmakoglu
force-pushed
the
release/2.0.0
branch
from
March 22, 2023 22:49
4e88c74 to
a2c840f
Compare
bcakmakoglu
force-pushed
the
release/2.0.0
branch
from
March 22, 2023 23:14
a2c840f to
c05e479
Compare
bcakmakoglu
force-pushed
the
release/2.0.0
branch
from
March 24, 2023 20:35
c05e479 to
6665419
Compare
bcakmakoglu
force-pushed
the
release/2.0.0
branch
from
March 29, 2023 11:30
6665419 to
469d395
Compare
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🚀 What's changed?
🐛 Fixes