From 1d07dc5a09e6eff28739ff70f31201303201481c Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Sun, 16 Mar 2025 14:02:43 -0700
Subject: [PATCH 01/10] WIP split nodes

---
 .../lexical-utils/flow/LexicalUtils.js.flow   |   7 +-
 ...xicalUtilsInsertNodeToNearestRoot.test.tsx |   6 +-
 packages/lexical-utils/src/index.ts           | 103 +++++++++++-------
 packages/lexical/flow/Lexical.js.flow         |   4 +-
 .../lexical/src/__tests__/utils/index.tsx     |  45 +++++++-
 packages/lexical/src/caret/LexicalCaret.ts    |   9 ++
 .../lexical/src/caret/LexicalCaretUtils.ts    |  95 +++++++++++++++-
 packages/lexical/src/index.ts                 |   3 +
 8 files changed, 224 insertions(+), 48 deletions(-)

diff --git a/packages/lexical-utils/flow/LexicalUtils.js.flow b/packages/lexical-utils/flow/LexicalUtils.js.flow
index 38f2c3107d9..512d10c0847 100644
--- a/packages/lexical-utils/flow/LexicalUtils.js.flow
+++ b/packages/lexical-utils/flow/LexicalUtils.js.flow
@@ -102,7 +102,12 @@ declare export function $restoreEditorState(
   editorState: EditorState,
 ): void;
 
