lexical 0.25.1-nightly.20250228.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Lexical.dev.js CHANGED
@@ -1837,6 +1837,7 @@ let isInsertLineBreak = false;
1837
1837
  let isFirefoxEndingComposition = false;
1838
1838
  let isSafariEndingComposition = false;
1839
1839
  let safariEndCompositionEventData = '';
1840
+ let postDeleteSelectionToRestore = null;
1840
1841
  let collapsedSelectionFormat = [0, '', 0, 'root', 0];
1841
1842
 
1842
1843
  // This function is used to determine if Lexical should attempt to override
@@ -1905,7 +1906,7 @@ function onSelectionChange(domSelection, editor, isActive) {
1905
1906
  // We also need to check if the offset is at the boundary,
1906
1907
  // because in this case, we might need to normalize to a
1907
1908
  // sibling instead.
1908
- if (shouldSkipSelectionChange(anchorDOM, anchorOffset) && shouldSkipSelectionChange(focusDOM, focusOffset)) {
1909
+ if (shouldSkipSelectionChange(anchorDOM, anchorOffset) && shouldSkipSelectionChange(focusDOM, focusOffset) && !postDeleteSelectionToRestore) {
1909
1910
  return;
1910
1911
  }
1911
1912
  }
@@ -1919,7 +1920,23 @@ function onSelectionChange(domSelection, editor, isActive) {
1919
1920
  if (!isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {
1920
1921
  return;
1921
1922
  }
1922
- const selection = $getSelection();
1923
+ let selection = $getSelection();
1924
+
1925
+ // Restore selection in the event of incorrect rightward shift after deletion
1926
+ if (postDeleteSelectionToRestore && $isRangeSelection(selection) && selection.isCollapsed()) {
1927
+ const curAnchor = selection.anchor;
1928
+ const prevAnchor = postDeleteSelectionToRestore.anchor;
1929
+ if (
1930
+ // Rightward shift in same node
1931
+ curAnchor.key === prevAnchor.key && curAnchor.offset === prevAnchor.offset + 1 ||
1932
+ // Or rightward shift into sibling node
1933
+ curAnchor.offset === 1 && prevAnchor.getNode().is(curAnchor.getNode().getPreviousSibling())) {
1934
+ // Restore selection
1935
+ selection = postDeleteSelectionToRestore.clone();
1936
+ $setSelection(selection);
1937
+ }
1938
+ }
1939
+ postDeleteSelectionToRestore = null;
1923
1940
 
1924
1941
  // Update the selection format
1925
1942
  if ($isRangeSelection(selection)) {
@@ -2156,6 +2173,14 @@ function onBeforeInput(event, editor) {
2156
2173
  }
2157
2174
  if (!shouldLetBrowserHandleDelete) {
2158
2175
  dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true);
2176
+ // When deleting across paragraphs, Chrome on Android incorrectly shifts the selection rightwards
2177
+ // We save the correct selection to restore later during handling of selectionchange event
2178
+ const selectionAfterDelete = $getSelection();
2179
+ if (IS_ANDROID_CHROME && $isRangeSelection(selectionAfterDelete) && selectionAfterDelete.isCollapsed()) {
2180
+ postDeleteSelectionToRestore = selectionAfterDelete;
2181
+ // Cleanup in case selectionchange does not fire
2182
+ setTimeout(() => postDeleteSelectionToRestore = null);
2183
+ }
2159
2184
  }
2160
2185
  }
2161
2186
  return;
@@ -3869,6 +3894,9 @@ class LineBreakNode extends LexicalNode {
3869
3894
  updateDOM() {
3870
3895
  return false;
3871
3896
  }
3897
+ isInline() {
3898
+ return true;
3899
+ }
3872
3900
  static importDOM() {
3873
3901
  return {
3874
3902
  br: node => {
@@ -4246,6 +4274,13 @@ class TextNode extends LexicalNode {
4246
4274
  return true;
4247
4275
  }
4248
4276
 
4277
+ /**
4278
+ * @returns true if the text node is inline, false otherwise.
4279
+ */
4280
+ isInline() {
4281
+ return true;
4282
+ }
4283
+
4249
4284
  // View
4250
4285
 
4251
4286
  createDOM(config, editor) {
@@ -5138,22 +5173,12 @@ class Point {
5138
5173
  return this.key === point.key && this.offset === point.offset && this.type === point.type;
5139
5174
  }
5140
5175
  isBefore(b) {
5141
- let aNode = this.getNode();
5142
- let bNode = b.getNode();
5143
- const aOffset = this.offset;
5144
- const bOffset = b.offset;
5145
- if ($isElementNode(aNode)) {
5146
- const aNodeDescendant = aNode.getDescendantByIndex(aOffset);
5147
- aNode = aNodeDescendant != null ? aNodeDescendant : aNode;
5148
- }
5149
- if ($isElementNode(bNode)) {
5150
- const bNodeDescendant = bNode.getDescendantByIndex(bOffset);
5151
- bNode = bNodeDescendant != null ? bNodeDescendant : bNode;
5152
- }
5153
- if (aNode === bNode) {
5154
- return aOffset < bOffset;
5176
+ if (this.key === b.key) {
5177
+ return this.offset < b.offset;
5155
5178
  }
5156
- return aNode.isBefore(bNode);
5179
+ const aCaret = $normalizeCaret($caretFromPoint(this, 'next'));
5180
+ const bCaret = $normalizeCaret($caretFromPoint(b, 'next'));
5181
+ return $comparePointCaretNext(aCaret, bCaret) < 0;
5157
5182
  }
5158
5183
  getNode() {
5159
5184
  const key = this.key;
@@ -10256,7 +10281,7 @@ class LexicalEditor {
10256
10281
  };
10257
10282
  }
10258
10283
  }
10259
- LexicalEditor.version = "0.25.1-nightly.20250228.0+dev.cjs";
10284
+ LexicalEditor.version = "0.26.0+dev.cjs";
10260
10285
 
10261
10286
  /**
10262
10287
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -12568,8 +12593,10 @@ function $caretRangeFromSelection(selection) {
12568
12593
  anchor,
12569
12594
  focus
12570
12595
  } = selection;
12571
- const direction = focus.isBefore(anchor) ? 'previous' : 'next';
12572
- return $getCaretRange($caretFromPoint(anchor, direction), $caretFromPoint(focus, direction));
12596
+ const anchorCaret = $caretFromPoint(anchor, 'next');
12597
+ const focusCaret = $caretFromPoint(focus, 'next');
12598
+ const direction = $comparePointCaretNext(anchorCaret, focusCaret) <= 0 ? 'next' : 'previous';
12599
+ return $getCaretRange($getCaretInDirection(anchorCaret, direction), $getCaretInDirection(focusCaret, direction));
12573
12600
  }
12574
12601
 
12575
12602
  /**
package/Lexical.dev.mjs CHANGED
@@ -1835,6 +1835,7 @@ let isInsertLineBreak = false;
1835
1835
  let isFirefoxEndingComposition = false;
1836
1836
  let isSafariEndingComposition = false;
1837
1837
  let safariEndCompositionEventData = '';
1838
+ let postDeleteSelectionToRestore = null;
1838
1839
  let collapsedSelectionFormat = [0, '', 0, 'root', 0];
1839
1840
 
1840
1841
  // This function is used to determine if Lexical should attempt to override
@@ -1903,7 +1904,7 @@ function onSelectionChange(domSelection, editor, isActive) {
1903
1904
  // We also need to check if the offset is at the boundary,
1904
1905
  // because in this case, we might need to normalize to a
1905
1906
  // sibling instead.
1906
- if (shouldSkipSelectionChange(anchorDOM, anchorOffset) && shouldSkipSelectionChange(focusDOM, focusOffset)) {
1907
+ if (shouldSkipSelectionChange(anchorDOM, anchorOffset) && shouldSkipSelectionChange(focusDOM, focusOffset) && !postDeleteSelectionToRestore) {
1907
1908
  return;
1908
1909
  }
1909
1910
  }
@@ -1917,7 +1918,23 @@ function onSelectionChange(domSelection, editor, isActive) {
1917
1918
  if (!isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {
1918
1919
  return;
1919
1920
  }
1920
- const selection = $getSelection();
1921
+ let selection = $getSelection();
1922
+
1923
+ // Restore selection in the event of incorrect rightward shift after deletion
1924
+ if (postDeleteSelectionToRestore && $isRangeSelection(selection) && selection.isCollapsed()) {
1925
+ const curAnchor = selection.anchor;
1926
+ const prevAnchor = postDeleteSelectionToRestore.anchor;
1927
+ if (
1928
+ // Rightward shift in same node
1929
+ curAnchor.key === prevAnchor.key && curAnchor.offset === prevAnchor.offset + 1 ||
1930
+ // Or rightward shift into sibling node
1931
+ curAnchor.offset === 1 && prevAnchor.getNode().is(curAnchor.getNode().getPreviousSibling())) {
1932
+ // Restore selection
1933
+ selection = postDeleteSelectionToRestore.clone();
1934
+ $setSelection(selection);
1935
+ }
1936
+ }
1937
+ postDeleteSelectionToRestore = null;
1921
1938
 
1922
1939
  // Update the selection format
1923
1940
  if ($isRangeSelection(selection)) {
@@ -2154,6 +2171,14 @@ function onBeforeInput(event, editor) {
2154
2171
  }
2155
2172
  if (!shouldLetBrowserHandleDelete) {
2156
2173
  dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true);
2174
+ // When deleting across paragraphs, Chrome on Android incorrectly shifts the selection rightwards
2175
+ // We save the correct selection to restore later during handling of selectionchange event
2176
+ const selectionAfterDelete = $getSelection();
2177
+ if (IS_ANDROID_CHROME && $isRangeSelection(selectionAfterDelete) && selectionAfterDelete.isCollapsed()) {
2178
+ postDeleteSelectionToRestore = selectionAfterDelete;
2179
+ // Cleanup in case selectionchange does not fire
2180
+ setTimeout(() => postDeleteSelectionToRestore = null);
2181
+ }
2157
2182
  }
2158
2183
  }
2159
2184
  return;
@@ -3867,6 +3892,9 @@ class LineBreakNode extends LexicalNode {
3867
3892
  updateDOM() {
3868
3893
  return false;
3869
3894
  }
3895
+ isInline() {
3896
+ return true;
3897
+ }
3870
3898
  static importDOM() {
3871
3899
  return {
3872
3900
  br: node => {
@@ -4244,6 +4272,13 @@ class TextNode extends LexicalNode {
4244
4272
  return true;
4245
4273
  }
4246
4274
 
4275
+ /**
4276
+ * @returns true if the text node is inline, false otherwise.
4277
+ */
4278
+ isInline() {
4279
+ return true;
4280
+ }
4281
+
4247
4282
  // View
4248
4283
 
4249
4284
  createDOM(config, editor) {
@@ -5136,22 +5171,12 @@ class Point {
5136
5171
  return this.key === point.key && this.offset === point.offset && this.type === point.type;
5137
5172
  }
5138
5173
  isBefore(b) {
5139
- let aNode = this.getNode();
5140
- let bNode = b.getNode();
5141
- const aOffset = this.offset;
5142
- const bOffset = b.offset;
5143
- if ($isElementNode(aNode)) {
5144
- const aNodeDescendant = aNode.getDescendantByIndex(aOffset);
5145
- aNode = aNodeDescendant != null ? aNodeDescendant : aNode;
5146
- }
5147
- if ($isElementNode(bNode)) {
5148
- const bNodeDescendant = bNode.getDescendantByIndex(bOffset);
5149
- bNode = bNodeDescendant != null ? bNodeDescendant : bNode;
5150
- }
5151
- if (aNode === bNode) {
5152
- return aOffset < bOffset;
5174
+ if (this.key === b.key) {
5175
+ return this.offset < b.offset;
5153
5176
  }
5154
- return aNode.isBefore(bNode);
5177
+ const aCaret = $normalizeCaret($caretFromPoint(this, 'next'));
5178
+ const bCaret = $normalizeCaret($caretFromPoint(b, 'next'));
5179
+ return $comparePointCaretNext(aCaret, bCaret) < 0;
5155
5180
  }
5156
5181
  getNode() {
5157
5182
  const key = this.key;
@@ -10254,7 +10279,7 @@ class LexicalEditor {
10254
10279
  };
10255
10280
  }
10256
10281
  }
10257
- LexicalEditor.version = "0.25.1-nightly.20250228.0+dev.esm";
10282
+ LexicalEditor.version = "0.26.0+dev.esm";
10258
10283
 
10259
10284
  /**
10260
10285
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -12566,8 +12591,10 @@ function $caretRangeFromSelection(selection) {
12566
12591
  anchor,
12567
12592
  focus
12568
12593
  } = selection;
12569
- const direction = focus.isBefore(anchor) ? 'previous' : 'next';
12570
- return $getCaretRange($caretFromPoint(anchor, direction), $caretFromPoint(focus, direction));
12594
+ const anchorCaret = $caretFromPoint(anchor, 'next');
12595
+ const focusCaret = $caretFromPoint(focus, 'next');
12596
+ const direction = $comparePointCaretNext(anchorCaret, focusCaret) <= 0 ? 'next' : 'previous';
12597
+ return $getCaretRange($getCaretInDirection(anchorCaret, direction), $getCaretInDirection(focusCaret, direction));
12571
12598
  }
12572
12599
 
12573
12600
  /**
package/Lexical.js.flow CHANGED
@@ -623,6 +623,7 @@ declare export class TextNode extends LexicalNode {
623
623
  getFormat(): number;
624
624
  getStyle(): string;
625
625
  isComposing(): boolean;
626
+ isInline(): true;
626
627
  isToken(): boolean;
627
628
  isSegmented(): boolean;
628
629
  isDirectionless(): boolean;
@@ -698,6 +699,7 @@ declare export class LineBreakNode extends LexicalNode {
698
699
  getTextContent(): '\n';
699
700
  createDOM(): HTMLElement;
700
701
  updateDOM(): false;
702
+ isInline(): true;
701
703
  static importJSON(
702
704
  serializedLineBreakNode: SerializedLineBreakNode,
703
705
  ): LineBreakNode;