mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-18 13:11:17 +02:00
deprecate isVoid and related properties/methods (#2102)
#### Is this adding or improving a _feature_ or fixing a _bug_? Improvement. #### What's the new behavior? This deprecates the `node.isVoid` property in favor of using `schema.isVoid(node)`, which will allow us to remove the hardcoded "void" concept from the data model, and have it depend on the schema instead. This allows you to build different kinds of editors, with different void semantics, depending on your use case, without having this information hardcoded in the data itself. Even switching the `isVoid` semantics on the fly based on a user toggling a setting for example. #### How does this change work? This is the first step, which just deprecates `node.isVoid`, and provides the new alternative of `schema.isVoid(node)`, while still using the `isVoid` value of nodes under the covers. The next step is to change the logic to search the schema for real, and completely remove the `isVoid` value from nodes. #### Have you checked that...? <!-- Please run through this checklist for your pull request: --> * [x] The new code matches the existing patterns and styles. * [x] The tests pass with `yarn test`. * [x] The linter passes with `yarn lint`. (Fix errors with `yarn prettier`.) * [x] The relevant examples still work. (Run examples with `yarn watch`.)
This commit is contained in:
@@ -126,11 +126,13 @@ class Leaf extends React.Component {
|
||||
*/
|
||||
|
||||
renderText() {
|
||||
const { block, node, parent, text, index, leaves } = this.props
|
||||
const { block, node, editor, parent, text, index, leaves } = this.props
|
||||
const { value } = editor
|
||||
const { schema } = value
|
||||
|
||||
// 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) {
|
||||
if (schema.isVoid(parent)) {
|
||||
return <span data-slate-zero-width="z">{'\u200B'}</span>
|
||||
}
|
||||
|
||||
|
@@ -131,7 +131,7 @@ class Node extends React.Component {
|
||||
readOnly,
|
||||
} = this.props
|
||||
const { value } = editor
|
||||
const { selection } = value
|
||||
const { selection, schema } = value
|
||||
const { stack } = editor
|
||||
const indexes = node.getSelectionIndexes(selection, isSelected)
|
||||
const decs = decorations.concat(node.getDecorations(stack))
|
||||
@@ -184,7 +184,11 @@ class Node extends React.Component {
|
||||
children,
|
||||
})
|
||||
|
||||
return node.isVoid ? <Void {...this.props}>{element}</Void> : element
|
||||
return schema.isVoid(node) ? (
|
||||
<Void {...this.props}>{element}</Void>
|
||||
) : (
|
||||
element
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -163,9 +163,11 @@ function AfterPlugin() {
|
||||
if (editor.props.readOnly) return true
|
||||
|
||||
const { value } = change
|
||||
const { document } = value
|
||||
const { document, schema } = value
|
||||
const node = findNode(event.target, value)
|
||||
const isVoid = node && (node.isVoid || document.hasVoidParent(node.key))
|
||||
const ancestors = document.getAncestors(node.key)
|
||||
const isVoid =
|
||||
node && (schema.isVoid(node) || ancestors.some(a => schema.isVoid(a)))
|
||||
|
||||
if (isVoid) {
|
||||
// COMPAT: In Chrome & Safari, selections that are at the zero offset of
|
||||
@@ -209,10 +211,10 @@ function AfterPlugin() {
|
||||
// If user cuts a void block node or a void inline node,
|
||||
// manually removes it since selection is collapsed in this case.
|
||||
const { value } = change
|
||||
const { endBlock, endInline, selection } = value
|
||||
const { endBlock, endInline, selection, schema } = value
|
||||
const { isCollapsed } = selection
|
||||
const isVoidBlock = endBlock && endBlock.isVoid && isCollapsed
|
||||
const isVoidInline = endInline && endInline.isVoid && isCollapsed
|
||||
const isVoidBlock = endBlock && schema.isVoid(endBlock) && isCollapsed
|
||||
const isVoidInline = endInline && schema.isVoid(endInline) && isCollapsed
|
||||
|
||||
if (isVoidBlock) {
|
||||
editor.change(c => c.removeNodeByKey(endBlock.key))
|
||||
@@ -264,9 +266,11 @@ function AfterPlugin() {
|
||||
isDraggingInternally = true
|
||||
|
||||
const { value } = change
|
||||
const { document } = value
|
||||
const { document, schema } = value
|
||||
const node = findNode(event.target, value)
|
||||
const isVoid = node && (node.isVoid || document.hasVoidParent(node.key))
|
||||
const ancestors = document.getAncestors(node.key)
|
||||
const isVoid =
|
||||
node && (schema.isVoid(node) || ancestors.some(a => schema.isVoid(a)))
|
||||
|
||||
if (isVoid) {
|
||||
const encoded = Base64.serializeNode(node, { preserveKeys: true })
|
||||
@@ -290,7 +294,7 @@ function AfterPlugin() {
|
||||
debug('onDrop', { event })
|
||||
|
||||
const { value } = change
|
||||
const { document, selection } = value
|
||||
const { document, selection, schema } = value
|
||||
const window = getWindow(event.target)
|
||||
let target = getEventRange(event, value)
|
||||
if (!target) return
|
||||
@@ -322,7 +326,7 @@ function AfterPlugin() {
|
||||
|
||||
if (type == 'text' || type == 'html') {
|
||||
const { anchor } = target
|
||||
let hasVoidParent = document.hasVoidParent(anchor.key)
|
||||
let hasVoidParent = document.hasVoidParent(anchor.key, schema)
|
||||
|
||||
if (hasVoidParent) {
|
||||
let n = document.getNode(anchor.key)
|
||||
@@ -330,7 +334,7 @@ function AfterPlugin() {
|
||||
while (hasVoidParent) {
|
||||
n = document.getNextText(n.key)
|
||||
if (!n) break
|
||||
hasVoidParent = document.hasVoidParent(n.key)
|
||||
hasVoidParent = document.hasVoidParent(n.key, schema)
|
||||
}
|
||||
|
||||
if (n) change.moveToStartOfNode(n)
|
||||
@@ -451,6 +455,7 @@ function AfterPlugin() {
|
||||
debug('onKeyDown', { event })
|
||||
|
||||
const { value } = change
|
||||
const { schema } = value
|
||||
|
||||
// COMPAT: In iOS, some of these hotkeys are handled in the
|
||||
// `onNativeBeforeInput` handler of the `<Content>` component in order to
|
||||
@@ -522,7 +527,7 @@ function AfterPlugin() {
|
||||
if (Hotkeys.isMoveBackward(event)) {
|
||||
const { document, isInVoid, previousText, startText } = value
|
||||
const isPreviousInVoid =
|
||||
previousText && document.hasVoidParent(previousText.key)
|
||||
previousText && document.hasVoidParent(previousText.key, schema)
|
||||
|
||||
if (isInVoid || isPreviousInVoid || startText.text == '') {
|
||||
event.preventDefault()
|
||||
@@ -532,7 +537,8 @@ function AfterPlugin() {
|
||||
|
||||
if (Hotkeys.isMoveForward(event)) {
|
||||
const { document, isInVoid, nextText, startText } = value
|
||||
const isNextInVoid = nextText && document.hasVoidParent(nextText.key)
|
||||
const isNextInVoid =
|
||||
nextText && document.hasVoidParent(nextText.key, schema)
|
||||
|
||||
if (isInVoid || isNextInVoid || startText.text == '') {
|
||||
event.preventDefault()
|
||||
@@ -543,7 +549,7 @@ function AfterPlugin() {
|
||||
if (Hotkeys.isExtendBackward(event)) {
|
||||
const { document, isInVoid, previousText, startText } = value
|
||||
const isPreviousInVoid =
|
||||
previousText && document.hasVoidParent(previousText.key)
|
||||
previousText && document.hasVoidParent(previousText.key, schema)
|
||||
|
||||
if (isInVoid || isPreviousInVoid || startText.text == '') {
|
||||
event.preventDefault()
|
||||
@@ -553,7 +559,8 @@ function AfterPlugin() {
|
||||
|
||||
if (Hotkeys.isExtendForward(event)) {
|
||||
const { document, isInVoid, nextText, startText } = value
|
||||
const isNextInVoid = nextText && document.hasVoidParent(nextText.key)
|
||||
const isNextInVoid =
|
||||
nextText && document.hasVoidParent(nextText.key, schema)
|
||||
|
||||
if (isInVoid || isNextInVoid || startText.text == '') {
|
||||
event.preventDefault()
|
||||
@@ -583,8 +590,8 @@ function AfterPlugin() {
|
||||
if (type == 'text' || type == 'html') {
|
||||
if (!text) return
|
||||
const { value } = change
|
||||
const { document, selection, startBlock } = value
|
||||
if (startBlock.isVoid) return
|
||||
const { document, selection, startBlock, schema } = value
|
||||
if (schema.isVoid(startBlock)) return
|
||||
|
||||
const defaultBlock = startBlock
|
||||
const defaultMarks = document.getInsertMarksAtRange(selection)
|
||||
@@ -607,7 +614,7 @@ function AfterPlugin() {
|
||||
|
||||
const window = getWindow(event.target)
|
||||
const { value } = change
|
||||
const { document } = value
|
||||
const { document, schema } = value
|
||||
const native = window.getSelection()
|
||||
|
||||
// If there are no ranges, the editor was blurred natively.
|
||||
@@ -637,10 +644,10 @@ function AfterPlugin() {
|
||||
// selection, go with `0`. (2017/09/07)
|
||||
if (
|
||||
anchorBlock &&
|
||||
!anchorBlock.isVoid &&
|
||||
!schema.isVoid(anchorBlock) &&
|
||||
anchor.offset == 0 &&
|
||||
focusBlock &&
|
||||
focusBlock.isVoid &&
|
||||
schema.isVoid(focusBlock) &&
|
||||
focus.offset != 0
|
||||
) {
|
||||
range = range.setFocus(focus.setOffset(0))
|
||||
@@ -651,7 +658,7 @@ function AfterPlugin() {
|
||||
// standardizes the behavior, since it's indistinguishable to the user.
|
||||
if (
|
||||
anchorInline &&
|
||||
!anchorInline.isVoid &&
|
||||
!schema.isVoid(anchorInline) &&
|
||||
anchor.offset == anchorText.text.length
|
||||
) {
|
||||
const block = document.getClosestBlock(anchor.key)
|
||||
@@ -661,7 +668,7 @@ function AfterPlugin() {
|
||||
|
||||
if (
|
||||
focusInline &&
|
||||
!focusInline.isVoid &&
|
||||
!schema.isVoid(focusInline) &&
|
||||
focus.offset == focusText.text.length
|
||||
) {
|
||||
const block = document.getClosestBlock(focus.key)
|
||||
|
@@ -66,6 +66,7 @@ function BeforePlugin() {
|
||||
if (editor.props.readOnly) return true
|
||||
|
||||
const { value } = change
|
||||
const { schema } = value
|
||||
const { relatedTarget, target } = event
|
||||
const window = getWindow(target)
|
||||
|
||||
@@ -93,7 +94,8 @@ function BeforePlugin() {
|
||||
// editable section of an element that isn't a void node (eg. a list item
|
||||
// of the check list example).
|
||||
const node = findNode(relatedTarget, value)
|
||||
if (el.contains(relatedTarget) && node && !node.isVoid) return true
|
||||
if (el.contains(relatedTarget) && node && !schema.isVoid(node))
|
||||
return true
|
||||
}
|
||||
|
||||
debug('onBlur', { event })
|
||||
@@ -269,8 +271,10 @@ function BeforePlugin() {
|
||||
// call `preventDefault` to signal that drops are allowed.
|
||||
// When the target is editable, dropping is already allowed by
|
||||
// default, and calling `preventDefault` hides the cursor.
|
||||
const { value } = editor
|
||||
const { schema } = value
|
||||
const node = findNode(event.target, editor.value)
|
||||
if (node.isVoid) event.preventDefault()
|
||||
if (schema.isVoid(node)) event.preventDefault()
|
||||
|
||||
// COMPAT: IE won't call onDrop on contentEditables unless the
|
||||
// default dragOver is prevented:
|
||||
|
@@ -26,9 +26,10 @@ function cloneFragment(
|
||||
) {
|
||||
const window = getWindow(event.target)
|
||||
const native = window.getSelection()
|
||||
const { schema } = value
|
||||
const { start, end } = value.selection
|
||||
const startVoid = value.document.getClosestVoid(start.key)
|
||||
const endVoid = value.document.getClosestVoid(end.key)
|
||||
const startVoid = value.document.getClosestVoid(start.key, schema)
|
||||
const endVoid = value.document.getClosestVoid(end.key, schema)
|
||||
|
||||
// If the selection is collapsed, and it isn't inside a void node, abort.
|
||||
if (native.isCollapsed && !startVoid) return
|
||||
|
@@ -19,14 +19,14 @@ function getEventRange(event, value) {
|
||||
const { x, y, target } = event
|
||||
if (x == null || y == null) return null
|
||||
|
||||
const { document } = value
|
||||
const { document, schema } = value
|
||||
const node = findNode(target, value)
|
||||
if (!node) return null
|
||||
|
||||
// If the drop target is inside a void node, move it into either the next or
|
||||
// previous node, depending on which side the `x` and `y` coordinates are
|
||||
// closest to.
|
||||
if (node.isVoid) {
|
||||
if (schema.isVoid(node)) {
|
||||
const rect = target.getBoundingClientRect()
|
||||
const isPrevious =
|
||||
node.object == 'inline'
|
||||
|
Reference in New Issue
Block a user