-declare export function $insertNodeToNearestRoot<T: LexicalNode>(node: T): T;
+
+export interface InsertNodeToNearestRootOptions {
+  skipEmptyParagraph?: boolean;
+  preventEmptyElements?: boolean;
+}
+declare export function $insertNodeToNearestRoot<T: LexicalNode>(node: T, options?: InsertNodeToNearestRootOptions): T;
 
 declare export function $wrapNodeInElement(
   node: LexicalNode,
diff --git a/packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx b/packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx
index 51902c01532..3fbf8204de4 100644
--- a/packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx
+++ b/packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx
@@ -86,7 +86,7 @@ describe('LexicalUtils#insertNodeToNearestRoot', () => {
         '<test-decorator></test-decorator>' +
         '<p><br></p>',
       initialHtml: '<p>Hello world</p>',
-      selectionOffset: 12, // Selection on text node after "Hello" world
+      selectionOffset: 'Hello world'.length, // Selection on text node after "Hello" world
       selectionPath: [0, 0],
     },
     {
@@ -96,7 +96,7 @@ describe('LexicalUtils#insertNodeToNearestRoot', () => {
         '<test-decorator></test-decorator>' +
         '<p><span style="white-space: pre-wrap;">Hello world</span></p>',
       initialHtml: '<p>Hello world</p>',
-      selectionOffset: 0, // Selection on text node after "Hello" world
+      selectionOffset: 0, // Selection on text node before "Hello" world
       selectionPath: [0, 0],
     },
     {
@@ -175,7 +175,7 @@ describe('LexicalUtils#insertNodeToNearestRoot', () => {
         );
         $setSelection(selection);
 
-        $insertNodeToNearestRoot($createTestDecoratorNode());
+        $insertNodeToNearestRoot($createTestDecoratorNode().setIsInline(false));
 
         // Cleaning up list value attributes as it's not really needed in this test
         // and it clutters expected output
diff --git a/packages/lexical-utils/src/index.ts b/packages/lexical-utils/src/index.ts
index e7f994829bd..4710d632ee2 100644
--- a/packages/lexical-utils/src/index.ts
+++ b/packages/lexical-utils/src/index.ts
@@ -7,12 +7,14 @@
  */
 
 import {
+  $caretFromPoint,
   $cloneWithProperties,
+  $copyNode,
   $createParagraphNode,
   $getAdjacentChildCaret,
   $getChildCaret,
-  $getChildCaretAtIndex,
   $getChildCaretOrSelf,
+  $getCollapsedCaretRange,
   $getPreviousSelection,
   $getRoot,
   $getSelection,
@@ -21,13 +23,13 @@ import {
   $isChildCaret,
   $isElementNode,
   $isRangeSelection,
-  $isRootOrShadowRoot,
   $isSiblingCaret,
-  $isTextNode,
+  $normalizeCaret,
   $rewindSiblingCaret,
   $setSelection,
+  $setSelectionFromCaretRange,
   $setState,
-  $splitNode,
+  $splitAtPointCaretNext,
   type CaretDirection,
   type EditorState,
   ElementNode,
@@ -37,8 +39,10 @@ import {
   makeStepwiseIterator,
   type NodeCaret,
   type NodeKey,
+  PointCaret,
   RootMode,
   type SiblingCaret,
+  SplitAtPointCaretNextOptions,
   StateConfig,
   ValueOrUpdater,
 } from 'lexical';
@@ -546,53 +550,76 @@ export function $restoreEditorState(
   $setSelection(selection === null ? null : selection.clone());
 }
 
+export interface InsertNodeToNearestRootOptions {
+  /** If true (default false), do not insert an empty paragraph before the inserted node at the root */
+  skipEmptyParagraph?: boolean;
+  /** If true (default false), do not split an ElementNode even if it can be empty */
+  preventEmptyElements?: boolean;
+}
+
 /**
  * If the selected insertion area is the root/shadow root node (see {@link lexical!$isRootOrShadowRoot}),
  * the node will be appended there, otherwise, it will be inserted before the insertion area.
  * If there is no selection where the node is to be inserted, it will be appended after any current nodes
- * within the tree, as a child of the root node. A paragraph node will then be added after the inserted node and selected.
+ * within the tree, as a child of the root node. A paragraph node will then be added after the inserted
+ * node and selected unless skipEmptyParagraph is true.
  * @param node - The node to be inserted
+ * @param options - see {@link InsertNodeToNearestRootOptions}
  * @returns The node after its insertion
  */
-export function $insertNodeToNearestRoot<T extends LexicalNode>(node: T): T {
+export function $insertNodeToNearestRoot<T extends LexicalNode>(
+  node: T,
+  {
+    skipEmptyParagraph = false,
+    preventEmptyElements = false,
+  }: InsertNodeToNearestRootOptions = {},
+): T {
   const selection = $getSelection() || $getPreviousSelection();
-
+  let initialCaret: undefined | PointCaret<'next'>;
   if ($isRangeSelection(selection)) {
-    const {focus} = selection;
-    const focusNode = focus.getNode();
-    const focusOffset = focus.offset;
-
-    if ($isRootOrShadowRoot(focusNode)) {
-      $getChildCaretAtIndex(focusNode, focusOffset, 'next').insert(node);
-      node.selectNext();
-    } else {
-      let splitNode: ElementNode;
-      let splitOffset: number;
-      if ($isTextNode(focusNode)) {
-        splitNode = focusNode.getParentOrThrow();
-        splitOffset = focusNode.getIndexWithinParent();
-        if (focusOffset > 0) {
-          splitOffset += 1;
-          focusNode.splitText(focusOffset);
-        }
-      } else {
-        splitNode = focusNode;
-        splitOffset = focusOffset;
-      }
-      const [, rightTree] = $splitNode(splitNode, splitOffset);
-      rightTree.insertBefore(node);
-      rightTree.selectStart();
-    }
+    initialCaret = $caretFromPoint(selection.focus, 'next');
   } else {
     if (selection != null) {
       const nodes = selection.getNodes();
-      nodes[nodes.length - 1].getTopLevelElementOrThrow().insertAfter(node);
-    } else {
-      $getRoot().append(node);
+      const lastNode = nodes[nodes.length - 1];
+      if (lastNode) {
+        initialCaret = $getSiblingCaret(lastNode, 'next');
+      }
     }
-    const paragraphNode = $createParagraphNode();
-    node.insertAfter(paragraphNode);
-    paragraphNode.select();
+  }
+  const splitOptions: SplitAtPointCaretNextOptions = {
+    $copyElementNode: $copyNode,
+    allowEmptyLeftSplit: !preventEmptyElements,
+    allowEmptyRightSplit: !preventEmptyElements,
+    rootMode: 'shadowRoot',
+  };
+  let insertCaret =
+    initialCaret || $getChildCaret($getRoot(), 'previous').getFlipped();
+  for (
+    let nextCaret: null | PointCaret<'next'> = insertCaret;
+    nextCaret;
+    nextCaret = $splitAtPointCaretNext(nextCaret, splitOptions)
+  ) {
+    insertCaret = nextCaret;
+  }
+  const emptyParagraphAfter = !(
+    skipEmptyParagraph ||
+    initialCaret ||
+    node.isInline()
+  )
+    ? $createParagraphNode()
+    : null;
+  if (emptyParagraphAfter) {
+    insertCaret.insert(emptyParagraphAfter);
+    emptyParagraphAfter.select();
+  }
+  insertCaret.insert(
+    node.isInline() ? $createParagraphNode().append(node) : node,
+  );
+  if (!emptyParagraphAfter) {
+    $setSelectionFromCaretRange(
+      $getCollapsedCaretRange($normalizeCaret($getSiblingCaret(node, 'next'))),
+    );
   }
   return node.getLatest();
 }
diff --git a/packages/lexical/flow/Lexical.js.flow b/packages/lexical/flow/Lexical.js.flow
index 4078d8802d8..e988981c883 100644
--- a/packages/lexical/flow/Lexical.js.flow
+++ b/packages/lexical/flow/Lexical.js.flow
@@ -1227,7 +1227,9 @@ declare export function $getCommonAncestor<
 declare export function $extendCaretToRange<D: CaretDirection>(
   anchor: PointCaret<D>,
 ): CaretRange<D>;
-
+declare export function $getCollapsedCaretRange<D: CaretDirection>(
+  anchor: PointCaret<D>,
+): CaretRange<D>;
 declare export function $isExtendableTextPointCaret<D: CaretDirection>(
   caret: PointCaret<D>
 ): implies caret is TextPointCaret<TextNode, D>;
diff --git a/packages/lexical/src/__tests__/utils/index.tsx b/packages/lexical/src/__tests__/utils/index.tsx
index 8206d550579..3eeecec272d 100644
--- a/packages/lexical/src/__tests__/utils/index.tsx
+++ b/packages/lexical/src/__tests__/utils/index.tsx
@@ -36,10 +36,12 @@ import {
   Klass,
   LexicalEditor,
   LexicalNode,
+  LexicalUpdateJSON,
   RangeSelection,
   SerializedElementNode,
   SerializedLexicalNode,
   SerializedTextNode,
+  Spread,
   TextNode,
 } from 'lexical';
 import path from 'path';
@@ -335,9 +337,13 @@ export function $createTestExcludeFromCopyElementNode(): TestExcludeFromCopyElem
   return new TestExcludeFromCopyElementNode();
 }
 
-export type SerializedTestDecoratorNode = SerializedLexicalNode;
+export type SerializedTestDecoratorNode = Spread<
+  SerializedLexicalNode,
+  {block?: boolean}
+>;
 
 export class TestDecoratorNode extends DecoratorNode<JSX.Element> {
+  __block: boolean = false;
   static getType(): string {
     return 'test_decorator';
   }
@@ -362,6 +368,37 @@ export class TestDecoratorNode extends DecoratorNode<JSX.Element> {
     };
   }
 
+  updateFromJSON(
+    serializedNode: LexicalUpdateJSON<SerializedTestDecoratorNode>,
+  ): this {
+    return super
+      .updateFromJSON(serializedNode)
+      .setIsInline(!serializedNode.block);
+  }
+
+  afterCloneFrom(prevNode: this): void {
+    super.afterCloneFrom(prevNode);
+    this.__block = prevNode.__block;
+  }
+
+  isInline(): boolean {
+    return !this.getLatest().__block;
+  }
+
+  setIsInline(inline: boolean): this {
+    const self = this.getWritable();
+    self.__block = !inline;
+    return self;
+  }
+
+  exportJSON(): SerializedTestDecoratorNode {
+    const json: SerializedTestDecoratorNode = super.exportJSON();
+    if (this.__block) {
+      json.block = this.__block;
+    }
+    return json;
+  }
+
   exportDOM() {
     return {
       element: document.createElement('test-decorator'),
@@ -373,11 +410,11 @@ export class TestDecoratorNode extends DecoratorNode<JSX.Element> {
   }
 
   createDOM() {
-    return document.createElement('span');
+    return document.createElement(this.__block ? 'div' : 'span');
   }
 
-  updateDOM() {
-    return false;
+  updateDOM(prevNode: this) {
+    return this.__block !== prevNode.__block;
   }
 
   decorate() {
diff --git a/packages/lexical/src/caret/LexicalCaret.ts b/packages/lexical/src/caret/LexicalCaret.ts
index b86fd87f281..c1af5986087 100644
--- a/packages/lexical/src/caret/LexicalCaret.ts
+++ b/packages/lexical/src/caret/LexicalCaret.ts
@@ -1121,6 +1121,15 @@ export function $extendCaretToRange<D extends CaretDirection>(
   return $getCaretRange(anchor, $getSiblingCaret($getRoot(), anchor.direction));
 }
 
+/**
+ * Construct a collapsed CaretRange that starts and ends at anchor.
+ */
+export function $getCollapsedCaretRange<D extends CaretDirection>(
+  anchor: PointCaret<D>,
+): CaretRange<D> {
+  return $getCaretRange(anchor, anchor);
+}
+
 /**
  * Construct a CaretRange from anchor and focus carets pointing in the
  * same direction. In order to get the expected behavior,
diff --git a/packages/lexical/src/caret/LexicalCaretUtils.ts b/packages/lexical/src/caret/LexicalCaretUtils.ts
index b509464af97..830b3e09f37 100644
--- a/packages/lexical/src/caret/LexicalCaretUtils.ts
+++ b/packages/lexical/src/caret/LexicalCaretUtils.ts
@@ -43,6 +43,7 @@ import {
   $getAdjacentChildCaret,
   $getCaretRange,
   $getChildCaret,
+  $getCollapsedCaretRange,
   $getSiblingCaret,
   $getTextNodeOffset,
   $getTextPointCaret,
@@ -357,7 +358,7 @@ export function $removeTextFromCaretRange<D extends CaretDirection>(
       $normalizeCaret(bestCandidate),
       initialRange.direction,
     );
-    return $getCaretRange(anchor, anchor);
+    return $getCollapsedCaretRange(anchor);
   }
   invariant(
     false,
@@ -610,3 +611,95 @@ export function $getAdjacentSiblingOrParentSiblingCaret<
   }
   return nextCaret && [nextCaret, depthDiff];
 }
+
+/**
+ * Get the adjacent nodes to initialCaret in the given direction.
+ *
+ * @example
+ * ```ts
+ * expect($getAdjacentNodes($getChildCaret(parent, 'next'))).toEqual(parent.getChildren());
+ * expect($getAdjacentNodes($getChildCaret(parent, 'previous'))).toEqual(parent.getChildren().reverse());
+ * expect($getAdjacentNodes($getSiblingCaret(node, 'next'))).toEqual(node.getNextSiblings());
+ * expect($getAdjacentNodes($getSiblingCaret(node, 'previous'))).toEqual(node.getPreviousSiblings().reverse());
+ * ```
+ *
+ * @param initialCaret The caret to start at (the origin will not be included)
+ * @returns An array of siblings.
+ */
+export function $getAdjacentNodes(
+  initialCaret: NodeCaret<CaretDirection>,
+): LexicalNode[] {
+  const siblings = [];
+  for (
+    let caret = initialCaret.getAdjacentCaret();
+    caret;
+    caret = caret.getAdjacentCaret()
+  ) {
+    siblings.push(caret.origin);
+  }
+  return siblings;
+}
+
+export interface SplitAtPointCaretNextOptions {
+  /** The function to create the right side of a split ElementNode */
+  $copyElementNode: (node: ElementNode) => ElementNode;
+  /** If the parent matches rootMode a split will not occur, default is 'shadowRoot' */
+  rootMode?: RootMode;
+  /** If true (default false), the parent may be split before its first child when parent.canBeEmpty() is true */
+  allowEmptyLeftSplit?: boolean;
+  /** If true (default false), the parent may be split after its last child when parent.canBeEmpty() is true */
+  allowEmptyRightSplit?: boolean;
+}
+
+/**
+ * Split a node at a PointCaret and return a NodeCaret at that point, or null if the
+ * node can't be split. This is non-recursive and will only perform at most one split.
+ *
+ * @returns The NodeCaret pointing to the location of the split (or null if a split is not possible)
+ */
+export function $splitAtPointCaretNext(
+  pointCaret: PointCaret<'next'>,
+  {
+    $copyElementNode,
+    rootMode = 'shadowRoot',
+    allowEmptyLeftSplit = false,
+    allowEmptyRightSplit = false,
+  }: SplitAtPointCaretNextOptions,
+): null | NodeCaret<'next'> {
+  if ($isTextPointCaret(pointCaret)) {
+    if (
+      pointCaret.offset === $getTextNodeOffset(pointCaret.origin, 'previous')
+    ) {
+      return $rewindSiblingCaret(pointCaret.getSiblingCaret());
+    }
+    const origin = $isExtendableTextPointCaret(pointCaret)
+      ? pointCaret.origin.splitText(pointCaret.offset)[0]
+      : pointCaret.origin;
+    invariant(
+      $isTextNode(origin),
+      '$splitTextAtPointCaretNext: splitText must return at least one TextNode',
+    );
+    return $getSiblingCaret(origin, 'next');
+  }
+  const parentCaret = pointCaret.getParentCaret(rootMode);
+  if (parentCaret) {
+    if (
+      $isChildCaret(pointCaret) &&
+      !(allowEmptyLeftSplit && parentCaret.origin.canBeEmpty())
+    ) {
+      // No split necessary, the left side would be empty
+      return $rewindSiblingCaret(parentCaret);
+    }
+    const siblings = $getAdjacentNodes(pointCaret);
+    if (
+      siblings.length > 0 ||
+      (allowEmptyRightSplit && parentCaret.origin.canBeEmpty())
+    ) {
+      // Split and insert the siblings into the new tree
+      parentCaret.insert(
+        $copyElementNode(parentCaret.origin).splice(0, 0, siblings),
+      );
+    }
+  }
+  return parentCaret;
+}
diff --git a/packages/lexical/src/index.ts b/packages/lexical/src/index.ts
index 4b15162d8b6..f26e603a6df 100644
--- a/packages/lexical/src/index.ts
+++ b/packages/lexical/src/index.ts
@@ -34,6 +34,7 @@ export {
   $getCaretRange,
   $getChildCaret,
   $getChildCaretOrSelf,
+  $getCollapsedCaretRange,
   $getCommonAncestor,
   $getCommonAncestorResultBranchOrder,
   $getSiblingCaret,
@@ -61,7 +62,9 @@ export {
   $rewindSiblingCaret,
   $setPointFromCaret,
   $setSelectionFromCaretRange,
+  $splitAtPointCaretNext,
   $updateRangeSelectionFromCaretRange,
+  type SplitAtPointCaretNextOptions,
 } from './caret/LexicalCaretUtils';
 export type {PasteCommandType} from './LexicalCommands';
 export {

From 9dac15d3ad47a0ec38b41da71c87b44bac8b79f2 Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 00:14:26 -0700
Subject: [PATCH 02/10] $insertNodeToNearestRootAtCaret

---
 .../__tests__/e2e/HorizontalRule.spec.mjs     |  2 +
 .../lexical-utils/flow/LexicalUtils.js.flow   |  9 +-
 packages/lexical-utils/src/index.ts           | 88 +++++++++----------
 packages/lexical/flow/Lexical.js.flow         | 13 +++
 .../lexical/src/caret/LexicalCaretUtils.ts    | 71 +++++++++------
 5 files changed, 106 insertions(+), 77 deletions(-)

diff --git a/packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs b/packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs
index fbcc79eb489..545d5575bd3 100644
--- a/packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs
@@ -245,6 +245,7 @@ test.describe('HorizontalRule', () => {
       focusPath: [0, 0, 0],
     });
 
+    await page.pause();
     await selectFromInsertDropdown(page, '.horizontal-rule');
 
     await waitForSelector(page, 'hr');
@@ -269,6 +270,7 @@ test.describe('HorizontalRule', () => {
       `,
     );
 
+    await page.pause();
     await assertSelection(page, {
       anchorOffset: 0,
       anchorPath: [2, 0, 0],
diff --git a/packages/lexical-utils/flow/LexicalUtils.js.flow b/packages/lexical-utils/flow/LexicalUtils.js.flow
index 512d10c0847..79bd89ec897 100644
--- a/packages/lexical-utils/flow/LexicalUtils.js.flow
+++ b/packages/lexical-utils/flow/LexicalUtils.js.flow
@@ -15,6 +15,8 @@ import type {
   CaretDirection,
   SiblingCaret,
   RootMode,
+  SplitAtPointCaretNextOptions,
+  PointCaret,
 } from 'lexical';
 declare export function addClassNamesToElement(
   element: HTMLElement,
@@ -103,11 +105,8 @@ declare export function $restoreEditorState(
 ): void;
 
 
-export interface InsertNodeToNearestRootOptions {
-  skipEmptyParagraph?: boolean;
-  preventEmptyElements?: boolean;
-}
-declare export function $insertNodeToNearestRoot<T: LexicalNode>(node: T, options?: InsertNodeToNearestRootOptions): T;
+declare export function $insertNodeToNearestRoot<T: LexicalNode>(node: T): T;
+declare export function $insertNodeToNearestRootAtCaret<T: LexicalNode>(node: T, caret: PointCaret<CaretDirection>, options?: SplitAtPointCaretNextOptions): T;
 
 declare export function $wrapNodeInElement(
   node: LexicalNode,
diff --git a/packages/lexical-utils/src/index.ts b/packages/lexical-utils/src/index.ts
index 4710d632ee2..4426cec0295 100644
--- a/packages/lexical-utils/src/index.ts
+++ b/packages/lexical-utils/src/index.ts
@@ -9,9 +9,9 @@
 import {
   $caretFromPoint,
   $cloneWithProperties,
-  $copyNode,
   $createParagraphNode,
   $getAdjacentChildCaret,
+  $getCaretInDirection,
   $getChildCaret,
   $getChildCaretOrSelf,
   $getCollapsedCaretRange,
@@ -24,6 +24,7 @@ import {
   $isElementNode,
   $isRangeSelection,
   $isSiblingCaret,
+  $isTextPointCaret,
   $normalizeCaret,
   $rewindSiblingCaret,
   $setSelection,
@@ -550,30 +551,15 @@ export function $restoreEditorState(
   $setSelection(selection === null ? null : selection.clone());
 }
 
-export interface InsertNodeToNearestRootOptions {
-  /** If true (default false), do not insert an empty paragraph before the inserted node at the root */
-  skipEmptyParagraph?: boolean;
-  /** If true (default false), do not split an ElementNode even if it can be empty */
-  preventEmptyElements?: boolean;
-}
-
 /**
  * If the selected insertion area is the root/shadow root node (see {@link lexical!$isRootOrShadowRoot}),
  * the node will be appended there, otherwise, it will be inserted before the insertion area.
  * If there is no selection where the node is to be inserted, it will be appended after any current nodes
- * within the tree, as a child of the root node. A paragraph node will then be added after the inserted
- * node and selected unless skipEmptyParagraph is true.
+ * within the tree, as a child of the root node. A paragraph will then be added after the inserted node and selected.
  * @param node - The node to be inserted
- * @param options - see {@link InsertNodeToNearestRootOptions}
  * @returns The node after its insertion
  */
-export function $insertNodeToNearestRoot<T extends LexicalNode>(
-  node: T,
-  {
-    skipEmptyParagraph = false,
-    preventEmptyElements = false,
-  }: InsertNodeToNearestRootOptions = {},
-): T {
+export function $insertNodeToNearestRoot<T extends LexicalNode>(node: T): T {
   const selection = $getSelection() || $getPreviousSelection();
   let initialCaret: undefined | PointCaret<'next'>;
   if ($isRangeSelection(selection)) {
@@ -586,42 +572,56 @@ export function $insertNodeToNearestRoot<T extends LexicalNode>(
         initialCaret = $getSiblingCaret(lastNode, 'next');
       }
     }
+    initialCaret =
+      initialCaret ||
+      $getChildCaret($getRoot(), 'previous')
+        .getFlipped()
+        .insert($createParagraphNode());
   }
-  const splitOptions: SplitAtPointCaretNextOptions = {
-    $copyElementNode: $copyNode,
-    allowEmptyLeftSplit: !preventEmptyElements,
-    allowEmptyRightSplit: !preventEmptyElements,
-    rootMode: 'shadowRoot',
-  };
-  let insertCaret =
-    initialCaret || $getChildCaret($getRoot(), 'previous').getFlipped();
+  const insertCaret = $insertNodeToNearestRootAtCaret(node, initialCaret);
+  const adjacent = $getAdjacentChildCaret(insertCaret);
+  const selectionCaret = $isChildCaret(adjacent)
+    ? $normalizeCaret(adjacent)
+    : insertCaret;
+  $setSelectionFromCaretRange($getCollapsedCaretRange(selectionCaret));
+  return node.getLatest();
+}
+
+/**
+ * If the insertion caret is the root/shadow root node (see {@link lexical!$isRootOrShadowRoot}),
+ * the node will be inserted there, otherwise the parent nodes will be split according to the
+ * given options.
+ * @param node - The node to be inserted
+ * @param caret - The location to insert or split from
+ * @returns The node after its insertion
+ */
+export function $insertNodeToNearestRootAtCaret<
+  T extends LexicalNode,
+  D extends CaretDirection,
+>(
+  node: T,
+  caret: PointCaret<D>,
+  options?: SplitAtPointCaretNextOptions,
+): NodeCaret<D> {
+  let insertCaret: PointCaret<'next'> = $getCaretInDirection(caret, 'next');
   for (
     let nextCaret: null | PointCaret<'next'> = insertCaret;
     nextCaret;
-    nextCaret = $splitAtPointCaretNext(nextCaret, splitOptions)
+    nextCaret = $splitAtPointCaretNext(nextCaret, options)
   ) {
     insertCaret = nextCaret;
   }
-  const emptyParagraphAfter = !(
-    skipEmptyParagraph ||
-    initialCaret ||
-    node.isInline()
-  )
-    ? $createParagraphNode()
-    : null;
-  if (emptyParagraphAfter) {
-    insertCaret.insert(emptyParagraphAfter);
-    emptyParagraphAfter.select();
-  }
+  invariant(
+    !$isTextPointCaret(insertCaret),
+    '$insertNodeToNearestRootAtCaret: An unattached TextNode can not be split',
+  );
   insertCaret.insert(
     node.isInline() ? $createParagraphNode().append(node) : node,
   );
-  if (!emptyParagraphAfter) {
-    $setSelectionFromCaretRange(
-      $getCollapsedCaretRange($normalizeCaret($getSiblingCaret(node, 'next'))),
-    );
-  }
-  return node.getLatest();
+  return $getCaretInDirection(
+    $getSiblingCaret(node.getLatest(), 'next'),
+    caret.direction,
+  );
 }
 
 /**
diff --git a/packages/lexical/flow/Lexical.js.flow b/packages/lexical/flow/Lexical.js.flow
index e988981c883..73e57102482 100644
--- a/packages/lexical/flow/Lexical.js.flow
+++ b/packages/lexical/flow/Lexical.js.flow
@@ -1233,3 +1233,16 @@ declare export function $getCollapsedCaretRange<D: CaretDirection>(
 declare export function $isExtendableTextPointCaret<D: CaretDirection>(
   caret: PointCaret<D>
 ): implies caret is TextPointCaret<TextNode, D>;
+
+export interface SplitAtPointCaretNextOptions {
+  $copyElementNode?: (node: ElementNode) => ElementNode;
+  $splitTextPointCaretNext?: (
+    caret: TextPointCaret<TextNode, 'next'>,
+  ) => NodeCaret<'next'>;
+  rootMode?: RootMode;
+  $shouldSplit?: (node: ElementNode, edge: 'first' | 'last') => boolean;
+}
+declare export function $splitAtPointCaretNext(
+  pointCaret: PointCaret<'next'>,
+  options?: SplitAtPointCaretNextOptions,
+): null | NodeCaret<'next'>;
diff --git a/packages/lexical/src/caret/LexicalCaretUtils.ts b/packages/lexical/src/caret/LexicalCaretUtils.ts
index 830b3e09f37..ac5668356db 100644
--- a/packages/lexical/src/caret/LexicalCaretUtils.ts
+++ b/packages/lexical/src/caret/LexicalCaretUtils.ts
@@ -27,6 +27,7 @@ import {
   type RangeSelection,
 } from '../LexicalSelection';
 import {
+  $copyNode,
   $getNodeByKeyOrThrow,
   $isRootOrShadowRoot,
   $setSelection,
@@ -640,15 +641,42 @@ export function $getAdjacentNodes(
   return siblings;
 }
 
+export function $splitTextPointCaret<D extends CaretDirection>(
+  textPointCaret: TextPointCaret<TextNode, D>,
+): NodeCaret<D> {
+  const {origin, offset, direction} = textPointCaret;
+  if (offset === $getTextNodeOffset(origin, direction)) {
+    return textPointCaret.getSiblingCaret();
+  } else if (offset === $getTextNodeOffset(origin, flipDirection(direction))) {
+    return $rewindSiblingCaret(textPointCaret.getSiblingCaret());
+  }
+  const [textNode] = origin.splitText(offset);
+  invariant(
+    $isTextNode(textNode),
+    '$splitTextPointCaret: splitText must return at least one TextNode',
+  );
+  return $getCaretInDirection($getSiblingCaret(textNode, 'next'), direction);
+}
+
 export interface SplitAtPointCaretNextOptions {
-  /** The function to create the right side of a split ElementNode */
-  $copyElementNode: (node: ElementNode) => ElementNode;
+  /** The function to create the right side of a split ElementNode (default {@link $copyNode}) */
+  $copyElementNode?: (node: ElementNode) => ElementNode;
+  /** The function to split a TextNode (default {@link $splitTextPointCaret}) */
+  $splitTextPointCaretNext?: (
+    caret: TextPointCaret<TextNode, 'next'>,
+  ) => NodeCaret<'next'>;
   /** If the parent matches rootMode a split will not occur, default is 'shadowRoot' */
   rootMode?: RootMode;
-  /** If true (default false), the parent may be split before its first child when parent.canBeEmpty() is true */
-  allowEmptyLeftSplit?: boolean;
-  /** If true (default false), the parent may be split after its last child when parent.canBeEmpty() is true */
-  allowEmptyRightSplit?: boolean;
+  /**
+   * If element.canBeEmpty() and would create an empty split, this function will be
+   * called with the element and 'first' | 'last'. If it returns false, the empty
+   * split will not be created. Default is `() => true` to always split when possible.
+   */
+  $shouldSplit?: (node: ElementNode, edge: 'first' | 'last') => boolean;
+}
+
+function $alwaysSplit(_node: ElementNode, _edge: 'first' | 'last'): true {
+  return true;
 }
 
 /**
@@ -660,32 +688,21 @@ export interface SplitAtPointCaretNextOptions {
 export function $splitAtPointCaretNext(
   pointCaret: PointCaret<'next'>,
   {
-    $copyElementNode,
+    $copyElementNode = $copyNode,
+    $splitTextPointCaretNext = $splitTextPointCaret,
     rootMode = 'shadowRoot',
-    allowEmptyLeftSplit = false,
-    allowEmptyRightSplit = false,
-  }: SplitAtPointCaretNextOptions,
+    $shouldSplit = $alwaysSplit,
+  }: SplitAtPointCaretNextOptions = {},
 ): null | NodeCaret<'next'> {
   if ($isTextPointCaret(pointCaret)) {
-    if (
-      pointCaret.offset === $getTextNodeOffset(pointCaret.origin, 'previous')
-    ) {
-      return $rewindSiblingCaret(pointCaret.getSiblingCaret());
-    }
-    const origin = $isExtendableTextPointCaret(pointCaret)
-      ? pointCaret.origin.splitText(pointCaret.offset)[0]
-      : pointCaret.origin;
-    invariant(
-      $isTextNode(origin),
-      '$splitTextAtPointCaretNext: splitText must return at least one TextNode',
-    );
-    return $getSiblingCaret(origin, 'next');
+    return $splitTextPointCaretNext(pointCaret);
   }
   const parentCaret = pointCaret.getParentCaret(rootMode);
   if (parentCaret) {
+    const {origin} = parentCaret;
     if (
       $isChildCaret(pointCaret) &&
-      !(allowEmptyLeftSplit && parentCaret.origin.canBeEmpty())
+      !(origin.canBeEmpty() && $shouldSplit(origin, 'first'))
     ) {
       // No split necessary, the left side would be empty
       return $rewindSiblingCaret(parentCaret);
@@ -693,12 +710,10 @@ export function $splitAtPointCaretNext(
     const siblings = $getAdjacentNodes(pointCaret);
     if (
       siblings.length > 0 ||
-      (allowEmptyRightSplit && parentCaret.origin.canBeEmpty())
+      (origin.canBeEmpty() && $shouldSplit(origin, 'last'))
     ) {
       // Split and insert the siblings into the new tree
-      parentCaret.insert(
-        $copyElementNode(parentCaret.origin).splice(0, 0, siblings),
-      );
+      parentCaret.insert($copyElementNode(origin).splice(0, 0, siblings));
     }
   }
   return parentCaret;

From edeb0d31710ebdf147f1649a00bbf8b9cfe83ef6 Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 09:33:41 -0700
Subject: [PATCH 03/10] e2e test

---
 .../__tests__/e2e/HorizontalRule.spec.mjs     | 146 +++++++++++++++++-
 1 file changed, 143 insertions(+), 3 deletions(-)

diff --git a/packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs b/packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs
index 545d5575bd3..070580d9cb0 100644
--- a/packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/HorizontalRule.spec.mjs
@@ -15,6 +15,7 @@ import {
 import {
   assertHTML,
   assertSelection,
+  click,
   copyToClipboard,
   focusEditor,
   html,
@@ -26,6 +27,11 @@ import {
   withExclusiveClipboardAccess,
 } from '../utils/index.mjs';
 
+async function toggleBulletList(page) {
+  await click(page, '.block-controls');
+  await click(page, '.dropdown .icon.bullet-list');
+}
+
 test.describe('HorizontalRule', () => {
   test.beforeEach(({isCollab, page}) => initialize({isCollab, page}));
   test(
@@ -209,7 +215,7 @@ test.describe('HorizontalRule', () => {
     });
   });
 
-  test('Will add a horizontal rule and split a TextNode across 2 paragraphs if the carat is in the middle of the TextNode, moving selection to the start of the new ParagraphNode.', async ({
+  test('Will add a horizontal rule and split a TextNode across 2 paragraphs if the caret is in the middle of the TextNode, moving selection to the start of the new ParagraphNode.', async ({
     page,
     isPlainText,
   }) => {
@@ -245,7 +251,6 @@ test.describe('HorizontalRule', () => {
       focusPath: [0, 0, 0],
     });
 
-    await page.pause();
     await selectFromInsertDropdown(page, '.horizontal-rule');
 
     await waitForSelector(page, 'hr');
@@ -270,7 +275,6 @@ test.describe('HorizontalRule', () => {
       `,
     );
 
-    await page.pause();
     await assertSelection(page, {
       anchorOffset: 0,
       anchorPath: [2, 0, 0],
@@ -279,6 +283,142 @@ test.describe('HorizontalRule', () => {
     });
   });
 
+  test('Will add a horizontal rule and split a TextNode across 2 ListItemNode if the caret is in the middle of the TextNode, moving selection to the start of the new ParagraphNode', async ({
+    page,
+    isPlainText,
+  }) => {
+    test.skip(isPlainText);
+    await focusEditor(page);
+    await toggleBulletList(page);
+
+    await page.keyboard.type('Test');
+
+    await assertSelection(page, {
+      anchorOffset: 4,
+      anchorPath: [0, 0, 0, 0],
+      focusOffset: 4,
+      focusPath: [0, 0, 0, 0],
+    });
+
+    await assertHTML(
+      page,
+      html`
+        <ul class="PlaygroundEditorTheme__ul">
+          <li
+            class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__ltr"
+            dir="ltr"
+            value="1">
+            <span data-lexical-text="true">Test</span>
+          </li>
+        </ul>
+      `,
+    );
+
+    await moveLeft(page, 2);
+
+    await assertSelection(page, {
+      anchorOffset: 2,
+      anchorPath: [0, 0, 0, 0],
+      focusOffset: 2,
+      focusPath: [0, 0, 0, 0],
+    });
+
+    await selectFromInsertDropdown(page, '.horizontal-rule');
+
+    await waitForSelector(page, 'hr');
+
+    await assertHTML(
+      page,
+      html`
+        <ul class="PlaygroundEditorTheme__ul">
+          <li
+            class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__ltr"
+            dir="ltr"
+            value="1">
+            <span data-lexical-text="true">Te</span>
+          </li>
+        </ul>
+        <hr
+          class="PlaygroundEditorTheme__hr"
+          contenteditable="false"
+          data-lexical-decorator="true" />
+        <ul class="PlaygroundEditorTheme__ul">
+          <li
+            class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__ltr"
+            dir="ltr"
+            value="1">
+            <span data-lexical-text="true">st</span>
+          </li>
+        </ul>
+      `,
+    );
+
+    await assertSelection(page, {
+      anchorOffset: 0,
+      anchorPath: [2, 0, 0, 0],
+      focusOffset: 0,
+      focusPath: [2, 0, 0, 0],
+    });
+  });
+
+  test('Will add a horizontal rule and split a TextNode across 2 ListItemNode if the caret is in an empty ListItemNode, moving selection to the start of the new ListItemNode (#6849)', async ({
+    page,
+    isPlainText,
+  }) => {
+    test.skip(isPlainText);
+    await focusEditor(page);
+    await toggleBulletList(page);
+
+    await assertSelection(page, {
+      anchorOffset: 0,
+      anchorPath: [0, 0],
+      focusOffset: 0,
+      focusPath: [0, 0],
+    });
+
+    await assertHTML(
+      page,
+      html`
+        <ul class="PlaygroundEditorTheme__ul">
+          <li class="PlaygroundEditorTheme__listItem" value="1">
+            <br />
+          </li>
+        </ul>
+      `,
+    );
+
+    await selectFromInsertDropdown(page, '.horizontal-rule');
+
+    await waitForSelector(page, 'hr');
+
+    await assertHTML(
+      page,
+      html`
+        <ul class="PlaygroundEditorTheme__ul">
+          <li class="PlaygroundEditorTheme__listItem" value="1">
+            <br />
+          </li>
+        </ul>
+        <hr
+          class="PlaygroundEditorTheme__hr"
+          contenteditable="false"
+          data-lexical-decorator="true" />
+        <ul class="PlaygroundEditorTheme__ul">
+          <li class="PlaygroundEditorTheme__listItem" value="1">
+            <br />
+          </li>
+        </ul>
+      `,
+    );
+
+    await assertSelection(page, {
+      anchorOffset: 0,
+      anchorPath: [2, 0],
+      focusOffset: 0,
+      focusPath: [2, 0],
+    });
+  });
+
   test('Can copy and paste a horizontal rule', async ({page, isPlainText}) => {
     test.skip(isPlainText);
 

From 3e60e64af629bf1ebff247eb8a53db3f77a326cb Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 09:39:16 -0700
Subject: [PATCH 04/10] trigger vercel re-deploy


From 5bea1a6e957ee00bfef2737fa6d0ddfc623edccc Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 09:53:52 -0700
Subject: [PATCH 05/10] unit tests for $splitAtPointCaretNext

---
 .../caret/__tests__/unit/LexicalCaret.test.ts | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts b/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
index 84e357baa1a..40886b1533c 100644
--- a/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
+++ b/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
@@ -31,6 +31,7 @@ import {
   $getSelection,
   $getSiblingCaret,
   $getTextPointCaret,
+  $isParagraphNode,
   $isSiblingCaret,
   $isTextNode,
   $isTextPointCaret,
@@ -41,6 +42,7 @@ import {
   $setPointFromCaret,
   $setSelection,
   $setSelectionFromCaretRange,
+  $splitAtPointCaretNext,
   ChildCaret,
   ElementNode,
   LexicalNode,
@@ -1947,3 +1949,65 @@ describe('LexicalSelectionHelpers', () => {
     });
   });
 });
+
+describe('$splitAtPointCaretNext', () => {
+  initializeUnitTest((testEnv) => {
+    test('Does not split a TextNode at the beginning', () => {
+      testEnv.editor.update(
+        () => {
+          const textNode = $createTextNode('test');
+          const paragraphNode = $createParagraphNode();
+          $getRoot().clear().append(paragraphNode.append(textNode));
+          const caret = $getTextPointCaret(textNode, 'next', 0);
+          const after = $splitAtPointCaretNext(caret);
+          expect(textNode.getTextContent()).toEqual('test');
+          expect(
+            $getChildCaret(paragraphNode, 'next').isSamePointCaret(after),
+          ).toBe(true);
+        },
+        {discrete: true},
+      );
+    });
+    test('Splits a TextNode in the middle', () => {
+      testEnv.editor.update(
+        () => {
+          const textNode = $createTextNode('test');
+          const paragraphNode = $createParagraphNode();
+          $getRoot().clear().append(paragraphNode.append(textNode));
+          const caret = $getTextPointCaret(textNode, 'next', 2);
+          const after = $splitAtPointCaretNext(caret);
+          expect(textNode.getTextContent()).toEqual('te');
+          const nextCaret = $getSiblingCaret(textNode, 'next');
+          expect(nextCaret.isSamePointCaret(after)).toBe(true);
+          const splitNode = nextCaret.getNodeAtCaret();
+          expect(
+            $isTextNode(splitNode) ? splitNode.getTextContent() : null,
+          ).toEqual('st');
+        },
+        {discrete: true},
+      );
+    });
+    test('Splits a ParagraphNode', () => {
+      testEnv.editor.update(
+        () => {
+          const beforeTextNode = $createTextNode('before');
+          const afterTextNode = $createTextNode('after');
+          const paragraphNode = $createParagraphNode();
+          $getRoot()
+            .clear()
+            .append(paragraphNode.append(beforeTextNode, afterTextNode));
+          const caret = $getSiblingCaret(beforeTextNode, 'next');
+          const after = $splitAtPointCaretNext(caret);
+          expect(paragraphNode.getAllTextNodes()).toEqual([beforeTextNode]);
+          const nextCaret = $getSiblingCaret(paragraphNode, 'next');
+          expect(nextCaret.isSamePointCaret(after)).toBe(true);
+          const splitNode = nextCaret.getNodeAtCaret();
+          expect(
+            $isParagraphNode(splitNode) ? splitNode.getAllTextNodes() : null,
+          ).toEqual([afterTextNode]);
+        },
+        {discrete: true},
+      );
+    });
+  });
+});

From f13380c9918c2950c1dcd0f7060b13c4229e8061 Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 11:43:54 -0700
Subject: [PATCH 06/10] update prettier

---
 .eslintignore                                 |   1 +
 .prettierignore                               |   1 +
 package-lock.json                             | 157 +++++++++---------
 package.json                                  |   8 +-
 .../__tests__/unit/rules-of-lexical.test.ts   |   4 +-
 packages/lexical-list/src/__tests__/utils.ts  |   4 +-
 .../__tests__/utils/index.mjs                 |   2 +-
 packages/lexical-playground/package.json      |   2 +-
 packages/lexical-website/package.json         |   2 +-
 .../lexical/src/__tests__/utils/index.tsx     |   6 +-
 .../unit/transform-error-messages.test.js     |  14 +-
 .../error-codes/transform-error-messages.js   |   6 +-
 12 files changed, 110 insertions(+), 97 deletions(-)

diff --git a/.eslintignore b/.eslintignore
index 568a2cf9313..5b987a70346 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -13,3 +13,4 @@
 **/.docusaurus
 /playwright-report
 test-results
+/libdefs/*.js
diff --git a/.prettierignore b/.prettierignore
index 580080b429f..0e75361aeac 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -23,3 +23,4 @@ flow-typed
 **/.docusaurus
 /playwright-report
 test-results
+/libdefs/*.js
diff --git a/package-lock.json b/package-lock.json
index 2593e2c90b8..80fc0981e68 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
         "packages/*"
       ],
       "dependencies": {
+        "@prettier/sync": "^0.5.2",
         "yjs": "^13.5.42"
       },
       "devDependencies": {
@@ -35,7 +36,6 @@
         "@types/jsdom": "^21.1.6",
         "@types/katex": "^0.16.7",
         "@types/node": "^17.0.31",
-        "@types/prettier": "^2.7.3",
         "@types/prismjs": "^1.26.0",
         "@types/proper-lockfile": "^4.1.4",
         "@types/react": "^18.0.8",
@@ -79,10 +79,10 @@
         "lint-staged": "^11.1.0",
         "minimist": "^1.2.5",
         "npm-run-all": "^4.1.5",
-        "prettier": "^2.3.2",
+        "prettier": "^3.5.3",
         "prettier-plugin-hermes-parser": "^0.26.0",
-        "prettier-plugin-organize-attributes": "^0.0.5",
-        "prettier-plugin-tailwindcss": "^0.4.1",
+        "prettier-plugin-organize-attributes": "^1.0.0",
+        "prettier-plugin-tailwindcss": "^0.6.11",
         "proper-lockfile": "^4.1.2",
         "react-test-renderer": "^17.0.2",
         "rollup": "^4.22.4",
@@ -7786,6 +7786,20 @@
         "url": "https://opencollective.com/popperjs"
       }
     },
+    "node_modules/@prettier/sync": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.5.2.tgz",
+      "integrity": "sha512-Yb569su456XNx5BsH/Vyem7xD6g/y9iLmLUzRKM1a/dhU/D7HqqvkAG72znulXlMXztbV0iiu9O5AL8K98TzZQ==",
+      "dependencies": {
+        "make-synchronized": "^0.2.8"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier-synchronized?sponsor=1"
+      },
+      "peerDependencies": {
+        "prettier": "*"
+      }
+    },
     "node_modules/@radix-ui/primitive": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
@@ -10058,12 +10072,6 @@
       "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
       "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw=="
     },
-    "node_modules/@types/prettier": {
-      "version": "2.7.3",
-      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz",
-      "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==",
-      "dev": true
-    },
     "node_modules/@types/prismjs": {
       "version": "1.26.0",
       "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz",
@@ -25692,6 +25700,14 @@
       "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
       "dev": true
     },
+    "node_modules/make-synchronized": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.2.9.tgz",
+      "integrity": "sha512-4wczOs8SLuEdpEvp3vGo83wh8rjJ78UsIk7DIX5fxdfmfMJGog4bQzxfvOwq7Q3yCHLC4jp1urPHIxRS/A93gA==",
+      "funding": {
+        "url": "https://github.com/fisker/make-synchronized?sponsor=1"
+      }
+    },
     "node_modules/makeerror": {
       "version": "1.0.12",
       "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
@@ -32021,15 +32037,14 @@
       }
     },
     "node_modules/prettier": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
-      "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
-      "dev": true,
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+      "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
       "bin": {
-        "prettier": "bin-prettier.js"
+        "prettier": "bin/prettier.cjs"
       },
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">=14"
       },
       "funding": {
         "url": "https://github.com/prettier/prettier?sponsor=1"
@@ -32050,42 +32065,43 @@
       }
     },
     "node_modules/prettier-plugin-organize-attributes": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-0.0.5.tgz",
-      "integrity": "sha512-dSts16q8wd+oq8Zwk5mwmYXo1aN3B+ZkEJqx/ar5fedNHdOvx7S4XDMH/pNK7rmBW0bPXkp/kJX5gAANsWzh3A==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-1.0.0.tgz",
+      "integrity": "sha512-+NmameaLxbCcylEXsKPmawtzla5EE6ECqvGkpfQz4KM847fXDifB1gFnPQEpoADAq6IXg+cMI8Z0ISJEXa6fhg==",
       "dev": true,
       "engines": {
-        "node": ">=11.0.0"
+        "node": ">=14.0.0"
       },
       "peerDependencies": {
-        "prettier": "^2.0.0"
+        "prettier": "^3.0.0"
       }
     },
     "node_modules/prettier-plugin-tailwindcss": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz",
-      "integrity": "sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==",
+      "version": "0.6.11",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.11.tgz",
+      "integrity": "sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==",
       "dev": true,
       "engines": {
-        "node": ">=12.17.0"
+        "node": ">=14.21.3"
       },
       "peerDependencies": {
         "@ianvs/prettier-plugin-sort-imports": "*",
         "@prettier/plugin-pug": "*",
         "@shopify/prettier-plugin-liquid": "*",
-        "@shufo/prettier-plugin-blade": "*",
         "@trivago/prettier-plugin-sort-imports": "*",
-        "prettier": "^2.2 || ^3.0",
+        "@zackad/prettier-plugin-twig": "*",
+        "prettier": "^3.0",
         "prettier-plugin-astro": "*",
         "prettier-plugin-css-order": "*",
         "prettier-plugin-import-sort": "*",
         "prettier-plugin-jsdoc": "*",
         "prettier-plugin-marko": "*",
+        "prettier-plugin-multiline-arrays": "*",
         "prettier-plugin-organize-attributes": "*",
         "prettier-plugin-organize-imports": "*",
+        "prettier-plugin-sort-imports": "*",
         "prettier-plugin-style-order": "*",
-        "prettier-plugin-svelte": "*",
-        "prettier-plugin-twig-melody": "*"
+        "prettier-plugin-svelte": "*"
       },
       "peerDependenciesMeta": {
         "@ianvs/prettier-plugin-sort-imports": {
@@ -32097,10 +32113,10 @@
         "@shopify/prettier-plugin-liquid": {
           "optional": true
         },
-        "@shufo/prettier-plugin-blade": {
+        "@trivago/prettier-plugin-sort-imports": {
           "optional": true
         },
-        "@trivago/prettier-plugin-sort-imports": {
+        "@zackad/prettier-plugin-twig": {
           "optional": true
         },
         "prettier-plugin-astro": {
@@ -32118,19 +32134,22 @@
         "prettier-plugin-marko": {
           "optional": true
         },
+        "prettier-plugin-multiline-arrays": {
+          "optional": true
+        },
         "prettier-plugin-organize-attributes": {
           "optional": true
         },
         "prettier-plugin-organize-imports": {
           "optional": true
         },
-        "prettier-plugin-style-order": {
+        "prettier-plugin-sort-imports": {
           "optional": true
         },
-        "prettier-plugin-svelte": {
+        "prettier-plugin-style-order": {
           "optional": true
         },
-        "prettier-plugin-twig-melody": {
+        "prettier-plugin-svelte": {
           "optional": true
         }
       }
@@ -40225,6 +40244,7 @@
       "version": "0.27.2",
       "license": "MIT",
       "dependencies": {
+        "@lexical/selection": "0.27.2",
         "@lexical/utils": "0.27.2",
         "lexical": "0.27.2"
       }
@@ -40300,7 +40320,7 @@
         "katex": "^0.16.10",
         "lexical": "0.27.2",
         "lodash-es": "^4.17.21",
-        "prettier": "^3.4.2",
+        "prettier": "^3.5.3",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-error-boundary": "^3.1.4",
@@ -40319,21 +40339,6 @@
         "vite-plugin-static-copy": "^2.1.0"
       }
     },
-    "packages/lexical-playground/node_modules/prettier": {
-      "version": "3.4.2",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
-      "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
-      "license": "MIT",
-      "bin": {
-        "prettier": "bin/prettier.cjs"
-      },
-      "engines": {
-        "node": ">=14"
-      },
-      "funding": {
-        "url": "https://github.com/prettier/prettier?sponsor=1"
-      }
-    },
     "packages/lexical-react": {
       "name": "@lexical/react",
       "version": "0.27.2",
@@ -40434,7 +40439,7 @@
       },
       "devDependencies": {
         "buffer": "^6.0.3",
-        "prettier-plugin-tailwindcss": "^0.4.1",
+        "prettier-plugin-tailwindcss": "^0.6.11",
         "tailwindcss": "^3.3.3",
         "typedoc": "^0.25.12",
         "typescript": "^5.4.5",
@@ -45274,6 +45279,7 @@
     "@lexical/list": {
       "version": "file:packages/lexical-list",
       "requires": {
+        "@lexical/selection": "0.27.2",
         "@lexical/utils": "0.27.2",
         "lexical": "0.27.2"
       }
@@ -45393,7 +45399,7 @@
         "docusaurus-plugin-internaldocs-fb": "1.19.0",
         "docusaurus-plugin-typedoc": "^0.22.0",
         "fs-extra": "^10.0.0",
-        "prettier-plugin-tailwindcss": "^0.4.1",
+        "prettier-plugin-tailwindcss": "^0.6.11",
         "prism-react-renderer": "^2.3.1",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
@@ -45581,6 +45587,14 @@
       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
       "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
     },
+    "@prettier/sync": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.5.2.tgz",
+      "integrity": "sha512-Yb569su456XNx5BsH/Vyem7xD6g/y9iLmLUzRKM1a/dhU/D7HqqvkAG72znulXlMXztbV0iiu9O5AL8K98TzZQ==",
+      "requires": {
+        "make-synchronized": "^0.2.8"
+      }
+    },
     "@radix-ui/primitive": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
@@ -46960,12 +46974,6 @@
       "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
       "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw=="
     },
-    "@types/prettier": {
-      "version": "2.7.3",
-      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz",
-      "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==",
-      "dev": true
-    },
     "@types/prismjs": {
       "version": "1.26.0",
       "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz",
@@ -57313,7 +57321,7 @@
         "katex": "^0.16.10",
         "lexical": "0.27.2",
         "lodash-es": "^4.17.21",
-        "prettier": "^3.4.2",
+        "prettier": "^3.5.3",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-error-boundary": "^3.1.4",
@@ -57322,13 +57330,6 @@
         "vite-plugin-static-copy": "^2.1.0",
         "y-websocket": "^1.5.4",
         "yjs": ">=13.5.42"
-      },
-      "dependencies": {
-        "prettier": {
-          "version": "3.4.2",
-          "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
-          "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ=="
-        }
       }
     },
     "lib0": {
@@ -57844,6 +57845,11 @@
       "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
       "dev": true
     },
+    "make-synchronized": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.2.9.tgz",
+      "integrity": "sha512-4wczOs8SLuEdpEvp3vGo83wh8rjJ78UsIk7DIX5fxdfmfMJGog4bQzxfvOwq7Q3yCHLC4jp1urPHIxRS/A93gA=="
+    },
     "makeerror": {
       "version": "1.0.12",
       "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
@@ -61547,10 +61553,9 @@
       "dev": true
     },
     "prettier": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
-      "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
-      "dev": true
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+      "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="
     },
     "prettier-plugin-hermes-parser": {
       "version": "0.26.0",
@@ -61564,15 +61569,15 @@
       }
     },
     "prettier-plugin-organize-attributes": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-0.0.5.tgz",
-      "integrity": "sha512-dSts16q8wd+oq8Zwk5mwmYXo1aN3B+ZkEJqx/ar5fedNHdOvx7S4XDMH/pNK7rmBW0bPXkp/kJX5gAANsWzh3A==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-1.0.0.tgz",
+      "integrity": "sha512-+NmameaLxbCcylEXsKPmawtzla5EE6ECqvGkpfQz4KM847fXDifB1gFnPQEpoADAq6IXg+cMI8Z0ISJEXa6fhg==",
       "dev": true
     },
     "prettier-plugin-tailwindcss": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz",
-      "integrity": "sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==",
+      "version": "0.6.11",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.11.tgz",
+      "integrity": "sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==",
       "dev": true
     },
     "pretty-error": {
diff --git a/package.json b/package.json
index 20e3d93c8d3..cd177852564 100644
--- a/package.json
+++ b/package.json
@@ -130,7 +130,6 @@
     "@types/jsdom": "^21.1.6",
     "@types/katex": "^0.16.7",
     "@types/node": "^17.0.31",
-    "@types/prettier": "^2.7.3",
     "@types/prismjs": "^1.26.0",
     "@types/proper-lockfile": "^4.1.4",
     "@types/react": "^18.0.8",
@@ -174,10 +173,10 @@
     "lint-staged": "^11.1.0",
     "minimist": "^1.2.5",
     "npm-run-all": "^4.1.5",
-    "prettier": "^2.3.2",
+    "prettier": "^3.5.3",
     "prettier-plugin-hermes-parser": "^0.26.0",
-    "prettier-plugin-organize-attributes": "^0.0.5",
-    "prettier-plugin-tailwindcss": "^0.4.1",
+    "prettier-plugin-organize-attributes": "^1.0.0",
+    "prettier-plugin-tailwindcss": "^0.6.11",
     "proper-lockfile": "^4.1.2",
     "react-test-renderer": "^17.0.2",
     "rollup": "^4.22.4",
@@ -190,6 +189,7 @@
     "vite": "^5.2.11"
   },
   "dependencies": {
+    "@prettier/sync": "^0.5.2",
     "yjs": "^13.5.42"
   }
 }
diff --git a/packages/lexical-eslint-plugin/src/__tests__/unit/rules-of-lexical.test.ts b/packages/lexical-eslint-plugin/src/__tests__/unit/rules-of-lexical.test.ts
index 5845696dc83..bebee3e8a58 100644
--- a/packages/lexical-eslint-plugin/src/__tests__/unit/rules-of-lexical.test.ts
+++ b/packages/lexical-eslint-plugin/src/__tests__/unit/rules-of-lexical.test.ts
@@ -6,10 +6,10 @@
  *
  */
 
+import * as prettierSync from '@prettier/sync';
 import {RuleTester} from 'eslint';
 import * as fs from 'node:fs';
 import * as path from 'node:path';
-import * as prettier from 'prettier';
 
 import plugin from '../../LexicalEslintPlugin.js';
 import {type RulesOfLexicalOptions} from '../../rules/rules-of-lexical.js';
@@ -39,7 +39,7 @@ function fmt(
     keys.forEach((key, i) => {
       result.push(key(name), strings[i + 1]);
     });
-    return prettier.format(result.join(''), {parser: 'typescript'});
+    return prettierSync.format(result.join(''), {parser: 'typescript'});
   };
   rval.keys = keys;
   rval.setOptions = (opts: RulesOfLexicalOptions) => {
diff --git a/packages/lexical-list/src/__tests__/utils.ts b/packages/lexical-list/src/__tests__/utils.ts
index aa95a7a01b0..13b75de4338 100644
--- a/packages/lexical-list/src/__tests__/utils.ts
+++ b/packages/lexical-list/src/__tests__/utils.ts
@@ -6,7 +6,7 @@
  *
  */
 import {expect} from '@playwright/test';
-import prettier from 'prettier';
+import * as prettierSync from '@prettier/sync';
 
 // This tag function is just used to trigger prettier auto-formatting.
 // (https://prettier.io/blog/2020/08/24/2.1.0.html#api)
@@ -29,5 +29,5 @@ export function expectHtmlToBeEqual(expected: string, actual: string): void {
 }
 
 export function prettifyHtml(s: string): string {
-  return prettier.format(s.replace(/\n/g, ''), {parser: 'html'});
+  return prettierSync.format(s.replace(/\n/g, ''), {parser: 'html'});
 }
diff --git a/packages/lexical-playground/__tests__/utils/index.mjs b/packages/lexical-playground/__tests__/utils/index.mjs
index deb209bfda9..ad4d9052a30 100644
--- a/packages/lexical-playground/__tests__/utils/index.mjs
+++ b/packages/lexical-playground/__tests__/utils/index.mjs
@@ -9,7 +9,7 @@
 import {expect, test as base} from '@playwright/test';
 import * as glob from 'glob';
 import {randomUUID} from 'node:crypto';
-import prettier from 'prettier';
+import * as prettier from 'prettier';
 import * as lockfile from 'proper-lockfile';
 import {URLSearchParams} from 'url';
 
diff --git a/packages/lexical-playground/package.json b/packages/lexical-playground/package.json
index 34e991c45c8..609947f4bd9 100644
--- a/packages/lexical-playground/package.json
+++ b/packages/lexical-playground/package.json
@@ -29,7 +29,7 @@
     "katex": "^0.16.10",
     "lexical": "0.27.2",
     "lodash-es": "^4.17.21",
-    "prettier": "^3.4.2",
+    "prettier": "^3.5.3",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-error-boundary": "^3.1.4",
diff --git a/packages/lexical-website/package.json b/packages/lexical-website/package.json
index 54294b27479..3145e16ceb7 100644
--- a/packages/lexical-website/package.json
+++ b/packages/lexical-website/package.json
@@ -34,7 +34,7 @@
   },
   "devDependencies": {
     "buffer": "^6.0.3",
-    "prettier-plugin-tailwindcss": "^0.4.1",
+    "prettier-plugin-tailwindcss": "^0.6.11",
     "tailwindcss": "^3.3.3",
     "typedoc": "^0.25.12",
     "typescript": "^5.4.5",
diff --git a/packages/lexical/src/__tests__/utils/index.tsx b/packages/lexical/src/__tests__/utils/index.tsx
index 3eeecec272d..31204e47258 100644
--- a/packages/lexical/src/__tests__/utils/index.tsx
+++ b/packages/lexical/src/__tests__/utils/index.tsx
@@ -26,6 +26,7 @@ import {
 import {HeadingNode, QuoteNode} from '@lexical/rich-text';
 import {TableCellNode, TableNode, TableRowNode} from '@lexical/table';
 import {expect} from '@playwright/test';
+import * as prettierSync from '@prettier/sync';
 import {
   $isRangeSelection,
   createEditor,
@@ -45,7 +46,6 @@ import {
   TextNode,
 } from 'lexical';
 import path from 'path';
-import * as prettier from 'prettier';
 import * as React from 'react';
 import {createRef} from 'react';
 import {createRoot} from 'react-dom/client';
@@ -58,7 +58,7 @@ import {
 } from '../../LexicalEditor';
 import {resetRandomKey} from '../../LexicalUtils';
 
-const prettierConfig = prettier.resolveConfig.sync(
+const prettierConfig = prettierSync.resolveConfig(
   path.resolve(__dirname, '../../../../.prettierrc'),
 );
 
@@ -784,7 +784,7 @@ export function expectHtmlToBeEqual(actual: string, expected: string): void {
 }
 
 export function prettifyHtml(s: string): string {
-  return prettier.format(s.replace(/\n/g, ''), {
+  return prettierSync.format(s.replace(/\n/g, ''), {
     ...prettierConfig,
     parser: 'html',
   });
diff --git a/scripts/error-codes/__tests__/unit/transform-error-messages.test.js b/scripts/error-codes/__tests__/unit/transform-error-messages.test.js
index 20f51881876..6e2d1b30147 100644
--- a/scripts/error-codes/__tests__/unit/transform-error-messages.test.js
+++ b/scripts/error-codes/__tests__/unit/transform-error-messages.test.js
@@ -12,9 +12,9 @@ const fs = require('fs-extra');
 const path = require('node:path');
 const transformErrorMessages = require('../../transform-error-messages');
 const babel = require('@babel/core');
-const prettier = require('prettier');
+const prettierSync = require('@prettier/sync');
 
-const prettierConfig = prettier.resolveConfig.sync('./') || {};
+const prettierConfig = prettierSync.resolveConfig('./') || {};
 
 /** @returns {Promise<void>} */
 function waitTick() {
@@ -39,7 +39,13 @@ async function withCodes(before, after, cb) {
   }
 }
 
-function fmt(strings: TemplateStringsArray, ...keys: unknown[]) {
+/**
+ *
+ * @param {TemplateStringsArray} strings
+ * @param  {...unknown} keys
+ * @returns
+ */
+function fmt(strings, ...keys) {
   const result = [strings[0]];
   keys.forEach((key, i) => {
     result.push(String(key), strings[i + 1]);
@@ -59,7 +65,7 @@ function fmt(strings: TemplateStringsArray, ...keys: unknown[]) {
       'format$1ErrorMessage',
     )
     .trim();
-  return prettier.format(before, {
+  return prettierSync.format(before, {
     ...prettierConfig,
     filepath: 'test.js',
   });
diff --git a/scripts/error-codes/transform-error-messages.js b/scripts/error-codes/transform-error-messages.js
index 3ccfd24a957..cb9ea1a882a 100644
--- a/scripts/error-codes/transform-error-messages.js
+++ b/scripts/error-codes/transform-error-messages.js
@@ -13,7 +13,7 @@ const fs = require('fs-extra');
 const ErrorMap = require('./ErrorMap');
 const evalToString = require('./evalToString');
 const helperModuleImports = require('@babel/helper-module-imports');
-const prettier = require('prettier');
+const prettierSync = require('@prettier/sync');
 
 /** @type {Map<string, ErrorMap>} */
 const errorMaps = new Map();
@@ -29,13 +29,13 @@ function getErrorMap(filepath) {
   let errorMap = errorMaps.get(filepath);
   if (!errorMap) {
     const prettierConfig = {
-      ...(prettier.resolveConfig.sync('./') || {}),
+      ...(prettierSync.resolveConfig('./') || {}),
       filepath,
     };
     errorMap = new ErrorMap(fs.readJsonSync(filepath), (newErrorMap) =>
       fs.writeFileSync(
         filepath,
-        prettier.format(JSON.stringify(newErrorMap), prettierConfig),
+        prettierSync.format(JSON.stringify(newErrorMap), prettierConfig),
       ),
     );
     errorMaps.set(filepath, errorMap);

From 108af6757559f924b57b8816b73433d6911fe7d0 Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 12:14:20 -0700
Subject: [PATCH 07/10] npm run prettier:fix

---
 examples/react-plain-text/index.html          |   2 +-
 examples/react-plain-text/src/styles.css      |   6 +-
 examples/react-rich-collab/app.html           |   2 +-
 examples/react-rich-collab/index.html         |   2 +-
 examples/react-rich-collab/src/styles.css     |   6 +-
 examples/react-rich/index.html                |   2 +-
 examples/react-rich/src/styles.css            |   6 +-
 examples/react-table/index.html               |   2 +-
 examples/react-table/src/styles.css           |   6 +-
 examples/vanilla-js-iframe/index.html         |   2 +-
 examples/vanilla-js-plugin/index.html         |   2 +-
 examples/vanilla-js/index.html                |   2 +-
 .../src/generateContent.ts                    |   8 +-
 .../Base.lproj/Main.html                      |   2 +-
 .../src/entrypoints/devtools-panel/index.html |   2 +-
 .../src/entrypoints/devtools/index.html       |   2 +-
 .../src/entrypoints/popup/index.html          |   2 +-
 packages/lexical-headless/src/index.ts        |   2 +-
 .../lexical-list/src/LexicalListItemNode.ts   |   4 +-
 .../src/MarkdownTransformers.ts               |   4 +-
 .../html/ListsHTMLCopyAndPaste.spec.mjs       |   5 +-
 .../__tests__/e2e/Extensions.spec.mjs         | 112 +++++++-----------
 .../__tests__/e2e/Links.spec.mjs              |  24 ++--
 packages/lexical-playground/esm/index.html    |   2 +-
 packages/lexical-playground/index.html        |   2 +-
 packages/lexical-playground/split/index.html  |   2 +-
 packages/lexical-playground/src/App.tsx       |   4 +-
 packages/lexical-playground/src/Editor.tsx    |   4 +-
 packages/lexical-playground/src/index.css     |  10 +-
 .../src/plugins/TableCellResizer/index.tsx    |   4 +-
 .../plugins/TableOfContentsPlugin/index.tsx   |   3 +-
 .../src/plugins/ToolbarPlugin/index.tsx       |   4 +-
 .../lexical-playground/src/ui/ColorPicker.css |   3 +-
 .../lexical-playground/src/ui/ColorPicker.tsx |   6 +-
 .../src/ui/ExcalidrawModal.css                |   4 +-
 .../src/ui/ImageResizer.tsx                   |   4 +-
 .../lexical-selection/src/lexical-node.ts     |   4 +-
 .../lexical-table/src/LexicalTableCellNode.ts |   2 +-
 packages/lexical-yjs/src/SyncCursors.ts       |   5 +-
 packages/lexical/src/LexicalEditor.ts         |   9 +-
 packages/lexical/src/LexicalNodeState.ts      |  16 +--
 packages/lexical/src/LexicalReconciler.ts     |   4 +-
 packages/lexical/src/LexicalSelection.ts      |   4 +-
 packages/lexical/src/LexicalUpdates.ts        |   2 +-
 packages/lexical/src/LexicalUtils.ts          |   4 +-
 .../__tests__/unit/LexicalNodeState.test.ts   |   9 +-
 .../__tests__/unit/LexicalSelection.test.ts   |   4 +-
 packages/lexical/src/caret/LexicalCaret.ts    |  19 +--
 .../caret/__tests__/unit/LexicalCaret.test.ts |   4 +-
 packages/shared/lexicalMonorepoPlugin.ts      |   4 +-
 scripts/lint-flow-types.js                    |   4 +-
 51 files changed, 173 insertions(+), 180 deletions(-)

diff --git a/examples/react-plain-text/index.html b/examples/react-plain-text/index.html
index ce9878e6d4a..58fb43978dd 100644
--- a/examples/react-plain-text/index.html
+++ b/examples/react-plain-text/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-plain-text/src/styles.css b/examples/react-plain-text/src/styles.css
index bf79e1f4e71..b6046673eba 100644
--- a/examples/react-plain-text/src/styles.css
+++ b/examples/react-plain-text/src/styles.css
@@ -9,7 +9,11 @@
 body {
   margin: 0;
   background: #eee;
-  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
+  font-family:
+    system-ui,
+    -apple-system,
+    BlinkMacSystemFont,
+    '.SFNSText-Regular',
     sans-serif;
   font-weight: 500;
   -webkit-font-smoothing: antialiased;
diff --git a/examples/react-rich-collab/app.html b/examples/react-rich-collab/app.html
index 8dbc32d5238..60a0fc531fe 100644
--- a/examples/react-rich-collab/app.html
+++ b/examples/react-rich-collab/app.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-rich-collab/index.html b/examples/react-rich-collab/index.html
index 4096ec03812..62d6948c5b1 100644
--- a/examples/react-rich-collab/index.html
+++ b/examples/react-rich-collab/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-rich-collab/src/styles.css b/examples/react-rich-collab/src/styles.css
index 79e45348998..2f55096faa3 100644
--- a/examples/react-rich-collab/src/styles.css
+++ b/examples/react-rich-collab/src/styles.css
@@ -10,7 +10,11 @@ body {
   margin: 0;
   font-size: 14px;
   background: #eee;
-  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
+  font-family:
+    system-ui,
+    -apple-system,
+    BlinkMacSystemFont,
+    '.SFNSText-Regular',
     sans-serif;
   font-weight: 500;
   -webkit-font-smoothing: antialiased;
diff --git a/examples/react-rich/index.html b/examples/react-rich/index.html
index 34bb34c5064..4c5c8f08d5a 100644
--- a/examples/react-rich/index.html
+++ b/examples/react-rich/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-rich/src/styles.css b/examples/react-rich/src/styles.css
index 071a794fc76..3071e94a118 100644
--- a/examples/react-rich/src/styles.css
+++ b/examples/react-rich/src/styles.css
@@ -9,7 +9,11 @@
 body {
   margin: 0;
   background: #eee;
-  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
+  font-family:
+    system-ui,
+    -apple-system,
+    BlinkMacSystemFont,
+    '.SFNSText-Regular',
     sans-serif;
   font-weight: 500;
   -webkit-font-smoothing: antialiased;
diff --git a/examples/react-table/index.html b/examples/react-table/index.html
index 8243eabc6b9..2f73f6bbf24 100644
--- a/examples/react-table/index.html
+++ b/examples/react-table/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-table/src/styles.css b/examples/react-table/src/styles.css
index 32b80315539..a6dd01a6fd7 100644
--- a/examples/react-table/src/styles.css
+++ b/examples/react-table/src/styles.css
@@ -9,7 +9,11 @@
 body {
   margin: 0;
   background: #eee;
-  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
+  font-family:
+    system-ui,
+    -apple-system,
+    BlinkMacSystemFont,
+    '.SFNSText-Regular',
     sans-serif;
   font-weight: 500;
   -webkit-font-smoothing: antialiased;
diff --git a/examples/vanilla-js-iframe/index.html b/examples/vanilla-js-iframe/index.html
index a730616c401..41e6c0c674a 100644
--- a/examples/vanilla-js-iframe/index.html
+++ b/examples/vanilla-js-iframe/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/vanilla-js-plugin/index.html b/examples/vanilla-js-plugin/index.html
index ef397bcc4d1..8b639835237 100644
--- a/examples/vanilla-js-plugin/index.html
+++ b/examples/vanilla-js-plugin/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/vanilla-js/index.html b/examples/vanilla-js/index.html
index 23cdfeba208..396a39da2d9 100644
--- a/examples/vanilla-js/index.html
+++ b/examples/vanilla-js/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/packages/lexical-devtools-core/src/generateContent.ts b/packages/lexical-devtools-core/src/generateContent.ts
index 5e431558d26..89a0eb7178d 100644
--- a/packages/lexical-devtools-core/src/generateContent.ts
+++ b/packages/lexical-devtools-core/src/generateContent.ts
@@ -145,10 +145,10 @@ export function generateContent(
     return selection === null
       ? ': null'
       : $isRangeSelection(selection)
-      ? printRangeSelection(selection)
-      : $isTableSelection(selection)
-      ? printTableSelection(selection)
-      : printNodeSelection(selection);
+        ? printRangeSelection(selection)
+        : $isTableSelection(selection)
+          ? printTableSelection(selection)
+          : printNodeSelection(selection);
   });
 
   res += '\n selection' + selectionString;
diff --git a/packages/lexical-devtools/safari-xcode/Lexical Developer Tools/Lexical Developer Tools/Base.lproj/Main.html b/packages/lexical-devtools/safari-xcode/Lexical Developer Tools/Lexical Developer Tools/Base.lproj/Main.html
index 105450678fa..d76d438dbfc 100644
--- a/packages/lexical-devtools/safari-xcode/Lexical Developer Tools/Lexical Developer Tools/Base.lproj/Main.html	
+++ b/packages/lexical-devtools/safari-xcode/Lexical Developer Tools/Lexical Developer Tools/Base.lproj/Main.html	
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html>
   <head>
     <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
diff --git a/packages/lexical-devtools/src/entrypoints/devtools-panel/index.html b/packages/lexical-devtools/src/entrypoints/devtools-panel/index.html
index 7db58aef1f0..9986ce8289b 100644
--- a/packages/lexical-devtools/src/entrypoints/devtools-panel/index.html
+++ b/packages/lexical-devtools/src/entrypoints/devtools-panel/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/packages/lexical-devtools/src/entrypoints/devtools/index.html b/packages/lexical-devtools/src/entrypoints/devtools/index.html
index b9a88d871cf..6e4ffeb705f 100644
--- a/packages/lexical-devtools/src/entrypoints/devtools/index.html
+++ b/packages/lexical-devtools/src/entrypoints/devtools/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/packages/lexical-devtools/src/entrypoints/popup/index.html b/packages/lexical-devtools/src/entrypoints/popup/index.html
index 68dd7ec9dc5..fffc2284f9f 100644
--- a/packages/lexical-devtools/src/entrypoints/popup/index.html
+++ b/packages/lexical-devtools/src/entrypoints/popup/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/packages/lexical-headless/src/index.ts b/packages/lexical-headless/src/index.ts
index 2b8eddb8ed3..04a18d356b7 100644
--- a/packages/lexical-headless/src/index.ts
+++ b/packages/lexical-headless/src/index.ts
@@ -33,7 +33,7 @@ export function createHeadlessEditor(
     'blur',
   ] as const;
 
-  unsupportedMethods.forEach((method: typeof unsupportedMethods[number]) => {
+  unsupportedMethods.forEach((method: (typeof unsupportedMethods)[number]) => {
     editor[method] = () => {
       throw new Error(`${method} is not supported in headless mode`);
     };
diff --git a/packages/lexical-list/src/LexicalListItemNode.ts b/packages/lexical-list/src/LexicalListItemNode.ts
index 757d706715b..0f03bf5701a 100644
--- a/packages/lexical-list/src/LexicalListItemNode.ts
+++ b/packages/lexical-list/src/LexicalListItemNode.ts
@@ -563,8 +563,8 @@ function $convertListItemElement(domNode: HTMLElement): DOMConversionOutput {
     ariaCheckedAttr === 'true'
       ? true
       : ariaCheckedAttr === 'false'
-      ? false
-      : undefined;
+        ? false
+        : undefined;
   return {node: $createListItemNode(checked)};
 }
 
diff --git a/packages/lexical-markdown/src/MarkdownTransformers.ts b/packages/lexical-markdown/src/MarkdownTransformers.ts
index f22067abc0c..21ba7642a65 100644
--- a/packages/lexical-markdown/src/MarkdownTransformers.ts
+++ b/packages/lexical-markdown/src/MarkdownTransformers.ts
@@ -299,8 +299,8 @@ const listExport = (
         listType === 'number'
           ? `${listNode.getStart() + index}. `
           : listType === 'check'
-          ? `- [${listItemNode.getChecked() ? 'x' : ' '}] `
-          : '- ';
+            ? `- [${listItemNode.getChecked() ? 'x' : ' '}] `
+            : '- ';
       output.push(indent + prefix + exportChildren(listItemNode));
       index++;
     }
diff --git a/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/ListsHTMLCopyAndPaste.spec.mjs b/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/ListsHTMLCopyAndPaste.spec.mjs
index 8d695141c17..87af282c4e0 100644
--- a/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/ListsHTMLCopyAndPaste.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/ListsHTMLCopyAndPaste.spec.mjs
@@ -322,9 +322,8 @@ test.describe('HTML Lists CopyAndPaste', () => {
     await focusEditor(page);
 
     // Ensure we preserve checked status.
-    clipboard[
-      'text/html'
-    ] = `<meta charset='utf-8'><ul __lexicallisttype="check"><li role="checkbox" tabindex="-1" aria-checked="true" value="1" class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__listItemChecked"><span>Hello</span></li><li role="checkbox" tabindex="-1" aria-checked="false" value="2" class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__listItemUnchecked"><span>world</span></li></ul>`;
+    clipboard['text/html'] =
+      `<meta charset='utf-8'><ul __lexicallisttype="check"><li role="checkbox" tabindex="-1" aria-checked="true" value="1" class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__listItemChecked"><span>Hello</span></li><li role="checkbox" tabindex="-1" aria-checked="false" value="2" class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__listItemUnchecked"><span>world</span></li></ul>`;
 
     await pasteFromClipboard(page, clipboard);
 
diff --git a/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs b/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs
index ba54a73aae1..6b8c6517948 100644
--- a/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs
@@ -25,13 +25,9 @@ test.describe('Extensions', () => {
   test(`document.execCommand("insertText")`, async ({page}) => {
     await focusEditor(page);
 
-    await evaluate(
-      page,
-      () => {
-        document.execCommand('insertText', false, 'foo');
-      },
-      [],
-    );
+    await evaluate(page, () => {
+      document.execCommand('insertText', false, 'foo');
+    }, []);
     await assertHTML(
       page,
       html`
@@ -58,31 +54,27 @@ test.describe('Extensions', () => {
     }
     await focusEditor(page);
 
-    await evaluate(
-      page,
-      () => {
-        function paste() {
-          const dataTransfer = new DataTransfer();
-          function dispatchPaste(target, text) {
-            dataTransfer.setData('text/plain', text);
-            target.dispatchEvent(
-              new ClipboardEvent('paste', {
-                bubbles: true,
-                cancelable: true,
-                clipboardData: dataTransfer,
-              }),
-            );
-            dataTransfer.clearData();
-          }
-          return dispatchPaste;
+    await evaluate(page, () => {
+      function paste() {
+        const dataTransfer = new DataTransfer();
+        function dispatchPaste(target, text) {
+          dataTransfer.setData('text/plain', text);
+          target.dispatchEvent(
+            new ClipboardEvent('paste', {
+              bubbles: true,
+              cancelable: true,
+              clipboardData: dataTransfer,
+            }),
+          );
+          dataTransfer.clearData();
         }
+        return dispatchPaste;
+      }
 
-        const editor = document.querySelector('div[contenteditable="true"]');
-        const dispatchPaste = paste();
-        dispatchPaste(editor, 'foo');
-      },
-      [],
-    );
+      const editor = document.querySelector('div[contenteditable="true"]');
+      const dispatchPaste = paste();
+      dispatchPaste(editor, 'foo');
+    }, []);
     await assertHTML(
       page,
       html`
@@ -214,29 +206,25 @@ test.describe('Extensions', () => {
     await page.keyboard.press('ArrowUp');
 
     // Selection is on the last paragraph
-    await evaluate(
-      page,
-      async () => {
-        const editor = document.querySelector('div[contenteditable="true"]');
-        const selection = window.getSelection();
-        const secondParagraphTextNode =
-          editor.firstChild.nextSibling.firstChild.firstChild;
-        selection.setBaseAndExtent(
-          secondParagraphTextNode,
-          0,
-          secondParagraphTextNode,
-          3,
-        );
+    await evaluate(page, async () => {
+      const editor = document.querySelector('div[contenteditable="true"]');
+      const selection = window.getSelection();
+      const secondParagraphTextNode =
+        editor.firstChild.nextSibling.firstChild.firstChild;
+      selection.setBaseAndExtent(
+        secondParagraphTextNode,
+        0,
+        secondParagraphTextNode,
+        3,
+      );
 
-        await new Promise((resolve) => {
-          setTimeout(() => {
-            document.execCommand('insertText', false, 'and');
-            resolve();
-          }, 50);
-        });
-      },
-      [],
-    );
+      await new Promise((resolve) => {
+        setTimeout(() => {
+          document.execCommand('insertText', false, 'and');
+          resolve();
+        }, 50);
+      });
+    }, []);
     await assertHTML(
       page,
       html`
@@ -278,13 +266,9 @@ test.describe('Extensions', () => {
       focusPath: [0, 0, 0],
     });
 
-    await evaluate(
-      page,
-      () => {
-        document.execCommand('insertText', false, 'New text');
-      },
-      [],
-    );
+    await evaluate(page, () => {
+      document.execCommand('insertText', false, 'New text');
+    }, []);
     await assertHTML(
       page,
       html`
@@ -321,13 +305,9 @@ test.describe('Extensions', () => {
       focusPath: [0, 0, 0],
     });
 
-    await evaluate(
-      page,
-      () => {
-        document.execCommand('insertText', false, 'New text');
-      },
-      [],
-    );
+    await evaluate(page, () => {
+      document.execCommand('insertText', false, 'New text');
+    }, []);
     await assertHTML(
       page,
       html`
diff --git a/packages/lexical-playground/__tests__/e2e/Links.spec.mjs b/packages/lexical-playground/__tests__/e2e/Links.spec.mjs
index 98fa7139d48..22a271cd360 100644
--- a/packages/lexical-playground/__tests__/e2e/Links.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/Links.spec.mjs
@@ -741,8 +741,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                ? clipboardData.html
-                : clipboardData.lexical;
+                  ? clipboardData.html
+                  : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -818,8 +818,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                ? clipboardData.html
-                : clipboardData.lexical;
+                  ? clipboardData.html
+                  : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -892,8 +892,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                ? clipboardData.html
-                : clipboardData.lexical;
+                  ? clipboardData.html
+                  : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -970,8 +970,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                ? clipboardData.html
-                : clipboardData.lexical;
+                  ? clipboardData.html
+                  : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -1046,8 +1046,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                ? clipboardData.html
-                : clipboardData.lexical;
+                  ? clipboardData.html
+                  : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -1122,8 +1122,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                ? clipboardData.html
-                : clipboardData.lexical;
+                  ? clipboardData.html
+                  : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
diff --git a/packages/lexical-playground/esm/index.html b/packages/lexical-playground/esm/index.html
index 211ce77ab43..08dbd4a342a 100644
--- a/packages/lexical-playground/esm/index.html
+++ b/packages/lexical-playground/esm/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="utf-8" />
diff --git a/packages/lexical-playground/index.html b/packages/lexical-playground/index.html
index d810340cd24..7b546d00562 100644
--- a/packages/lexical-playground/index.html
+++ b/packages/lexical-playground/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="utf-8" />
diff --git a/packages/lexical-playground/split/index.html b/packages/lexical-playground/split/index.html
index d98f0a12996..e800b478d9f 100644
--- a/packages/lexical-playground/split/index.html
+++ b/packages/lexical-playground/split/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="utf-8" />
diff --git a/packages/lexical-playground/src/App.tsx b/packages/lexical-playground/src/App.tsx
index d667ed12c32..5ab43df6e92 100644
--- a/packages/lexical-playground/src/App.tsx
+++ b/packages/lexical-playground/src/App.tsx
@@ -197,8 +197,8 @@ function App(): JSX.Element {
     editorState: isCollab
       ? null
       : emptyEditor
-      ? undefined
-      : $prepopulatedRichText,
+        ? undefined
+        : $prepopulatedRichText,
     html: {import: buildImportMap()},
     namespace: 'Playground',
     nodes: [...PlaygroundNodes],
diff --git a/packages/lexical-playground/src/Editor.tsx b/packages/lexical-playground/src/Editor.tsx
index 2b97ddd63ac..d3939b4b285 100644
--- a/packages/lexical-playground/src/Editor.tsx
+++ b/packages/lexical-playground/src/Editor.tsx
@@ -106,8 +106,8 @@ export default function Editor(): JSX.Element {
   const placeholder = isCollab
     ? 'Enter some collaborative rich text...'
     : isRichText
-    ? 'Enter some rich text...'
-    : 'Enter some plain text...';
+      ? 'Enter some rich text...'
+      : 'Enter some plain text...';
   const [floatingAnchorElem, setFloatingAnchorElem] =
     useState<HTMLDivElement | null>(null);
   const [isSmallWidthViewport, setIsSmallWidthViewport] =
diff --git a/packages/lexical-playground/src/index.css b/packages/lexical-playground/src/index.css
index 90c3841900d..1b9c3986c28 100644
--- a/packages/lexical-playground/src/index.css
+++ b/packages/lexical-playground/src/index.css
@@ -10,7 +10,11 @@
 
 body {
   margin: 0;
-  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
+  font-family:
+    system-ui,
+    -apple-system,
+    BlinkMacSystemFont,
+    '.SFNSText-Regular',
     sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
@@ -757,7 +761,9 @@ i.page-break,
   z-index: 100;
   display: block;
   position: fixed;
-  box-shadow: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1),
+  box-shadow:
+    0 12px 28px 0 rgba(0, 0, 0, 0.2),
+    0 2px 4px 0 rgba(0, 0, 0, 0.1),
     inset 0 0 0 1px rgba(255, 255, 255, 0.5);
   border-radius: 8px;
   min-height: 40px;
diff --git a/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx b/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx
index e1a05a61ec8..025e877e858 100644
--- a/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx
+++ b/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx
@@ -346,8 +346,8 @@ function TableCellResizer({editor}: {editor: LexicalEditor}): JSX.Element {
 
   const toggleResize = useCallback(
     (
-        direction: PointerDraggingDirection,
-      ): PointerEventHandler<HTMLDivElement> =>
+      direction: PointerDraggingDirection,
+    ): PointerEventHandler<HTMLDivElement> =>
       (event) => {
         event.preventDefault();
         event.stopPropagation();
diff --git a/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx
index e8d3256a590..9f22f494d77 100644
--- a/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx
+++ b/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx
@@ -171,8 +171,7 @@ function TableOfContentsList({
                   <li
                     className={`normal-heading ${
                       selectedKey === key ? 'selected-heading' : ''
-                    }
-                    `}>
+                    } `}>
                     {('' + text).length > 27
                       ? text.substring(0, 27) + '...'
                       : text}
diff --git a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
index 44f353bcb31..d08dc79548f 100644
--- a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
+++ b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
@@ -597,8 +597,8 @@ export default function ToolbarPlugin({
         $isElementNode(matchingParent)
           ? matchingParent.getFormatType()
           : $isElementNode(node)
-          ? node.getFormatType()
-          : parent?.getFormatType() || 'left',
+            ? node.getFormatType()
+            : parent?.getFormatType() || 'left',
       );
     }
     if ($isRangeSelection(selection) || $isTableSelection(selection)) {
diff --git a/packages/lexical-playground/src/ui/ColorPicker.css b/packages/lexical-playground/src/ui/ColorPicker.css
index 63217ba3784..a10c5b8243f 100644
--- a/packages/lexical-playground/src/ui/ColorPicker.css
+++ b/packages/lexical-playground/src/ui/ColorPicker.css
@@ -36,7 +36,8 @@
   position: relative;
   margin-top: 15px;
   height: 150px;
-  background-image: linear-gradient(transparent, black),
+  background-image:
+    linear-gradient(transparent, black),
     linear-gradient(to right, white, transparent);
   user-select: none;
 }
diff --git a/packages/lexical-playground/src/ui/ColorPicker.tsx b/packages/lexical-playground/src/ui/ColorPicker.tsx
index 6593c02389f..d647a700211 100644
--- a/packages/lexical-playground/src/ui/ColorPicker.tsx
+++ b/packages/lexical-playground/src/ui/ColorPicker.tsx
@@ -124,7 +124,7 @@ export default function ColorPicker({
       <div className="color-picker-basic-color">
         {basicColors.map((basicColor) => (
           <button
-            className={basicColor === selfColor.hex ? ' active' : ''}
+            className={basicColor === selfColor.hex ? 'active' : ''}
             key={basicColor}
             style={{backgroundColor: basicColor}}
             onClick={() => {
@@ -307,8 +307,8 @@ function rgb2hsv({r, g, b}: RGB): HSV {
     ? (max === r
         ? (g - b) / d + (g < b ? 6 : 0)
         : max === g
-        ? 2 + (b - r) / d
-        : 4 + (r - g) / d) * 60
+          ? 2 + (b - r) / d
+          : 4 + (r - g) / d) * 60
     : 0;
   const s = max ? (d / max) * 100 : 0;
   const v = max * 100;
diff --git a/packages/lexical-playground/src/ui/ExcalidrawModal.css b/packages/lexical-playground/src/ui/ExcalidrawModal.css
index 7438d60ecae..6e83f9e759a 100644
--- a/packages/lexical-playground/src/ui/ExcalidrawModal.css
+++ b/packages/lexical-playground/src/ui/ExcalidrawModal.css
@@ -38,7 +38,9 @@
   width: 70vw;
   height: 70vh;
   border-radius: 8px;
-  box-shadow: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1),
+  box-shadow:
+    0 12px 28px 0 rgba(0, 0, 0, 0.2),
+    0 2px 4px 0 rgba(0, 0, 0, 0.1),
     inset 0 0 0 1px rgba(255, 255, 255, 0.5);
 }
 .ExcalidrawModal__row > div {
diff --git a/packages/lexical-playground/src/ui/ImageResizer.tsx b/packages/lexical-playground/src/ui/ImageResizer.tsx
index e2c52ebfbc9..e38afdcafb1 100644
--- a/packages/lexical-playground/src/ui/ImageResizer.tsx
+++ b/packages/lexical-playground/src/ui/ImageResizer.tsx
@@ -76,8 +76,8 @@ export default function ImageResizer({
   const maxWidthContainer = maxWidth
     ? maxWidth
     : editorRootElement !== null
-    ? editorRootElement.getBoundingClientRect().width - 20
-    : 100;
+      ? editorRootElement.getBoundingClientRect().width - 20
+      : 100;
   const maxHeightContainer =
     editorRootElement !== null
       ? editorRootElement.getBoundingClientRect().height - 20
diff --git a/packages/lexical-selection/src/lexical-node.ts b/packages/lexical-selection/src/lexical-node.ts
index 91b5d9a3df3..404f81400a4 100644
--- a/packages/lexical-selection/src/lexical-node.ts
+++ b/packages/lexical-selection/src/lexical-node.ts
@@ -269,8 +269,8 @@ export function $patchStyle(
     $isRangeSelection(target)
       ? target.style
       : $isTextNode(target)
-      ? target.getStyle()
-      : target.getTextStyle(),
+        ? target.getStyle()
+        : target.getTextStyle(),
   );
   const newStyles = Object.entries(patch).reduce<Record<string, string>>(
     (styles, [key, value]) => {
diff --git a/packages/lexical-table/src/LexicalTableCellNode.ts b/packages/lexical-table/src/LexicalTableCellNode.ts
index 987ba11d51d..9ba1a49947c 100644
--- a/packages/lexical-table/src/LexicalTableCellNode.ts
+++ b/packages/lexical-table/src/LexicalTableCellNode.ts
@@ -41,7 +41,7 @@ export const TableCellHeaderStates = {
 };
 
 export type TableCellHeaderState =
-  typeof TableCellHeaderStates[keyof typeof TableCellHeaderStates];
+  (typeof TableCellHeaderStates)[keyof typeof TableCellHeaderStates];
 
 export type SerializedTableCellNode = Spread<
   {
diff --git a/packages/lexical-yjs/src/SyncCursors.ts b/packages/lexical-yjs/src/SyncCursors.ts
index 31cf7010c6d..21dd80a573b 100644
--- a/packages/lexical-yjs/src/SyncCursors.ts
+++ b/packages/lexical-yjs/src/SyncCursors.ts
@@ -277,9 +277,8 @@ function updateCursor(
     const style = `position:absolute;top:${top}px;left:${left}px;height:${selectionRect.height}px;width:${selectionRect.width}px;pointer-events:none;z-index:5;`;
     selection.style.cssText = style;
 
-    (
-      selection.firstChild as HTMLSpanElement
-    ).style.cssText = `${style}left:0;top:0;background-color:${color};opacity:0.3;`;
+    (selection.firstChild as HTMLSpanElement).style.cssText =
+      `${style}left:0;top:0;background-color:${color};opacity:0.3;`;
 
     if (i === selectionRectsLength - 1) {
       if (caret.parentNode !== selection) {
diff --git a/packages/lexical/src/LexicalEditor.ts b/packages/lexical/src/LexicalEditor.ts
index c4b0be353d7..7f8e4f9f2dc 100644
--- a/packages/lexical/src/LexicalEditor.ts
+++ b/packages/lexical/src/LexicalEditor.ts
@@ -58,11 +58,10 @@ export type KlassConstructor<Cls extends GenericConstructor<any>> =
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 type GenericConstructor<T> = new (...args: any[]) => T;
 
-export type Klass<T extends LexicalNode> = InstanceType<
-  T['constructor']
-> extends T
-  ? T['constructor']
-  : GenericConstructor<T> & T['constructor'];
+export type Klass<T extends LexicalNode> =
+  InstanceType<T['constructor']> extends T
+    ? T['constructor']
+    : GenericConstructor<T> & T['constructor'];
 
 export type EditorThemeClassName = string;
 
diff --git a/packages/lexical/src/LexicalNodeState.ts b/packages/lexical/src/LexicalNodeState.ts
index d0b746e715c..6129b344006 100644
--- a/packages/lexical/src/LexicalNodeState.ts
+++ b/packages/lexical/src/LexicalNodeState.ts
@@ -75,21 +75,13 @@ export type AnyStateConfig = StateConfig<any, any>;
 /**
  * Get the value type (V) from a StateConfig
  */
-export type StateConfigValue<S extends AnyStateConfig> = S extends StateConfig<
-  infer _K,
-  infer V
->
-  ? V
-  : never;
+export type StateConfigValue<S extends AnyStateConfig> =
+  S extends StateConfig<infer _K, infer V> ? V : never;
 /**
  * Get the key type (K) from a StateConfig
  */
-export type StateConfigKey<S extends AnyStateConfig> = S extends StateConfig<
-  infer K,
-  infer _V
->
-  ? K
-  : never;
+export type StateConfigKey<S extends AnyStateConfig> =
+  S extends StateConfig<infer K, infer _V> ? K : never;
 /**
  * A value type, or an updater for that value type. For use with
  * {@link $setState} or any user-defined wrappers around it.
diff --git a/packages/lexical/src/LexicalReconciler.ts b/packages/lexical/src/LexicalReconciler.ts
index 0bff573024c..af97f01b100 100644
--- a/packages/lexical/src/LexicalReconciler.ts
+++ b/packages/lexical/src/LexicalReconciler.ts
@@ -303,8 +303,8 @@ function isLastChildLineBreakOrDecorator(
         return $isLineBreakNode(node)
           ? 'line-break'
           : $isDecoratorNode(node) && node.isInline()
-          ? 'decorator'
-          : null;
+            ? 'decorator'
+            : null;
       }
     }
     return 'empty';
diff --git a/packages/lexical/src/LexicalSelection.ts b/packages/lexical/src/LexicalSelection.ts
index 96e4634db8d..5a29cfd56d5 100644
--- a/packages/lexical/src/LexicalSelection.ts
+++ b/packages/lexical/src/LexicalSelection.ts
@@ -3075,8 +3075,8 @@ export function updateDOMSelection(
         ? (nextAnchorNode.childNodes[nextAnchorOffset] as HTMLElement | Text) ||
           null
         : domSelection.rangeCount > 0
-        ? domSelection.getRangeAt(0)
-        : null;
+          ? domSelection.getRangeAt(0)
+          : null;
     if (selectionTarget !== null) {
       let selectionRect: DOMRect;
       if (selectionTarget instanceof Text) {
diff --git a/packages/lexical/src/LexicalUpdates.ts b/packages/lexical/src/LexicalUpdates.ts
index fb151f5fb7f..0e1012e4e88 100644
--- a/packages/lexical/src/LexicalUpdates.ts
+++ b/packages/lexical/src/LexicalUpdates.ts
@@ -133,7 +133,7 @@ function collectBuildInformation(): string {
       } else if (editor) {
         let version = String(
           (
-            editor.constructor as typeof editor['constructor'] &
+            editor.constructor as (typeof editor)['constructor'] &
               Record<string, unknown>
           ).version || '<0.17.1',
         );
diff --git a/packages/lexical/src/LexicalUtils.ts b/packages/lexical/src/LexicalUtils.ts
index 691b4be0bcc..8ed1031c145 100644
--- a/packages/lexical/src/LexicalUtils.ts
+++ b/packages/lexical/src/LexicalUtils.ts
@@ -1333,8 +1333,8 @@ export function getDOMOwnerDocument(
   return isDOMDocumentNode(target)
     ? target
     : isHTMLElement(target)
-    ? target.ownerDocument
-    : null;
+      ? target.ownerDocument
+      : null;
 }
 
 export function scrollIntoViewIfNeeded(
diff --git a/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts b/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts
index 0a47cd24477..d06211b6ba4 100644
--- a/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts
+++ b/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts
@@ -27,11 +27,10 @@ import {TestNode} from './LexicalNode.test';
 
 // https://www.totaltypescript.com/how-to-test-your-types
 type Expect<T extends true> = T;
-type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
-  ? 1
-  : 2
-  ? true
-  : false;
+type Equal<X, Y> =
+  (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
+    ? true
+    : false;
 
 const numberState = createState('numberState', {
   parse: (v) => (typeof v === 'number' ? v : 0),
diff --git a/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts b/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts
index b936c3d346a..f2fdf226f8c 100644
--- a/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts
+++ b/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts
@@ -88,8 +88,8 @@ describe('LexicalSelection tests', () => {
           mode === 'start-of-paragraph'
             ? '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><a href="https://" dir="ltr"><span data-lexical-text="true">a</span></a><span data-lexical-text="true">b</span></p></div>'
             : mode === 'mid-paragraph'
-            ? '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">a</span><a href="https://" dir="ltr"><span data-lexical-text="true">b</span></a><span data-lexical-text="true">c</span></p></div>'
-            : '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">a</span><a href="https://" dir="ltr"><span data-lexical-text="true">b</span></a></p></div>';
+              ? '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">a</span><a href="https://" dir="ltr"><span data-lexical-text="true">b</span></a><span data-lexical-text="true">c</span></p></div>'
+              : '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">a</span><a href="https://" dir="ltr"><span data-lexical-text="true">b</span></a></p></div>';
 
         expect(container.innerHTML).toBe(expectation);
 
diff --git a/packages/lexical/src/caret/LexicalCaret.ts b/packages/lexical/src/caret/LexicalCaret.ts
index c1af5986087..5389c7970a3 100644
--- a/packages/lexical/src/caret/LexicalCaret.ts
+++ b/packages/lexical/src/caret/LexicalCaret.ts
@@ -22,7 +22,8 @@ export type CaretDirection = 'next' | 'previous';
 /**
  * A type utility to flip next and previous
  */
-export type FlipDirection<D extends CaretDirection> = typeof FLIP_DIRECTION[D];
+export type FlipDirection<D extends CaretDirection> =
+  (typeof FLIP_DIRECTION)[D];
 /**
  * A sibling caret type points from a LexicalNode origin to its next or previous sibling,
  * and a child caret type points from an ElementNode origin to its first or last child.
@@ -1235,14 +1236,14 @@ export function $comparePointCaretNext(
       return aIsText && bIsText
         ? compareNumber(a.offset, b.offset)
         : a.type === b.type
-        ? 0
-        : aIsText
-        ? -1
-        : bIsText
-        ? 1
-        : a.type === 'child'
-        ? -1
-        : 1;
+          ? 0
+          : aIsText
+            ? -1
+            : bIsText
+              ? 1
+              : a.type === 'child'
+                ? -1
+                : 1;
     }
     case 'ancestor': {
       return a.type === 'child' ? -1 : 1;
diff --git a/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts b/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
index 40886b1533c..3ec82345db6 100644
--- a/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
+++ b/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
@@ -1205,8 +1205,8 @@ describe('LexicalCaret', () => {
                     anchorBias === 'outside' && focusBias === 'outside'
                       ? []
                       : (anchorBias === 'inside') === (direction === 'next')
-                      ? [{caret: {offset: 0}, distance: size}]
-                      : [{caret: {offset: size}, distance: -size}],
+                        ? [{caret: {offset: 0}, distance: size}]
+                        : [{caret: {offset: size}, distance: -size}],
                   );
                   const resultRange = $removeTextFromCaretRange(range);
                   $setSelection(null);
diff --git a/packages/shared/lexicalMonorepoPlugin.ts b/packages/shared/lexicalMonorepoPlugin.ts
index fd0660304a8..458d0e0e60c 100644
--- a/packages/shared/lexicalMonorepoPlugin.ts
+++ b/packages/shared/lexicalMonorepoPlugin.ts
@@ -26,8 +26,8 @@ export default function lexicalMonorepoPlugin(): Plugin {
               env.mode === 'production'
                 ? 'production'
                 : env.command === 'serve'
-                ? 'source'
-                : 'development',
+                  ? 'source'
+                  : 'development',
             ),
           },
         }),
diff --git a/scripts/lint-flow-types.js b/scripts/lint-flow-types.js
index eb6804a6740..b61d89ac4d4 100644
--- a/scripts/lint-flow-types.js
+++ b/scripts/lint-flow-types.js
@@ -47,8 +47,8 @@ function collectFlowExports(flowAst) {
       node.type === 'Identifier'
         ? node
         : 'id' in node && node.id.type === 'Identifier'
-        ? node.id
-        : null;
+          ? node.id
+          : null;
     if (identifier) {
       exportNames.set(identifier.name, identifier);
       return true;

From 7685f2f48e13f303a74378d3a7549af6462bf805 Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 12:34:12 -0700
Subject: [PATCH 08/10] Revert "npm run prettier:fix"

This reverts commit 108af6757559f924b57b8816b73433d6911fe7d0.
---
 examples/react-plain-text/index.html          |   2 +-
 examples/react-plain-text/src/styles.css      |   6 +-
 examples/react-rich-collab/app.html           |   2 +-
 examples/react-rich-collab/index.html         |   2 +-
 examples/react-rich-collab/src/styles.css     |   6 +-
 examples/react-rich/index.html                |   2 +-
 examples/react-rich/src/styles.css            |   6 +-
 examples/react-table/index.html               |   2 +-
 examples/react-table/src/styles.css           |   6 +-
 examples/vanilla-js-iframe/index.html         |   2 +-
 examples/vanilla-js-plugin/index.html         |   2 +-
 examples/vanilla-js/index.html                |   2 +-
 .../src/generateContent.ts                    |   8 +-
 .../Base.lproj/Main.html                      |   2 +-
 .../src/entrypoints/devtools-panel/index.html |   2 +-
 .../src/entrypoints/devtools/index.html       |   2 +-
 .../src/entrypoints/popup/index.html          |   2 +-
 packages/lexical-headless/src/index.ts        |   2 +-
 .../lexical-list/src/LexicalListItemNode.ts   |   4 +-
 .../src/MarkdownTransformers.ts               |   4 +-
 .../html/ListsHTMLCopyAndPaste.spec.mjs       |   5 +-
 .../__tests__/e2e/Extensions.spec.mjs         | 112 +++++++++++-------
 .../__tests__/e2e/Links.spec.mjs              |  24 ++--
 packages/lexical-playground/esm/index.html    |   2 +-
 packages/lexical-playground/index.html        |   2 +-
 packages/lexical-playground/split/index.html  |   2 +-
 packages/lexical-playground/src/App.tsx       |   4 +-
 packages/lexical-playground/src/Editor.tsx    |   4 +-
 packages/lexical-playground/src/index.css     |  10 +-
 .../src/plugins/TableCellResizer/index.tsx    |   4 +-
 .../plugins/TableOfContentsPlugin/index.tsx   |   3 +-
 .../src/plugins/ToolbarPlugin/index.tsx       |   4 +-
 .../lexical-playground/src/ui/ColorPicker.css |   3 +-
 .../lexical-playground/src/ui/ColorPicker.tsx |   6 +-
 .../src/ui/ExcalidrawModal.css                |   4 +-
 .../src/ui/ImageResizer.tsx                   |   4 +-
 .../lexical-selection/src/lexical-node.ts     |   4 +-
 .../lexical-table/src/LexicalTableCellNode.ts |   2 +-
 packages/lexical-yjs/src/SyncCursors.ts       |   5 +-
 packages/lexical/src/LexicalEditor.ts         |   9 +-
 packages/lexical/src/LexicalNodeState.ts      |  16 ++-
 packages/lexical/src/LexicalReconciler.ts     |   4 +-
 packages/lexical/src/LexicalSelection.ts      |   4 +-
 packages/lexical/src/LexicalUpdates.ts        |   2 +-
 packages/lexical/src/LexicalUtils.ts          |   4 +-
 .../__tests__/unit/LexicalNodeState.test.ts   |   9 +-
 .../__tests__/unit/LexicalSelection.test.ts   |   4 +-
 packages/lexical/src/caret/LexicalCaret.ts    |  19 ++-
 .../caret/__tests__/unit/LexicalCaret.test.ts |   4 +-
 packages/shared/lexicalMonorepoPlugin.ts      |   4 +-
 scripts/lint-flow-types.js                    |   4 +-
 51 files changed, 180 insertions(+), 173 deletions(-)

diff --git a/examples/react-plain-text/index.html b/examples/react-plain-text/index.html
index 58fb43978dd..ce9878e6d4a 100644
--- a/examples/react-plain-text/index.html
+++ b/examples/react-plain-text/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-plain-text/src/styles.css b/examples/react-plain-text/src/styles.css
index b6046673eba..bf79e1f4e71 100644
--- a/examples/react-plain-text/src/styles.css
+++ b/examples/react-plain-text/src/styles.css
@@ -9,11 +9,7 @@
 body {
   margin: 0;
   background: #eee;
-  font-family:
-    system-ui,
-    -apple-system,
-    BlinkMacSystemFont,
-    '.SFNSText-Regular',
+  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
     sans-serif;
   font-weight: 500;
   -webkit-font-smoothing: antialiased;
diff --git a/examples/react-rich-collab/app.html b/examples/react-rich-collab/app.html
index 60a0fc531fe..8dbc32d5238 100644
--- a/examples/react-rich-collab/app.html
+++ b/examples/react-rich-collab/app.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-rich-collab/index.html b/examples/react-rich-collab/index.html
index 62d6948c5b1..4096ec03812 100644
--- a/examples/react-rich-collab/index.html
+++ b/examples/react-rich-collab/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-rich-collab/src/styles.css b/examples/react-rich-collab/src/styles.css
index 2f55096faa3..79e45348998 100644
--- a/examples/react-rich-collab/src/styles.css
+++ b/examples/react-rich-collab/src/styles.css
@@ -10,11 +10,7 @@ body {
   margin: 0;
   font-size: 14px;
   background: #eee;
-  font-family:
-    system-ui,
-    -apple-system,
-    BlinkMacSystemFont,
-    '.SFNSText-Regular',
+  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
     sans-serif;
   font-weight: 500;
   -webkit-font-smoothing: antialiased;
diff --git a/examples/react-rich/index.html b/examples/react-rich/index.html
index 4c5c8f08d5a..34bb34c5064 100644
--- a/examples/react-rich/index.html
+++ b/examples/react-rich/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-rich/src/styles.css b/examples/react-rich/src/styles.css
index 3071e94a118..071a794fc76 100644
--- a/examples/react-rich/src/styles.css
+++ b/examples/react-rich/src/styles.css
@@ -9,11 +9,7 @@
 body {
   margin: 0;
   background: #eee;
-  font-family:
-    system-ui,
-    -apple-system,
-    BlinkMacSystemFont,
-    '.SFNSText-Regular',
+  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
     sans-serif;
   font-weight: 500;
   -webkit-font-smoothing: antialiased;
diff --git a/examples/react-table/index.html b/examples/react-table/index.html
index 2f73f6bbf24..8243eabc6b9 100644
--- a/examples/react-table/index.html
+++ b/examples/react-table/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/react-table/src/styles.css b/examples/react-table/src/styles.css
index a6dd01a6fd7..32b80315539 100644
--- a/examples/react-table/src/styles.css
+++ b/examples/react-table/src/styles.css
@@ -9,11 +9,7 @@
 body {
   margin: 0;
   background: #eee;
-  font-family:
-    system-ui,
-    -apple-system,
-    BlinkMacSystemFont,
-    '.SFNSText-Regular',
+  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
     sans-serif;
   font-weight: 500;
   -webkit-font-smoothing: antialiased;
diff --git a/examples/vanilla-js-iframe/index.html b/examples/vanilla-js-iframe/index.html
index 41e6c0c674a..a730616c401 100644
--- a/examples/vanilla-js-iframe/index.html
+++ b/examples/vanilla-js-iframe/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/vanilla-js-plugin/index.html b/examples/vanilla-js-plugin/index.html
index 8b639835237..ef397bcc4d1 100644
--- a/examples/vanilla-js-plugin/index.html
+++ b/examples/vanilla-js-plugin/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/examples/vanilla-js/index.html b/examples/vanilla-js/index.html
index 396a39da2d9..23cdfeba208 100644
--- a/examples/vanilla-js/index.html
+++ b/examples/vanilla-js/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/packages/lexical-devtools-core/src/generateContent.ts b/packages/lexical-devtools-core/src/generateContent.ts
index 89a0eb7178d..5e431558d26 100644
--- a/packages/lexical-devtools-core/src/generateContent.ts
+++ b/packages/lexical-devtools-core/src/generateContent.ts
@@ -145,10 +145,10 @@ export function generateContent(
     return selection === null
       ? ': null'
       : $isRangeSelection(selection)
-        ? printRangeSelection(selection)
-        : $isTableSelection(selection)
-          ? printTableSelection(selection)
-          : printNodeSelection(selection);
+      ? printRangeSelection(selection)
+      : $isTableSelection(selection)
+      ? printTableSelection(selection)
+      : printNodeSelection(selection);
   });
 
   res += '\n selection' + selectionString;
diff --git a/packages/lexical-devtools/safari-xcode/Lexical Developer Tools/Lexical Developer Tools/Base.lproj/Main.html b/packages/lexical-devtools/safari-xcode/Lexical Developer Tools/Lexical Developer Tools/Base.lproj/Main.html
index d76d438dbfc..105450678fa 100644
--- a/packages/lexical-devtools/safari-xcode/Lexical Developer Tools/Lexical Developer Tools/Base.lproj/Main.html	
+++ b/packages/lexical-devtools/safari-xcode/Lexical Developer Tools/Lexical Developer Tools/Base.lproj/Main.html	
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html>
   <head>
     <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
diff --git a/packages/lexical-devtools/src/entrypoints/devtools-panel/index.html b/packages/lexical-devtools/src/entrypoints/devtools-panel/index.html
index 9986ce8289b..7db58aef1f0 100644
--- a/packages/lexical-devtools/src/entrypoints/devtools-panel/index.html
+++ b/packages/lexical-devtools/src/entrypoints/devtools-panel/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/packages/lexical-devtools/src/entrypoints/devtools/index.html b/packages/lexical-devtools/src/entrypoints/devtools/index.html
index 6e4ffeb705f..b9a88d871cf 100644
--- a/packages/lexical-devtools/src/entrypoints/devtools/index.html
+++ b/packages/lexical-devtools/src/entrypoints/devtools/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/packages/lexical-devtools/src/entrypoints/popup/index.html b/packages/lexical-devtools/src/entrypoints/popup/index.html
index fffc2284f9f..68dd7ec9dc5 100644
--- a/packages/lexical-devtools/src/entrypoints/popup/index.html
+++ b/packages/lexical-devtools/src/entrypoints/popup/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
diff --git a/packages/lexical-headless/src/index.ts b/packages/lexical-headless/src/index.ts
index 04a18d356b7..2b8eddb8ed3 100644
--- a/packages/lexical-headless/src/index.ts
+++ b/packages/lexical-headless/src/index.ts
@@ -33,7 +33,7 @@ export function createHeadlessEditor(
     'blur',
   ] as const;
 
-  unsupportedMethods.forEach((method: (typeof unsupportedMethods)[number]) => {
+  unsupportedMethods.forEach((method: typeof unsupportedMethods[number]) => {
     editor[method] = () => {
       throw new Error(`${method} is not supported in headless mode`);
     };
diff --git a/packages/lexical-list/src/LexicalListItemNode.ts b/packages/lexical-list/src/LexicalListItemNode.ts
index 0f03bf5701a..757d706715b 100644
--- a/packages/lexical-list/src/LexicalListItemNode.ts
+++ b/packages/lexical-list/src/LexicalListItemNode.ts
@@ -563,8 +563,8 @@ function $convertListItemElement(domNode: HTMLElement): DOMConversionOutput {
     ariaCheckedAttr === 'true'
       ? true
       : ariaCheckedAttr === 'false'
-        ? false
-        : undefined;
+      ? false
+      : undefined;
   return {node: $createListItemNode(checked)};
 }
 
diff --git a/packages/lexical-markdown/src/MarkdownTransformers.ts b/packages/lexical-markdown/src/MarkdownTransformers.ts
index 21ba7642a65..f22067abc0c 100644
--- a/packages/lexical-markdown/src/MarkdownTransformers.ts
+++ b/packages/lexical-markdown/src/MarkdownTransformers.ts
@@ -299,8 +299,8 @@ const listExport = (
         listType === 'number'
           ? `${listNode.getStart() + index}. `
           : listType === 'check'
-            ? `- [${listItemNode.getChecked() ? 'x' : ' '}] `
-            : '- ';
+          ? `- [${listItemNode.getChecked() ? 'x' : ' '}] `
+          : '- ';
       output.push(indent + prefix + exportChildren(listItemNode));
       index++;
     }
diff --git a/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/ListsHTMLCopyAndPaste.spec.mjs b/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/ListsHTMLCopyAndPaste.spec.mjs
index 87af282c4e0..8d695141c17 100644
--- a/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/ListsHTMLCopyAndPaste.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/ListsHTMLCopyAndPaste.spec.mjs
@@ -322,8 +322,9 @@ test.describe('HTML Lists CopyAndPaste', () => {
     await focusEditor(page);
 
     // Ensure we preserve checked status.
-    clipboard['text/html'] =
-      `<meta charset='utf-8'><ul __lexicallisttype="check"><li role="checkbox" tabindex="-1" aria-checked="true" value="1" class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__listItemChecked"><span>Hello</span></li><li role="checkbox" tabindex="-1" aria-checked="false" value="2" class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__listItemUnchecked"><span>world</span></li></ul>`;
+    clipboard[
+      'text/html'
+    ] = `<meta charset='utf-8'><ul __lexicallisttype="check"><li role="checkbox" tabindex="-1" aria-checked="true" value="1" class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__listItemChecked"><span>Hello</span></li><li role="checkbox" tabindex="-1" aria-checked="false" value="2" class="PlaygroundEditorTheme__listItem PlaygroundEditorTheme__listItemUnchecked"><span>world</span></li></ul>`;
 
     await pasteFromClipboard(page, clipboard);
 
diff --git a/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs b/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs
index 6b8c6517948..ba54a73aae1 100644
--- a/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs
@@ -25,9 +25,13 @@ test.describe('Extensions', () => {
   test(`document.execCommand("insertText")`, async ({page}) => {
     await focusEditor(page);
 
-    await evaluate(page, () => {
-      document.execCommand('insertText', false, 'foo');
-    }, []);
+    await evaluate(
+      page,
+      () => {
+        document.execCommand('insertText', false, 'foo');
+      },
+      [],
+    );
     await assertHTML(
       page,
       html`
@@ -54,27 +58,31 @@ test.describe('Extensions', () => {
     }
     await focusEditor(page);
 
-    await evaluate(page, () => {
-      function paste() {
-        const dataTransfer = new DataTransfer();
-        function dispatchPaste(target, text) {
-          dataTransfer.setData('text/plain', text);
-          target.dispatchEvent(
-            new ClipboardEvent('paste', {
-              bubbles: true,
-              cancelable: true,
-              clipboardData: dataTransfer,
-            }),
-          );
-          dataTransfer.clearData();
+    await evaluate(
+      page,
+      () => {
+        function paste() {
+          const dataTransfer = new DataTransfer();
+          function dispatchPaste(target, text) {
+            dataTransfer.setData('text/plain', text);
+            target.dispatchEvent(
+              new ClipboardEvent('paste', {
+                bubbles: true,
+                cancelable: true,
+                clipboardData: dataTransfer,
+              }),
+            );
+            dataTransfer.clearData();
+          }
+          return dispatchPaste;
         }
-        return dispatchPaste;
-      }
 
-      const editor = document.querySelector('div[contenteditable="true"]');
-      const dispatchPaste = paste();
-      dispatchPaste(editor, 'foo');
-    }, []);
+        const editor = document.querySelector('div[contenteditable="true"]');
+        const dispatchPaste = paste();
+        dispatchPaste(editor, 'foo');
+      },
+      [],
+    );
     await assertHTML(
       page,
       html`
@@ -206,25 +214,29 @@ test.describe('Extensions', () => {
     await page.keyboard.press('ArrowUp');
 
     // Selection is on the last paragraph
-    await evaluate(page, async () => {
-      const editor = document.querySelector('div[contenteditable="true"]');
-      const selection = window.getSelection();
-      const secondParagraphTextNode =
-        editor.firstChild.nextSibling.firstChild.firstChild;
-      selection.setBaseAndExtent(
-        secondParagraphTextNode,
-        0,
-        secondParagraphTextNode,
-        3,
-      );
+    await evaluate(
+      page,
+      async () => {
+        const editor = document.querySelector('div[contenteditable="true"]');
+        const selection = window.getSelection();
+        const secondParagraphTextNode =
+          editor.firstChild.nextSibling.firstChild.firstChild;
+        selection.setBaseAndExtent(
+          secondParagraphTextNode,
+          0,
+          secondParagraphTextNode,
+          3,
+        );
 
-      await new Promise((resolve) => {
-        setTimeout(() => {
-          document.execCommand('insertText', false, 'and');
-          resolve();
-        }, 50);
-      });
-    }, []);
+        await new Promise((resolve) => {
+          setTimeout(() => {
+            document.execCommand('insertText', false, 'and');
+            resolve();
+          }, 50);
+        });
+      },
+      [],
+    );
     await assertHTML(
       page,
       html`
@@ -266,9 +278,13 @@ test.describe('Extensions', () => {
       focusPath: [0, 0, 0],
     });
 
-    await evaluate(page, () => {
-      document.execCommand('insertText', false, 'New text');
-    }, []);
+    await evaluate(
+      page,
+      () => {
+        document.execCommand('insertText', false, 'New text');
+      },
+      [],
+    );
     await assertHTML(
       page,
       html`
@@ -305,9 +321,13 @@ test.describe('Extensions', () => {
       focusPath: [0, 0, 0],
     });
 
-    await evaluate(page, () => {
-      document.execCommand('insertText', false, 'New text');
-    }, []);
+    await evaluate(
+      page,
+      () => {
+        document.execCommand('insertText', false, 'New text');
+      },
+      [],
+    );
     await assertHTML(
       page,
       html`
diff --git a/packages/lexical-playground/__tests__/e2e/Links.spec.mjs b/packages/lexical-playground/__tests__/e2e/Links.spec.mjs
index 22a271cd360..98fa7139d48 100644
--- a/packages/lexical-playground/__tests__/e2e/Links.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/Links.spec.mjs
@@ -741,8 +741,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                  ? clipboardData.html
-                  : clipboardData.lexical;
+                ? clipboardData.html
+                : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -818,8 +818,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                  ? clipboardData.html
-                  : clipboardData.lexical;
+                ? clipboardData.html
+                : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -892,8 +892,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                  ? clipboardData.html
-                  : clipboardData.lexical;
+                ? clipboardData.html
+                : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -970,8 +970,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                  ? clipboardData.html
-                  : clipboardData.lexical;
+                ? clipboardData.html
+                : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -1046,8 +1046,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                  ? clipboardData.html
-                  : clipboardData.lexical;
+                ? clipboardData.html
+                : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
@@ -1122,8 +1122,8 @@ test.describe.parallel('Links', () => {
               insertMethod === 'paste:plain'
                 ? clipboardData.plain
                 : insertMethod === 'paste:html'
-                  ? clipboardData.html
-                  : clipboardData.lexical;
+                ? clipboardData.html
+                : clipboardData.lexical;
             await pasteFromClipboard(page, data);
           }
 
diff --git a/packages/lexical-playground/esm/index.html b/packages/lexical-playground/esm/index.html
index 08dbd4a342a..211ce77ab43 100644
--- a/packages/lexical-playground/esm/index.html
+++ b/packages/lexical-playground/esm/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="utf-8" />
diff --git a/packages/lexical-playground/index.html b/packages/lexical-playground/index.html
index 7b546d00562..d810340cd24 100644
--- a/packages/lexical-playground/index.html
+++ b/packages/lexical-playground/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="utf-8" />
diff --git a/packages/lexical-playground/split/index.html b/packages/lexical-playground/split/index.html
index e800b478d9f..d98f0a12996 100644
--- a/packages/lexical-playground/split/index.html
+++ b/packages/lexical-playground/split/index.html
@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
   <head>
     <meta charset="utf-8" />
diff --git a/packages/lexical-playground/src/App.tsx b/packages/lexical-playground/src/App.tsx
index 5ab43df6e92..d667ed12c32 100644
--- a/packages/lexical-playground/src/App.tsx
+++ b/packages/lexical-playground/src/App.tsx
@@ -197,8 +197,8 @@ function App(): JSX.Element {
     editorState: isCollab
       ? null
       : emptyEditor
-        ? undefined
-        : $prepopulatedRichText,
+      ? undefined
+      : $prepopulatedRichText,
     html: {import: buildImportMap()},
     namespace: 'Playground',
     nodes: [...PlaygroundNodes],
diff --git a/packages/lexical-playground/src/Editor.tsx b/packages/lexical-playground/src/Editor.tsx
index d3939b4b285..2b97ddd63ac 100644
--- a/packages/lexical-playground/src/Editor.tsx
+++ b/packages/lexical-playground/src/Editor.tsx
@@ -106,8 +106,8 @@ export default function Editor(): JSX.Element {
   const placeholder = isCollab
     ? 'Enter some collaborative rich text...'
     : isRichText
-      ? 'Enter some rich text...'
-      : 'Enter some plain text...';
+    ? 'Enter some rich text...'
+    : 'Enter some plain text...';
   const [floatingAnchorElem, setFloatingAnchorElem] =
     useState<HTMLDivElement | null>(null);
   const [isSmallWidthViewport, setIsSmallWidthViewport] =
diff --git a/packages/lexical-playground/src/index.css b/packages/lexical-playground/src/index.css
index 1b9c3986c28..90c3841900d 100644
--- a/packages/lexical-playground/src/index.css
+++ b/packages/lexical-playground/src/index.css
@@ -10,11 +10,7 @@
 
 body {
   margin: 0;
-  font-family:
-    system-ui,
-    -apple-system,
-    BlinkMacSystemFont,
-    '.SFNSText-Regular',
+  font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
     sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
@@ -761,9 +757,7 @@ i.page-break,
   z-index: 100;
   display: block;
   position: fixed;
-  box-shadow:
-    0 12px 28px 0 rgba(0, 0, 0, 0.2),
-    0 2px 4px 0 rgba(0, 0, 0, 0.1),
+  box-shadow: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1),
     inset 0 0 0 1px rgba(255, 255, 255, 0.5);
   border-radius: 8px;
   min-height: 40px;
diff --git a/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx b/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx
index 025e877e858..e1a05a61ec8 100644
--- a/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx
+++ b/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx
@@ -346,8 +346,8 @@ function TableCellResizer({editor}: {editor: LexicalEditor}): JSX.Element {
 
   const toggleResize = useCallback(
     (
-      direction: PointerDraggingDirection,
-    ): PointerEventHandler<HTMLDivElement> =>
+        direction: PointerDraggingDirection,
+      ): PointerEventHandler<HTMLDivElement> =>
       (event) => {
         event.preventDefault();
         event.stopPropagation();
diff --git a/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx
index 9f22f494d77..e8d3256a590 100644
--- a/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx
+++ b/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx
@@ -171,7 +171,8 @@ function TableOfContentsList({
                   <li
                     className={`normal-heading ${
                       selectedKey === key ? 'selected-heading' : ''
-                    } `}>
+                    }
+                    `}>
                     {('' + text).length > 27
                       ? text.substring(0, 27) + '...'
                       : text}
diff --git a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
index d08dc79548f..44f353bcb31 100644
--- a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
+++ b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
@@ -597,8 +597,8 @@ export default function ToolbarPlugin({
         $isElementNode(matchingParent)
           ? matchingParent.getFormatType()
           : $isElementNode(node)
-            ? node.getFormatType()
-            : parent?.getFormatType() || 'left',
+          ? node.getFormatType()
+          : parent?.getFormatType() || 'left',
       );
     }
     if ($isRangeSelection(selection) || $isTableSelection(selection)) {
diff --git a/packages/lexical-playground/src/ui/ColorPicker.css b/packages/lexical-playground/src/ui/ColorPicker.css
index a10c5b8243f..63217ba3784 100644
--- a/packages/lexical-playground/src/ui/ColorPicker.css
+++ b/packages/lexical-playground/src/ui/ColorPicker.css
@@ -36,8 +36,7 @@
   position: relative;
   margin-top: 15px;
   height: 150px;
-  background-image:
-    linear-gradient(transparent, black),
+  background-image: linear-gradient(transparent, black),
     linear-gradient(to right, white, transparent);
   user-select: none;
 }
diff --git a/packages/lexical-playground/src/ui/ColorPicker.tsx b/packages/lexical-playground/src/ui/ColorPicker.tsx
index d647a700211..6593c02389f 100644
--- a/packages/lexical-playground/src/ui/ColorPicker.tsx
+++ b/packages/lexical-playground/src/ui/ColorPicker.tsx
@@ -124,7 +124,7 @@ export default function ColorPicker({
       <div className="color-picker-basic-color">
         {basicColors.map((basicColor) => (
           <button
-            className={basicColor === selfColor.hex ? 'active' : ''}
+            className={basicColor === selfColor.hex ? ' active' : ''}
             key={basicColor}
             style={{backgroundColor: basicColor}}
             onClick={() => {
@@ -307,8 +307,8 @@ function rgb2hsv({r, g, b}: RGB): HSV {
     ? (max === r
         ? (g - b) / d + (g < b ? 6 : 0)
         : max === g
-          ? 2 + (b - r) / d
-          : 4 + (r - g) / d) * 60
+        ? 2 + (b - r) / d
+        : 4 + (r - g) / d) * 60
     : 0;
   const s = max ? (d / max) * 100 : 0;
   const v = max * 100;
diff --git a/packages/lexical-playground/src/ui/ExcalidrawModal.css b/packages/lexical-playground/src/ui/ExcalidrawModal.css
index 6e83f9e759a..7438d60ecae 100644
--- a/packages/lexical-playground/src/ui/ExcalidrawModal.css
+++ b/packages/lexical-playground/src/ui/ExcalidrawModal.css
@@ -38,9 +38,7 @@
   width: 70vw;
   height: 70vh;
   border-radius: 8px;
-  box-shadow:
-    0 12px 28px 0 rgba(0, 0, 0, 0.2),
-    0 2px 4px 0 rgba(0, 0, 0, 0.1),
+  box-shadow: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1),
     inset 0 0 0 1px rgba(255, 255, 255, 0.5);
 }
 .ExcalidrawModal__row > div {
diff --git a/packages/lexical-playground/src/ui/ImageResizer.tsx b/packages/lexical-playground/src/ui/ImageResizer.tsx
index e38afdcafb1..e2c52ebfbc9 100644
--- a/packages/lexical-playground/src/ui/ImageResizer.tsx
+++ b/packages/lexical-playground/src/ui/ImageResizer.tsx
@@ -76,8 +76,8 @@ export default function ImageResizer({
   const maxWidthContainer = maxWidth
     ? maxWidth
     : editorRootElement !== null
-      ? editorRootElement.getBoundingClientRect().width - 20
-      : 100;
+    ? editorRootElement.getBoundingClientRect().width - 20
+    : 100;
   const maxHeightContainer =
     editorRootElement !== null
       ? editorRootElement.getBoundingClientRect().height - 20
diff --git a/packages/lexical-selection/src/lexical-node.ts b/packages/lexical-selection/src/lexical-node.ts
index 404f81400a4..91b5d9a3df3 100644
--- a/packages/lexical-selection/src/lexical-node.ts
+++ b/packages/lexical-selection/src/lexical-node.ts
@@ -269,8 +269,8 @@ export function $patchStyle(
     $isRangeSelection(target)
       ? target.style
       : $isTextNode(target)
-        ? target.getStyle()
-        : target.getTextStyle(),
+      ? target.getStyle()
+      : target.getTextStyle(),
   );
   const newStyles = Object.entries(patch).reduce<Record<string, string>>(
     (styles, [key, value]) => {
diff --git a/packages/lexical-table/src/LexicalTableCellNode.ts b/packages/lexical-table/src/LexicalTableCellNode.ts
index 9ba1a49947c..987ba11d51d 100644
--- a/packages/lexical-table/src/LexicalTableCellNode.ts
+++ b/packages/lexical-table/src/LexicalTableCellNode.ts
@@ -41,7 +41,7 @@ export const TableCellHeaderStates = {
 };
 
 export type TableCellHeaderState =
-  (typeof TableCellHeaderStates)[keyof typeof TableCellHeaderStates];
+  typeof TableCellHeaderStates[keyof typeof TableCellHeaderStates];
 
 export type SerializedTableCellNode = Spread<
   {
diff --git a/packages/lexical-yjs/src/SyncCursors.ts b/packages/lexical-yjs/src/SyncCursors.ts
index 21dd80a573b..31cf7010c6d 100644
--- a/packages/lexical-yjs/src/SyncCursors.ts
+++ b/packages/lexical-yjs/src/SyncCursors.ts
@@ -277,8 +277,9 @@ function updateCursor(
     const style = `position:absolute;top:${top}px;left:${left}px;height:${selectionRect.height}px;width:${selectionRect.width}px;pointer-events:none;z-index:5;`;
     selection.style.cssText = style;
 
-    (selection.firstChild as HTMLSpanElement).style.cssText =
-      `${style}left:0;top:0;background-color:${color};opacity:0.3;`;
+    (
+      selection.firstChild as HTMLSpanElement
+    ).style.cssText = `${style}left:0;top:0;background-color:${color};opacity:0.3;`;
 
     if (i === selectionRectsLength - 1) {
       if (caret.parentNode !== selection) {
diff --git a/packages/lexical/src/LexicalEditor.ts b/packages/lexical/src/LexicalEditor.ts
index 7f8e4f9f2dc..c4b0be353d7 100644
--- a/packages/lexical/src/LexicalEditor.ts
+++ b/packages/lexical/src/LexicalEditor.ts
@@ -58,10 +58,11 @@ export type KlassConstructor<Cls extends GenericConstructor<any>> =
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 type GenericConstructor<T> = new (...args: any[]) => T;
 
-export type Klass<T extends LexicalNode> =
-  InstanceType<T['constructor']> extends T
-    ? T['constructor']
-    : GenericConstructor<T> & T['constructor'];
+export type Klass<T extends LexicalNode> = InstanceType<
+  T['constructor']
+> extends T
+  ? T['constructor']
+  : GenericConstructor<T> & T['constructor'];
 
 export type EditorThemeClassName = string;
 
diff --git a/packages/lexical/src/LexicalNodeState.ts b/packages/lexical/src/LexicalNodeState.ts
index 6129b344006..d0b746e715c 100644
--- a/packages/lexical/src/LexicalNodeState.ts
+++ b/packages/lexical/src/LexicalNodeState.ts
@@ -75,13 +75,21 @@ export type AnyStateConfig = StateConfig<any, any>;
 /**
  * Get the value type (V) from a StateConfig
  */
-export type StateConfigValue<S extends AnyStateConfig> =
-  S extends StateConfig<infer _K, infer V> ? V : never;
+export type StateConfigValue<S extends AnyStateConfig> = S extends StateConfig<
+  infer _K,
+  infer V
+>
+  ? V
+  : never;
 /**
  * Get the key type (K) from a StateConfig
  */
-export type StateConfigKey<S extends AnyStateConfig> =
-  S extends StateConfig<infer K, infer _V> ? K : never;
+export type StateConfigKey<S extends AnyStateConfig> = S extends StateConfig<
+  infer K,
+  infer _V
+>
+  ? K
+  : never;
 /**
  * A value type, or an updater for that value type. For use with
  * {@link $setState} or any user-defined wrappers around it.
diff --git a/packages/lexical/src/LexicalReconciler.ts b/packages/lexical/src/LexicalReconciler.ts
index af97f01b100..0bff573024c 100644
--- a/packages/lexical/src/LexicalReconciler.ts
+++ b/packages/lexical/src/LexicalReconciler.ts
@@ -303,8 +303,8 @@ function isLastChildLineBreakOrDecorator(
         return $isLineBreakNode(node)
           ? 'line-break'
           : $isDecoratorNode(node) && node.isInline()
-            ? 'decorator'
-            : null;
+          ? 'decorator'
+          : null;
       }
     }
     return 'empty';
diff --git a/packages/lexical/src/LexicalSelection.ts b/packages/lexical/src/LexicalSelection.ts
index 5a29cfd56d5..96e4634db8d 100644
--- a/packages/lexical/src/LexicalSelection.ts
+++ b/packages/lexical/src/LexicalSelection.ts
@@ -3075,8 +3075,8 @@ export function updateDOMSelection(
         ? (nextAnchorNode.childNodes[nextAnchorOffset] as HTMLElement | Text) ||
           null
         : domSelection.rangeCount > 0
-          ? domSelection.getRangeAt(0)
-          : null;
+        ? domSelection.getRangeAt(0)
+        : null;
     if (selectionTarget !== null) {
       let selectionRect: DOMRect;
       if (selectionTarget instanceof Text) {
diff --git a/packages/lexical/src/LexicalUpdates.ts b/packages/lexical/src/LexicalUpdates.ts
index 0e1012e4e88..fb151f5fb7f 100644
--- a/packages/lexical/src/LexicalUpdates.ts
+++ b/packages/lexical/src/LexicalUpdates.ts
@@ -133,7 +133,7 @@ function collectBuildInformation(): string {
       } else if (editor) {
         let version = String(
           (
-            editor.constructor as (typeof editor)['constructor'] &
+            editor.constructor as typeof editor['constructor'] &
               Record<string, unknown>
           ).version || '<0.17.1',
         );
diff --git a/packages/lexical/src/LexicalUtils.ts b/packages/lexical/src/LexicalUtils.ts
index 8ed1031c145..691b4be0bcc 100644
--- a/packages/lexical/src/LexicalUtils.ts
+++ b/packages/lexical/src/LexicalUtils.ts
@@ -1333,8 +1333,8 @@ export function getDOMOwnerDocument(
   return isDOMDocumentNode(target)
     ? target
     : isHTMLElement(target)
-      ? target.ownerDocument
-      : null;
+    ? target.ownerDocument
+    : null;
 }
 
 export function scrollIntoViewIfNeeded(
diff --git a/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts b/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts
index d06211b6ba4..0a47cd24477 100644
--- a/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts
+++ b/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts
@@ -27,10 +27,11 @@ import {TestNode} from './LexicalNode.test';
 
 // https://www.totaltypescript.com/how-to-test-your-types
 type Expect<T extends true> = T;
-type Equal<X, Y> =
-  (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
-    ? true
-    : false;
+type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
+  ? 1
+  : 2
+  ? true
+  : false;
 
 const numberState = createState('numberState', {
   parse: (v) => (typeof v === 'number' ? v : 0),
diff --git a/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts b/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts
index f2fdf226f8c..b936c3d346a 100644
--- a/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts
+++ b/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts
@@ -88,8 +88,8 @@ describe('LexicalSelection tests', () => {
           mode === 'start-of-paragraph'
             ? '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><a href="https://" dir="ltr"><span data-lexical-text="true">a</span></a><span data-lexical-text="true">b</span></p></div>'
             : mode === 'mid-paragraph'
-              ? '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">a</span><a href="https://" dir="ltr"><span data-lexical-text="true">b</span></a><span data-lexical-text="true">c</span></p></div>'
-              : '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">a</span><a href="https://" dir="ltr"><span data-lexical-text="true">b</span></a></p></div>';
+            ? '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">a</span><a href="https://" dir="ltr"><span data-lexical-text="true">b</span></a><span data-lexical-text="true">c</span></p></div>'
+            : '<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">a</span><a href="https://" dir="ltr"><span data-lexical-text="true">b</span></a></p></div>';
 
         expect(container.innerHTML).toBe(expectation);
 
diff --git a/packages/lexical/src/caret/LexicalCaret.ts b/packages/lexical/src/caret/LexicalCaret.ts
index 5389c7970a3..c1af5986087 100644
--- a/packages/lexical/src/caret/LexicalCaret.ts
+++ b/packages/lexical/src/caret/LexicalCaret.ts
@@ -22,8 +22,7 @@ export type CaretDirection = 'next' | 'previous';
 /**
  * A type utility to flip next and previous
  */
-export type FlipDirection<D extends CaretDirection> =
-  (typeof FLIP_DIRECTION)[D];
+export type FlipDirection<D extends CaretDirection> = typeof FLIP_DIRECTION[D];
 /**
  * A sibling caret type points from a LexicalNode origin to its next or previous sibling,
  * and a child caret type points from an ElementNode origin to its first or last child.
@@ -1236,14 +1235,14 @@ export function $comparePointCaretNext(
       return aIsText && bIsText
         ? compareNumber(a.offset, b.offset)
         : a.type === b.type
-          ? 0
-          : aIsText
-            ? -1
-            : bIsText
-              ? 1
-              : a.type === 'child'
-                ? -1
-                : 1;
+        ? 0
+        : aIsText
+        ? -1
+        : bIsText
+        ? 1
+        : a.type === 'child'
+        ? -1
+        : 1;
     }
     case 'ancestor': {
       return a.type === 'child' ? -1 : 1;
diff --git a/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts b/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
index 3ec82345db6..40886b1533c 100644
--- a/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
+++ b/packages/lexical/src/caret/__tests__/unit/LexicalCaret.test.ts
@@ -1205,8 +1205,8 @@ describe('LexicalCaret', () => {
                     anchorBias === 'outside' && focusBias === 'outside'
                       ? []
                       : (anchorBias === 'inside') === (direction === 'next')
-                        ? [{caret: {offset: 0}, distance: size}]
-                        : [{caret: {offset: size}, distance: -size}],
+                      ? [{caret: {offset: 0}, distance: size}]
+                      : [{caret: {offset: size}, distance: -size}],
                   );
                   const resultRange = $removeTextFromCaretRange(range);
                   $setSelection(null);
diff --git a/packages/shared/lexicalMonorepoPlugin.ts b/packages/shared/lexicalMonorepoPlugin.ts
index 458d0e0e60c..fd0660304a8 100644
--- a/packages/shared/lexicalMonorepoPlugin.ts
+++ b/packages/shared/lexicalMonorepoPlugin.ts
@@ -26,8 +26,8 @@ export default function lexicalMonorepoPlugin(): Plugin {
               env.mode === 'production'
                 ? 'production'
                 : env.command === 'serve'
-                  ? 'source'
-                  : 'development',
+                ? 'source'
+                : 'development',
             ),
           },
         }),
diff --git a/scripts/lint-flow-types.js b/scripts/lint-flow-types.js
index b61d89ac4d4..eb6804a6740 100644
--- a/scripts/lint-flow-types.js
+++ b/scripts/lint-flow-types.js
@@ -47,8 +47,8 @@ function collectFlowExports(flowAst) {
       node.type === 'Identifier'
         ? node
         : 'id' in node && node.id.type === 'Identifier'
-          ? node.id
-          : null;
+        ? node.id
+        : null;
     if (identifier) {
       exportNames.set(identifier.name, identifier);
       return true;

From 219e692c4ea10acdcc7d231848e427b579a2d67c Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 12:34:15 -0700
Subject: [PATCH 09/10] Revert "update prettier"

This reverts commit f13380c9918c2950c1dcd0f7060b13c4229e8061.
---
 .eslintignore                                 |   1 -
 .prettierignore                               |   1 -
 package-lock.json                             | 157 +++++++++---------
 package.json                                  |   8 +-
 .../__tests__/unit/rules-of-lexical.test.ts   |   4 +-
 packages/lexical-list/src/__tests__/utils.ts  |   4 +-
 .../__tests__/utils/index.mjs                 |   2 +-
 packages/lexical-playground/package.json      |   2 +-
 packages/lexical-website/package.json         |   2 +-
 .../lexical/src/__tests__/utils/index.tsx     |   6 +-
 .../unit/transform-error-messages.test.js     |  14 +-
 .../error-codes/transform-error-messages.js   |   6 +-
 12 files changed, 97 insertions(+), 110 deletions(-)

diff --git a/.eslintignore b/.eslintignore
index 5b987a70346..568a2cf9313 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -13,4 +13,3 @@
 **/.docusaurus
 /playwright-report
 test-results
-/libdefs/*.js
diff --git a/.prettierignore b/.prettierignore
index 0e75361aeac..580080b429f 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -23,4 +23,3 @@ flow-typed
 **/.docusaurus
 /playwright-report
 test-results
-/libdefs/*.js
diff --git a/package-lock.json b/package-lock.json
index 80fc0981e68..2593e2c90b8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,6 @@
         "packages/*"
       ],
       "dependencies": {
-        "@prettier/sync": "^0.5.2",
         "yjs": "^13.5.42"
       },
       "devDependencies": {
@@ -36,6 +35,7 @@
         "@types/jsdom": "^21.1.6",
         "@types/katex": "^0.16.7",
         "@types/node": "^17.0.31",
+        "@types/prettier": "^2.7.3",
         "@types/prismjs": "^1.26.0",
         "@types/proper-lockfile": "^4.1.4",
         "@types/react": "^18.0.8",
@@ -79,10 +79,10 @@
         "lint-staged": "^11.1.0",
         "minimist": "^1.2.5",
         "npm-run-all": "^4.1.5",
-        "prettier": "^3.5.3",
+        "prettier": "^2.3.2",
         "prettier-plugin-hermes-parser": "^0.26.0",
-        "prettier-plugin-organize-attributes": "^1.0.0",
-        "prettier-plugin-tailwindcss": "^0.6.11",
+        "prettier-plugin-organize-attributes": "^0.0.5",
+        "prettier-plugin-tailwindcss": "^0.4.1",
         "proper-lockfile": "^4.1.2",
         "react-test-renderer": "^17.0.2",
         "rollup": "^4.22.4",
@@ -7786,20 +7786,6 @@
         "url": "https://opencollective.com/popperjs"
       }
     },
-    "node_modules/@prettier/sync": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.5.2.tgz",
-      "integrity": "sha512-Yb569su456XNx5BsH/Vyem7xD6g/y9iLmLUzRKM1a/dhU/D7HqqvkAG72znulXlMXztbV0iiu9O5AL8K98TzZQ==",
-      "dependencies": {
-        "make-synchronized": "^0.2.8"
-      },
-      "funding": {
-        "url": "https://github.com/prettier/prettier-synchronized?sponsor=1"
-      },
-      "peerDependencies": {
-        "prettier": "*"
-      }
-    },
     "node_modules/@radix-ui/primitive": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
@@ -10072,6 +10058,12 @@
       "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
       "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw=="
     },
+    "node_modules/@types/prettier": {
+      "version": "2.7.3",
+      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz",
+      "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==",
+      "dev": true
+    },
     "node_modules/@types/prismjs": {
       "version": "1.26.0",
       "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz",
@@ -25700,14 +25692,6 @@
       "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
       "dev": true
     },
-    "node_modules/make-synchronized": {
-      "version": "0.2.9",
-      "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.2.9.tgz",
-      "integrity": "sha512-4wczOs8SLuEdpEvp3vGo83wh8rjJ78UsIk7DIX5fxdfmfMJGog4bQzxfvOwq7Q3yCHLC4jp1urPHIxRS/A93gA==",
-      "funding": {
-        "url": "https://github.com/fisker/make-synchronized?sponsor=1"
-      }
-    },
     "node_modules/makeerror": {
       "version": "1.0.12",
       "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
@@ -32037,14 +32021,15 @@
       }
     },
     "node_modules/prettier": {
-      "version": "3.5.3",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
-      "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+      "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+      "dev": true,
       "bin": {
-        "prettier": "bin/prettier.cjs"
+        "prettier": "bin-prettier.js"
       },
       "engines": {
-        "node": ">=14"
+        "node": ">=10.13.0"
       },
       "funding": {
         "url": "https://github.com/prettier/prettier?sponsor=1"
@@ -32065,43 +32050,42 @@
       }
     },
     "node_modules/prettier-plugin-organize-attributes": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-1.0.0.tgz",
-      "integrity": "sha512-+NmameaLxbCcylEXsKPmawtzla5EE6ECqvGkpfQz4KM847fXDifB1gFnPQEpoADAq6IXg+cMI8Z0ISJEXa6fhg==",
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-0.0.5.tgz",
+      "integrity": "sha512-dSts16q8wd+oq8Zwk5mwmYXo1aN3B+ZkEJqx/ar5fedNHdOvx7S4XDMH/pNK7rmBW0bPXkp/kJX5gAANsWzh3A==",
       "dev": true,
       "engines": {
-        "node": ">=14.0.0"
+        "node": ">=11.0.0"
       },
       "peerDependencies": {
-        "prettier": "^3.0.0"
+        "prettier": "^2.0.0"
       }
     },
     "node_modules/prettier-plugin-tailwindcss": {
-      "version": "0.6.11",
-      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.11.tgz",
-      "integrity": "sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==",
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz",
+      "integrity": "sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==",
       "dev": true,
       "engines": {
-        "node": ">=14.21.3"
+        "node": ">=12.17.0"
       },
       "peerDependencies": {
         "@ianvs/prettier-plugin-sort-imports": "*",
         "@prettier/plugin-pug": "*",
         "@shopify/prettier-plugin-liquid": "*",
+        "@shufo/prettier-plugin-blade": "*",
         "@trivago/prettier-plugin-sort-imports": "*",
-        "@zackad/prettier-plugin-twig": "*",
-        "prettier": "^3.0",
+        "prettier": "^2.2 || ^3.0",
         "prettier-plugin-astro": "*",
         "prettier-plugin-css-order": "*",
         "prettier-plugin-import-sort": "*",
         "prettier-plugin-jsdoc": "*",
         "prettier-plugin-marko": "*",
-        "prettier-plugin-multiline-arrays": "*",
         "prettier-plugin-organize-attributes": "*",
         "prettier-plugin-organize-imports": "*",
-        "prettier-plugin-sort-imports": "*",
         "prettier-plugin-style-order": "*",
-        "prettier-plugin-svelte": "*"
+        "prettier-plugin-svelte": "*",
+        "prettier-plugin-twig-melody": "*"
       },
       "peerDependenciesMeta": {
         "@ianvs/prettier-plugin-sort-imports": {
@@ -32113,10 +32097,10 @@
         "@shopify/prettier-plugin-liquid": {
           "optional": true
         },
-        "@trivago/prettier-plugin-sort-imports": {
+        "@shufo/prettier-plugin-blade": {
           "optional": true
         },
-        "@zackad/prettier-plugin-twig": {
+        "@trivago/prettier-plugin-sort-imports": {
           "optional": true
         },
         "prettier-plugin-astro": {
@@ -32134,23 +32118,20 @@
         "prettier-plugin-marko": {
           "optional": true
         },
-        "prettier-plugin-multiline-arrays": {
-          "optional": true
-        },
         "prettier-plugin-organize-attributes": {
           "optional": true
         },
         "prettier-plugin-organize-imports": {
           "optional": true
         },
-        "prettier-plugin-sort-imports": {
-          "optional": true
-        },
         "prettier-plugin-style-order": {
           "optional": true
         },
         "prettier-plugin-svelte": {
           "optional": true
+        },
+        "prettier-plugin-twig-melody": {
+          "optional": true
         }
       }
     },
@@ -40244,7 +40225,6 @@
       "version": "0.27.2",
       "license": "MIT",
       "dependencies": {
-        "@lexical/selection": "0.27.2",
         "@lexical/utils": "0.27.2",
         "lexical": "0.27.2"
       }
@@ -40320,7 +40300,7 @@
         "katex": "^0.16.10",
         "lexical": "0.27.2",
         "lodash-es": "^4.17.21",
-        "prettier": "^3.5.3",
+        "prettier": "^3.4.2",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-error-boundary": "^3.1.4",
@@ -40339,6 +40319,21 @@
         "vite-plugin-static-copy": "^2.1.0"
       }
     },
+    "packages/lexical-playground/node_modules/prettier": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
+      "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
+      "license": "MIT",
+      "bin": {
+        "prettier": "bin/prettier.cjs"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
     "packages/lexical-react": {
       "name": "@lexical/react",
       "version": "0.27.2",
@@ -40439,7 +40434,7 @@
       },
       "devDependencies": {
         "buffer": "^6.0.3",
-        "prettier-plugin-tailwindcss": "^0.6.11",
+        "prettier-plugin-tailwindcss": "^0.4.1",
         "tailwindcss": "^3.3.3",
         "typedoc": "^0.25.12",
         "typescript": "^5.4.5",
@@ -45279,7 +45274,6 @@
     "@lexical/list": {
       "version": "file:packages/lexical-list",
       "requires": {
-        "@lexical/selection": "0.27.2",
         "@lexical/utils": "0.27.2",
         "lexical": "0.27.2"
       }
@@ -45399,7 +45393,7 @@
         "docusaurus-plugin-internaldocs-fb": "1.19.0",
         "docusaurus-plugin-typedoc": "^0.22.0",
         "fs-extra": "^10.0.0",
-        "prettier-plugin-tailwindcss": "^0.6.11",
+        "prettier-plugin-tailwindcss": "^0.4.1",
         "prism-react-renderer": "^2.3.1",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
@@ -45587,14 +45581,6 @@
       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
       "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
     },
-    "@prettier/sync": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.5.2.tgz",
-      "integrity": "sha512-Yb569su456XNx5BsH/Vyem7xD6g/y9iLmLUzRKM1a/dhU/D7HqqvkAG72znulXlMXztbV0iiu9O5AL8K98TzZQ==",
-      "requires": {
-        "make-synchronized": "^0.2.8"
-      }
-    },
     "@radix-ui/primitive": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
@@ -46974,6 +46960,12 @@
       "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
       "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw=="
     },
+    "@types/prettier": {
+      "version": "2.7.3",
+      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz",
+      "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==",
+      "dev": true
+    },
     "@types/prismjs": {
       "version": "1.26.0",
       "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz",
@@ -57321,7 +57313,7 @@
         "katex": "^0.16.10",
         "lexical": "0.27.2",
         "lodash-es": "^4.17.21",
-        "prettier": "^3.5.3",
+        "prettier": "^3.4.2",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-error-boundary": "^3.1.4",
@@ -57330,6 +57322,13 @@
         "vite-plugin-static-copy": "^2.1.0",
         "y-websocket": "^1.5.4",
         "yjs": ">=13.5.42"
+      },
+      "dependencies": {
+        "prettier": {
+          "version": "3.4.2",
+          "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
+          "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ=="
+        }
       }
     },
     "lib0": {
@@ -57845,11 +57844,6 @@
       "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
       "dev": true
     },
-    "make-synchronized": {
-      "version": "0.2.9",
-      "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.2.9.tgz",
-      "integrity": "sha512-4wczOs8SLuEdpEvp3vGo83wh8rjJ78UsIk7DIX5fxdfmfMJGog4bQzxfvOwq7Q3yCHLC4jp1urPHIxRS/A93gA=="
-    },
     "makeerror": {
       "version": "1.0.12",
       "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
@@ -61553,9 +61547,10 @@
       "dev": true
     },
     "prettier": {
-      "version": "3.5.3",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
-      "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+      "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+      "dev": true
     },
     "prettier-plugin-hermes-parser": {
       "version": "0.26.0",
@@ -61569,15 +61564,15 @@
       }
     },
     "prettier-plugin-organize-attributes": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-1.0.0.tgz",
-      "integrity": "sha512-+NmameaLxbCcylEXsKPmawtzla5EE6ECqvGkpfQz4KM847fXDifB1gFnPQEpoADAq6IXg+cMI8Z0ISJEXa6fhg==",
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-0.0.5.tgz",
+      "integrity": "sha512-dSts16q8wd+oq8Zwk5mwmYXo1aN3B+ZkEJqx/ar5fedNHdOvx7S4XDMH/pNK7rmBW0bPXkp/kJX5gAANsWzh3A==",
       "dev": true
     },
     "prettier-plugin-tailwindcss": {
-      "version": "0.6.11",
-      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.11.tgz",
-      "integrity": "sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==",
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz",
+      "integrity": "sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==",
       "dev": true
     },
     "pretty-error": {
diff --git a/package.json b/package.json
index cd177852564..20e3d93c8d3 100644
--- a/package.json
+++ b/package.json
@@ -130,6 +130,7 @@
     "@types/jsdom": "^21.1.6",
     "@types/katex": "^0.16.7",
     "@types/node": "^17.0.31",
+    "@types/prettier": "^2.7.3",
     "@types/prismjs": "^1.26.0",
     "@types/proper-lockfile": "^4.1.4",
     "@types/react": "^18.0.8",
@@ -173,10 +174,10 @@
     "lint-staged": "^11.1.0",
     "minimist": "^1.2.5",
     "npm-run-all": "^4.1.5",
-    "prettier": "^3.5.3",
+    "prettier": "^2.3.2",
     "prettier-plugin-hermes-parser": "^0.26.0",
-    "prettier-plugin-organize-attributes": "^1.0.0",
-    "prettier-plugin-tailwindcss": "^0.6.11",
+    "prettier-plugin-organize-attributes": "^0.0.5",
+    "prettier-plugin-tailwindcss": "^0.4.1",
     "proper-lockfile": "^4.1.2",
     "react-test-renderer": "^17.0.2",
     "rollup": "^4.22.4",
@@ -189,7 +190,6 @@
     "vite": "^5.2.11"
   },
   "dependencies": {
-    "@prettier/sync": "^0.5.2",
     "yjs": "^13.5.42"
   }
 }
diff --git a/packages/lexical-eslint-plugin/src/__tests__/unit/rules-of-lexical.test.ts b/packages/lexical-eslint-plugin/src/__tests__/unit/rules-of-lexical.test.ts
index bebee3e8a58..5845696dc83 100644
--- a/packages/lexical-eslint-plugin/src/__tests__/unit/rules-of-lexical.test.ts
+++ b/packages/lexical-eslint-plugin/src/__tests__/unit/rules-of-lexical.test.ts
@@ -6,10 +6,10 @@
  *
  */
 
-import * as prettierSync from '@prettier/sync';
 import {RuleTester} from 'eslint';
 import * as fs from 'node:fs';
 import * as path from 'node:path';
+import * as prettier from 'prettier';
 
 import plugin from '../../LexicalEslintPlugin.js';
 import {type RulesOfLexicalOptions} from '../../rules/rules-of-lexical.js';
@@ -39,7 +39,7 @@ function fmt(
     keys.forEach((key, i) => {
       result.push(key(name), strings[i + 1]);
     });
-    return prettierSync.format(result.join(''), {parser: 'typescript'});
+    return prettier.format(result.join(''), {parser: 'typescript'});
   };
   rval.keys = keys;
   rval.setOptions = (opts: RulesOfLexicalOptions) => {
diff --git a/packages/lexical-list/src/__tests__/utils.ts b/packages/lexical-list/src/__tests__/utils.ts
index 13b75de4338..aa95a7a01b0 100644
--- a/packages/lexical-list/src/__tests__/utils.ts
+++ b/packages/lexical-list/src/__tests__/utils.ts
@@ -6,7 +6,7 @@
  *
  */
 import {expect} from '@playwright/test';
-import * as prettierSync from '@prettier/sync';
+import prettier from 'prettier';
 
 // This tag function is just used to trigger prettier auto-formatting.
 // (https://prettier.io/blog/2020/08/24/2.1.0.html#api)
@@ -29,5 +29,5 @@ export function expectHtmlToBeEqual(expected: string, actual: string): void {
 }
 
 export function prettifyHtml(s: string): string {
-  return prettierSync.format(s.replace(/\n/g, ''), {parser: 'html'});
+  return prettier.format(s.replace(/\n/g, ''), {parser: 'html'});
 }
diff --git a/packages/lexical-playground/__tests__/utils/index.mjs b/packages/lexical-playground/__tests__/utils/index.mjs
index ad4d9052a30..deb209bfda9 100644
--- a/packages/lexical-playground/__tests__/utils/index.mjs
+++ b/packages/lexical-playground/__tests__/utils/index.mjs
@@ -9,7 +9,7 @@
 import {expect, test as base} from '@playwright/test';
 import * as glob from 'glob';
 import {randomUUID} from 'node:crypto';
-import * as prettier from 'prettier';
+import prettier from 'prettier';
 import * as lockfile from 'proper-lockfile';
 import {URLSearchParams} from 'url';
 
diff --git a/packages/lexical-playground/package.json b/packages/lexical-playground/package.json
index 609947f4bd9..34e991c45c8 100644
--- a/packages/lexical-playground/package.json
+++ b/packages/lexical-playground/package.json
@@ -29,7 +29,7 @@
     "katex": "^0.16.10",
     "lexical": "0.27.2",
     "lodash-es": "^4.17.21",
-    "prettier": "^3.5.3",
+    "prettier": "^3.4.2",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-error-boundary": "^3.1.4",
diff --git a/packages/lexical-website/package.json b/packages/lexical-website/package.json
index 3145e16ceb7..54294b27479 100644
--- a/packages/lexical-website/package.json
+++ b/packages/lexical-website/package.json
@@ -34,7 +34,7 @@
   },
   "devDependencies": {
     "buffer": "^6.0.3",
-    "prettier-plugin-tailwindcss": "^0.6.11",
+    "prettier-plugin-tailwindcss": "^0.4.1",
     "tailwindcss": "^3.3.3",
     "typedoc": "^0.25.12",
     "typescript": "^5.4.5",
diff --git a/packages/lexical/src/__tests__/utils/index.tsx b/packages/lexical/src/__tests__/utils/index.tsx
index 31204e47258..3eeecec272d 100644
--- a/packages/lexical/src/__tests__/utils/index.tsx
+++ b/packages/lexical/src/__tests__/utils/index.tsx
@@ -26,7 +26,6 @@ import {
 import {HeadingNode, QuoteNode} from '@lexical/rich-text';
 import {TableCellNode, TableNode, TableRowNode} from '@lexical/table';
 import {expect} from '@playwright/test';
-import * as prettierSync from '@prettier/sync';
 import {
   $isRangeSelection,
   createEditor,
@@ -46,6 +45,7 @@ import {
   TextNode,
 } from 'lexical';
 import path from 'path';
+import * as prettier from 'prettier';
 import * as React from 'react';
 import {createRef} from 'react';
 import {createRoot} from 'react-dom/client';
@@ -58,7 +58,7 @@ import {
 } from '../../LexicalEditor';
 import {resetRandomKey} from '../../LexicalUtils';
 
-const prettierConfig = prettierSync.resolveConfig(
+const prettierConfig = prettier.resolveConfig.sync(
   path.resolve(__dirname, '../../../../.prettierrc'),
 );
 
@@ -784,7 +784,7 @@ export function expectHtmlToBeEqual(actual: string, expected: string): void {
 }
 
 export function prettifyHtml(s: string): string {
-  return prettierSync.format(s.replace(/\n/g, ''), {
+  return prettier.format(s.replace(/\n/g, ''), {
     ...prettierConfig,
     parser: 'html',
   });
diff --git a/scripts/error-codes/__tests__/unit/transform-error-messages.test.js b/scripts/error-codes/__tests__/unit/transform-error-messages.test.js
index 6e2d1b30147..20f51881876 100644
--- a/scripts/error-codes/__tests__/unit/transform-error-messages.test.js
+++ b/scripts/error-codes/__tests__/unit/transform-error-messages.test.js
@@ -12,9 +12,9 @@ const fs = require('fs-extra');
 const path = require('node:path');
 const transformErrorMessages = require('../../transform-error-messages');
 const babel = require('@babel/core');
-const prettierSync = require('@prettier/sync');
+const prettier = require('prettier');
 
-const prettierConfig = prettierSync.resolveConfig('./') || {};
+const prettierConfig = prettier.resolveConfig.sync('./') || {};
 
 /** @returns {Promise<void>} */
 function waitTick() {
@@ -39,13 +39,7 @@ async function withCodes(before, after, cb) {
   }
 }
 
-/**
- *
- * @param {TemplateStringsArray} strings
- * @param  {...unknown} keys
- * @returns
- */
-function fmt(strings, ...keys) {
+function fmt(strings: TemplateStringsArray, ...keys: unknown[]) {
   const result = [strings[0]];
   keys.forEach((key, i) => {
     result.push(String(key), strings[i + 1]);
@@ -65,7 +59,7 @@ function fmt(strings, ...keys) {
       'format$1ErrorMessage',
     )
     .trim();
-  return prettierSync.format(before, {
+  return prettier.format(before, {
     ...prettierConfig,
     filepath: 'test.js',
   });
diff --git a/scripts/error-codes/transform-error-messages.js b/scripts/error-codes/transform-error-messages.js
index cb9ea1a882a..3ccfd24a957 100644
--- a/scripts/error-codes/transform-error-messages.js
+++ b/scripts/error-codes/transform-error-messages.js
@@ -13,7 +13,7 @@ const fs = require('fs-extra');
 const ErrorMap = require('./ErrorMap');
 const evalToString = require('./evalToString');
 const helperModuleImports = require('@babel/helper-module-imports');
-const prettierSync = require('@prettier/sync');
+const prettier = require('prettier');
 
 /** @type {Map<string, ErrorMap>} */
 const errorMaps = new Map();
@@ -29,13 +29,13 @@ function getErrorMap(filepath) {
   let errorMap = errorMaps.get(filepath);
   if (!errorMap) {
     const prettierConfig = {
-      ...(prettierSync.resolveConfig('./') || {}),
+      ...(prettier.resolveConfig.sync('./') || {}),
       filepath,
     };
     errorMap = new ErrorMap(fs.readJsonSync(filepath), (newErrorMap) =>
       fs.writeFileSync(
         filepath,
-        prettierSync.format(JSON.stringify(newErrorMap), prettierConfig),
+        prettier.format(JSON.stringify(newErrorMap), prettierConfig),
       ),
     );
     errorMaps.set(filepath, errorMap);

From 35349e18b11e925ef67c1be5b92fb285392c1403 Mon Sep 17 00:00:00 2001
From: Bob Ippolito <bob@redivi.com>
Date: Mon, 17 Mar 2025 12:39:44 -0700
Subject: [PATCH 10/10] downgrade playground prettier

---
 package-lock.json                             | 23 ++++++++++---------
 package.json                                  |  2 +-
 packages/lexical-headless/src/index.ts        |  2 +-
 packages/lexical-playground/package.json      |  2 +-
 .../lexical-table/src/LexicalTableCellNode.ts |  2 +-
 packages/lexical/src/LexicalUpdates.ts        |  2 +-
 packages/lexical/src/caret/LexicalCaret.ts    |  3 ++-
 7 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 2593e2c90b8..cdc0a35bc58 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -79,7 +79,7 @@
         "lint-staged": "^11.1.0",
         "minimist": "^1.2.5",
         "npm-run-all": "^4.1.5",
-        "prettier": "^2.3.2",
+        "prettier": "^2.8.8",
         "prettier-plugin-hermes-parser": "^0.26.0",
         "prettier-plugin-organize-attributes": "^0.0.5",
         "prettier-plugin-tailwindcss": "^0.4.1",
@@ -32021,9 +32021,9 @@
       }
     },
     "node_modules/prettier": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
-      "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
       "dev": true,
       "bin": {
         "prettier": "bin-prettier.js"
@@ -40225,6 +40225,7 @@
       "version": "0.27.2",
       "license": "MIT",
       "dependencies": {
+        "@lexical/selection": "0.27.2",
         "@lexical/utils": "0.27.2",
         "lexical": "0.27.2"
       }
@@ -40300,7 +40301,7 @@
         "katex": "^0.16.10",
         "lexical": "0.27.2",
         "lodash-es": "^4.17.21",
-        "prettier": "^3.4.2",
+        "prettier": "^2.8.8",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-error-boundary": "^3.1.4",
@@ -45274,6 +45275,7 @@
     "@lexical/list": {
       "version": "file:packages/lexical-list",
       "requires": {
+        "@lexical/selection": "0.27.2",
         "@lexical/utils": "0.27.2",
         "lexical": "0.27.2"
       }
@@ -57313,7 +57315,7 @@
         "katex": "^0.16.10",
         "lexical": "0.27.2",
         "lodash-es": "^4.17.21",
-        "prettier": "^3.4.2",
+        "prettier": "^2.8.8",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-error-boundary": "^3.1.4",
@@ -57325,8 +57327,7 @@
       },
       "dependencies": {
         "prettier": {
-          "version": "3.4.2",
-          "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
+          "version": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
           "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ=="
         }
       }
@@ -61547,9 +61548,9 @@
       "dev": true
     },
     "prettier": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
-      "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
       "dev": true
     },
     "prettier-plugin-hermes-parser": {
diff --git a/package.json b/package.json
index 20e3d93c8d3..36abab2201f 100644
--- a/package.json
+++ b/package.json
@@ -174,7 +174,7 @@
     "lint-staged": "^11.1.0",
     "minimist": "^1.2.5",
     "npm-run-all": "^4.1.5",
-    "prettier": "^2.3.2",
+    "prettier": "^2.8.8",
     "prettier-plugin-hermes-parser": "^0.26.0",
     "prettier-plugin-organize-attributes": "^0.0.5",
     "prettier-plugin-tailwindcss": "^0.4.1",
diff --git a/packages/lexical-headless/src/index.ts b/packages/lexical-headless/src/index.ts
index 2b8eddb8ed3..04a18d356b7 100644
--- a/packages/lexical-headless/src/index.ts
+++ b/packages/lexical-headless/src/index.ts
@@ -33,7 +33,7 @@ export function createHeadlessEditor(
     'blur',
   ] as const;
 
-  unsupportedMethods.forEach((method: typeof unsupportedMethods[number]) => {
+  unsupportedMethods.forEach((method: (typeof unsupportedMethods)[number]) => {
     editor[method] = () => {
       throw new Error(`${method} is not supported in headless mode`);
     };
diff --git a/packages/lexical-playground/package.json b/packages/lexical-playground/package.json
index 34e991c45c8..7fd63ccb16a 100644
--- a/packages/lexical-playground/package.json
+++ b/packages/lexical-playground/package.json
@@ -29,7 +29,7 @@
     "katex": "^0.16.10",
     "lexical": "0.27.2",
     "lodash-es": "^4.17.21",
-    "prettier": "^3.4.2",
+    "prettier": "^2.8.8",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-error-boundary": "^3.1.4",
diff --git a/packages/lexical-table/src/LexicalTableCellNode.ts b/packages/lexical-table/src/LexicalTableCellNode.ts
index 987ba11d51d..9ba1a49947c 100644
--- a/packages/lexical-table/src/LexicalTableCellNode.ts
+++ b/packages/lexical-table/src/LexicalTableCellNode.ts
@@ -41,7 +41,7 @@ export const TableCellHeaderStates = {
 };
 
 export type TableCellHeaderState =
-  typeof TableCellHeaderStates[keyof typeof TableCellHeaderStates];
+  (typeof TableCellHeaderStates)[keyof typeof TableCellHeaderStates];
 
 export type SerializedTableCellNode = Spread<
   {
diff --git a/packages/lexical/src/LexicalUpdates.ts b/packages/lexical/src/LexicalUpdates.ts
index fb151f5fb7f..0e1012e4e88 100644
--- a/packages/lexical/src/LexicalUpdates.ts
+++ b/packages/lexical/src/LexicalUpdates.ts
@@ -133,7 +133,7 @@ function collectBuildInformation(): string {
       } else if (editor) {
         let version = String(
           (
-            editor.constructor as typeof editor['constructor'] &
+            editor.constructor as (typeof editor)['constructor'] &
               Record<string, unknown>
           ).version || '<0.17.1',
         );
diff --git a/packages/lexical/src/caret/LexicalCaret.ts b/packages/lexical/src/caret/LexicalCaret.ts
index c1af5986087..25ca9c53c78 100644
--- a/packages/lexical/src/caret/LexicalCaret.ts
+++ b/packages/lexical/src/caret/LexicalCaret.ts
@@ -22,7 +22,8 @@ export type CaretDirection = 'next' | 'previous';
 /**
  * A type utility to flip next and previous
  */
-export type FlipDirection<D extends CaretDirection> = typeof FLIP_DIRECTION[D];
+export type FlipDirection<D extends CaretDirection> =
+  (typeof FLIP_DIRECTION)[D];
 /**
  * A sibling caret type points from a LexicalNode origin to its next or previous sibling,
  * and a child caret type points from an ElementNode origin to its first or last child.