mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-22 14:21:54 +02:00
Consistent insert* methods (#5415)
* feat: add reviewpad.yml file * Update reviewpad.yml * ✨ options to `Editor.insert*` * 📝 options to `Editor.insert*` * ✨ getDefaultInsertLocation * ✨ getDefaultInsertLocation * ✨ getDefaultInsertLocation * 📝 consistent selection * Create tasty-lizards-remain.md * Update tasty-lizards-remain.md --------- Co-authored-by: reviewpad[bot] <104832597+reviewpad[bot]@users.noreply.github.com> Co-authored-by: Dylan Schiemann <dylan@dojotoolkit.org>
This commit is contained in:
parent
48c18b5368
commit
01f0210bcc
6
.changeset/tasty-lizards-remain.md
Normal file
6
.changeset/tasty-lizards-remain.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
'slate': patch
|
||||
---
|
||||
|
||||
`Editor.insertFragment`, `Editor.insertNode`, `Editor.insertText` now accept `options`.
|
||||
For all insert methods, the default location is now the editor selection if `at` is not defined, or the end of document if `editor.selection` is not defined.
|
@ -246,23 +246,23 @@ Delete the content in the current selection.
|
||||
|
||||
Insert a block break at the current selection.
|
||||
|
||||
#### `Editor.insertFragment(editor: Editor, fragment: Node[]) => void`
|
||||
#### `Editor.insertFragment(editor: Editor, fragment: Node[], options?) => void`
|
||||
|
||||
Inserts a fragment _at the current selection_.
|
||||
Inserts a fragment at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
|
||||
If the selection is currently expanded, it will be deleted first. To atomically insert nodes (including at the very beginning or end), use [Transforms.insertNodes](../transforms.md#transformsinsertnodeseditor-editor-nodes-node--node-options).
|
||||
Options: `{at?: Location, hanging?: boolean, voids?: boolean}`
|
||||
|
||||
#### `Editor.insertNode(editor: Editor, node: Node) => void`
|
||||
#### `Editor.insertNode(editor: Editor, node: Node, options?) => void`
|
||||
|
||||
Inserts a node _at the current selection_.
|
||||
Atomically insert `node` at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
|
||||
If the selection is currently expanded, it will be deleted first. To atomically insert a node (including at the very beginning or end), use [Transforms.insertNodes](../transforms.md#transformsinsertnodeseditor-editor-nodes-node--node-options).
|
||||
Options supported: `NodeOptions & {hanging?: boolean, select?: boolean}`.
|
||||
|
||||
#### `Editor.insertText(editor: Editor, text: string) => void`
|
||||
#### `Editor.insertText(editor: Editor, text: string, options?) => void`
|
||||
|
||||
Inserts text _at the current selection_.
|
||||
Insert a string of text at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
|
||||
If the selection is currently expanded, it will be deleted first.
|
||||
Options: `{at?: Location, voids?: boolean}`
|
||||
|
||||
#### `Editor.removeMark(editor: Editor, key: string) => void`
|
||||
|
||||
|
@ -38,13 +38,13 @@ Transforms that operate on nodes.
|
||||
|
||||
#### `Transforms.insertFragment(editor: Editor, fragment: Node[], options?)`
|
||||
|
||||
Insert of fragment of nodes at the specified location in the document. If no location is specified, insert at the current selection.
|
||||
Insert of fragment of nodes at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
|
||||
Options: `{at?: Location, hanging?: boolean, voids?: boolean}`
|
||||
|
||||
#### `Transforms.insertNodes(editor: Editor, nodes: Node | Node[], options?)`
|
||||
|
||||
Atomically inserts `nodes` at the specified location in the document. If no location is specified, inserts at the current selection. If there is no selection, inserts at the end of the document.
|
||||
Atomically inserts `nodes` at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
|
||||
Options supported: `NodeOptions & {hanging?: boolean, select?: boolean}`.
|
||||
|
||||
@ -170,7 +170,7 @@ Options: `{at?: Location, distance?: number, unit?: 'character' | 'word' | 'line
|
||||
|
||||
#### `Transforms.insertText(editor: Editor, text: string, options?)`
|
||||
|
||||
Insert a string of text at the specified location in the document. If no location is specified, insert at the current selection.
|
||||
Insert a string of text at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
|
||||
Options: `{at?: Location, voids?: boolean}`
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { Transforms } from '../interfaces/transforms'
|
||||
import { EditorInterface } from '../interfaces/editor'
|
||||
|
||||
export const insertNode: EditorInterface['insertNode'] = (editor, node) => {
|
||||
Transforms.insertNodes(editor, node)
|
||||
export const insertNode: EditorInterface['insertNode'] = (
|
||||
editor,
|
||||
node,
|
||||
options
|
||||
) => {
|
||||
Transforms.insertNodes(editor, node, options)
|
||||
}
|
||||
|
@ -11,7 +11,10 @@ export const insertText: EditorInterface['insertText'] = (
|
||||
if (selection) {
|
||||
if (marks) {
|
||||
const node = { text, ...marks }
|
||||
Transforms.insertNodes(editor, node)
|
||||
Transforms.insertNodes(editor, node, {
|
||||
at: options.at,
|
||||
voids: options.voids,
|
||||
})
|
||||
} else {
|
||||
Transforms.insertText(editor, text, options)
|
||||
}
|
||||
|
@ -28,7 +28,11 @@ import {
|
||||
} from '../types/types'
|
||||
import { OmitFirstArg } from '../utils/types'
|
||||
import { isEditor } from '../editor/is-editor'
|
||||
import { TextInsertTextOptions } from './transforms/text'
|
||||
import {
|
||||
TextInsertFragmentOptions,
|
||||
TextInsertTextOptions,
|
||||
} from './transforms/text'
|
||||
import { NodeInsertNodesOptions } from './transforms/node'
|
||||
|
||||
/**
|
||||
* The `Editor` interface stores all the state of a Slate editor. It is extended
|
||||
@ -412,18 +416,24 @@ export interface EditorInterface {
|
||||
insertBreak: (editor: Editor) => void
|
||||
|
||||
/**
|
||||
* Insert a fragment at the current selection.
|
||||
*
|
||||
* If the selection is currently expanded, it will be deleted first.
|
||||
* Inserts a fragment
|
||||
* at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
*/
|
||||
insertFragment: (editor: Editor, fragment: Node[]) => void
|
||||
insertFragment: (
|
||||
editor: Editor,
|
||||
fragment: Node[],
|
||||
options?: TextInsertFragmentOptions
|
||||
) => void
|
||||
|
||||
/**
|
||||
* Insert a node at the current selection.
|
||||
*
|
||||
* If the selection is currently expanded, it will be deleted first.
|
||||
* Atomically inserts `nodes`
|
||||
* at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
*/
|
||||
insertNode: (editor: Editor, node: Node) => void
|
||||
insertNode: <T extends Node>(
|
||||
editor: Editor,
|
||||
node: Node,
|
||||
options?: NodeInsertNodesOptions<T>
|
||||
) => void
|
||||
|
||||
/**
|
||||
* Insert a soft break at the current selection.
|
||||
@ -433,9 +443,8 @@ export interface EditorInterface {
|
||||
insertSoftBreak: (editor: Editor) => void
|
||||
|
||||
/**
|
||||
* Insert text at the current selection.
|
||||
*
|
||||
* If the selection is currently expanded, it will be deleted first.
|
||||
* Insert a string of text
|
||||
* at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
*/
|
||||
insertText: (
|
||||
editor: Editor,
|
||||
@ -774,8 +783,8 @@ export const Editor: EditorInterface = {
|
||||
editor.insertBreak()
|
||||
},
|
||||
|
||||
insertFragment(editor, fragment) {
|
||||
editor.insertFragment(fragment)
|
||||
insertFragment(editor, fragment, options) {
|
||||
editor.insertFragment(fragment, options)
|
||||
},
|
||||
|
||||
insertNode(editor, node) {
|
||||
|
@ -2,21 +2,24 @@ import { Editor, Element, Location, Node, Path } from '../../index'
|
||||
import { NodeMatch, PropsCompare, PropsMerge } from '../editor'
|
||||
import { MaximizeMode, RangeMode } from '../../types/types'
|
||||
|
||||
export interface NodeInsertNodesOptions<T extends Node> {
|
||||
at?: Location
|
||||
match?: NodeMatch<T>
|
||||
mode?: RangeMode
|
||||
hanging?: boolean
|
||||
select?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
|
||||
export interface NodeTransforms {
|
||||
/**
|
||||
* Insert nodes at a specific location in the Editor.
|
||||
* Insert nodes in the editor
|
||||
* at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
*/
|
||||
insertNodes: <T extends Node>(
|
||||
editor: Editor,
|
||||
nodes: Node | Node[],
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: NodeMatch<T>
|
||||
mode?: RangeMode
|
||||
hanging?: boolean
|
||||
select?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
options?: NodeInsertNodesOptions<T>
|
||||
) => void
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Editor, Location, Node, Path, Range, Transforms } from '../../index'
|
||||
import { TextUnit } from '../../types/types'
|
||||
import { getDefaultInsertLocation } from '../../utils'
|
||||
|
||||
export interface TextDeleteOptions {
|
||||
at?: Location
|
||||
@ -28,7 +29,8 @@ export interface TextTransforms {
|
||||
delete: (editor: Editor, options?: TextDeleteOptions) => void
|
||||
|
||||
/**
|
||||
* Insert a fragment at a specific location in the editor.
|
||||
* Insert a fragment in the editor
|
||||
* at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
*/
|
||||
insertFragment: (
|
||||
editor: Editor,
|
||||
@ -37,7 +39,8 @@ export interface TextTransforms {
|
||||
) => void
|
||||
|
||||
/**
|
||||
* Insert a string of text in the Editor.
|
||||
* Insert a string of text in the editor
|
||||
* at the specified location or (if not defined) the current selection or (if not defined) the end of the document.
|
||||
*/
|
||||
insertText: (
|
||||
editor: Editor,
|
||||
@ -61,11 +64,7 @@ export const TextTransforms: TextTransforms = {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { voids = false } = options
|
||||
let { at = editor.selection } = options
|
||||
|
||||
if (!at) {
|
||||
return
|
||||
}
|
||||
let { at = getDefaultInsertLocation(editor) } = options
|
||||
|
||||
if (Path.isPath(at)) {
|
||||
at = Editor.range(editor, at)
|
||||
|
@ -7,6 +7,7 @@ import { Point } from '../interfaces/point'
|
||||
import { Text } from '../interfaces/text'
|
||||
import { Element } from '../interfaces/element'
|
||||
import { Path } from '../interfaces/path'
|
||||
import { getDefaultInsertLocation } from '../utils'
|
||||
|
||||
export const insertNodes: NodeTransforms['insertNodes'] = (
|
||||
editor,
|
||||
@ -27,18 +28,8 @@ export const insertNodes: NodeTransforms['insertNodes'] = (
|
||||
|
||||
const [node] = nodes
|
||||
|
||||
// By default, use the selection as the target location. But if there is
|
||||
// no selection, insert at the end of the document since that is such a
|
||||
// common use case when inserting from a non-selected state.
|
||||
if (!at) {
|
||||
if (editor.selection) {
|
||||
at = editor.selection
|
||||
} else if (editor.children.length > 0) {
|
||||
at = Editor.end(editor, [])
|
||||
} else {
|
||||
at = [0]
|
||||
}
|
||||
|
||||
at = getDefaultInsertLocation(editor)
|
||||
select = true
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { Element } from '../interfaces/element'
|
||||
import { Node, NodeEntry } from '../interfaces/node'
|
||||
import { Text } from '../interfaces/text'
|
||||
import { TextTransforms } from '../interfaces/transforms/text'
|
||||
import { getDefaultInsertLocation } from '../utils'
|
||||
|
||||
export const insertFragment: TextTransforms['insertFragment'] = (
|
||||
editor,
|
||||
@ -14,15 +15,13 @@ export const insertFragment: TextTransforms['insertFragment'] = (
|
||||
) => {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { hanging = false, voids = false } = options
|
||||
let { at = editor.selection } = options
|
||||
let { at = getDefaultInsertLocation(editor) } = options
|
||||
|
||||
if (!fragment.length) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!at) {
|
||||
return
|
||||
} else if (Range.isRange(at)) {
|
||||
if (Range.isRange(at)) {
|
||||
if (!hanging) {
|
||||
at = Editor.unhangRange(editor, at, { voids })
|
||||
}
|
||||
|
17
packages/slate/src/utils/get-default-insert-location.ts
Normal file
17
packages/slate/src/utils/get-default-insert-location.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { Editor, Location } from '../interfaces'
|
||||
|
||||
/**
|
||||
* Get the default location to insert content into the editor.
|
||||
* By default, use the selection as the target location. But if there is
|
||||
* no selection, insert at the end of the document since that is such a
|
||||
* common use case when inserting from a non-selected state.
|
||||
*/
|
||||
export const getDefaultInsertLocation = (editor: Editor): Location => {
|
||||
if (editor.selection) {
|
||||
return editor.selection
|
||||
} else if (editor.children.length > 0) {
|
||||
return Editor.end(editor, [])
|
||||
} else {
|
||||
return [0]
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
export * from './deep-equal'
|
||||
export * from './get-default-insert-location'
|
||||
export * from './match-path'
|
||||
export * from './string'
|
||||
export * from './types'
|
||||
|
Loading…
x
Reference in New Issue
Block a user