v0.46.0

Expensify/Appv0.46.0Jun 26, 2026by etrepum

AI Summary

Lexical v0.46.0 introduces Named slots and Shadow DOM support. This release includes several breaking changes to node traversal methods, DOM import rules, and deprecated exports.

Key Highlights

  • Introduce Named slots and Shadow DOM support
  • Breaking change: Node traversal methods no longer accept unsafe type parameters
  • Breaking change: DOMImportExtension rules register implicitly
  • DOM shadow root support for editors
  • Add editor.read(mode, fn) API

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
  • Removed exports deprecated since v0.32.1

New Features

  • Named slots for isolated editable regions
  • Shadow DOM support for editors
  • Add editor.read(mode, fn) and EditorReadMode
  • Add onWarn editor hook
  • Support split-origin attachment previews

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