diff --git a/.changeset/stupid-ants-buy.md b/.changeset/stupid-ants-buy.md new file mode 100644 index 000000000..6cced8280 --- /dev/null +++ b/.changeset/stupid-ants-buy.md @@ -0,0 +1,9 @@ +--- +'slate': minor +--- + +- When removing a text node containing the cursor, always perfer placing the cursor in a sibling text node if one exists. + - Previously, the selection would enter a sibling inline in some circumstances, even when a sibling text node was available. + - The most noticeable effect of this change occurs when pressing backspace at the start of line N when the last non-empty node in line N-1 is an inline. + - Before, the cursor would be placed inside the inline. + - Now, the cursor is placed outside the inline. diff --git a/packages/slate/src/interfaces/transforms/general.ts b/packages/slate/src/interfaces/transforms/general.ts index 825d3d79c..d2e44c54d 100644 --- a/packages/slate/src/interfaces/transforms/general.ts +++ b/packages/slate/src/interfaces/transforms/general.ts @@ -246,8 +246,10 @@ export const GeneralTransforms: GeneralTransforms = { let preferNext = false if (prev && next) { - if (Path.equals(next[1], path)) { - preferNext = !Path.hasPrevious(next[1]) + if (Path.isSibling(prev[1], path)) { + preferNext = false + } else if (Path.equals(next[1], path)) { + preferNext = true } else { preferNext = Path.common(prev[1], path).length < diff --git a/packages/slate/test/operations/remove_node/cursor-aunt-text-after.tsx b/packages/slate/test/operations/remove_node/cursor-aunt-text-after.tsx new file mode 100644 index 000000000..12a73e2bb --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-aunt-text-after.tsx @@ -0,0 +1,37 @@ +/** @jsx jsx */ +import { jsx } from '../../' + +export const input = ( + + + + + a + + + + + b + + +) +export const operations = [ + { + type: 'remove_node', + path: [0, 1, 1], + node: { text: '', id: '1' }, + }, +] +export const output = ( + + + + + + a + + + b + + +) diff --git a/packages/slate/test/operations/remove_node/cursor-aunt-text-before.tsx b/packages/slate/test/operations/remove_node/cursor-aunt-text-before.tsx new file mode 100644 index 000000000..59312c818 --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-aunt-text-before.tsx @@ -0,0 +1,37 @@ +/** @jsx jsx */ +import { jsx } from '../../' + +export const input = ( + + + a + + + + + b + + + + +) +export const operations = [ + { + type: 'remove_node', + path: [0, 1, 0], + node: { text: '', id: '0' }, + }, +] +export const output = ( + + + a + + + b + + + + + +) diff --git a/packages/slate/test/operations/remove_node/cursor-sibling-inline-after.tsx b/packages/slate/test/operations/remove_node/cursor-sibling-inline-after.tsx new file mode 100644 index 000000000..375ab920c --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-sibling-inline-after.tsx @@ -0,0 +1,35 @@ +/** @jsx jsx */ +import { jsx } from '../../' + +export const input = ( + + a + + + + + b + + + +) +export const operations = [ + { + type: 'remove_node', + path: [1, 0], + node: { text: '' }, + }, +] +export const output = ( + + a + + {/* Recreated by normalizer */} + + + b + + + + +) diff --git a/packages/slate/test/operations/remove_node/cursor-sibling-inline-before-text-after.tsx b/packages/slate/test/operations/remove_node/cursor-sibling-inline-before-text-after.tsx new file mode 100644 index 000000000..e4d004b9e --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-sibling-inline-before-text-after.tsx @@ -0,0 +1,33 @@ +/** @jsx jsx */ +import { jsx } from '../../' + +export const input = ( + + + + a + + + + b + + +) +export const operations = [ + { + type: 'remove_node', + path: [0, 2], + node: { text: '', id: '0' }, + }, +] +export const output = ( + + + + a + + b + + + +) diff --git a/packages/slate/test/operations/remove_node/cursor-sibling-inline-before.tsx b/packages/slate/test/operations/remove_node/cursor-sibling-inline-before.tsx new file mode 100644 index 000000000..c885341fb --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-sibling-inline-before.tsx @@ -0,0 +1,35 @@ +/** @jsx jsx */ +import { jsx } from '../../' + +export const input = ( + + + + a + + + + + b + +) +export const operations = [ + { + type: 'remove_node', + path: [0, 2], + node: { text: '' }, + }, +] +export const output = ( + + + + + a + + {/* Recreated by normalizer */} + + + b + +) diff --git a/packages/slate/test/operations/remove_node/cursor-sibling-text-after.tsx b/packages/slate/test/operations/remove_node/cursor-sibling-text-after.tsx new file mode 100644 index 000000000..87456b1f9 --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-sibling-text-after.tsx @@ -0,0 +1,31 @@ +/** @jsx jsx */ +import { jsx } from 'slate-hyperscript' + +export const input = ( + + a + + + + + b + + +) +export const operations = [ + { + type: 'remove_node', + path: [1, 0], + node: { text: '', id: '0' }, + }, +] +export const output = ( + + a + + + b + + + +) diff --git a/packages/slate/test/operations/remove_node/cursor-sibling-text-before-inline-after.tsx b/packages/slate/test/operations/remove_node/cursor-sibling-text-before-inline-after.tsx new file mode 100644 index 000000000..60d2d9631 --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-sibling-text-before-inline-after.tsx @@ -0,0 +1,33 @@ +/** @jsx jsx */ +import { jsx } from '../../' + +export const input = ( + + + a + + + + b + + + +) +export const operations = [ + { + type: 'remove_node', + path: [0, 1], + node: { text: '', id: '1' }, + }, +] +export const output = ( + + + + a + + b + + + +) diff --git a/packages/slate/test/operations/remove_node/cursor-sibling-text-before.tsx b/packages/slate/test/operations/remove_node/cursor-sibling-text-before.tsx new file mode 100644 index 000000000..69e5111a6 --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-sibling-text-before.tsx @@ -0,0 +1,31 @@ +/** @jsx jsx */ +import { jsx } from 'slate-hyperscript' + +export const input = ( + + + a + + + + + b + +) +export const operations = [ + { + type: 'remove_node', + path: [0, 1], + node: { text: '', id: '1' }, + }, +] +export const output = ( + + + + a + + + b + +) diff --git a/packages/slate/test/operations/remove_node/cursor-sibling-text-both-sides.tsx b/packages/slate/test/operations/remove_node/cursor-sibling-text-both-sides.tsx new file mode 100644 index 000000000..930e3ce89 --- /dev/null +++ b/packages/slate/test/operations/remove_node/cursor-sibling-text-both-sides.tsx @@ -0,0 +1,31 @@ +/** @jsx jsx */ +import { jsx } from 'slate-hyperscript' + +export const input = ( + + + a + + + + b + + +) +export const operations = [ + { + type: 'remove_node', + path: [0, 1], + node: { text: '', id: '1' }, + }, +] +export const output = ( + + + + a + + b + + +) diff --git a/packages/slate/test/transforms/delete/point/inline-void-reverse.tsx b/packages/slate/test/transforms/delete/point/inline-void-reverse.tsx index d9cd964fa..6b6b26a04 100644 --- a/packages/slate/test/transforms/delete/point/inline-void-reverse.tsx +++ b/packages/slate/test/transforms/delete/point/inline-void-reverse.tsx @@ -25,10 +25,9 @@ export const output = ( - - - + + word