diff --git a/packages/slate-plain-serializer/test/serialize/block-with-is-void.js b/packages/slate-plain-serializer/test/serialize/block-with-is-void.js index 0b4e46734..220dc880b 100644 --- a/packages/slate-plain-serializer/test/serialize/block-with-is-void.js +++ b/packages/slate-plain-serializer/test/serialize/block-with-is-void.js @@ -10,4 +10,4 @@ export const input = ( ) -export const output = ' ' +export const output = '' diff --git a/packages/slate-plain-serializer/test/serialize/inline-with-is-void.js b/packages/slate-plain-serializer/test/serialize/inline-with-is-void.js index 258673c34..c7a7b3b39 100644 --- a/packages/slate-plain-serializer/test/serialize/inline-with-is-void.js +++ b/packages/slate-plain-serializer/test/serialize/inline-with-is-void.js @@ -12,4 +12,4 @@ export const input = ( ) -export const output = ' ' +export const output = '' diff --git a/packages/slate-react/src/components/leaf.js b/packages/slate-react/src/components/leaf.js index 98df01b4b..1fb2024d6 100644 --- a/packages/slate-react/src/components/leaf.js +++ b/packages/slate-react/src/components/leaf.js @@ -116,28 +116,38 @@ class Leaf extends React.Component { renderText() { const { block, node, parent, text, index, leaves } = this.props - // COMPAT: If the text is empty and the only child, we need to render a - // line break when copying and pasting to support expected plain text. - if (text == '' && parent.kind == 'block' && parent.text == '') { - return {'\u200B'} - } - // COMPAT: Render text inside void nodes with a zero-width space. // So the node can contain selection but the text is not visible. - if (parent.isVoid) return {'\u200B'} + if (parent.isVoid) { + return {'\u200B'} + } + + // COMPAT: If this is the last text node in an empty block, render a zero- + // width space that will convert into a line break when copying and pasting + // to support expected plain text. + if ( + text === '' && + parent.kind === 'block' && + parent.text === '' && + parent.nodes.size === 1 + ) { + return {'\u200B'} + } // COMPAT: If the text is empty, it's because it's on the edge of an inline // void node, so we render a zero-width space so that the selection can be // inserted next to it still. - if (text == '') return {'\u200B'} + if (text === '') { + return {'\u200B'} + } // COMPAT: Browsers will collapse trailing new lines at the end of blocks, // so we need to add an extra trailing new lines to prevent that. const lastText = block.getLastText() const lastChar = text.charAt(text.length - 1) - const isLastText = node == lastText - const isLastLeaf = index == leaves.size - 1 - if (isLastText && isLastLeaf && lastChar == '\n') return `${text}\n` + const isLastText = node === lastText + const isLastLeaf = index === leaves.size - 1 + if (isLastText && isLastLeaf && lastChar === '\n') return `${text}\n` // Otherwise, just return the text. return text diff --git a/packages/slate/src/changes/at-range.js b/packages/slate/src/changes/at-range.js index abed00552..1bae929ba 100644 --- a/packages/slate/src/changes/at-range.js +++ b/packages/slate/src/changes/at-range.js @@ -298,25 +298,8 @@ Changes.deleteLineBackwardAtRange = (change, range, options) => { const { startKey, startOffset } = range const startBlock = document.getClosestBlock(startKey) const offset = startBlock.getOffset(startKey) - const startWithVoidInline = - startBlock.nodes.size > 1 && - startBlock.nodes.get(0).text == '' && - startBlock.nodes.get(1).object == 'inline' - - let o = offset + startOffset - - // If line starts with an void inline node, the text node inside this inline - // node disturbs the offset. Ignore this inline node and delete it afterwards. - if (startWithVoidInline) { - o -= 1 - } - + const o = offset + startOffset change.deleteBackwardAtRange(range, o, options) - - // Delete the remaining first inline node if needed. - if (startWithVoidInline) { - change.deleteBackward() - } } /** @@ -362,27 +345,22 @@ Changes.deleteBackwardAtRange = (change, range, n = 1, options = {}) => { return } + const voidParent = document.getClosestVoid(startKey) + + // If there is a void parent, delete it. + if (voidParent) { + change.removeNodeByKey(voidParent.key, { normalize }) + return + } + const block = document.getClosestBlock(startKey) - // If the closest block is void, delete it. - if (block && block.isVoid) { - change.removeNodeByKey(block.key, { normalize }) - return - } - // If the closest is not void, but empty, remove it - if (block && !block.isVoid && block.isEmpty && document.nodes.size !== 1) { + if (block && block.isEmpty && document.nodes.size !== 1) { change.removeNodeByKey(block.key, { normalize }) return } - // If the closest inline is void, delete it. - const inline = document.getClosestInline(startKey) - if (inline && inline.isVoid) { - change.removeNodeByKey(inline.key, { normalize }) - return - } - // If the range is at the start of the document, abort. if (range.isAtStartOf(document)) { return @@ -394,17 +372,11 @@ Changes.deleteBackwardAtRange = (change, range, n = 1, options = {}) => { if (range.isAtStartOf(text)) { const prev = document.getPreviousText(text.key) const prevBlock = document.getClosestBlock(prev.key) - const prevInline = document.getClosestInline(prev.key) + const prevVoid = document.getClosestVoid(prev.key) - // If the previous block is void, remove it. - if (prevBlock && prevBlock.isVoid) { - change.removeNodeByKey(prevBlock.key, { normalize }) - return - } - - // If the previous inline is void, remove it. - if (prevInline && prevInline.isVoid) { - change.removeNodeByKey(prevInline.key, { normalize }) + // If the previous text node has a void parent, remove it. + if (prevVoid) { + change.removeNodeByKey(prevVoid.key, { normalize }) return } @@ -449,13 +421,6 @@ Changes.deleteBackwardAtRange = (change, range, n = 1, options = {}) => { } } - // If the focus node is inside a void, go up until right after it. - if (document.hasVoidParent(node.key)) { - const parent = document.getClosestVoid(node.key) - node = document.getNextText(parent.key) - offset = 0 - } - range = range.merge({ focusKey: node.key, focusOffset: offset, @@ -548,16 +513,18 @@ Changes.deleteForwardAtRange = (change, range, n = 1, options = {}) => { return } - const block = document.getClosestBlock(startKey) + const voidParent = document.getClosestVoid(startKey) - // If the closest block is void, delete it. - if (block && block.isVoid) { - change.removeNodeByKey(block.key, { normalize }) + // If the node has a void parent, delete it. + if (voidParent) { + change.removeNodeByKey(voidParent.key, { normalize }) return } + const block = document.getClosestBlock(startKey) + // If the closest is not void, but empty, remove it - if (block && !block.isVoid && block.isEmpty && document.nodes.size !== 1) { + if (block && block.isEmpty && document.nodes.size !== 1) { const nextBlock = document.getNextBlock(block.key) change.removeNodeByKey(block.key, { normalize }) if (nextBlock && nextBlock.key) { @@ -566,13 +533,6 @@ Changes.deleteForwardAtRange = (change, range, n = 1, options = {}) => { return } - // If the closest inline is void, delete it. - const inline = document.getClosestInline(startKey) - if (inline && inline.isVoid) { - change.removeNodeByKey(inline.key, { normalize }) - return - } - // If the range is at the start of the document, abort. if (range.isAtEndOf(document)) { return @@ -584,17 +544,11 @@ Changes.deleteForwardAtRange = (change, range, n = 1, options = {}) => { if (range.isAtEndOf(text)) { const next = document.getNextText(text.key) const nextBlock = document.getClosestBlock(next.key) - const nextInline = document.getClosestInline(next.key) + const nextVoid = document.getClosestVoid(next.key) - // If the previous block is void, remove it. - if (nextBlock && nextBlock.isVoid) { - change.removeNodeByKey(nextBlock.key, { normalize }) - return - } - - // If the previous inline is void, remove it. - if (nextInline && nextInline.isVoid) { - change.removeNodeByKey(nextInline.key, { normalize }) + // If the next text node has a void parent, remove it. + if (nextVoid) { + change.removeNodeByKey(nextVoid.key, { normalize }) return } diff --git a/packages/slate/src/constants/core-schema-rules.js b/packages/slate/src/constants/core-schema-rules.js index 4a8294af1..0f574e131 100644 --- a/packages/slate/src/constants/core-schema-rules.js +++ b/packages/slate/src/constants/core-schema-rules.js @@ -93,32 +93,7 @@ const CORE_SCHEMA_RULES = [ }, /** - * Ensure that void nodes contain a text node with a single space of text. - * - * @type {Object} - */ - - { - validateNode(node) { - if (!node.isVoid) return - if (node.object != 'block' && node.object != 'inline') return - if (node.text == ' ' && node.nodes.size == 1) return - - return change => { - const text = Text.create(' ') - const index = node.nodes.size - - change.insertNodeByKey(node.key, index, text, { normalize: false }) - - node.nodes.forEach(child => { - change.removeNodeByKey(child.key, { normalize: false }) - }) - } - }, - }, - - /** - * Ensure that inline nodes are never empty. + * Ensure that inline non-void nodes are never empty. * * This rule is applied to all blocks, because when they contain an empty * inline, we need to remove the inline from that parent block. If `validate` @@ -131,9 +106,11 @@ const CORE_SCHEMA_RULES = [ { validateNode(node) { if (node.object != 'block') return + const invalids = node.nodes.filter( - n => n.object == 'inline' && n.text == '' + n => n.object === 'inline' && n.isVoid === false && n.text === '' ) + if (!invalids.size) return return change => { @@ -167,7 +144,9 @@ const CORE_SCHEMA_RULES = [ const prev = index > 0 ? node.nodes.get(index - 1) : null const next = node.nodes.get(index + 1) - // We don't test if "prev" is inline, since it has already been processed in the loop + + // We don't test if "prev" is inline, since it has already been + // processed in the loop const insertBefore = !prev const insertAfter = !next || next.object == 'inline' diff --git a/packages/slate/src/models/node.js b/packages/slate/src/models/node.js index 651e4dde9..be670172e 100644 --- a/packages/slate/src/models/node.js +++ b/packages/slate/src/models/node.js @@ -1692,7 +1692,7 @@ class Node { */ hasVoidParent(key) { - return !!this.getClosest(key, parent => parent.isVoid) + return !!this.getClosestVoid(key) } /** @@ -2071,7 +2071,6 @@ memoize( 'getPreviousText', 'getTextAtOffset', 'getTextsAtRangeAsArray', - 'hasVoidParent', 'validate', ], { diff --git a/packages/slate/test/changes/at-current-range/delete-backward/empty-after-void-block.js b/packages/slate/test/changes/at-current-range/delete-backward/empty-after-void-block.js index b8fa5f419..3b60f3b75 100644 --- a/packages/slate/test/changes/at-current-range/delete-backward/empty-after-void-block.js +++ b/packages/slate/test/changes/at-current-range/delete-backward/empty-after-void-block.js @@ -21,7 +21,6 @@ export const output = ( - {' '} diff --git a/packages/slate/test/changes/at-current-range/delete-forward/empty-before-void-block.js b/packages/slate/test/changes/at-current-range/delete-forward/empty-before-void-block.js index aafb1633a..3ac76c0c5 100644 --- a/packages/slate/test/changes/at-current-range/delete-forward/empty-before-void-block.js +++ b/packages/slate/test/changes/at-current-range/delete-forward/empty-before-void-block.js @@ -21,7 +21,7 @@ export const output = ( - {' '} + diff --git a/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-only-non-void.js b/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-only-non-void.js index 24b87ec32..090207500 100644 --- a/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-only-non-void.js +++ b/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-only-non-void.js @@ -13,7 +13,7 @@ export const input = ( one - {' '} + two diff --git a/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-partially-non-void-and-up-to-start-of-void.js b/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-partially-non-void-and-up-to-start-of-void.js index 7526cac6b..4061fdbd8 100644 --- a/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-partially-non-void-and-up-to-start-of-void.js +++ b/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-partially-non-void-and-up-to-start-of-void.js @@ -13,7 +13,7 @@ export const input = ( one - {' '} + three diff --git a/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-partially-non-void-and-void.js b/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-partially-non-void-and-void.js index 94f39ab3f..4061fdbd8 100644 --- a/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-partially-non-void-and-void.js +++ b/packages/slate/test/changes/at-current-range/delete/non-void-block-as-first-with-void-siblings-partially-non-void-and-void.js @@ -13,7 +13,6 @@ export const input = ( one - {' '} three diff --git a/packages/slate/test/changes/at-current-range/delete/void-block-as-first-with-non-void-siblings-select-void-end-and-next-word.js b/packages/slate/test/changes/at-current-range/delete/void-block-as-first-with-non-void-siblings-select-void-end-and-next-word.js index ec0cf17b1..06376f6df 100644 --- a/packages/slate/test/changes/at-current-range/delete/void-block-as-first-with-non-void-siblings-select-void-end-and-next-word.js +++ b/packages/slate/test/changes/at-current-range/delete/void-block-as-first-with-non-void-siblings-select-void-end-and-next-word.js @@ -10,7 +10,6 @@ export const input = ( - {' '} diff --git a/packages/slate/test/changes/at-current-range/delete/void-blocks-as-first-with-non-void-siblings-only-first-void.js b/packages/slate/test/changes/at-current-range/delete/void-blocks-as-first-with-non-void-siblings-only-first-void.js index f31cc2583..019ec3295 100644 --- a/packages/slate/test/changes/at-current-range/delete/void-blocks-as-first-with-non-void-siblings-only-first-void.js +++ b/packages/slate/test/changes/at-current-range/delete/void-blocks-as-first-with-non-void-siblings-only-first-void.js @@ -10,10 +10,10 @@ export const input = ( - {' '} + - {' '} + one two diff --git a/packages/slate/test/changes/at-current-range/delete/void-inline-as-first-with-non-void-sibling.js b/packages/slate/test/changes/at-current-range/delete/void-inline-as-first-with-non-void-sibling.js index cd0d1432e..c6057e166 100644 --- a/packages/slate/test/changes/at-current-range/delete/void-inline-as-first-with-non-void-sibling.js +++ b/packages/slate/test/changes/at-current-range/delete/void-inline-as-first-with-non-void-sibling.js @@ -11,7 +11,7 @@ export const input = ( - {' '} + abc diff --git a/packages/slate/test/changes/at-current-range/insert-block/is-void-end.js b/packages/slate/test/changes/at-current-range/insert-block/is-void-end.js index aa9fc35ec..0781baf72 100644 --- a/packages/slate/test/changes/at-current-range/insert-block/is-void-end.js +++ b/packages/slate/test/changes/at-current-range/insert-block/is-void-end.js @@ -10,8 +10,7 @@ export const input = ( - {' '} - + text text @@ -21,7 +20,7 @@ export const input = ( export const output = ( - + text diff --git a/packages/slate/test/changes/at-current-range/insert-block/is-void-start.js b/packages/slate/test/changes/at-current-range/insert-block/is-void-start.js index 5f555db00..ec663c430 100644 --- a/packages/slate/test/changes/at-current-range/insert-block/is-void-start.js +++ b/packages/slate/test/changes/at-current-range/insert-block/is-void-start.js @@ -10,7 +10,7 @@ export const input = ( - {' '} + text text @@ -23,7 +23,7 @@ export const output = ( - + text text diff --git a/packages/slate/test/changes/at-current-range/insert-inline/block-end.js b/packages/slate/test/changes/at-current-range/insert-inline/block-end.js index 147355711..ee6130f47 100644 --- a/packages/slate/test/changes/at-current-range/insert-inline/block-end.js +++ b/packages/slate/test/changes/at-current-range/insert-inline/block-end.js @@ -24,7 +24,6 @@ export const output = ( word - {' '} diff --git a/packages/slate/test/changes/at-current-range/insert-inline/block-middle.js b/packages/slate/test/changes/at-current-range/insert-inline/block-middle.js index 294a7ea4a..4df9aae97 100644 --- a/packages/slate/test/changes/at-current-range/insert-inline/block-middle.js +++ b/packages/slate/test/changes/at-current-range/insert-inline/block-middle.js @@ -24,7 +24,6 @@ export const output = ( wo - {' '} rd diff --git a/packages/slate/test/changes/at-current-range/insert-inline/block-start.js b/packages/slate/test/changes/at-current-range/insert-inline/block-start.js index f72bd8567..dac0a2de3 100644 --- a/packages/slate/test/changes/at-current-range/insert-inline/block-start.js +++ b/packages/slate/test/changes/at-current-range/insert-inline/block-start.js @@ -24,7 +24,6 @@ export const output = ( - {' '} word diff --git a/packages/slate/test/changes/at-current-range/insert-inline/inline-middle.js b/packages/slate/test/changes/at-current-range/insert-inline/inline-middle.js index 8414eb7c0..b877d7df3 100644 --- a/packages/slate/test/changes/at-current-range/insert-inline/inline-middle.js +++ b/packages/slate/test/changes/at-current-range/insert-inline/inline-middle.js @@ -27,7 +27,6 @@ export const output = ( wo - {' '} rd diff --git a/packages/slate/test/changes/at-current-range/insert-inline/is-empty.js b/packages/slate/test/changes/at-current-range/insert-inline/is-empty.js index e696168ac..df38230ef 100644 --- a/packages/slate/test/changes/at-current-range/insert-inline/is-empty.js +++ b/packages/slate/test/changes/at-current-range/insert-inline/is-empty.js @@ -24,7 +24,6 @@ export const output = ( - {' '} diff --git a/packages/slate/test/changes/at-current-range/insert-inline/with-inline.js b/packages/slate/test/changes/at-current-range/insert-inline/with-inline.js index 08b8ff562..ca81bd9ac 100644 --- a/packages/slate/test/changes/at-current-range/insert-inline/with-inline.js +++ b/packages/slate/test/changes/at-current-range/insert-inline/with-inline.js @@ -27,7 +27,6 @@ export const output = ( wo - {' '} rd diff --git a/packages/slate/test/changes/at-current-range/set-block/with-is-void.js b/packages/slate/test/changes/at-current-range/set-block/with-is-void.js index c4e0fe9bc..3f93a404b 100644 --- a/packages/slate/test/changes/at-current-range/set-block/with-is-void.js +++ b/packages/slate/test/changes/at-current-range/set-block/with-is-void.js @@ -23,7 +23,7 @@ export const output = ( - {' '} + word diff --git a/packages/slate/test/changes/at-current-range/set-inline/with-is-void.js b/packages/slate/test/changes/at-current-range/set-inline/with-is-void.js index 45e98a2f0..e71e2e5f8 100644 --- a/packages/slate/test/changes/at-current-range/set-inline/with-is-void.js +++ b/packages/slate/test/changes/at-current-range/set-inline/with-is-void.js @@ -21,13 +21,13 @@ export const input = ( ) -// TODO: fix cursor placement export const output = ( - - + + word + diff --git a/packages/slate/test/changes/by-key/remove-text-by-key/inline-void.js b/packages/slate/test/changes/by-key/remove-text-by-key/inline-void.js index dd69661a7..dbaa9f680 100644 --- a/packages/slate/test/changes/by-key/remove-text-by-key/inline-void.js +++ b/packages/slate/test/changes/by-key/remove-text-by-key/inline-void.js @@ -12,7 +12,7 @@ export const input = ( - {' '} + a @@ -24,8 +24,9 @@ export const output = ( - - + + + diff --git a/packages/slate/test/changes/by-key/set-node-by-key/inline-with-is-void.js b/packages/slate/test/changes/by-key/set-node-by-key/inline-with-is-void.js index bb12869eb..2913c7055 100644 --- a/packages/slate/test/changes/by-key/set-node-by-key/inline-with-is-void.js +++ b/packages/slate/test/changes/by-key/set-node-by-key/inline-with-is-void.js @@ -25,8 +25,9 @@ export const output = ( - - + + word + diff --git a/packages/slate/test/changes/general/call/call-no-arguments.js b/packages/slate/test/changes/general/call/call-no-arguments.js index 899e17a66..1deda9021 100644 --- a/packages/slate/test/changes/general/call/call-no-arguments.js +++ b/packages/slate/test/changes/general/call/call-no-arguments.js @@ -28,7 +28,6 @@ export const output = ( - {' '} one diff --git a/packages/slate/test/changes/general/call/call-with-arguments.js b/packages/slate/test/changes/general/call/call-with-arguments.js index a10213835..03330a39a 100644 --- a/packages/slate/test/changes/general/call/call-with-arguments.js +++ b/packages/slate/test/changes/general/call/call-with-arguments.js @@ -28,7 +28,6 @@ export const output = ( - {' '} one diff --git a/packages/slate/test/schema/custom/node-is-void-invalid-default.js b/packages/slate/test/schema/custom/node-is-void-invalid-default.js index 9b3dff941..a6b2bef78 100644 --- a/packages/slate/test/schema/custom/node-is-void-invalid-default.js +++ b/packages/slate/test/schema/custom/node-is-void-invalid-default.js @@ -21,7 +21,7 @@ export const input = ( export const output = ( - {/* prettier-ignore */ ' '} + ) diff --git a/packages/slate/test/serializers/raw/deserialize/block-with-is-void.js b/packages/slate/test/serializers/raw/deserialize/block-with-is-void.js index 9cf4589b5..6812cab48 100644 --- a/packages/slate/test/serializers/raw/deserialize/block-with-is-void.js +++ b/packages/slate/test/serializers/raw/deserialize/block-with-is-void.js @@ -19,7 +19,7 @@ export const input = { leaves: [ { object: 'leaf', - text: ' ', + text: '', marks: [], }, ], diff --git a/packages/slate/test/serializers/raw/deserialize/inline-with-is-void.js b/packages/slate/test/serializers/raw/deserialize/inline-with-is-void.js index 4d9ccc331..d01ad602c 100644 --- a/packages/slate/test/serializers/raw/deserialize/inline-with-is-void.js +++ b/packages/slate/test/serializers/raw/deserialize/inline-with-is-void.js @@ -35,7 +35,7 @@ export const input = { leaves: [ { object: 'leaf', - text: ' ', + text: '', marks: [], }, ], diff --git a/packages/slate/test/serializers/raw/serialize/block-with-is-void.js b/packages/slate/test/serializers/raw/serialize/block-with-is-void.js index d3c7018bb..61987804d 100644 --- a/packages/slate/test/serializers/raw/serialize/block-with-is-void.js +++ b/packages/slate/test/serializers/raw/serialize/block-with-is-void.js @@ -27,7 +27,7 @@ export const output = { leaves: [ { object: 'leaf', - text: ' ', + text: '', marks: [], }, ], diff --git a/packages/slate/test/serializers/raw/serialize/inline-with-is-void.js b/packages/slate/test/serializers/raw/serialize/inline-with-is-void.js index 7e03ffad4..2cfb8aa85 100644 --- a/packages/slate/test/serializers/raw/serialize/inline-with-is-void.js +++ b/packages/slate/test/serializers/raw/serialize/inline-with-is-void.js @@ -45,7 +45,7 @@ export const output = { leaves: [ { object: 'leaf', - text: ' ', + text: '', marks: [], }, ],