mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-02-01 13:18:29 +01:00
parent
c5f0626a05
commit
514f3de1be
@ -10,4 +10,4 @@ export const input = (
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = ' '
|
||||
export const output = ''
|
||||
|
@ -12,4 +12,4 @@ export const input = (
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = ' '
|
||||
export const output = ''
|
||||
|
@ -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 <span data-slate-zero-width="n">{'\u200B'}</span>
|
||||
}
|
||||
|
||||
// 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 <span data-slate-zero-width="z">{'\u200B'}</span>
|
||||
if (parent.isVoid) {
|
||||
return <span data-slate-zero-width="z">{'\u200B'}</span>
|
||||
}
|
||||
|
||||
// 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 <span data-slate-zero-width="n">{'\u200B'}</span>
|
||||
}
|
||||
|
||||
// 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 <span data-slate-zero-width="z">{'\u200B'}</span>
|
||||
if (text === '') {
|
||||
return <span data-slate-zero-width="z">{'\u200B'}</span>
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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',
|
||||
],
|
||||
{
|
||||
|
@ -21,7 +21,6 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
{' '}
|
||||
<cursor />
|
||||
</image>
|
||||
</document>
|
||||
|
@ -21,7 +21,7 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
<cursor />{' '}
|
||||
<cursor />
|
||||
</image>
|
||||
</document>
|
||||
</value>
|
||||
|
@ -13,7 +13,7 @@ export const input = (
|
||||
<anchor />one
|
||||
</paragraph>
|
||||
<image>
|
||||
<focus />{' '}
|
||||
<focus />
|
||||
</image>
|
||||
<paragraph>two</paragraph>
|
||||
</document>
|
||||
|
@ -13,7 +13,7 @@ export const input = (
|
||||
on<anchor />e
|
||||
</paragraph>
|
||||
<image>
|
||||
<focus />{' '}
|
||||
<focus />
|
||||
</image>
|
||||
<paragraph>three</paragraph>
|
||||
</document>
|
||||
|
@ -13,7 +13,6 @@ export const input = (
|
||||
on<anchor />e
|
||||
</paragraph>
|
||||
<image>
|
||||
{' '}
|
||||
<focus />
|
||||
</image>
|
||||
<paragraph>three</paragraph>
|
||||
|
@ -10,7 +10,6 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
{' '}
|
||||
<anchor />
|
||||
</image>
|
||||
<paragraph>
|
||||
|
@ -10,10 +10,10 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
<anchor />{' '}
|
||||
<anchor />
|
||||
</image>
|
||||
<image>
|
||||
<focus />{' '}
|
||||
<focus />
|
||||
</image>
|
||||
<paragraph>one</paragraph>
|
||||
<paragraph>two</paragraph>
|
||||
|
@ -11,7 +11,7 @@ export const input = (
|
||||
<document>
|
||||
<paragraph>
|
||||
<emoji>
|
||||
<anchor />{' '}
|
||||
<anchor />
|
||||
</emoji>
|
||||
<focus />abc
|
||||
</paragraph>
|
||||
|
@ -10,8 +10,7 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
{' '}
|
||||
<cursor />
|
||||
text<cursor />
|
||||
</image>
|
||||
<paragraph>text</paragraph>
|
||||
</document>
|
||||
@ -21,7 +20,7 @@ export const input = (
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<image />
|
||||
<image>text</image>
|
||||
<quote>
|
||||
<cursor />
|
||||
</quote>
|
||||
|
@ -10,7 +10,7 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
<cursor />{' '}
|
||||
<cursor />text
|
||||
</image>
|
||||
<paragraph>text</paragraph>
|
||||
</document>
|
||||
@ -23,7 +23,7 @@ export const output = (
|
||||
<quote>
|
||||
<cursor />
|
||||
</quote>
|
||||
<image />
|
||||
<image>text</image>
|
||||
<paragraph>text</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@ -24,7 +24,6 @@ export const output = (
|
||||
<document>
|
||||
<paragraph>
|
||||
word<emoji>
|
||||
{' '}
|
||||
<cursor />
|
||||
</emoji>
|
||||
</paragraph>
|
||||
|
@ -24,7 +24,6 @@ export const output = (
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<emoji>
|
||||
{' '}
|
||||
<cursor />
|
||||
</emoji>rd
|
||||
</paragraph>
|
||||
|
@ -24,7 +24,6 @@ export const output = (
|
||||
<document>
|
||||
<paragraph>
|
||||
<emoji>
|
||||
{' '}
|
||||
<cursor />
|
||||
</emoji>word
|
||||
</paragraph>
|
||||
|
@ -27,7 +27,6 @@ export const output = (
|
||||
<paragraph>
|
||||
<link>
|
||||
wo<emoji>
|
||||
{' '}
|
||||
<cursor />
|
||||
</emoji>rd
|
||||
</link>
|
||||
|
@ -24,7 +24,6 @@ export const output = (
|
||||
<document>
|
||||
<paragraph>
|
||||
<emoji>
|
||||
{' '}
|
||||
<cursor />
|
||||
</emoji>
|
||||
</paragraph>
|
||||
|
@ -27,7 +27,6 @@ export const output = (
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<emoji>
|
||||
{' '}
|
||||
<cursor />
|
||||
</emoji>rd
|
||||
</paragraph>
|
||||
|
@ -23,7 +23,7 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
<cursor />{' '}
|
||||
<cursor />word
|
||||
</image>
|
||||
</document>
|
||||
</value>
|
||||
|
@ -21,13 +21,13 @@ export const input = (
|
||||
</value>
|
||||
)
|
||||
|
||||
// TODO: fix cursor placement
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<cursor />
|
||||
<emoji />
|
||||
<emoji>
|
||||
<cursor />word
|
||||
</emoji>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@ -12,7 +12,7 @@ export const input = (
|
||||
<paragraph>
|
||||
<emoji>
|
||||
<text key="a">
|
||||
<cursor />{' '}
|
||||
<cursor />a
|
||||
</text>
|
||||
</emoji>
|
||||
</paragraph>
|
||||
@ -24,8 +24,9 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<cursor />
|
||||
<emoji />
|
||||
<emoji>
|
||||
<cursor />
|
||||
</emoji>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@ -25,8 +25,9 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<cursor />
|
||||
<emoji />
|
||||
<emoji>
|
||||
<cursor />word
|
||||
</emoji>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@ -28,7 +28,6 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
{' '}
|
||||
<cursor />
|
||||
</image>
|
||||
<paragraph>one</paragraph>
|
||||
|
@ -28,7 +28,6 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<image>
|
||||
{' '}
|
||||
<cursor />
|
||||
</image>
|
||||
<paragraph>one</paragraph>
|
||||
|
@ -21,7 +21,7 @@ export const input = (
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>{/* prettier-ignore */ ' '}</paragraph>
|
||||
<paragraph />
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ export const input = {
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' ',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
|
@ -35,7 +35,7 @@ export const input = {
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' ',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
|
@ -27,7 +27,7 @@ export const output = {
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' ',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
|
@ -45,7 +45,7 @@ export const output = {
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' ',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user