v0.46.0

hexgrad/kokorov0.46.0Jun 26, 2026by etrepum

AI Summary

A major release introducing experimental Named slots and Shadow DOM support. It also refines node traversal types and removes deprecated exports.

Key Highlights

  • Introduction of Named slots for isolated editable regions
  • Support for hosting the editor in an open Shadow DOM
  • Removal of deprecated exports from v0.32.1

Breaking Changes

  • Node traversal methods no longer accept unsafe type parameters
  • `$getNearestNodeFromDOMNode(rootElement)` now returns `RootNode`
  • `insertNodes` preserves a leading linebreak; managed `<br>`s are now tagged
  • DOMImportExtension rules now register implicitly
  • Named slots changes to `syncLexicalUpdateToYjsV2__EXPERIMENTAL` and `NodeSelection` copy behavior
  • Removal of deprecated exports (`toggleLink`, `insertList`, `ContentEditable` Props)

New Features

  • New `editor.read(mode, fn)` modes (`force-commit`, `pending`, `latest`)
  • DOM shadow root support with platform API integration
  • New `onWarn` editor hook for handling warnings

Full Release Notes

v0.46.0 is a monthly release headlined by two major new experimental capabilities:
- [Named slots](https://lexical.dev/docs/concepts/named-slots) - a model that lets a single host element or decorator node own several isolated editable regions inside the host's own `editorState`
- [Shadow DOM](https://lexical.dev/docs/concepts/shadow-dom) - the root element can now be hosted in an open shadow root (or iframe)

This release also includes many other fixes and new features across IME/composition, collaboration, markdown round-tripping, lists, code blocks, links, and mobile keyboards. It is also our first release (other than nightlies) to use NPM Trusted Publishing.

Special recognition for this release goes to @mayrang for doing the majority of the work on both of these new features as well as fixing some tricky IME/composition issues πŸ‘  @levensta has also been doing a fantastic job going through the issue backlog, providing valuable feedback on these bleeding edge features, and identifying long-standing edge cases.

## Breaking Changes

### `lexical` β€” Node traversal methods no longer accept unsafe type parameters (#8661)

The zero-argument generics on `getParent(OrThrow)`, `getPreviousSibling(s)`, `getNextSibling(s)`, `getChildren`, `getFirstChild(OrThrow)`, `getLastChild(OrThrow)`, `getChildAtIndex`, `getFirstDescendant`, `getLastDescendant`, and `getDescendantByIndex` were implicit unchecked casts β€” there is no inference site, so any non-base type argument was equivalent to an `as` cast. Each method is now an overload pair: a documented non-generic signature returning the base type (`LexicalNode` / `ElementNode | null`), plus the old generic signature marked `@deprecated`. Code that leaned on contextual-type inference no longer type-checks:

```ts
// Before: compiled (unsound). After: type error.
const node: ParagraphNode | null = $getRoot().getFirstChild();

// Port directly with an explicit cast (no behavior change):
const node = $getRoot().getFirstChild() as ParagraphNode | null;

// Or, better, narrow with a guard:
const node = $getRoot().getFirstChild();
if ($isParagraphNode(node)) { /* node: ParagraphNode */ }
```

Existing `getFirstChild<ParagraphNode>()`-style calls still compile but are now deprecated and will be removed in a future release. This is a types-only change with no runtime impact.

### `lexical` β€” `$getNearestNodeFromDOMNode(rootElement)` now returns `RootNode` (#8588)

The "selection captured outside of Lexical" mechanism is generalized beyond `DecoratorNode` subtrees: `setDOMUnmanaged(dom, {captureSelection: true})` now marks any subtree (e.g. a `DOMRenderExtension` override or a `getDOMSlot` widget) as selection-captured, and `isDOMCapturingSelection(dom)` walks ancestors so a descendant `<input>` reports as captured. As part of this, the root element now carries a `__lexicalKey_*` stash, so `$getNodeFromDOM` / `$getNearestNodeFromDOMNode` resolve the root element to the `RootNode` instead of `null`. Two call sites become more correct (drop-on-root in clipboard, table-selection→range conversion), but **external callers that relied on `$getNearestNodeFromDOMNode(rootElement)` returning `null` must update**. The internal-only `$isSelectionCapturedInDecorator` was removed.

### `lexical` β€” `insertNodes` preserves a leading linebreak; managed `<br>`s are now tagged (#8615)

`RangeSelection.insertNodes` now preserves the first `LineBreakNode` when inserting inline content ahead of a block element, instead of silently dropping it. Separately, the reconciler-inserted "managed" line breaks (the otherwise-invisible `<br>`s Lexical adds so the caret can land in empty lines) are now identifiable in the DOM as `<br data-lexical-managed-linebreak="true">` β€” and, on iOS Safari, an analogous `<img data-lexical-managed-linebreak="true" …>` in some cases. **DOM/HTML snapshot test expectations may need to ignore or expect this attribute.** Closes #3980.

### `@lexical/html` and node extensions β€” DOMImportExtension rules now register implicitly (#8662) _(experimental)_

The experimental DOM-import pipeline no longer requires you to list a per-package import extension. Each node-providing extension (`RichTextExtension`, `ListExtension`, `LinkExtension`, `TableExtension`, `CodeExtension`) now registers its own import rules, and the standalone `RichTextImportExtension` / `ListImportExtension` / `LinkImportExtension` / `TableImportExtension` / `CodeImportExtension` / `HorizontalRuleImportExtension` become **deprecated aliases that may be removed as early as v0.47.0**. Rules stay inert unless HTML is routed through `ClipboardDOMImportExtension` or `$generateNodesFromDOMViaExtension`; the legacy `importDOM` paste path is unchanged. If you had not adopted these v0.45.0 extensions yet, there is no breaking change.

### `lexical` / `@lexical/yjs` / `@lexical/clipboard` / `@lexical/html` β€” Named slots (#8603) _(experimental)_

All slot machinery is opt-in and gated (an editor latches `_slotsUsed` on the first `$setSlot`), so editors that never use slots take identical code paths to before. Two changes are observable regardless:

- **`syncLexicalUpdateToYjsV2__EXPERIMENTAL` takes a new `dirtyLeaves` parameter**, inserted between `dirtyElements` and `normalizedNodes` (a slot host's values surface as dirty *leaves*).
- **A `NodeSelection` containing an `ElementNode` now includes that element's children on copy/export** (`$getHtmlContent` / `$generateJSONFromSelectedNodes`). The previous behavior serialized a childless shell, making cut of an element `NodeSelection` silently lossy; partial `RangeSelection`s keep per-child slicing and `excludeFromCopy` children remain excluded.

### `@lexical/link` / `@lexical/list` / `@lexical/react` β€” Removed exports deprecated since v0.32.1 (#8704)

Exports marked `@deprecated` in v0.32.1 (2025-06-04, >12 months ago) with no Meta-internal consumers are removed:

- `@lexical/link`: `toggleLink` β†’ use `$toggleLink`
- `@lexical/list`: `insertList` / `removeList` β†’ use `$insertList` / `$removeList` (from an update or command listener)
- `@lexical/react`: the `ContentEditable` `Props` type alias β†’ use `ContentEditableProps`

Note: `lexical`'s `$nodesOfType` is intentionally **un-deprecated** (it still has many consumers). The remaining v0.32.1 deprecations that still have internal consumers (`KEY_MODIFIER_COMMAND`, `$wrapNodes`, the `@lexical/table` row/column helpers, etc.) are left for a follow-up.

## New APIs

### `lexical` β€” `editor.read(mode, fn)` and `EditorReadMode` (#8702)

`read` gains an optional first argument: `'force-commit'` (the default; flushes pending updates first β€” the previous one-argument behavior), `'pending'` (reads the pending state without flushing β€” the old `editor.readPending`, now removed), and `'latest'` (reads the committed state without flushing, equivalent to `editor.getEditorState().read(fn, {editor})`). `EditorReadMode` is exported. `readPending` only shipped after v0.45.0, so its removal is not considered a breaking change.

### `lexical` β€” DOM shadow root support (#8694)

An editor can now mount inside an open shadow tree without losing selection, focus, drag-and-drop, IME composition, or floating-UI behavior. Reads go through platform APIs β€” `Selection.getComposedRanges`, `Selection.direction`, `ShadowRoot.activeElement`, `Document.caretPositionFromPoint(x, y, {shadowRoots})` β€” and nine new helpers ship from `lexical`; the light-DOM code paths are unchanged. Follow-ups #8708 (insert nodes at the block cursor inside a shadow root) and #8740 (ignore `beforeinput`/`input` in captured decorators, fixing Firefox 152) complete the surface.

### `lexical` β€” `onWarn` editor hook (#8644)

`CreateEditorArgs` gains an optional `onWarn?: ErrorHandler` (stored as `_onWarn`, defaulting to `console.warn`), mirroring `onError`. The infinite-update-loop guard's recoverable warning now routes through it (wired end-to-end in #8658), so embedders that bridge reporting to their own telemetry no longer lose this signal to each user's browser console.

### `lexical` β€” `$config()` accessor-based nominal typing (#8645)

An additive extension of the `$config()` protocol: abstract base classes can declare configuration shared with their subclasses under a `Symbol.for(<ClassName>)` key (resolved by `getStaticNodeConfig`), and accessor-based nominal typing lets subclasses opt into stricter `$config()` checks. No existing node class is changed.

### `@lexical/history` β€” Cut/paste get their own undo entry (#8649)

Any update tagged `PASTE_TAG` or `CUT_TAG` is now classified as an `OTHER` change inside `@lexical/history`, which keeps it from merging into the **preceding** keystrokes and keeps **following** keystrokes from merging into it. Undoing a short paste (or an iOS autocorrect/prediction) or a cut no longer also undoes the text you typed immediately before it.

### `@lexical/extension` β€” `SelectBlockExtension` (#8532)

Overrides `SELECT_ALL_COMMAND` so the first invocation selects the nearest block element and the second selects the entire document; a selection already spanning multiple blocks expands straight to the document, and select-all is a no-op when everything is already selected. Includes an opt-in `cascadeSelection` option for nested editors (image captions, etc.) and enables `PreventSelectAllExtension` by default to keep `keydown` from leaking out of `input`/`textarea` elements. (Also introduced `editor.read('pending', …)` via the now-generalized #8702.)

### `@lexical/yjs` / `@lexical/react` β€” Collaborative cursors via the CSS Custom Highlight API (#8550)

Remote collaborators' selections are now painted with the widely-supported CSS Custom Highlight API; the error-prone absolutely-positioned overlay remains only as a fallback. The remote caret is still rendered as a positioned element. Closes #4457, #5837.

### `@lexical/utils` β€” `dedupeSelectionRects` (#8709)

A new exported helper that drops zero-area rects and any rect that contains another (with 1px tolerance) from `Range.getClientRects()`, fixing the duplicate/over-bright and spurious extra-wide fake-selection rects WebKit produces on some blocks. It is wired into `positionNodeOnRange`, so every fake-selection consumer (`markSelection`, `selectionAlwaysOnDisplay`, the extension) gets clean rects. Addresses #7106, #7492.

### `@lexical/code-core` β€” `escapeWithArrows` (#8393)

`CodeIndentExtension` gains an `escapeWithArrows` option (default `false`): when a code block is the terminal node and the caret is at the end of its text, pressing the arrow keys creates a new paragraph and moves the caret into it. New `$onEscapeDown` / `$onEscapeUp` helpers back it in `@lexical/utils`. Closes #7912, #4685, #5968.

### `@lexical/react` β€” Self-contained `LexicalErrorBoundary` (#8720)

`LexicalErrorBoundary` no longer wraps `react-error-boundary` (the dependency is dropped) and gains an optional `fallback` prop β€” omit it for the default message, or pass `fallback={null}` to render nothing. Its public type is unchanged, so it remains usable as the `ErrorBoundary` prop of `RichTextPlugin` / `PlainTextPlugin`.

## Highlights

### Core (`lexical`):

* ⚠️ #8661 Deprecate unsafe type parameters on node traversal methods
* ⚠️ #8588 `$getNearestNodeFromDOMNode(rootElement)` resolves to `RootNode`; generalized captured selection via `setDOMUnmanaged({captureSelection})`
* ⚠️ #8615 Preserve the first linebreak in `insertNodes`; tag managed `<br>` with `data-lexical-managed-linebreak`
* πŸ†• #8694 DOM shadow root support via platform selection APIs
* πŸ†• #8702 `editor.read(mode, fn)` overload + `EditorReadMode` (replaces `readPending`)
* πŸ†• #8644 `onWarn` editor hook (#8658 routes the recursion guard through it end-to-end)
* πŸ†• #8645 `$config()` accessor-based nominal typing
* βœ… #8598 `TabNode.setTextContent` for Safari IME composition
* βœ… #8604 Caret stuck when a block has no leading or trailing text
* βœ… #8680 Emit `COMPOSITION_END_TAG` from the Firefox `onInput` defer branch
* βœ… #8701 Recheck text-node contents on deletion with composition
* βœ… #8686 Reuse the empty trailing block when typing at root + last-offset selection
* βœ… #8708 Insert nodes at the block cursor inside a shadow root
* βœ… #8715 Normalize non-inline nodes when inserting into inline-only parents
* βœ… #8740 Ignore `beforeinput`/`input` in captured decorators (Firefox 152)
* βœ… #8635 #8631 #8612 #8638 Stop the infinite-update-loop detector over-firing on fast typing; report via `devInvariant`
* βœ… #8617 `$assumeEditor` warns via `devInvariant` instead of throwing in prod
* βœ… #8726 Guard the `klass.prototype` null check in `getStaticNodeConfig`
* βœ… #8739 Use an `inheritsLoose`-safe helper for class-inheritance loops
* βœ… #8593 Harden against ReDoS and prototype pollution (linear-time regexes, prototype guards); faster CSS parsing
* 🧹 #8628 Surface a clear error when TypeScript (<5.2) can't read the package exports
* 🧹 #8579 Consolidate tokenization through `tokenizeRawText` / `$generateNodesFromRawText`
* 🧹 #8735 Better error messages for invalid node classes; cache `getStaticNodeConfig`
* 🧹 #8675 #8742 #8667 `T[]` over `Array<T>`, modernized Flow stubs, dropped deprecated traversal type params in tests

### Named slots _(experimental)_:

* βš οΈπŸ†• #8603 Named slots β€” a host node owns multiple isolated editable regions inside its own `editorState`
* βœ… #8716 Named-slot typing / Backspace / Copy / hydrate paths

### HTML / DOM import:

* ⚠️ #8662 Register DOMImportExtension rules implicitly via node extensions; make tree-shaking annotations effective
* 🧹 #8590 Migrate the playground's HTML import/export to the DOMImportExtension pipeline
* βœ… #8589 `$generateHtmlFromNodes` self-establishes active-editor scope (back-compat for #8519)

### Extension / History:

* πŸ†• #8532 `SelectBlockExtension`
* πŸ†• #8649 Snapshot history before cut/paste so an undo doesn't swallow prior typing

### Code:

* πŸ†• #8393 `escapeWithArrows`: create a paragraph around a terminal code block with the arrow keys
* πŸ†• #8600 Add Go to the code-language options
* βœ… #8606 Set the unsupported-syntax flag only once (shiki)

### Link / List:

* βœ… #8513 Skip link wrapping on paste for non-simple text nodes
* βœ… #8705 Preserve the `LinkNode` wrap on copy in Firefox/Safari
* βœ… #8676 Preserve a previous `DecoratorNode` on Backspace at the start of a top-level list

### Markdown:

* βœ… #8688 Code spans bind tighter than text-match transformers
* βœ… #8723 Inline code spans containing backticks
* βœ… #8728 Preserve inline formatting when wrapping already-formatted text with matching markers
* βœ… #8678 Update the ordered-list start when typing a marker before it
* βœ… #8562 Preserve block equation markdown

### Mark / Clipboard / Table:

* 🧹 #8717 Widen `MarkNode` method return types to `boolean` (restores subclass overrides)
* βœ… #8706 Correct clipboard type-checking
* βœ… #8674 Don't throw on stale table node keys in `$handleTableSelectionChangeCommand`

### Collaboration (`@lexical/yjs`) / Dragon:

* πŸ†• #8550 Render collab cursors via the CSS Custom Highlight API
* βœ… #8611 Local range selection no longer grows when a collaborator edits
* βœ… #8652 Keep the collab cursor at element end when decoding an out-of-range position
* βœ… #8651 #6614 Avoid empty-paragraph echo and a splice crash on collab undo; don't preserve tags on non-dirty updates
* βœ… #8646 Fix Yjs desync after clearing all nodes
* βœ… #8665 `@lexical/dragon`: handle `makeChanges` messages and the listener-registration race

### Utils / React:

* πŸ†• #8709 `dedupeSelectionRects` β€” clean up WebKit fake-selection rects
* 🧹 #8733 Move `getScrollParent` to `@lexical/utils`
* βœ… #8684 Fix double paragraph creation when exiting a nested code block
* 🧹 #8720 Self-contained `LexicalErrorBoundary` (drops `react-error-boundary`) with an optional `fallback` prop
* 🧹 #8682 Hook syntax in `.js.flow` files; πŸ“ #8714 API doc coverage of `@lexical/react` exports

### Rich Text / Plain Text:

* βœ… #8725 Refresh the iOS keyboard suggestion bar after Backspace for all locales
* βœ… #8663 Call `preventDefault()` in `dragover` for HTML5 DnD compliance

### Playground:

* πŸ†• #8574 Korean IME autocomplete with composition-idle ghost text (pluggable `AutocompleteDictionary`)
* πŸ†• #8594 Non-printing marks (`ΒΆ`, `↡`, `β†’`, `Β·`), toggled from Settings
* βœ… #8599 Autocomplete wordlist returns the highest-priority completion
* βœ… #8666 Clear block alignment/indent on a collapsed (but not partial) selection
* βœ… #8719 Render `PageBreakNode` as `<hr>` so Safari fires `beforeinput` after paste
* βœ… #8655 Fix the importmap of the `/esm/` proof of concept
* βœ… #8695 Correct the CodeBlock layout-exit e2e expected HTML
* 🧹 #8585 #8595 #8637 Audit and de-flake the e2e suite (remove all `@flaky` tags)
* 🧹 #8639 Remove the localhost:1235 validation-server code from `ActionsPlugin`

### Infrastructure / Tooling:

* 🧹 #8587 #8597 #8747 Consolidate release workflows and adopt npm trusted publishing
* 🧹 #8614 Vitest browser-mode tests via the Playwright runner
* 🧹 #8673 Fix intermittent `EACCES` in Windows CI browser tests
* 🧹 #8703 Migrate `editor.getEditorState().read(...)` to `editor.read('latest', ...)`
* 🧹 #8634 Require all changes to be backwards compatible (`AGENTS.md` / `CLAUDE.md`)
* 🧹 #8693 Remove the unused `tmp` dependency; #8647 replace the `node-state-style` example with the dev-examples version
* 🧹 Dependency bumps: #8566 #8573 #8618 #8619 #8621 #8622 #8624 #8625 #8626 #8629 #8630 #8632 #8633

## What's Changed
* v0.45.0 by @etrepum in https://github.com/facebook/lexical/pull/8580
* build(deps-dev): bump tmp from 0.2.5 to 0.2.6 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8573
* [lexical-playground] Chore: Audit and de-flake the e2e suite (remove all @flaky tags) by @etrepum in https://github.com/facebook/lexical/pull/8585
* [lexical][lexical-code-core][lexical-code-prism][lexical-code-shiki] Chore: Consolidate text tokenization through tokenizeRawText / $generateNodesFromRawText by @etrepum in https://github.com/facebook/lexical/pull/8579
* fix(lexical-html): $generateHtmlFromNodes should self-establish active-editor scope (back-compat for #8519) by @potatowagon in https://github.com/facebook/lexical/pull/8589
* [lexical-link] Bug Fix: Skip link wrapping on paste for non-simple text nodes by @abhishekvishwakarma007 in https://github.com/facebook/lexical/pull/8513
* [lexical-playground][lexical-html][lexical-extension] Refactor: Migrate playground HTML import/export to the DOMImportExtension pipeline by @etrepum in https://github.com/facebook/lexical/pull/8590
* [Breaking Change][lexical] Feature: Generalize captured selection via setDOMUnmanaged({captureSelection}) + root __lexicalKey_* stash by @mayrang in https://github.com/facebook/lexical/pull/8588
* [ci] Refactor: Consolidate release workflows + npm trusted publishing by @etrepum in https://github.com/facebook/lexical/pull/8587
* [lexical][lexical-extension][lexical-markdown][lexical-playground][lexical-yjs] Bug Fix: Linear-time regexes, prototype-pollution guards, and faster CSS parsing by @etrepum in https://github.com/facebook/lexical/pull/8593
* [lexical] Bug Fix: TabNode.setTextContent for Safari IME composition by @mayrang in https://github.com/facebook/lexical/pull/8598
* [lexical-playground] Feature: Korean IME autocomplete with composition-idle ghost by @mayrang in https://github.com/facebook/lexical/pull/8574
* [ci] Bug Fix: Trusted-publishing follow-ups (TTY-aware setup script, unify nightly, drop NPM_TOKEN) by @etrepum in https://github.com/facebook/lexical/pull/8597
* [lexical-playground] Bug Fix: AutocompleteExtension wordlist returns the highest-priority completion by @etrepum in https://github.com/facebook/lexical/pull/8599
* [lexical-playground][lexical-website] Feature: Non-printing marks (#8592) by @mayrang in https://github.com/facebook/lexical/pull/8594
* [lexical-playground] Chore: De-flake e2e timing- and history-dependent tests by @etrepum in https://github.com/facebook/lexical/pull/8595
* [lexical-code-shiki] Bug Fix: Set the unsupported syntax flag only once by @levensta in https://github.com/facebook/lexical/pull/8606
* [lexical-code-prism][lexical-playground] Feature: Add Go to code language options by @meaqua9420 in https://github.com/facebook/lexical/pull/8600
* [lexical-rich-text] Bug Fix: Caret stuck when block has no leading or trailing text by @mayrang in https://github.com/facebook/lexical/pull/8604
* Include editor namespace in infinite-update-loop detector error by @potatowagon in https://github.com/facebook/lexical/pull/8612
* [lexical-extension][lexical-react][lexical-playground] Chore: Add Vitest browser-mode tests via the Playwright runner by @etrepum in https://github.com/facebook/lexical/pull/8614
* fix(lexical): reconcile DOM mutations targeting the root element by @potatowagon in https://github.com/facebook/lexical/pull/8613
* revert(lexical): remove root-element carveout from #8613 (keep the typing test) by @potatowagon in https://github.com/facebook/lexical/pull/8616
* [lexical-yjs] Bug Fix: Local range selection grows when collaborator … by @sahiee-dev in https://github.com/facebook/lexical/pull/8611
* [lexical] Refactor: $assumeEditor now uses devInvariant instead of invariant to warn instead of throwing in prod by @etrepum in https://github.com/facebook/lexical/pull/8617
* build(deps): bump the docusaurus-and-typedoc group with 2 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/8618
* build(deps): bump @rollup/rollup-linux-x64-gnu from 4.52.0 to 4.61.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8621
* build(deps-dev): bump the flow-and-hermes group with 5 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/8619
* build(deps): bump @shikijs/engine-javascript from 4.0.2 to 4.2.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8622
* build(deps): bump yjs from 13.6.30 to 13.6.31 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8624
* build(deps): bump @shikijs/langs from 3.23.0 to 4.2.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8626
* build(deps): bump lucide-react from 0.503.0 to 1.17.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8625
* build(deps): bump @huggingface/transformers from 4.0.1 to 4.2.0 by @dependabot[bot] in https://github.com/facebook/lexical/pull/8629
* build(deps-dev): bump the dev-dependencies group across 1 directory with 29 updates by @dependabot[bot] in https://github.com/facebook/lexical/pull/8630
* build(deps): bump webpack-dev-server to >=5.2.4 (CVE-2026-6402) by @xiezhenjia-meta in https://github.com/facebook/lexical/pull/8632
* build(deps): bump vitest to ^4.1.8 in examples (CVE-2026-47429) by @xiezhenjia-meta in https://github.com/facebook/lexical/pull/8633
* fix: bump astro to ^6.1.10 to resolve CVE-2026-45028 by @freddymeta in https://github.com/facebook/lexical/pull/8566
* [lexical] Bug Fix: use devInvariant for update recursion guard to avoid reporting a recovered condition as an uncaught error by @potatowagon in https://github.com/facebook/lexical/pull/8631
* [*] Bug Fix: Surface a clear error when TypeScript (<5.2) can't read the package exports by @etrepum in https://github.com/facebook/lexical/pull/8628
* [lexical-playground] Chore: De-flake collab "Undo with collaboration on" e2e test by @etrepum in https://github.com/facebook/lexical/pull/8637
* [lexical] Chore: cover both devInvariant branches in update-recursion guard test by @potatowagon in https://github.com/facebook/lexical/pull/8638
* [lexical-playground] Chore: Remove localhost:1235 validation server code from ActionsPlugin by @etrepum in https://github.com/facebook/lexical/pull/8639
* [*] Chore: require all changes to be backwards compatible by @potatowagon in https://github.com/facebook/lexical/pull/8634
* [lexical-code-core][lexical-playground] Feature: Create paragraph around the code node when navigating with the arrow keys by @levensta in https://github.com/facebook/lexical/pull/8393
* [lexical] Extend the $config() protocol with accessor-based nominal typing by @etrepum in https://github.com/facebook/lexical/pull/8645
* [lexical-yjs][lexical-react] Feature: Render collab cursors via CSS custom Highlight API by @hamza512b in https://github.com/facebook/lexical/pull/8550
* [examples] Chore: Replace node-state-style with the dev-examples version by @etrepum in https://github.com/facebook/lexical/pull/8647
* [lexical][lexical-history][lexical-rich-text][lexical-plain-text] Feature: Snapshot history before cut/paste operations by @etrepum in https://github.com/facebook/lexical/pull/8649
* [lexical] Feature: add an onWarn editor hook and route the update-recursion guard through it by @potatowagon in https://github.com/facebook/lexical/pull/8644
* [lexical-playground] Bug Fix: Fix the importmap of the /esm/ proof of concept by @etrepum in https://github.com/facebook/lexical/pull/8655
* [lexical-yjs] Bug Fix: keep collab cursor at element end when decoding an out-of-range position by @ivanscm in https://github.com/facebook/lexical/pull/8652
* [lexical][lexical-react] Bug Fix: actually route the update-recursion guard through editor._onWarn end-to-end (follow-up to #8644) by @potatowagon in https://github.com/facebook/lexical/pull/8658
* [lexical][lexical-yjs] Bug Fix: avoid empty-paragraph echo and splice crash on collab undo (#6614) and don't preserve tags on non-dirty update by @ivanscm in https://github.com/facebook/lexical/pull/8651
* [lexical-yjs] Bug Fix: Yjs desynchronizes after clearing all nodes by @sahiee-dev in https://github.com/facebook/lexical/pull/8646
* [Breaking Change][lexical][*] Chore: deprecate unsafe type parameters on node traversal methods by @etrepum in https://github.com/facebook/lexical/pull/8661
* [Breaking Changes][*] Refactor: Register DOMImportExtension rules implicitly via node extensions and make tree-shaking annotations effective by @etrepum in https://github.com/facebook/lexical/pull/8662
* [lexical][*] Chore: stop using deprecated traversal type parameters in tests by @etrepum in https://github.com/facebook/lexical/pull/8667
* [lexical] Bug Fix: stop infinite-update-loop detector over-firing on bounded activity (fast typing) by @potatowagon in https://github.com/facebook/lexical/pull/8635
* [lexical-dragon] Bug Fix: Handle makeChanges messages and the listener registration race by @brunoprietog in https://github.com/facebook/lexical/pull/8665
* [lexical][lexical-utils][lexical-extension][lexical-playground] Feature: SelectBlockExtension by @levensta in https://github.com/facebook/lexical/pull/8532
* [ci] Bug Fix: Fix intermittent EACCES in Windows CI browser tests by pinning Vitest browser port by @etrepum in https://github.com/facebook/lexical/pull/8673
* [lexical-table] Bug Fix: don't throw on stale table node keys in $handleTableSelectionChangeCommand by @etrepum in https://github.com/facebook/lexical/pull/8674
* [*] Chore: always use T[] syntax instead of Array<T> in TypeScript and Flow by @etrepum in https://github.com/facebook/lexical/pull/8675
* [lexical] Bug Fix: Emit COMPOSITION_END_TAG from the Firefox onInput defer branch by @mayrang in https://github.com/facebook/lexical/pull/8680
* [lexical-markdown] Bug Fix: Update ordered list start when typing a marker before it by @mayrang in https://github.com/facebook/lexical/pull/8678
* [lexical-list] Bug Fix: Preserve previous DecoratorNode on Backspace at the start of a top-level list by @mayrang in https://github.com/facebook/lexical/pull/8676
* [lexical-playground] Bug Fix: clear block alignment and indent with a collapsed selection but not a partial one by @achaljhawar in https://github.com/facebook/lexical/pull/8666
* [lexical-react] Refactor: Use hook syntax in .js.flow files to better declare intent by @SamChou19815 in https://github.com/facebook/lexical/pull/8682
* [lexical-rich-text][lexical-plain-text] Spec hardening: call event.preventDefault() in dragover for HTML5 DnD compliance by @sahiee-dev in https://github.com/facebook/lexical/pull/8663
* [lexical-utils][lexical-playground] Bug Fix: Double paragraph creation when exiting a nested code block by @levensta in https://github.com/facebook/lexical/pull/8684
* [lexical-markdown] Bug Fix: code spans should bind tighter than text-match transformers by @etrepum in https://github.com/facebook/lexical/pull/8688
* [lexical] Bug Fix: Reuse the empty trailing block when typing at root + last-offset selection by @mayrang in https://github.com/facebook/lexical/pull/8686
* [lexical] Chore: Remove unused tmp dependency by @noritaka1166 in https://github.com/facebook/lexical/pull/8693
* [Breaking Change][lexical] Fix: Preserve the first linebreak when passing inline nodes to insertNodes and add data-lexical-managed-linebreak attribute to managed linebreaks by @levensta in https://github.com/facebook/lexical/pull/8615
* [lexical-playground] Bug Fix: CodeBlock layout-exit e2e expected HTML by @mayrang in https://github.com/facebook/lexical/pull/8695
* [lexical] Feature: Replace LexicalEditor.readPending with editor.read(mode, fn) overload by @etrepum in https://github.com/facebook/lexical/pull/8702
* [lexical] Bug Fix: Recheck text node contents on deletion with composition by @ewsbr in https://github.com/facebook/lexical/pull/8701
* [lexical-playground] Bug Fix: Preserve block equation markdown by @vivekjm in https://github.com/facebook/lexical/pull/8562
* [Breaking Changes][lexical][lexical-yjs][lexical-clipboard][lexical-html][lexical-playground] Feature: Named slots by @mayrang in https://github.com/facebook/lexical/pull/8603
* [lexical-clipboard] Bug Fix: Correct type-checking by @levensta in https://github.com/facebook/lexical/pull/8706
* [Breaking Changes][lexical-link][lexical-list][lexical-react] Chore: Remove a subset of v0.32.1-deprecated exports by @etrepum in https://github.com/facebook/lexical/pull/8704
* [lexical-link] Bug Fix: Preserve LinkNode wrap on copy in Firefox/Safari by @mayrang in https://github.com/facebook/lexical/pull/8705
* [lexical] Bug Fix: Insert nodes at the block cursor inside a shadow root by @etrepum in https://github.com/facebook/lexical/pull/8708
* [lexical-react][lexical-link][lexical-history][lexical-extension] Docs: API doc coverage of react exports by @etrepum in https://github.com/facebook/lexical/pull/8714
* [lexical-react][lexical-playground] Refactor: Replace react-error-boundary with a self-contained LexicalErrorBoundary by @etrepum in https://github.com/facebook/lexical/pull/8720
* [*] Refactor: Migrate editor.getEditorState().read(...) to editor.read('latest', ...) by @etrepum in https://github.com/facebook/lexical/pull/8703
* [lexical-playground] Bug Fix: Render PageBreakNode as <hr> so Safari fires beforeinput after paste by @mayrang in https://github.com/facebook/lexical/pull/8719
* [lexical-mark] Chore: Widen MarkNode method return types to boolean by @patrick-atticus in https://github.com/facebook/lexical/pull/8717
* [lexical][lexical-rich-text][lexical-clipboard] Bug Fix: Named-slot typing / Backspace / Copy / hydrate paths by @mayrang in https://github.com/facebook/lexical/pull/8716
* [lexical-markdown] Bug Fix: Inline code spans containing backticks by @baptistejamin in https://github.com/facebook/lexical/pull/8723
* [lexical-plain-text][lexical-rich-text] Bug Fix: Refresh iOS keyboard suggestion bar after Backspace for all locales by @levensta in https://github.com/facebook/lexical/pull/8725
* fix(lexical): guard klass.prototype null check in getStaticNodeConfig by @potatowagon in https://github.com/facebook/lexical/pull/8726
* [lexical-markdown] Bug Fix: Preserve inline formatting when wrapping already-formatted text with matching markers by @koki-develop in https://github.com/facebook/lexical/pull/8728
* [lexical-utils] Add dedupeSelectionRects: fix duplicate/extra selection rects on WebKit (#7106, #7492) by @pro-vi in https://github.com/facebook/lexical/pull/8709
* [lexical] Bug Fix: Normalize non-inline nodes when inserting into inline-only parents by @etrepum in https://github.com/facebook/lexical/pull/8715
* [lexical] Feature: Support DOM shadow roots via platform selection APIs by @mayrang in https://github.com/facebook/lexical/pull/8694
* [lexical-utils][lexical-react] Chore: Move getScrollParent to @lexical/utils by @mayrang in https://github.com/facebook/lexical/pull/8733
* [lexical] Refactor: Improve error messages for invalid node classes and cache getStaticNodeConfig by @etrepum in https://github.com/facebook/lexical/pull/8735
* [lexical] Bug Fix: Refactor class inheritance loops to use an inheritsLoose-safe helper by @etrepum in https://github.com/facebook/lexical/pull/8739
* [lexical] Modernize Flow type-stub syntax rejected by fb-www flow strict by @potatowagon in https://github.com/facebook/lexical/pull/8742
* [lexical] Bug Fix: Ignore beforeinput and input events in captured decorators by @etrepum in https://github.com/facebook/lexical/pull/8740
* [ci] Bug Fix: grant id-token: write in version.yml release call by @etrepum in https://github.com/facebook/lexical/pull/8747

## New Contributors
* @meaqua9420 made their first contribution in https://github.com/facebook/lexical/pull/8600
* @sahiee-dev made their first contribution in https://github.com/facebook/lexical/pull/8611
* @xiezhenjia-meta made their first contribution in https://github.com/facebook/lexical/pull/8632
* @freddymeta made their first contribution in https://github.com/facebook/lexical/pull/8566
* @hamza512b made their first contribution in https://github.com/facebook/lexical/pull/8550
* @ivanscm made their first contribution in https://github.com/facebook/lexical/pull/8652
* @brunoprietog made their first contribution in https://github.com/facebook/lexical/pull/8665
* @ewsbr made their first contribution in https://github.com/facebook/lexical/pull/8701
* @vivekjm made their first contribution in https://github.com/facebook/lexical/pull/8562
* @koki-develop made their first contribution in https://github.com/facebook/lexical/pull/8728

**Full Changelog**: https://github.com/facebook/lexical/compare/v0.45.0...v0.46.0