mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-15 11:44:05 +02:00
Remove commands (#3351)
* remove commands in favor of editor-level functions * update examples * fix lint
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
import React, { useEffect, useRef, useMemo, useCallback } from 'react'
|
||||
import { Editor, Element, NodeEntry, Node, Range, Text } from 'slate'
|
||||
import {
|
||||
Editor,
|
||||
Element,
|
||||
NodeEntry,
|
||||
Node,
|
||||
Range,
|
||||
Text,
|
||||
Transforms,
|
||||
} from 'slate'
|
||||
import debounce from 'debounce'
|
||||
import scrollIntoView from 'scroll-into-view-if-needed'
|
||||
|
||||
@@ -252,7 +260,7 @@ export const Editable = (props: EditableProps) => {
|
||||
const range = ReactEditor.toSlateRange(editor, targetRange)
|
||||
|
||||
if (!selection || !Range.equals(selection, range)) {
|
||||
Editor.select(editor, range)
|
||||
Transforms.select(editor, range)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,7 +272,7 @@ export const Editable = (props: EditableProps) => {
|
||||
Range.isExpanded(selection) &&
|
||||
type.startsWith('delete')
|
||||
) {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -272,60 +280,60 @@ export const Editable = (props: EditableProps) => {
|
||||
case 'deleteByComposition':
|
||||
case 'deleteByCut':
|
||||
case 'deleteByDrag': {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteContent':
|
||||
case 'deleteContentForward': {
|
||||
editor.exec({ type: 'delete_forward', unit: 'character' })
|
||||
Editor.deleteForward(editor)
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteContentBackward': {
|
||||
editor.exec({ type: 'delete_backward', unit: 'character' })
|
||||
Editor.deleteBackward(editor)
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteEntireSoftLine': {
|
||||
editor.exec({ type: 'delete_backward', unit: 'line' })
|
||||
editor.exec({ type: 'delete_forward', unit: 'line' })
|
||||
Editor.deleteBackward(editor, { unit: 'line' })
|
||||
Editor.deleteForward(editor, { unit: 'line' })
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteHardLineBackward': {
|
||||
editor.exec({ type: 'delete_backward', unit: 'block' })
|
||||
Editor.deleteBackward(editor, { unit: 'block' })
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteSoftLineBackward': {
|
||||
editor.exec({ type: 'delete_backward', unit: 'line' })
|
||||
Editor.deleteBackward(editor, { unit: 'line' })
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteHardLineForward': {
|
||||
editor.exec({ type: 'delete_forward', unit: 'block' })
|
||||
Editor.deleteForward(editor, { unit: 'block' })
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteSoftLineForward': {
|
||||
editor.exec({ type: 'delete_forward', unit: 'line' })
|
||||
Editor.deleteForward(editor, { unit: 'line' })
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteWordBackward': {
|
||||
editor.exec({ type: 'delete_backward', unit: 'word' })
|
||||
Editor.deleteBackward(editor, { unit: 'word' })
|
||||
break
|
||||
}
|
||||
|
||||
case 'deleteWordForward': {
|
||||
editor.exec({ type: 'delete_forward', unit: 'word' })
|
||||
Editor.deleteForward(editor, { unit: 'word' })
|
||||
break
|
||||
}
|
||||
|
||||
case 'insertLineBreak':
|
||||
case 'insertParagraph': {
|
||||
editor.exec({ type: 'insert_break' })
|
||||
Editor.insertBreak(editor)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -336,9 +344,9 @@ export const Editable = (props: EditableProps) => {
|
||||
case 'insertReplacementText':
|
||||
case 'insertText': {
|
||||
if (data instanceof DataTransfer) {
|
||||
editor.exec({ type: 'insert_data', data })
|
||||
ReactEditor.insertData(editor, data)
|
||||
} else if (typeof data === 'string') {
|
||||
editor.exec({ type: 'insert_text', text: data })
|
||||
Editor.insertText(editor, data)
|
||||
}
|
||||
|
||||
break
|
||||
@@ -378,9 +386,9 @@ export const Editable = (props: EditableProps) => {
|
||||
hasEditableTarget(editor, domRange.endContainer)
|
||||
) {
|
||||
const range = ReactEditor.toSlateRange(editor, domRange)
|
||||
Editor.select(editor, range)
|
||||
Transforms.select(editor, range)
|
||||
} else {
|
||||
Editor.deselect(editor)
|
||||
Transforms.deselect(editor)
|
||||
}
|
||||
}
|
||||
}, 100),
|
||||
@@ -441,7 +449,7 @@ export const Editable = (props: EditableProps) => {
|
||||
if (IS_FIREFOX && !readOnly) {
|
||||
event.preventDefault()
|
||||
const text = (event as any).data as string
|
||||
editor.exec({ type: 'insert_text', text })
|
||||
Editor.insertText(editor, text)
|
||||
}
|
||||
},
|
||||
[readOnly]
|
||||
@@ -517,7 +525,7 @@ export const Editable = (props: EditableProps) => {
|
||||
|
||||
if (Editor.void(editor, { at: start })) {
|
||||
const range = Editor.range(editor, start)
|
||||
Editor.select(editor, range)
|
||||
Transforms.select(editor, range)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -536,7 +544,7 @@ export const Editable = (props: EditableProps) => {
|
||||
// type that we need. So instead, insert whenever a composition
|
||||
// ends since it will already have been committed to the DOM.
|
||||
if (!IS_SAFARI && !IS_FIREFOX && event.data) {
|
||||
editor.exec({ type: 'insert_text', text: event.data })
|
||||
Editor.insertText(editor, event.data)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -577,7 +585,7 @@ export const Editable = (props: EditableProps) => {
|
||||
const { selection } = editor
|
||||
|
||||
if (selection && Range.isExpanded(selection)) {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -615,7 +623,7 @@ export const Editable = (props: EditableProps) => {
|
||||
// so that it shows up in the selection's fragment.
|
||||
if (voidMatch) {
|
||||
const range = Editor.range(editor, path)
|
||||
Editor.select(editor, range)
|
||||
Transforms.select(editor, range)
|
||||
}
|
||||
|
||||
setFragmentData(event.dataTransfer, editor)
|
||||
@@ -641,8 +649,8 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
const range = ReactEditor.findEventRange(editor, event)
|
||||
const data = event.dataTransfer
|
||||
Editor.select(editor, range)
|
||||
editor.exec({ type: 'insert_data', data })
|
||||
Transforms.select(editor, range)
|
||||
ReactEditor.insertData(editor, data)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -688,13 +696,21 @@ export const Editable = (props: EditableProps) => {
|
||||
// hotkeys ourselves. (2019/11/06)
|
||||
if (Hotkeys.isRedo(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
editor.exec({ type: 'redo' })
|
||||
|
||||
if (editor.undo) {
|
||||
editor.undo()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (Hotkeys.isUndo(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
editor.exec({ type: 'undo' })
|
||||
|
||||
if (editor.redo) {
|
||||
editor.redo()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -704,19 +720,19 @@ export const Editable = (props: EditableProps) => {
|
||||
// (2017/10/17)
|
||||
if (Hotkeys.isMoveLineBackward(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
Editor.move(editor, { unit: 'line', reverse: true })
|
||||
Transforms.move(editor, { unit: 'line', reverse: true })
|
||||
return
|
||||
}
|
||||
|
||||
if (Hotkeys.isMoveLineForward(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
Editor.move(editor, { unit: 'line' })
|
||||
Transforms.move(editor, { unit: 'line' })
|
||||
return
|
||||
}
|
||||
|
||||
if (Hotkeys.isExtendLineBackward(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
Editor.move(editor, {
|
||||
Transforms.move(editor, {
|
||||
unit: 'line',
|
||||
edge: 'focus',
|
||||
reverse: true,
|
||||
@@ -726,7 +742,7 @@ export const Editable = (props: EditableProps) => {
|
||||
|
||||
if (Hotkeys.isExtendLineForward(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
Editor.move(editor, { unit: 'line', edge: 'focus' })
|
||||
Transforms.move(editor, { unit: 'line', edge: 'focus' })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -739,9 +755,9 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (selection && Range.isCollapsed(selection)) {
|
||||
Editor.move(editor, { reverse: true })
|
||||
Transforms.move(editor, { reverse: true })
|
||||
} else {
|
||||
Editor.collapse(editor, { edge: 'start' })
|
||||
Transforms.collapse(editor, { edge: 'start' })
|
||||
}
|
||||
|
||||
return
|
||||
@@ -751,9 +767,9 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (selection && Range.isCollapsed(selection)) {
|
||||
Editor.move(editor)
|
||||
Transforms.move(editor)
|
||||
} else {
|
||||
Editor.collapse(editor, { edge: 'end' })
|
||||
Transforms.collapse(editor, { edge: 'end' })
|
||||
}
|
||||
|
||||
return
|
||||
@@ -761,13 +777,13 @@ export const Editable = (props: EditableProps) => {
|
||||
|
||||
if (Hotkeys.isMoveWordBackward(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
Editor.move(editor, { unit: 'word', reverse: true })
|
||||
Transforms.move(editor, { unit: 'word', reverse: true })
|
||||
return
|
||||
}
|
||||
|
||||
if (Hotkeys.isMoveWordForward(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
Editor.move(editor, { unit: 'word' })
|
||||
Transforms.move(editor, { unit: 'word' })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -788,7 +804,7 @@ export const Editable = (props: EditableProps) => {
|
||||
|
||||
if (Hotkeys.isSplitBlock(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
editor.exec({ type: 'insert_break' })
|
||||
Editor.insertBreak(editor)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -796,9 +812,9 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (selection && Range.isExpanded(selection)) {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
} else {
|
||||
editor.exec({ type: 'delete_backward', unit: 'character' })
|
||||
Editor.deleteBackward(editor)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -808,9 +824,9 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (selection && Range.isExpanded(selection)) {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
} else {
|
||||
editor.exec({ type: 'delete_forward', unit: 'character' })
|
||||
Editor.deleteForward(editor)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -820,9 +836,9 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (selection && Range.isExpanded(selection)) {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
} else {
|
||||
editor.exec({ type: 'delete_backward', unit: 'line' })
|
||||
Editor.deleteBackward(editor, { unit: 'line' })
|
||||
}
|
||||
|
||||
return
|
||||
@@ -832,9 +848,9 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (selection && Range.isExpanded(selection)) {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
} else {
|
||||
editor.exec({ type: 'delete_forward', unit: 'line' })
|
||||
Editor.deleteForward(editor, { unit: 'line' })
|
||||
}
|
||||
|
||||
return
|
||||
@@ -844,9 +860,9 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (selection && Range.isExpanded(selection)) {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
} else {
|
||||
editor.exec({ type: 'delete_backward', unit: 'word' })
|
||||
Editor.deleteBackward(editor, { unit: 'word' })
|
||||
}
|
||||
|
||||
return
|
||||
@@ -856,9 +872,9 @@ export const Editable = (props: EditableProps) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (selection && Range.isExpanded(selection)) {
|
||||
editor.exec({ type: 'delete_fragment' })
|
||||
Editor.deleteFragment(editor)
|
||||
} else {
|
||||
editor.exec({ type: 'delete_forward', unit: 'word' })
|
||||
Editor.deleteForward(editor, { unit: 'word' })
|
||||
}
|
||||
|
||||
return
|
||||
@@ -879,10 +895,7 @@ export const Editable = (props: EditableProps) => {
|
||||
!isEventHandled(event, attributes.onPaste)
|
||||
) {
|
||||
event.preventDefault()
|
||||
editor.exec({
|
||||
type: 'insert_data',
|
||||
data: event.clipboardData,
|
||||
})
|
||||
ReactEditor.insertData(editor, event.clipboardData)
|
||||
}
|
||||
},
|
||||
[readOnly, attributes.onPaste]
|
||||
@@ -984,7 +997,10 @@ const isDOMEventHandled = (event: Event, handler?: (event: Event) => void) => {
|
||||
* Set the currently selected fragment to the clipboard.
|
||||
*/
|
||||
|
||||
const setFragmentData = (dataTransfer: DataTransfer, editor: Editor): void => {
|
||||
const setFragmentData = (
|
||||
dataTransfer: DataTransfer,
|
||||
editor: ReactEditor
|
||||
): void => {
|
||||
const { selection } = editor
|
||||
|
||||
if (!selection) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo, useState, useCallback } from 'react'
|
||||
import { Editor, Node, Range } from 'slate'
|
||||
import { Node } from 'slate'
|
||||
|
||||
import { ReactEditor } from '../plugin/react-editor'
|
||||
import { FocusedContext } from '../hooks/use-focused'
|
||||
@@ -13,7 +13,7 @@ import { EDITOR_TO_ON_CHANGE } from '../utils/weak-maps'
|
||||
*/
|
||||
|
||||
export const Slate = (props: {
|
||||
editor: Editor
|
||||
editor: ReactEditor
|
||||
value: Node[]
|
||||
children: React.ReactNode
|
||||
onChange: (value: Node[]) => void
|
||||
@@ -21,7 +21,7 @@ export const Slate = (props: {
|
||||
}) => {
|
||||
const { editor, children, onChange, value, ...rest } = props
|
||||
const [key, setKey] = useState(0)
|
||||
const context: [Editor] = useMemo(() => {
|
||||
const context: [ReactEditor] = useMemo(() => {
|
||||
editor.children = value
|
||||
Object.assign(editor, rest)
|
||||
return [editor]
|
||||
|
@@ -1,14 +1,15 @@
|
||||
import { Editor } from 'slate'
|
||||
import { createContext, useContext } from 'react'
|
||||
|
||||
import { ReactEditor } from '../plugin/react-editor'
|
||||
|
||||
/**
|
||||
* A React context for sharing the `Editor` class.
|
||||
* A React context for sharing the editor object.
|
||||
*/
|
||||
|
||||
export const EditorContext = createContext<Editor | null>(null)
|
||||
export const EditorContext = createContext<ReactEditor | null>(null)
|
||||
|
||||
/**
|
||||
* Get the current `Editor` class that the component lives under.
|
||||
* Get the current editor object from the React context.
|
||||
*/
|
||||
|
||||
export const useEditor = () => {
|
||||
|
@@ -1,15 +1,16 @@
|
||||
import { Editor } from 'slate'
|
||||
import { createContext, useContext } from 'react'
|
||||
|
||||
import { ReactEditor } from '../plugin/react-editor'
|
||||
|
||||
/**
|
||||
* A React context for sharing the `Editor` class, in a way that re-renders the
|
||||
* A React context for sharing the editor object, in a way that re-renders the
|
||||
* context whenever changes occur.
|
||||
*/
|
||||
|
||||
export const SlateContext = createContext<[Editor] | null>(null)
|
||||
export const SlateContext = createContext<[ReactEditor] | null>(null)
|
||||
|
||||
/**
|
||||
* Get the current `Editor` class that the component lives under.
|
||||
* Get the current editor object from the React context.
|
||||
*/
|
||||
|
||||
export const useSlate = () => {
|
||||
|
@@ -16,6 +16,5 @@ export { useSelected } from './hooks/use-selected'
|
||||
export { useSlate } from './hooks/use-slate'
|
||||
|
||||
// Plugin
|
||||
export { InsertDataCommand, ReactCommand } from './plugin/react-command'
|
||||
export { ReactEditor } from './plugin/react-editor'
|
||||
export { withReact } from './plugin/with-react'
|
||||
|
@@ -1,33 +0,0 @@
|
||||
import { Command } from 'slate'
|
||||
|
||||
/**
|
||||
* The `InsertDataCommand` inserts content from a `DataTransfer` object.
|
||||
*/
|
||||
|
||||
export interface InsertDataCommand {
|
||||
type: 'insert_data'
|
||||
data: DataTransfer
|
||||
}
|
||||
|
||||
/**
|
||||
* The `ReactCommand` union for all commands that the React plugins defines.
|
||||
*/
|
||||
|
||||
export type ReactCommand = InsertDataCommand
|
||||
|
||||
export const ReactCommand = {
|
||||
/**
|
||||
* Check if a value is a `ReactCommand` object.
|
||||
*/
|
||||
|
||||
isReactCommand(value: any): value is InsertDataCommand {
|
||||
if (Command.isCommand(value)) {
|
||||
switch (value.type) {
|
||||
case 'insert_data':
|
||||
return value.data instanceof DataTransfer
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
import { Editor, Element, Node, Path, Point, Range } from 'slate'
|
||||
import { Editor, Node, Path, Point, Range, Transforms } from 'slate'
|
||||
|
||||
import { Key } from '../utils/key'
|
||||
import {
|
||||
@@ -22,7 +22,13 @@ import {
|
||||
normalizeDOMPoint,
|
||||
} from '../utils/dom'
|
||||
|
||||
export interface ReactEditor extends Editor {}
|
||||
/**
|
||||
* A React and DOM-specific version of the `Editor` interface.
|
||||
*/
|
||||
|
||||
export interface ReactEditor extends Editor {
|
||||
insertData: (data: DataTransfer) => void
|
||||
}
|
||||
|
||||
export const ReactEditor = {
|
||||
/**
|
||||
@@ -129,7 +135,7 @@ export const ReactEditor = {
|
||||
}
|
||||
|
||||
if (selection) {
|
||||
Editor.deselect(editor)
|
||||
Transforms.deselect(editor)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -170,6 +176,14 @@ export const ReactEditor = {
|
||||
)
|
||||
},
|
||||
|
||||
/**
|
||||
* Insert data from a `DataTransfer` into the editor.
|
||||
*/
|
||||
|
||||
insertData(editor: ReactEditor, data: DataTransfer): void {
|
||||
editor.insertData(data)
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the native DOM element from a Slate node.
|
||||
*/
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Editor, Node, Path, Operation, Command } from 'slate'
|
||||
import { Editor, Node, Path, Operation, Transforms } from 'slate'
|
||||
|
||||
import { ReactEditor } from './react-editor'
|
||||
import { ReactCommand } from './react-command'
|
||||
import { Key } from '../utils/key'
|
||||
import { EDITOR_TO_ON_CHANGE, NODE_TO_KEY } from '../utils/weak-maps'
|
||||
|
||||
@@ -10,18 +9,19 @@ import { EDITOR_TO_ON_CHANGE, NODE_TO_KEY } from '../utils/weak-maps'
|
||||
* `withReact` adds React and DOM specific behaviors to the editor.
|
||||
*/
|
||||
|
||||
export const withReact = (editor: Editor): Editor => {
|
||||
const { apply, exec, onChange } = editor
|
||||
export const withReact = (editor: Editor): ReactEditor => {
|
||||
const e = editor as ReactEditor
|
||||
const { apply, onChange } = e
|
||||
|
||||
editor.apply = (op: Operation) => {
|
||||
e.apply = (op: Operation) => {
|
||||
const matches: [Path, Key][] = []
|
||||
|
||||
switch (op.type) {
|
||||
case 'insert_text':
|
||||
case 'remove_text':
|
||||
case 'set_node': {
|
||||
for (const [node, path] of Editor.levels(editor, { at: op.path })) {
|
||||
const key = ReactEditor.findKey(editor, node)
|
||||
for (const [node, path] of Editor.levels(e, { at: op.path })) {
|
||||
const key = ReactEditor.findKey(e, node)
|
||||
matches.push([path, key])
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ export const withReact = (editor: Editor): Editor => {
|
||||
case 'remove_node':
|
||||
case 'merge_node':
|
||||
case 'split_node': {
|
||||
for (const [node, path] of Editor.levels(editor, {
|
||||
for (const [node, path] of Editor.levels(e, {
|
||||
at: Path.parent(op.path),
|
||||
})) {
|
||||
const key = ReactEditor.findKey(editor, node)
|
||||
const key = ReactEditor.findKey(e, node)
|
||||
matches.push([path, key])
|
||||
}
|
||||
|
||||
@@ -51,53 +51,45 @@ export const withReact = (editor: Editor): Editor => {
|
||||
apply(op)
|
||||
|
||||
for (const [path, key] of matches) {
|
||||
const [node] = Editor.node(editor, path)
|
||||
const [node] = Editor.node(e, path)
|
||||
NODE_TO_KEY.set(node, key)
|
||||
}
|
||||
}
|
||||
|
||||
editor.exec = (command: Command) => {
|
||||
if (
|
||||
ReactCommand.isReactCommand(command) &&
|
||||
command.type === 'insert_data'
|
||||
) {
|
||||
const { data } = command
|
||||
const fragment = data.getData('application/x-slate-fragment')
|
||||
e.insertData = (data: DataTransfer) => {
|
||||
const fragment = data.getData('application/x-slate-fragment')
|
||||
|
||||
if (fragment) {
|
||||
const decoded = decodeURIComponent(window.atob(fragment))
|
||||
const parsed = JSON.parse(decoded) as Node[]
|
||||
Editor.insertFragment(editor, parsed)
|
||||
return
|
||||
}
|
||||
if (fragment) {
|
||||
const decoded = decodeURIComponent(window.atob(fragment))
|
||||
const parsed = JSON.parse(decoded) as Node[]
|
||||
Transforms.insertFragment(e, parsed)
|
||||
return
|
||||
}
|
||||
|
||||
const text = data.getData('text/plain')
|
||||
const text = data.getData('text/plain')
|
||||
|
||||
if (text) {
|
||||
const lines = text.split('\n')
|
||||
let split = false
|
||||
if (text) {
|
||||
const lines = text.split('\n')
|
||||
let split = false
|
||||
|
||||
for (const line of lines) {
|
||||
if (split) {
|
||||
Editor.splitNodes(editor)
|
||||
}
|
||||
|
||||
Editor.insertText(editor, line)
|
||||
split = true
|
||||
for (const line of lines) {
|
||||
if (split) {
|
||||
Transforms.splitNodes(e)
|
||||
}
|
||||
|
||||
Transforms.insertText(e, line)
|
||||
split = true
|
||||
}
|
||||
} else {
|
||||
exec(command)
|
||||
}
|
||||
}
|
||||
|
||||
editor.onChange = () => {
|
||||
e.onChange = () => {
|
||||
// COMPAT: React doesn't batch `setState` hook calls, which means that the
|
||||
// children and selection can get out of sync for one render pass. So we
|
||||
// have to use this unstable API to ensure it batches them. (2019/12/03)
|
||||
// https://github.com/facebook/react/issues/14259#issuecomment-439702367
|
||||
ReactDOM.unstable_batchedUpdates(() => {
|
||||
const onContextChange = EDITOR_TO_ON_CHANGE.get(editor)
|
||||
const onContextChange = EDITOR_TO_ON_CHANGE.get(e)
|
||||
|
||||
if (onContextChange) {
|
||||
onContextChange()
|
||||
@@ -107,5 +99,5 @@ export const withReact = (editor: Editor): Editor => {
|
||||
})
|
||||
}
|
||||
|
||||
return editor
|
||||
return e
|
||||
}
|
||||
|
Reference in New Issue
Block a user