Skip to content

Commit

Permalink
Consistent insert* methods (#5415)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people committed May 6, 2023
1 parent 48c18b5 commit 01f0210
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 60 deletions.
6 changes: 6 additions & 0 deletions .changeset/tasty-lizards-remain.md
Original file line number Diff line number Diff line change
@@ -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.
18 changes: 9 additions & 9 deletions docs/api/nodes/editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
6 changes: 3 additions & 3 deletions docs/api/transforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}`.

Expand Down Expand Up @@ -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}`

Expand Down
8 changes: 6 additions & 2 deletions packages/slate/src/editor/insert-node.ts
Original file line number Diff line number Diff line change
@@ -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)
}
5 changes: 4 additions & 1 deletion packages/slate/src/editor/insert-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
37 changes: 23 additions & 14 deletions packages/slate/src/interfaces/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
21 changes: 12 additions & 9 deletions packages/slate/src/interfaces/transforms/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down
13 changes: 6 additions & 7 deletions packages/slate/src/interfaces/transforms/text.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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)
Expand Down
13 changes: 2 additions & 11 deletions packages/slate/src/transforms-node/insert-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
}

Expand Down
7 changes: 3 additions & 4 deletions packages/slate/src/transforms-text/insert-fragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 })
}
Expand Down
17 changes: 17 additions & 0 deletions packages/slate/src/utils/get-default-insert-location.ts
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions packages/slate/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './deep-equal'
export * from './get-default-insert-location'
export * from './match-path'
export * from './string'
export * from './types'
Expand Down

0 comments on commit 01f0210

Please sign in to comment.