Skip to content

v0.49.0

Latest

Choose a tag to compare

@etrepum etrepum released this 30 Jul 16:18

v0.49.0 is a monthly release headlined by the completion of the $config() protocol migration for Lexical's built-in node classes (#8640), a breaking change that replaces per-node getType()/clone()/importJSON()/importDOM()/transform() boilerplate with runtime-synthesized behavior. It ships with a cluster of follow-up fixes hardening the synthesized getType() and clone() (including a stack overflow in compiled builds), an opt-in sticky horizontal scrollbar for overflowing tables, and a broad batch of fixes across tables, Markdown, HTML, code highlighting, and selection.

Breaking Changes

  • lexical — Built-in node classes are ported to the $config() protocol. The static importJSON(), importDOM(), clone(), and transform() methods are no longer present on ported nodes; use the higher-level equivalents instead (LexicalEditor.parseEditorState/$generateNodesFromDOM, the $cloneWithProperties helper, and extensions or $transform in $config). getType() is unchanged and safe to keep using, __type is now readonly, and node constructors require zero-argument defaults. Custom nodes may keep their static methods, but adopting $config() is recommended (#8640)
  • lexicalLexicalCommand<T>'s payload type is now invariant to prevent unsafe structural compatibility between commands. Previously correct code (including explicit generics) needs no changes; only unsafe LexicalCommand<unknown> usage must switch to the newly exported AnyLexicalCommand alias. dispatchCommand's payload argument is now optional when a command's payload type is undefined or void, and redundant explicit type parameters were dropped from the registerCommand/registerNodeTransform call sites (#8877)

New APIs & Features

  • @lexical/table — Opt-in sticky horizontal scrollbar for tables wider than their container, so the scrollbar stays anchored at the viewport bottom instead of only being reachable at the end of the table. Enable it with hasStickyScrollbar: true in the table config; style it via the new tableStickyScrollbar theme key (#8790)
  • @lexical/table — The <colgroup> element is now omitted from the table DOM when column widths are undefined, producing cleaner markup and letting the browser auto-size columns; it is created or removed dynamically as widths change (#8850)
  • lexical — Added an editor operation benchmark suite (paragraph split, bold formatting, range deletion, paste, select-all format) measured through full DOM reconciliation, to help contributors track core editing performance (#8856)

Deprecations

  • @lexical/table$createTableSelection is deprecated in favor of $createTableSelectionFrom, which takes the table node plus anchor/focus cells and validates them, instead of returning a blank selection with placeholder 'root' keys that must be overwritten (#8855)
  • @lexical/tablegetShape() is deprecated because it computes incorrect bounds for merged cells; use the now-exported $computeTableCellRectBoundary (with $computeTableMap) instead (#8853)

Notable Fixes

$config() follow-ups (#8640)

  • The synthesized clone() now applies afterCloneFrom() when called directly (e.g. NodeClass.clone(node)), fixing silent property loss across 25+ core nodes (#8864)
  • The synthesized getType() no longer returns the superclass type when inherited, fixing node-type collisions during editor registration (#8867)
  • The synthesized getType() no longer recurses infinitely when a bundler copies it onto a subclass as an own static, fixing stack overflows in compiled/minified builds (#8869)

Tables

  • DELETE_LINE_COMMAND (Cmd/Ctrl-based delete-line shortcuts) now works inside table cells instead of being silently swallowed (#8851)
  • Table alignment now works when cells are selected in any direction, not just top-left→bottom-right (#8883)

Selection & editing

  • Editor updates dispatched from a read-only context (e.g. inside editor.read()) now run in a fresh writable update instead of being silently dropped, with a dev warning (#8863)
  • Firefox now creates a selection and shows the block cursor when clicking in the gap between block decorators (#8862)
  • Pressing ArrowUp before a leading non-inline decorator no longer moves the selection out of the editor (#8887)

Markdown, HTML & code

  • Typing a list marker at the start of a heading no longer converts the heading into a list (#8879)
  • HTML import now evaluates unrestricted CSS selector groups (e.g. p, .foo) against all elements instead of only tag-matched ones (#8873)
  • Concurrent async language/theme loads in the Shiki highlighter are deduplicated and merged into a single history entry, avoiding spurious undo states (#8854)
  • QuoteNode.updateDOM now accepts the EditorConfig argument the reconciler passes to every other node, for API consistency (#8882)

Playground & website

  • Playground scroll padding now accounts for the sticky toolbar so selections scrolled into view from above aren't hidden behind it (#8849)
  • Fixed a homepage crash caused by a minified dev build, and isolated each embedded example in its own error boundary so one failure no longer takes down the page (#8861)

What's Changed

  • [lexical] Bug Fix: Scope bench vitest projects to exclude regular test files by @mayrang in #8852
  • [lexical-table] Bug Fix: Enable DELETE_LINE_COMMAND in table cells by @mayrang in #8851
  • [lexical-table] Chore: Deprecate $createTableSelection in favor of $createTableSelectionFrom by @mayrang in #8855
  • [Breaking Changes][lexical] Refactor: Port node classes to the $config() protocol by @etrepum in #8640
  • [lexical-playground] Bug Fix: account for sticky toolbar in scroll padding by @etrepum in #8849
  • [lexical-list] Chore: Rename isNestedListNode to $isNestedListNode by @etrepum in #8843
  • [lexical-table][lexical-playground] Chore: Deprecate getShape() and migrate playground by @mayrang in #8853
  • [lexical-table] Chore: Remove dead code in table command handlers by @mayrang in #8857
  • [lexical-code-shiki] Bug Fix: Deduplicate async loads and merge into history by @Alxs39 in #8854
  • [lexical-table][lexical] Feature: Sticky scrollbar for overflowing tables by @mayrang in #8790
  • fix: $config() auto-synthesized clone() loses properties when called directly (#8640) by @potatowagon in #8864
  • fix: $config() synthesized getType() inherited by subclasses causes node-type collision (#8640) by @potatowagon in #8867
  • [lexical] Chore: Migrate LexicalSelection tests to buildEditorFromExtensions by @mayrang in #8865
  • [lexical] Feature: Editor operation benchmarks by @mayrang in #8856
  • [lexical] Bug Fix: run editor updates dispatched from a read-only context in a fresh writable update by @potatowagon in #8863
  • [lexical][lexical-website] Bug Fix: Homepage crash from optimized dev build by @etrepum in #8861
  • fix: $config() synthesized getType() recurses infinitely when inherited as own static (#8867 follow-up) by @potatowagon in #8869
  • [lexical] Bug Fix: Create selection when clicking between block decorators on Firefox by @mayrang in #8862
  • [lexical-table] Feature: Skip colgroup element in table DOM with undefined col widths by @zacharyg-qualtrics in #8850
  • [lexical-list] Chore: Remove redundant decorator-adjacent backspace handler by @mayrang in #8871
  • [lexical] Refactor: Simplify RangeSelection.insertText via removeText decomposition by @mayrang in #8870
  • [lexical] Performance: Skip redundant selection restoration in $removeTextFromCaretRange by @mayrang in #8872
  • [lexical-playground] Bug Fix: Deterministic history coalescing for flaky webkit undo tests by @etrepum in #8874
  • [lexical-html] Bug Fix: Dispatch unrestricted CSS selector groups by @winklemad in #8873
  • [Breaking Change][lexical] Chore: Remove redundant registerCommand/registerNodeTransform generics by @mayrang in #8877
  • [lexical-table] Bug Fix: Table alignment fails when selecting in non-TL->BR direction by @sahiee-dev in #8883
  • [lexical-rich-text] Bug Fix: Forward editorConfig to QuoteNode.updateDOM by @werterhalimi in #8882
  • [lexical-markdown] Bug Fix: Preserve headings when typing list shortcuts by @StevenPDang in #8879
  • [lexical-rich-text] Bug Fix: Keep block cursor in editor when ArrowUp at start of root (#8886) by @etrepum in #8887

New Contributors

Full Changelog: v0.48.0...v0.49.0