mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-31 10:51:44 +02:00
Merge TypeScript types from master into main
This commit is contained in:
@@ -13,7 +13,7 @@ export const MERGING = new WeakMap<Editor, boolean | undefined>()
|
||||
* `HistoryEditor` contains helpers for history-enabled editors.
|
||||
*/
|
||||
|
||||
export interface HistoryEditor extends Editor {
|
||||
export type HistoryEditor = Editor & {
|
||||
history: History
|
||||
undo: () => void
|
||||
redo: () => void
|
||||
@@ -25,7 +25,7 @@ export const HistoryEditor = {
|
||||
*/
|
||||
|
||||
isHistoryEditor(value: any): value is HistoryEditor {
|
||||
return Editor.isEditor(value) && History.isHistory(value.history)
|
||||
return History.isHistory(value.history) && Editor.isEditor(value)
|
||||
},
|
||||
|
||||
/**
|
||||
|
6
packages/slate-history/test/jsx.d.ts
vendored
Normal file
6
packages/slate-history/test/jsx.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// This allows tests to include Slate Nodes written in JSX without TypeScript complaining.
|
||||
declare namespace jsx.JSX {
|
||||
interface IntrinsicElements {
|
||||
[elemName: string]: any // eslint-disable-line
|
||||
}
|
||||
}
|
@@ -237,7 +237,7 @@ export function createEditor(
|
||||
const selection: Partial<Range> = {}
|
||||
const editor = makeEditor()
|
||||
Object.assign(editor, attributes)
|
||||
editor.children = descendants
|
||||
editor.children = descendants as Element[]
|
||||
|
||||
// Search the document's texts to see if any of them have tokens associated
|
||||
// that need incorporated into the selection.
|
||||
|
6
packages/slate-hyperscript/test/jsx.d.ts
vendored
Normal file
6
packages/slate-hyperscript/test/jsx.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// This allows tests to include Slate Nodes written in JSX without TypeScript complaining.
|
||||
declare namespace jsx.JSX {
|
||||
interface IntrinsicElements {
|
||||
[elemName: string]: any // eslint-disable-line
|
||||
}
|
||||
}
|
@@ -24,6 +24,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"slate": "^0.60.0",
|
||||
"slate-history": "^0.60.0",
|
||||
"slate-hyperscript": "^0.60.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@@ -9,6 +9,7 @@ import {
|
||||
Transforms,
|
||||
Path,
|
||||
} from 'slate'
|
||||
import { HistoryEditor } from 'slate-history'
|
||||
import throttle from 'lodash/throttle'
|
||||
import scrollIntoView from 'scroll-into-view-if-needed'
|
||||
|
||||
@@ -766,7 +767,7 @@ export const Editable = (props: EditableProps) => {
|
||||
if (Hotkeys.isRedo(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
|
||||
if (typeof editor.redo === 'function') {
|
||||
if (HistoryEditor.isHistoryEditor(editor)) {
|
||||
editor.redo()
|
||||
}
|
||||
|
||||
@@ -776,7 +777,7 @@ export const Editable = (props: EditableProps) => {
|
||||
if (Hotkeys.isUndo(nativeEvent)) {
|
||||
event.preventDefault()
|
||||
|
||||
if (typeof editor.undo === 'function') {
|
||||
if (HistoryEditor.isHistoryEditor(editor)) {
|
||||
editor.undo()
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Text, Element } from 'slate'
|
||||
|
||||
import { Element, Text } from 'slate'
|
||||
import String from './string'
|
||||
import { PLACEHOLDER_SYMBOL } from '../utils/weak-maps'
|
||||
import { RenderLeafProps } from './editable'
|
||||
@@ -46,7 +45,7 @@ const Leaf = (props: {
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
>
|
||||
{leaf.placeholder as React.ReactNode}
|
||||
{leaf.placeholder}
|
||||
</span>
|
||||
{children}
|
||||
</React.Fragment>
|
||||
@@ -75,10 +74,6 @@ const MemoizedLeaf = React.memo(Leaf, (prev, next) => {
|
||||
)
|
||||
})
|
||||
|
||||
/**
|
||||
* The default custom leaf renderer.
|
||||
*/
|
||||
|
||||
export const DefaultLeaf = (props: RenderLeafProps) => {
|
||||
const { attributes, children } = props
|
||||
return <span {...attributes}>{children}</span>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo, useState, useCallback, useEffect } from 'react'
|
||||
import { Node } from 'slate'
|
||||
import { Node, Element, Descendant } from 'slate'
|
||||
|
||||
import { ReactEditor } from '../plugin/react-editor'
|
||||
import { FocusedContext } from '../hooks/use-focused'
|
||||
@@ -14,10 +14,9 @@ import { EDITOR_TO_ON_CHANGE } from '../utils/weak-maps'
|
||||
|
||||
export const Slate = (props: {
|
||||
editor: ReactEditor
|
||||
value: Node[]
|
||||
value: Descendant[]
|
||||
children: React.ReactNode
|
||||
onChange: (value: Node[]) => void
|
||||
[key: string]: unknown
|
||||
onChange: (value: Descendant[]) => void
|
||||
}) => {
|
||||
const { editor, children, onChange, value, ...rest } = props
|
||||
const [key, setKey] = useState(0)
|
||||
|
12
packages/slate-react/src/custom-types.ts
Normal file
12
packages/slate-react/src/custom-types.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { CustomTypes } from 'slate'
|
||||
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Text: {
|
||||
placeholder: string
|
||||
}
|
||||
Range: {
|
||||
placeholder?: string
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,6 +12,7 @@ import DOMText = globalThis.Text
|
||||
import DOMRange = globalThis.Range
|
||||
import DOMSelection = globalThis.Selection
|
||||
import DOMStaticRange = globalThis.StaticRange
|
||||
|
||||
export {
|
||||
DOMNode,
|
||||
DOMComment,
|
||||
|
@@ -1 +1,3 @@
|
||||
This package contains the core logic of Slate. Feel free to poke around to learn more!
|
||||
|
||||
Note: A number of source files contain extracted types for `Interfaces` or `Transforms`. This is done currently to enable custom type extensions as found in `packages/src/interfaces/custom-types.ts`.
|
||||
|
@@ -307,7 +307,7 @@ export const createEditor = (): Editor => {
|
||||
* Get the "dirty" paths generated from an operation.
|
||||
*/
|
||||
|
||||
const getDirtyPaths = (op: Operation) => {
|
||||
const getDirtyPaths = (op: Operation): Path[] => {
|
||||
switch (op.type) {
|
||||
case 'insert_text':
|
||||
case 'remove_text':
|
||||
|
@@ -11,4 +11,5 @@ export * from './interfaces/point-ref'
|
||||
export * from './interfaces/range'
|
||||
export * from './interfaces/range-ref'
|
||||
export * from './interfaces/text'
|
||||
export * from './interfaces/custom-types'
|
||||
export * from './transforms'
|
||||
|
11
packages/slate/src/interfaces/custom-types.ts
Normal file
11
packages/slate/src/interfaces/custom-types.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Extendable Custom Types Interface
|
||||
*/
|
||||
|
||||
export interface CustomTypes {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type ExtendedType<K extends string, B> = unknown extends CustomTypes[K]
|
||||
? B
|
||||
: B & CustomTypes[K]
|
@@ -4,8 +4,7 @@ import { reverse as reverseText } from 'esrever'
|
||||
|
||||
import {
|
||||
Ancestor,
|
||||
Descendant,
|
||||
Element,
|
||||
ExtendedType,
|
||||
Location,
|
||||
Node,
|
||||
NodeEntry,
|
||||
@@ -27,18 +26,23 @@ import {
|
||||
RANGE_REFS,
|
||||
} from '../utils/weak-maps'
|
||||
import { getWordDistance, getCharacterDistance } from '../utils/string'
|
||||
import { Descendant } from './node'
|
||||
import { Element } from './element'
|
||||
|
||||
export type BaseSelection = Range | null
|
||||
|
||||
export type Selection = ExtendedType<'Selection', BaseSelection>
|
||||
|
||||
/**
|
||||
* The `Editor` interface stores all the state of a Slate editor. It is extended
|
||||
* by plugins that wish to add their own helpers and implement new behaviors.
|
||||
*/
|
||||
|
||||
export interface Editor {
|
||||
children: Node[]
|
||||
selection: Range | null
|
||||
export interface BaseEditor {
|
||||
children: Descendant[]
|
||||
selection: Selection
|
||||
operations: Operation[]
|
||||
marks: Record<string, any> | null
|
||||
[key: string]: unknown
|
||||
marks: Omit<Text, 'text'> | null
|
||||
|
||||
// Schema-specific node behaviors.
|
||||
isInline: (element: Element) => boolean
|
||||
@@ -60,7 +64,208 @@ export interface Editor {
|
||||
removeMark: (key: string) => void
|
||||
}
|
||||
|
||||
export const Editor = {
|
||||
export type Editor = ExtendedType<'Editor', BaseEditor>
|
||||
|
||||
export interface EditorInterface {
|
||||
above: <T extends Ancestor>(
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: NodeMatch<T>
|
||||
mode?: 'highest' | 'lowest'
|
||||
voids?: boolean
|
||||
}
|
||||
) => NodeEntry<T> | undefined
|
||||
addMark: (editor: Editor, key: string, value: any) => void
|
||||
after: (
|
||||
editor: Editor,
|
||||
at: Location,
|
||||
options?: {
|
||||
distance?: number
|
||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||
}
|
||||
) => Point | undefined
|
||||
before: (
|
||||
editor: Editor,
|
||||
at: Location,
|
||||
options?: {
|
||||
distance?: number
|
||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||
}
|
||||
) => Point | undefined
|
||||
deleteBackward: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
unit?: 'character' | 'word' | 'line' | 'block'
|
||||
}
|
||||
) => void
|
||||
deleteForward: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
unit?: 'character' | 'word' | 'line' | 'block'
|
||||
}
|
||||
) => void
|
||||
deleteFragment: (editor: Editor) => void
|
||||
edges: (editor: Editor, at: Location) => [Point, Point]
|
||||
end: (editor: Editor, at: Location) => Point
|
||||
first: (editor: Editor, at: Location) => NodeEntry
|
||||
fragment: (editor: Editor, at: Location) => Descendant[]
|
||||
hasBlocks: (editor: Editor, element: Element) => boolean
|
||||
hasInlines: (editor: Editor, element: Element) => boolean
|
||||
hasTexts: (editor: Editor, element: Element) => boolean
|
||||
insertBreak: (editor: Editor) => void
|
||||
insertFragment: (editor: Editor, fragment: Node[]) => void
|
||||
insertNode: (editor: Editor, node: Node) => void
|
||||
insertText: (editor: Editor, text: string) => void
|
||||
isBlock: (editor: Editor, value: any) => value is Element
|
||||
isEditor: (value: any) => value is Editor
|
||||
isEnd: (editor: Editor, point: Point, at: Location) => boolean
|
||||
isEdge: (editor: Editor, point: Point, at: Location) => boolean
|
||||
isEmpty: (editor: Editor, element: Element) => boolean
|
||||
isInline: (editor: Editor, value: any) => value is Element
|
||||
isNormalizing: (editor: Editor) => boolean
|
||||
isStart: (editor: Editor, point: Point, at: Location) => boolean
|
||||
isVoid: (editor: Editor, value: any) => value is Element
|
||||
last: (editor: Editor, at: Location) => NodeEntry
|
||||
leaf: (
|
||||
editor: Editor,
|
||||
at: Location,
|
||||
options?: {
|
||||
depth?: number
|
||||
edge?: 'start' | 'end'
|
||||
}
|
||||
) => NodeEntry<Text>
|
||||
levels: <T extends Node>(
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: NodeMatch<T>
|
||||
reverse?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => Generator<NodeEntry<T>, void, undefined>
|
||||
marks: (editor: Editor) => Omit<Text, 'text'> | null
|
||||
next: <T extends Descendant>(
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: NodeMatch<T>
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
voids?: boolean
|
||||
}
|
||||
) => NodeEntry<T> | undefined
|
||||
node: (
|
||||
editor: Editor,
|
||||
at: Location,
|
||||
options?: {
|
||||
depth?: number
|
||||
edge?: 'start' | 'end'
|
||||
}
|
||||
) => NodeEntry
|
||||
nodes: <T extends Node>(
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location | Span
|
||||
match?: NodeMatch<T>
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
universal?: boolean
|
||||
reverse?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => Generator<NodeEntry<T>, void, undefined>
|
||||
normalize: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
force?: boolean
|
||||
}
|
||||
) => void
|
||||
parent: (
|
||||
editor: Editor,
|
||||
at: Location,
|
||||
options?: {
|
||||
depth?: number
|
||||
edge?: 'start' | 'end'
|
||||
}
|
||||
) => NodeEntry<Ancestor>
|
||||
path: (
|
||||
editor: Editor,
|
||||
at: Location,
|
||||
options?: {
|
||||
depth?: number
|
||||
edge?: 'start' | 'end'
|
||||
}
|
||||
) => Path
|
||||
pathRef: (
|
||||
editor: Editor,
|
||||
path: Path,
|
||||
options?: {
|
||||
affinity?: 'backward' | 'forward' | null
|
||||
}
|
||||
) => PathRef
|
||||
pathRefs: (editor: Editor) => Set<PathRef>
|
||||
point: (
|
||||
editor: Editor,
|
||||
at: Location,
|
||||
options?: {
|
||||
edge?: 'start' | 'end'
|
||||
}
|
||||
) => Point
|
||||
pointRef: (
|
||||
editor: Editor,
|
||||
point: Point,
|
||||
options?: {
|
||||
affinity?: 'backward' | 'forward' | null
|
||||
}
|
||||
) => PointRef
|
||||
pointRefs: (editor: Editor) => Set<PointRef>
|
||||
positions: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||
reverse?: boolean
|
||||
}
|
||||
) => Generator<Point, void, undefined>
|
||||
previous: <T extends Node>(
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: NodeMatch<T>
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
voids?: boolean
|
||||
}
|
||||
) => NodeEntry<T> | undefined
|
||||
range: (editor: Editor, at: Location, to?: Location) => Range
|
||||
rangeRef: (
|
||||
editor: Editor,
|
||||
range: Range,
|
||||
options?: {
|
||||
affinity?: 'backward' | 'forward' | 'outward' | 'inward' | null
|
||||
}
|
||||
) => RangeRef
|
||||
rangeRefs: (editor: Editor) => Set<RangeRef>
|
||||
removeMark: (editor: Editor, key: string) => void
|
||||
start: (editor: Editor, at: Location) => Point
|
||||
string: (editor: Editor, at: Location) => string
|
||||
unhangRange: (
|
||||
editor: Editor,
|
||||
range: Range,
|
||||
options?: {
|
||||
voids?: boolean
|
||||
}
|
||||
) => Range
|
||||
void: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
mode?: 'highest' | 'lowest'
|
||||
voids?: boolean
|
||||
}
|
||||
) => NodeEntry<Element> | undefined
|
||||
withoutNormalizing: (editor: Editor, fn: () => void) => void
|
||||
}
|
||||
|
||||
export const Editor: EditorInterface = {
|
||||
/**
|
||||
* Get the ancestor above a location in the document.
|
||||
*/
|
||||
@@ -121,6 +326,7 @@ export const Editor = {
|
||||
options: {
|
||||
distance?: number
|
||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||
voids?: boolean
|
||||
} = {}
|
||||
): Point | undefined {
|
||||
const anchor = Editor.point(editor, at, { edge: 'end' })
|
||||
@@ -130,7 +336,10 @@ export const Editor = {
|
||||
let d = 0
|
||||
let target
|
||||
|
||||
for (const p of Editor.positions(editor, { ...options, at: range })) {
|
||||
for (const p of Editor.positions(editor, {
|
||||
...options,
|
||||
at: range,
|
||||
})) {
|
||||
if (d > distance) {
|
||||
break
|
||||
}
|
||||
@@ -155,6 +364,7 @@ export const Editor = {
|
||||
options: {
|
||||
distance?: number
|
||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||
voids?: boolean
|
||||
} = {}
|
||||
): Point | undefined {
|
||||
const anchor = Editor.start(editor, [])
|
||||
@@ -503,7 +713,7 @@ export const Editor = {
|
||||
* Get the marks that would be added to text at the current selection.
|
||||
*/
|
||||
|
||||
marks(editor: Editor): Record<string, any> | null {
|
||||
marks(editor: Editor): Omit<Text, 'text'> | null {
|
||||
const { marks, selection } = editor
|
||||
|
||||
if (!selection) {
|
||||
@@ -554,7 +764,7 @@ export const Editor = {
|
||||
* Get the matching node in the branch of the document after a location.
|
||||
*/
|
||||
|
||||
next<T extends Node>(
|
||||
next<T extends Descendant>(
|
||||
editor: Editor,
|
||||
options: {
|
||||
at?: Location
|
||||
@@ -570,9 +780,13 @@ export const Editor = {
|
||||
return
|
||||
}
|
||||
|
||||
const [, from] = Editor.last(editor, at)
|
||||
const pointAfterLocation = Editor.after(editor, at, { voids })
|
||||
|
||||
if (!pointAfterLocation) return
|
||||
|
||||
const [, to] = Editor.last(editor, [])
|
||||
const span: Span = [from, to]
|
||||
|
||||
const span: Span = [pointAfterLocation.path, to]
|
||||
|
||||
if (Path.isPath(at) && at.length === 0) {
|
||||
throw new Error(`Cannot get the next node from the root node!`)
|
||||
@@ -587,7 +801,7 @@ export const Editor = {
|
||||
}
|
||||
}
|
||||
|
||||
const [, next] = Editor.nodes(editor, { at: span, match, mode, voids })
|
||||
const [next] = Editor.nodes(editor, { at: span, match, mode, voids })
|
||||
return next
|
||||
},
|
||||
|
||||
@@ -727,7 +941,7 @@ export const Editor = {
|
||||
options: {
|
||||
force?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
const { force = false } = options
|
||||
const getDirtyPaths = (editor: Editor) => {
|
||||
return DIRTY_PATHS.get(editor) || []
|
||||
@@ -973,8 +1187,9 @@ export const Editor = {
|
||||
* can pass the `unit: 'character'` option to moved forward one character, word,
|
||||
* or line at at time.
|
||||
*
|
||||
* Note: void nodes are treated as a single point, and iteration will not
|
||||
* happen inside their content.
|
||||
* Note: By default void nodes are treated as a single point and iteration
|
||||
* will not happen inside their content unless you pass in true for the
|
||||
* voids option, then iteration will occur.
|
||||
*/
|
||||
|
||||
*positions(
|
||||
@@ -983,9 +1198,15 @@ export const Editor = {
|
||||
at?: Location
|
||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||
reverse?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
): Generator<Point, void, undefined> {
|
||||
const { at = editor.selection, unit = 'offset', reverse = false } = options
|
||||
const {
|
||||
at = editor.selection,
|
||||
unit = 'offset',
|
||||
reverse = false,
|
||||
voids = false,
|
||||
} = options
|
||||
|
||||
if (!at) {
|
||||
return
|
||||
@@ -1024,11 +1245,12 @@ export const Editor = {
|
||||
distance = available >= 0 ? null : 0 - available
|
||||
}
|
||||
|
||||
for (const [node, path] of Editor.nodes(editor, { at, reverse })) {
|
||||
for (const [node, path] of Editor.nodes(editor, { at, reverse, voids })) {
|
||||
if (Element.isElement(node)) {
|
||||
// Void nodes are a special case, since we don't want to iterate over
|
||||
// their content. We instead always just yield their first point.
|
||||
if (editor.isVoid(node)) {
|
||||
// Void nodes are a special case, so by default we will always
|
||||
// yield their first point. If the voids option is set to true,
|
||||
// then we will iterate over their content
|
||||
if (!voids && editor.isVoid(node)) {
|
||||
yield Editor.start(editor, path)
|
||||
continue
|
||||
}
|
||||
@@ -1045,7 +1267,7 @@ export const Editor = {
|
||||
? start
|
||||
: Editor.start(editor, path)
|
||||
|
||||
const text = Editor.string(editor, { anchor: s, focus: e })
|
||||
const text = Editor.string(editor, { anchor: s, focus: e }, { voids })
|
||||
string = reverse ? reverseText(text) : text
|
||||
isNewBlock = true
|
||||
}
|
||||
@@ -1107,9 +1329,17 @@ export const Editor = {
|
||||
return
|
||||
}
|
||||
|
||||
const [, from] = Editor.first(editor, at)
|
||||
const pointBeforeLocation = Editor.before(editor, at, { voids })
|
||||
|
||||
if (!pointBeforeLocation) {
|
||||
return
|
||||
}
|
||||
|
||||
const [, to] = Editor.first(editor, [])
|
||||
const span: Span = [from, to]
|
||||
|
||||
// The search location is from the start of the document to the path of
|
||||
// the point before the location passed in
|
||||
const span: Span = [pointBeforeLocation.path, to]
|
||||
|
||||
if (Path.isPath(at) && at.length === 0) {
|
||||
throw new Error(`Cannot get the previous node from the root node!`)
|
||||
@@ -1124,7 +1354,7 @@ export const Editor = {
|
||||
}
|
||||
}
|
||||
|
||||
const [, previous] = Editor.nodes(editor, {
|
||||
const [previous] = Editor.nodes(editor, {
|
||||
reverse: true,
|
||||
at: span,
|
||||
match,
|
||||
@@ -1217,11 +1447,18 @@ export const Editor = {
|
||||
/**
|
||||
* Get the text string content of a location.
|
||||
*
|
||||
* Note: the text of void nodes is presumed to be an empty string, regardless
|
||||
* of what their actual content is.
|
||||
* Note: by default the text of void nodes is considered to be an empty
|
||||
* string, regardless of content, unless you pass in true for the voids option
|
||||
*/
|
||||
|
||||
string(editor: Editor, at: Location): string {
|
||||
string(
|
||||
editor: Editor,
|
||||
at: Location,
|
||||
options: {
|
||||
voids?: boolean
|
||||
} = {}
|
||||
): string {
|
||||
const { voids = false } = options
|
||||
const range = Editor.range(editor, at)
|
||||
const [start, end] = Range.edges(range)
|
||||
let text = ''
|
||||
@@ -1229,6 +1466,7 @@ export const Editor = {
|
||||
for (const [node, path] of Editor.nodes(editor, {
|
||||
at: range,
|
||||
match: Text.isText,
|
||||
voids,
|
||||
})) {
|
||||
let t = node.text
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import isPlainObject from 'is-plain-object'
|
||||
import { Editor, Node, Path } from '..'
|
||||
import { Editor, Node, Path, Descendant, ExtendedType, Ancestor } from '..'
|
||||
|
||||
/**
|
||||
* `Element` objects are a type of node in a Slate document that contain other
|
||||
@@ -7,12 +7,29 @@ import { Editor, Node, Path } from '..'
|
||||
* depending on the Slate editor's configuration.
|
||||
*/
|
||||
|
||||
export interface Element {
|
||||
children: Node[]
|
||||
[key: string]: unknown
|
||||
export interface BaseElement {
|
||||
children: Descendant[]
|
||||
}
|
||||
|
||||
export const Element = {
|
||||
export type Element = ExtendedType<'Element', BaseElement>
|
||||
|
||||
export interface ElementInterface {
|
||||
isAncestor: (value: any) => value is Ancestor
|
||||
isElement: (value: any) => value is Element
|
||||
isElementList: (value: any) => value is Element[]
|
||||
isElementProps: (props: any) => props is Partial<Element>
|
||||
matches: (element: Element, props: Partial<Element>) => boolean
|
||||
}
|
||||
|
||||
export const Element: ElementInterface = {
|
||||
/**
|
||||
* Check if a value implements the 'Ancestor' interface.
|
||||
*/
|
||||
|
||||
isAncestor(value: any): value is Ancestor {
|
||||
return isPlainObject(value) && Node.isNodeList(value.children)
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a value implements the `Element` interface.
|
||||
*/
|
||||
@@ -36,6 +53,14 @@ export const Element = {
|
||||
)
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a set of props is a partial of Element.
|
||||
*/
|
||||
|
||||
isElementProps(props: any): props is Partial<Element> {
|
||||
return (props as Partial<Element>).children !== undefined
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if an element matches set of properties.
|
||||
*
|
||||
|
@@ -11,7 +11,11 @@ import { Path, Point, Range } from '..'
|
||||
|
||||
export type Location = Path | Point | Range
|
||||
|
||||
export const Location = {
|
||||
export interface LocationInterface {
|
||||
isLocation: (value: any) => value is Location
|
||||
}
|
||||
|
||||
export const Location: LocationInterface = {
|
||||
/**
|
||||
* Check if a value implements the `Location` interface.
|
||||
*/
|
||||
@@ -28,7 +32,11 @@ export const Location = {
|
||||
|
||||
export type Span = [Path, Path]
|
||||
|
||||
export const Span = {
|
||||
export interface SpanInterface {
|
||||
isSpan: (value: any) => value is Span
|
||||
}
|
||||
|
||||
export const Span: SpanInterface = {
|
||||
/**
|
||||
* Check if a value implements the `Span` interface.
|
||||
*/
|
||||
|
@@ -1,14 +1,93 @@
|
||||
import { produce } from 'immer'
|
||||
import { Editor, Element, ElementEntry, Path, Range, Text } from '..'
|
||||
import { Editor, Path, Range, Text } from '..'
|
||||
import { Element, ElementEntry } from './element'
|
||||
import { ExtendedType } from './custom-types'
|
||||
|
||||
/**
|
||||
* The `Node` union type represents all of the different types of nodes that
|
||||
* occur in a Slate document tree.
|
||||
*/
|
||||
|
||||
export type Node = Editor | Element | Text
|
||||
export type BaseNode = Editor | Element | Text
|
||||
export type Node = ExtendedType<'Node', BaseNode>
|
||||
|
||||
export const Node = {
|
||||
export interface NodeInterface {
|
||||
ancestor: (root: Node, path: Path) => Ancestor
|
||||
ancestors: (
|
||||
root: Node,
|
||||
path: Path,
|
||||
options?: {
|
||||
reverse?: boolean
|
||||
}
|
||||
) => Generator<NodeEntry<Ancestor>, void, undefined>
|
||||
child: (root: Node, index: number) => Descendant
|
||||
children: (
|
||||
root: Node,
|
||||
path: Path,
|
||||
options?: {
|
||||
reverse?: boolean
|
||||
}
|
||||
) => Generator<NodeEntry<Descendant>, void, undefined>
|
||||
common: (root: Node, path: Path, another: Path) => NodeEntry
|
||||
descendant: (root: Node, path: Path) => Descendant
|
||||
descendants: (
|
||||
root: Node,
|
||||
options?: {
|
||||
from?: Path
|
||||
to?: Path
|
||||
reverse?: boolean
|
||||
pass?: (node: NodeEntry) => boolean
|
||||
}
|
||||
) => Generator<NodeEntry<Descendant>, void, undefined>
|
||||
elements: (
|
||||
root: Node,
|
||||
options?: {
|
||||
from?: Path
|
||||
to?: Path
|
||||
reverse?: boolean
|
||||
pass?: (node: NodeEntry) => boolean
|
||||
}
|
||||
) => Generator<ElementEntry, void, undefined>
|
||||
extractProps: (node: Node) => NodeProps
|
||||
first: (root: Node, path: Path) => NodeEntry
|
||||
fragment: (root: Node, range: Range) => Descendant[]
|
||||
get: (root: Node, path: Path) => Node
|
||||
has: (root: Node, path: Path) => boolean
|
||||
isNode: (value: any) => value is Node
|
||||
isNodeList: (value: any) => value is Node[]
|
||||
last: (root: Node, path: Path) => NodeEntry
|
||||
leaf: (root: Node, path: Path) => Text
|
||||
levels: (
|
||||
root: Node,
|
||||
path: Path,
|
||||
options?: {
|
||||
reverse?: boolean
|
||||
}
|
||||
) => Generator<NodeEntry, void, undefined>
|
||||
matches: (node: Node, props: Partial<Node>) => boolean
|
||||
nodes: (
|
||||
root: Node,
|
||||
options?: {
|
||||
from?: Path
|
||||
to?: Path
|
||||
reverse?: boolean
|
||||
pass?: (entry: NodeEntry) => boolean
|
||||
}
|
||||
) => Generator<NodeEntry, void, undefined>
|
||||
parent: (root: Node, path: Path) => Ancestor
|
||||
string: (node: Node) => string
|
||||
texts: (
|
||||
root: Node,
|
||||
options?: {
|
||||
from?: Path
|
||||
to?: Path
|
||||
reverse?: boolean
|
||||
pass?: (node: NodeEntry) => boolean
|
||||
}
|
||||
) => Generator<NodeEntry<Text>, void, undefined>
|
||||
}
|
||||
|
||||
export const Node: NodeInterface = {
|
||||
/**
|
||||
* Get the node at a specific path, asserting that it's an ancestor node.
|
||||
*/
|
||||
@@ -164,6 +243,22 @@ export const Node = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Extract props from a Node.
|
||||
*/
|
||||
|
||||
extractProps(node: Node): NodeProps {
|
||||
if (Element.isAncestor(node)) {
|
||||
const { children, ...properties } = node
|
||||
|
||||
return properties
|
||||
} else {
|
||||
const { text, ...properties } = node
|
||||
|
||||
return properties
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the first node entry in a root node from a path.
|
||||
*/
|
||||
@@ -222,7 +317,7 @@ export const Node = {
|
||||
}
|
||||
}
|
||||
|
||||
delete r.selection
|
||||
if (Editor.isEditor(r)) delete r.selection
|
||||
})
|
||||
|
||||
return newRoot.children
|
||||
@@ -354,8 +449,12 @@ export const Node = {
|
||||
|
||||
matches(node: Node, props: Partial<Node>): boolean {
|
||||
return (
|
||||
(Element.isElement(node) && Element.matches(node, props)) ||
|
||||
(Text.isText(node) && Text.matches(node, props))
|
||||
(Element.isElement(node) &&
|
||||
Element.isElementProps(props) &&
|
||||
Element.matches(node, props)) ||
|
||||
(Text.isText(node) &&
|
||||
Text.isTextProps(props) &&
|
||||
Text.matches(node, props))
|
||||
)
|
||||
},
|
||||
|
||||
@@ -516,3 +615,11 @@ export type Ancestor = Editor | Element
|
||||
*/
|
||||
|
||||
export type NodeEntry<T extends Node = Node> = [T, Path]
|
||||
|
||||
/**
|
||||
* Convenience type for returning the props of a node.
|
||||
*/
|
||||
export type NodeProps =
|
||||
| Omit<Editor, 'children'>
|
||||
| Omit<Element, 'children'>
|
||||
| Omit<Text, 'text'>
|
||||
|
@@ -1,87 +1,121 @@
|
||||
import { Node, Path, Range } from '..'
|
||||
import { ExtendedType, Node, Path, Range } from '..'
|
||||
import isPlainObject from 'is-plain-object'
|
||||
|
||||
export type InsertNodeOperation = {
|
||||
export type BaseInsertNodeOperation = {
|
||||
type: 'insert_node'
|
||||
path: Path
|
||||
node: Node
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type InsertTextOperation = {
|
||||
export type InsertNodeOperation = ExtendedType<
|
||||
'InsertNodeOperation',
|
||||
BaseInsertNodeOperation
|
||||
>
|
||||
|
||||
export type BaseInsertTextOperation = {
|
||||
type: 'insert_text'
|
||||
path: Path
|
||||
offset: number
|
||||
text: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type MergeNodeOperation = {
|
||||
export type InsertTextOperation = ExtendedType<
|
||||
'InsertTextOperation',
|
||||
BaseInsertTextOperation
|
||||
>
|
||||
|
||||
export type BaseMergeNodeOperation = {
|
||||
type: 'merge_node'
|
||||
path: Path
|
||||
position: number
|
||||
properties: Partial<Node>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type MoveNodeOperation = {
|
||||
export type MergeNodeOperation = ExtendedType<
|
||||
'MergeNodeOperation',
|
||||
BaseMergeNodeOperation
|
||||
>
|
||||
|
||||
export type BaseMoveNodeOperation = {
|
||||
type: 'move_node'
|
||||
path: Path
|
||||
newPath: Path
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type RemoveNodeOperation = {
|
||||
export type MoveNodeOperation = ExtendedType<
|
||||
'MoveNodeOperation',
|
||||
BaseMoveNodeOperation
|
||||
>
|
||||
|
||||
export type BaseRemoveNodeOperation = {
|
||||
type: 'remove_node'
|
||||
path: Path
|
||||
node: Node
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type RemoveTextOperation = {
|
||||
export type RemoveNodeOperation = ExtendedType<
|
||||
'RemoveNodeOperation',
|
||||
BaseRemoveNodeOperation
|
||||
>
|
||||
|
||||
export type BaseRemoveTextOperation = {
|
||||
type: 'remove_text'
|
||||
path: Path
|
||||
offset: number
|
||||
text: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SetNodeOperation = {
|
||||
export type RemoveTextOperation = ExtendedType<
|
||||
'RemoveTextOperation',
|
||||
BaseRemoveTextOperation
|
||||
>
|
||||
|
||||
export type BaseSetNodeOperation = {
|
||||
type: 'set_node'
|
||||
path: Path
|
||||
properties: Partial<Node>
|
||||
newProperties: Partial<Node>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SetSelectionOperation =
|
||||
export type SetNodeOperation = ExtendedType<
|
||||
'SetNodeOperation',
|
||||
BaseSetNodeOperation
|
||||
>
|
||||
|
||||
export type BaseSetSelectionOperation =
|
||||
| {
|
||||
type: 'set_selection'
|
||||
[key: string]: unknown
|
||||
properties: null
|
||||
newProperties: Range
|
||||
}
|
||||
| {
|
||||
type: 'set_selection'
|
||||
[key: string]: unknown
|
||||
properties: Partial<Range>
|
||||
newProperties: Partial<Range>
|
||||
}
|
||||
| {
|
||||
type: 'set_selection'
|
||||
[key: string]: unknown
|
||||
properties: Range
|
||||
newProperties: null
|
||||
}
|
||||
|
||||
export type SplitNodeOperation = {
|
||||
export type SetSelectionOperation = ExtendedType<
|
||||
'SetSelectionOperation',
|
||||
BaseSetSelectionOperation
|
||||
>
|
||||
|
||||
export type BaseSplitNodeOperation = {
|
||||
type: 'split_node'
|
||||
path: Path
|
||||
position: number
|
||||
properties: Partial<Node>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type SplitNodeOperation = ExtendedType<
|
||||
'SplitNodeOperation',
|
||||
BaseSplitNodeOperation
|
||||
>
|
||||
|
||||
export type NodeOperation =
|
||||
| InsertNodeOperation
|
||||
| MergeNodeOperation
|
||||
@@ -103,7 +137,16 @@ export type TextOperation = InsertTextOperation | RemoveTextOperation
|
||||
|
||||
export type Operation = NodeOperation | SelectionOperation | TextOperation
|
||||
|
||||
export const Operation = {
|
||||
export interface OperationInterface {
|
||||
isNodeOperation: (value: any) => value is NodeOperation
|
||||
isOperation: (value: any) => value is Operation
|
||||
isOperationList: (value: any) => value is Operation[]
|
||||
isSelectionOperation: (value: any) => value is SelectionOperation
|
||||
isTextOperation: (value: any) => value is TextOperation
|
||||
inverse: (op: Operation) => Operation
|
||||
}
|
||||
|
||||
export const Operation: OperationInterface = {
|
||||
/**
|
||||
* Check of a value is a `NodeOperation` object.
|
||||
*/
|
||||
|
@@ -12,7 +12,11 @@ export interface PathRef {
|
||||
unref(): Path | null
|
||||
}
|
||||
|
||||
export const PathRef = {
|
||||
export interface PathRefInterface {
|
||||
transform: (ref: PathRef, op: Operation) => void
|
||||
}
|
||||
|
||||
export const PathRef: PathRefInterface = {
|
||||
/**
|
||||
* Transform the path ref's current value by an operation.
|
||||
*/
|
||||
|
@@ -9,7 +9,41 @@ import { Operation } from '..'
|
||||
|
||||
export type Path = number[]
|
||||
|
||||
export const Path = {
|
||||
export interface PathInterface {
|
||||
ancestors: (path: Path, options?: { reverse?: boolean }) => Path[]
|
||||
common: (path: Path, another: Path) => Path
|
||||
compare: (path: Path, another: Path) => -1 | 0 | 1
|
||||
endsAfter: (path: Path, another: Path) => boolean
|
||||
endsAt: (path: Path, another: Path) => boolean
|
||||
endsBefore: (path: Path, another: Path) => boolean
|
||||
equals: (path: Path, another: Path) => boolean
|
||||
isAfter: (path: Path, another: Path) => boolean
|
||||
isAncestor: (path: Path, another: Path) => boolean
|
||||
isBefore: (path: Path, another: Path) => boolean
|
||||
isChild: (path: Path, another: Path) => boolean
|
||||
isCommon: (path: Path, another: Path) => boolean
|
||||
isDescendant: (path: Path, another: Path) => boolean
|
||||
isParent: (path: Path, another: Path) => boolean
|
||||
isPath: (value: any) => value is Path
|
||||
isSibling: (path: Path, another: Path) => boolean
|
||||
levels: (
|
||||
path: Path,
|
||||
options?: {
|
||||
reverse?: boolean
|
||||
}
|
||||
) => Path[]
|
||||
next: (path: Path) => Path
|
||||
parent: (path: Path) => Path
|
||||
previous: (path: Path) => Path
|
||||
relative: (path: Path, ancestor: Path) => Path
|
||||
transform: (
|
||||
path: Path,
|
||||
operation: Operation,
|
||||
options?: { affinity?: 'forward' | 'backward' | null }
|
||||
) => Path | null
|
||||
}
|
||||
|
||||
export const Path: PathInterface = {
|
||||
/**
|
||||
* Get a list of ancestor paths for a given path.
|
||||
*
|
||||
|
@@ -12,7 +12,11 @@ export interface PointRef {
|
||||
unref(): Point | null
|
||||
}
|
||||
|
||||
export const PointRef = {
|
||||
export interface PointRefInterface {
|
||||
transform: (ref: PointRef, op: Operation) => void
|
||||
}
|
||||
|
||||
export const PointRef: PointRefInterface = {
|
||||
/**
|
||||
* Transform the point ref's current value by an operation.
|
||||
*/
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import isPlainObject from 'is-plain-object'
|
||||
import { produce } from 'immer'
|
||||
import { Operation, Path } from '..'
|
||||
import { ExtendedType, Operation, Path } from '..'
|
||||
|
||||
/**
|
||||
* `Point` objects refer to a specific location in a text node in a Slate
|
||||
@@ -9,13 +9,27 @@ import { Operation, Path } from '..'
|
||||
* only refer to `Text` nodes.
|
||||
*/
|
||||
|
||||
export interface Point {
|
||||
export interface BasePoint {
|
||||
path: Path
|
||||
offset: number
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export const Point = {
|
||||
export type Point = ExtendedType<'Point', BasePoint>
|
||||
|
||||
export interface PointInterface {
|
||||
compare: (point: Point, another: Point) => -1 | 0 | 1
|
||||
isAfter: (point: Point, another: Point) => boolean
|
||||
isBefore: (point: Point, another: Point) => boolean
|
||||
equals: (point: Point, another: Point) => boolean
|
||||
isPoint: (value: any) => value is Point
|
||||
transform: (
|
||||
point: Point,
|
||||
op: Operation,
|
||||
options?: { affinity?: 'forward' | 'backward' | null }
|
||||
) => Point | null
|
||||
}
|
||||
|
||||
export const Point: PointInterface = {
|
||||
/**
|
||||
* Compare a point to another, returning an integer indicating whether the
|
||||
* point was before, at, or after the other.
|
||||
|
@@ -12,7 +12,11 @@ export interface RangeRef {
|
||||
unref(): Range | null
|
||||
}
|
||||
|
||||
export const RangeRef = {
|
||||
export interface RangeRefInterface {
|
||||
transform: (ref: RangeRef, op: Operation) => void
|
||||
}
|
||||
|
||||
export const RangeRef: RangeRefInterface = {
|
||||
/**
|
||||
* Transform the range ref's current value by an operation.
|
||||
*/
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { produce } from 'immer'
|
||||
import isPlainObject from 'is-plain-object'
|
||||
import { Operation, Path, Point, PointEntry } from '..'
|
||||
import { ExtendedType, Operation, Path, Point, PointEntry } from '..'
|
||||
|
||||
/**
|
||||
* `Range` objects are a set of points that refer to a specific span of a Slate
|
||||
@@ -8,13 +8,41 @@ import { Operation, Path, Point, PointEntry } from '..'
|
||||
* multiple nodes.
|
||||
*/
|
||||
|
||||
export interface Range {
|
||||
export interface BaseRange {
|
||||
anchor: Point
|
||||
focus: Point
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export const Range = {
|
||||
export type Range = ExtendedType<'Range', BaseRange>
|
||||
|
||||
export interface RangeInterface {
|
||||
edges: (
|
||||
range: Range,
|
||||
options?: {
|
||||
reverse?: boolean
|
||||
}
|
||||
) => [Point, Point]
|
||||
end: (range: Range) => Point
|
||||
equals: (range: Range, another: Range) => boolean
|
||||
includes: (range: Range, target: Path | Point | Range) => boolean
|
||||
intersection: (range: Range, another: Range) => Range | null
|
||||
isBackward: (range: Range) => boolean
|
||||
isCollapsed: (range: Range) => boolean
|
||||
isExpanded: (range: Range) => boolean
|
||||
isForward: (range: Range) => boolean
|
||||
isRange: (value: any) => value is Range
|
||||
points: (range: Range) => Generator<PointEntry, void, undefined>
|
||||
start: (range: Range) => Point
|
||||
transform: (
|
||||
range: Range,
|
||||
op: Operation,
|
||||
options?: {
|
||||
affinity?: 'forward' | 'backward' | 'outward' | 'inward' | null
|
||||
}
|
||||
) => Range | null
|
||||
}
|
||||
|
||||
export const Range: RangeInterface = {
|
||||
/**
|
||||
* Get the start and end points of a range, in the order in which they appear
|
||||
* in the document.
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import isPlainObject from 'is-plain-object'
|
||||
import { Range } from '..'
|
||||
import { ExtendedType } from './custom-types'
|
||||
|
||||
/**
|
||||
* `Text` objects represent the nodes that contain the actual text content of a
|
||||
@@ -7,12 +8,22 @@ import { Range } from '..'
|
||||
* nodes in the document tree as they cannot contain any children.
|
||||
*/
|
||||
|
||||
export interface Text {
|
||||
export interface BaseText {
|
||||
text: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export const Text = {
|
||||
export type Text = ExtendedType<'Text', BaseText>
|
||||
|
||||
export interface TextInterface {
|
||||
equals: (text: Text, another: Text, options?: { loose?: boolean }) => boolean
|
||||
isText: (value: any) => value is Text
|
||||
isTextList: (value: any) => value is Text[]
|
||||
isTextProps: (props: any) => props is Partial<Text>
|
||||
matches: (text: Text, props: Partial<Text>) => boolean
|
||||
decorations: (node: Text, decorations: Range[]) => Text[]
|
||||
}
|
||||
|
||||
export const Text: TextInterface = {
|
||||
/**
|
||||
* Check if two text nodes are equal.
|
||||
*/
|
||||
@@ -63,6 +74,14 @@ export const Text = {
|
||||
return Array.isArray(value) && (value.length === 0 || Text.isText(value[0]))
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if some props are a partial of Text.
|
||||
*/
|
||||
|
||||
isTextProps(props: any): props is Partial<Text> {
|
||||
return (props as Partial<Text>).text !== undefined
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if an text matches set of properties.
|
||||
*
|
||||
|
@@ -13,12 +13,16 @@ import {
|
||||
Ancestor,
|
||||
} from '..'
|
||||
|
||||
export const GeneralTransforms = {
|
||||
export interface GeneralTransforms {
|
||||
transform: (editor: Editor, op: Operation) => void
|
||||
}
|
||||
|
||||
export const GeneralTransforms: GeneralTransforms = {
|
||||
/**
|
||||
* Transform the editor by an operation.
|
||||
*/
|
||||
|
||||
transform(editor: Editor, op: Operation) {
|
||||
transform(editor: Editor, op: Operation): void {
|
||||
editor.children = createDraft(editor.children)
|
||||
let selection = editor.selection && createDraft(editor.selection)
|
||||
|
||||
@@ -272,7 +276,7 @@ export const GeneralTransforms = {
|
||||
}
|
||||
}
|
||||
|
||||
editor.children = finishDraft(editor.children) as Node[]
|
||||
editor.children = finishDraft(editor.children)
|
||||
|
||||
if (selection) {
|
||||
editor.selection = isDraft(selection)
|
||||
|
@@ -12,7 +12,116 @@ import {
|
||||
Ancestor,
|
||||
} from '..'
|
||||
|
||||
export const NodeTransforms = {
|
||||
export interface NodeTransforms {
|
||||
insertNodes: (
|
||||
editor: Editor,
|
||||
nodes: Node | Node[],
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'highest' | 'lowest'
|
||||
hanging?: boolean
|
||||
select?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
liftNodes: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
mergeNodes: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'highest' | 'lowest'
|
||||
hanging?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
moveNodes: (
|
||||
editor: Editor,
|
||||
options: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
to: Path
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
removeNodes: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'highest' | 'lowest'
|
||||
hanging?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
setNodes: (
|
||||
editor: Editor,
|
||||
props: Partial<Node>,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
hanging?: boolean
|
||||
split?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
splitNodes: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'highest' | 'lowest'
|
||||
always?: boolean
|
||||
height?: number
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
unsetNodes: (
|
||||
editor: Editor,
|
||||
props: string | string[],
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
split?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
unwrapNodes: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
split?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
wrapNodes: (
|
||||
editor: Editor,
|
||||
element: Element,
|
||||
options?: {
|
||||
at?: Location
|
||||
match?: (node: Node) => boolean
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
split?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
}
|
||||
|
||||
export const NodeTransforms: NodeTransforms = {
|
||||
/**
|
||||
* Insert nodes at a specific location in the Editor.
|
||||
*/
|
||||
@@ -28,7 +137,7 @@ export const NodeTransforms = {
|
||||
select?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { hanging = false, voids = false, mode = 'lowest' } = options
|
||||
let { at, match, select } = options
|
||||
@@ -143,7 +252,7 @@ export const NodeTransforms = {
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { at = editor.selection, mode = 'lowest', voids = false } = options
|
||||
let { match } = options
|
||||
@@ -208,7 +317,7 @@ export const NodeTransforms = {
|
||||
hanging?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
let { match, at = editor.selection } = options
|
||||
const { hanging = false, voids = false, mode = 'lowest' } = options
|
||||
@@ -346,7 +455,7 @@ export const NodeTransforms = {
|
||||
to: Path
|
||||
voids?: boolean
|
||||
}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const {
|
||||
to,
|
||||
@@ -396,7 +505,7 @@ export const NodeTransforms = {
|
||||
hanging?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { hanging = false, voids = false, mode = 'lowest' } = options
|
||||
let { at = editor.selection, match } = options
|
||||
@@ -444,7 +553,7 @@ export const NodeTransforms = {
|
||||
split?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
let { match, at = editor.selection } = options
|
||||
const {
|
||||
@@ -542,7 +651,7 @@ export const NodeTransforms = {
|
||||
height?: number
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { mode = 'lowest', voids = false } = options
|
||||
let { match, at = editor.selection, height = 0, always = false } = options
|
||||
@@ -631,7 +740,7 @@ export const NodeTransforms = {
|
||||
|
||||
if (always || !beforeRef || !Editor.isEdge(editor, point, path)) {
|
||||
split = true
|
||||
const { text, children, ...properties } = node
|
||||
const properties = Node.extractProps(node)
|
||||
editor.apply({
|
||||
type: 'split_node',
|
||||
path,
|
||||
@@ -667,7 +776,7 @@ export const NodeTransforms = {
|
||||
split?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
if (!Array.isArray(props)) {
|
||||
props = [props]
|
||||
}
|
||||
@@ -694,8 +803,8 @@ export const NodeTransforms = {
|
||||
mode?: 'all' | 'highest' | 'lowest'
|
||||
split?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) {
|
||||
} = {}
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { mode = 'lowest', split = false, voids = false } = options
|
||||
let { at = editor.selection, match } = options
|
||||
@@ -720,7 +829,7 @@ export const NodeTransforms = {
|
||||
|
||||
for (const pathRef of pathRefs) {
|
||||
const path = pathRef.unref()!
|
||||
const [node] = Editor.node(editor, path) as NodeEntry<Ancestor>
|
||||
const [node] = Editor.node(editor, path)
|
||||
let range = Editor.range(editor, path)
|
||||
|
||||
if (split && rangeRef) {
|
||||
@@ -729,7 +838,7 @@ export const NodeTransforms = {
|
||||
|
||||
Transforms.liftNodes(editor, {
|
||||
at: range,
|
||||
match: n => node.children.includes(n),
|
||||
match: n => Element.isAncestor(node) && node.children.includes(n),
|
||||
voids,
|
||||
})
|
||||
}
|
||||
@@ -755,7 +864,7 @@ export const NodeTransforms = {
|
||||
split?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { mode = 'lowest', split = false, voids = false } = options
|
||||
let { match, at = editor.selection } = options
|
||||
@@ -823,7 +932,7 @@ export const NodeTransforms = {
|
||||
|
||||
const range = Editor.range(editor, firstPath, lastPath)
|
||||
const commonNodeEntry = Editor.node(editor, commonPath)
|
||||
const [commonNode] = commonNodeEntry as NodeEntry<Ancestor>
|
||||
const [commonNode] = commonNodeEntry
|
||||
const depth = commonPath.length + 1
|
||||
const wrapperPath = Path.next(lastPath.slice(0, depth))
|
||||
const wrapper = { ...element, children: [] }
|
||||
@@ -831,7 +940,8 @@ export const NodeTransforms = {
|
||||
|
||||
Transforms.moveNodes(editor, {
|
||||
at: range,
|
||||
match: n => commonNode.children.includes(n),
|
||||
match: n =>
|
||||
Element.isAncestor(commonNode) && commonNode.children.includes(n),
|
||||
to: wrapperPath.concat(0),
|
||||
voids,
|
||||
})
|
||||
|
@@ -1,6 +1,34 @@
|
||||
import { Editor, Location, Point, Range, Transforms } from '..'
|
||||
|
||||
export const SelectionTransforms = {
|
||||
export interface SelectionTransforms {
|
||||
collapse: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
edge?: 'anchor' | 'focus' | 'start' | 'end'
|
||||
}
|
||||
) => void
|
||||
deselect: (editor: Editor) => void
|
||||
move: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
distance?: number
|
||||
unit?: 'offset' | 'character' | 'word' | 'line'
|
||||
reverse?: boolean
|
||||
edge?: 'anchor' | 'focus' | 'start' | 'end'
|
||||
}
|
||||
) => void
|
||||
select: (editor: Editor, target: Location) => void
|
||||
setPoint: (
|
||||
editor: Editor,
|
||||
props: Partial<Point>,
|
||||
options?: {
|
||||
edge?: 'anchor' | 'focus' | 'start' | 'end'
|
||||
}
|
||||
) => void
|
||||
setSelection: (editor: Editor, props: Partial<Range>) => void
|
||||
}
|
||||
|
||||
export const SelectionTransforms: SelectionTransforms = {
|
||||
/**
|
||||
* Collapse the selection.
|
||||
*/
|
||||
@@ -10,7 +38,7 @@ export const SelectionTransforms = {
|
||||
options: {
|
||||
edge?: 'anchor' | 'focus' | 'start' | 'end'
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
const { edge = 'anchor' } = options
|
||||
const { selection } = editor
|
||||
|
||||
@@ -33,7 +61,7 @@ export const SelectionTransforms = {
|
||||
* Unset the selection.
|
||||
*/
|
||||
|
||||
deselect(editor: Editor) {
|
||||
deselect(editor: Editor): void {
|
||||
const { selection } = editor
|
||||
|
||||
if (selection) {
|
||||
@@ -57,7 +85,7 @@ export const SelectionTransforms = {
|
||||
reverse?: boolean
|
||||
edge?: 'anchor' | 'focus' | 'start' | 'end'
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
const { selection } = editor
|
||||
const { distance = 1, unit = 'character', reverse = false } = options
|
||||
let { edge = null } = options
|
||||
@@ -105,7 +133,7 @@ export const SelectionTransforms = {
|
||||
* Set the selection to a new value.
|
||||
*/
|
||||
|
||||
select(editor: Editor, target: Location) {
|
||||
select(editor: Editor, target: Location): void {
|
||||
const { selection } = editor
|
||||
target = Editor.range(editor, target)
|
||||
|
||||
@@ -138,8 +166,8 @@ export const SelectionTransforms = {
|
||||
props: Partial<Point>,
|
||||
options: {
|
||||
edge?: 'anchor' | 'focus' | 'start' | 'end'
|
||||
}
|
||||
) {
|
||||
} = {}
|
||||
): void {
|
||||
const { selection } = editor
|
||||
let { edge = 'both' } = options
|
||||
|
||||
@@ -167,7 +195,7 @@ export const SelectionTransforms = {
|
||||
* Set new properties on the selection.
|
||||
*/
|
||||
|
||||
setSelection(editor: Editor, props: Partial<Range>) {
|
||||
setSelection(editor: Editor, props: Partial<Range>): void {
|
||||
const { selection } = editor
|
||||
const oldProps: Partial<Range> | null = {}
|
||||
const newProps: Partial<Range> = {}
|
||||
|
@@ -11,7 +11,38 @@ import {
|
||||
Transforms,
|
||||
} from '..'
|
||||
|
||||
export const TextTransforms = {
|
||||
export interface TextTransforms {
|
||||
delete: (
|
||||
editor: Editor,
|
||||
options?: {
|
||||
at?: Location
|
||||
distance?: number
|
||||
unit?: 'character' | 'word' | 'line' | 'block'
|
||||
reverse?: boolean
|
||||
hanging?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
insertFragment: (
|
||||
editor: Editor,
|
||||
fragment: Node[],
|
||||
options?: {
|
||||
at?: Location
|
||||
hanging?: boolean
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
insertText: (
|
||||
editor: Editor,
|
||||
text: string,
|
||||
options?: {
|
||||
at?: Location
|
||||
voids?: boolean
|
||||
}
|
||||
) => void
|
||||
}
|
||||
|
||||
export const TextTransforms: TextTransforms = {
|
||||
/**
|
||||
* Delete content in the editor.
|
||||
*/
|
||||
@@ -26,7 +57,7 @@ export const TextTransforms = {
|
||||
hanging?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const {
|
||||
reverse = false,
|
||||
@@ -196,7 +227,7 @@ export const TextTransforms = {
|
||||
hanging?: boolean
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { hanging = false, voids = false } = options
|
||||
let { at = editor.selection } = options
|
||||
@@ -410,7 +441,7 @@ export const TextTransforms = {
|
||||
at?: Location
|
||||
voids?: boolean
|
||||
} = {}
|
||||
) {
|
||||
): void {
|
||||
Editor.withoutNormalizing(editor, () => {
|
||||
const { voids = false } = options
|
||||
let { at = editor.selection } = options
|
||||
|
@@ -0,0 +1,11 @@
|
||||
import { Text } from 'slate'
|
||||
import { isBoldText } from './type-guards'
|
||||
|
||||
export const input: Text = {
|
||||
placeholder: 'heading',
|
||||
text: 'mytext',
|
||||
}
|
||||
|
||||
export const test = isBoldText
|
||||
|
||||
export const output = false
|
12
packages/slate/test/interfaces/CustomTypes/boldText-true.tsx
Normal file
12
packages/slate/test/interfaces/CustomTypes/boldText-true.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
// show that regular methods that are imported work as expected
|
||||
import { Text } from 'slate'
|
||||
import { isBoldText } from './type-guards'
|
||||
|
||||
export const input: Text = {
|
||||
bold: true,
|
||||
text: 'mytext',
|
||||
}
|
||||
|
||||
export const test = isBoldText
|
||||
|
||||
export const output = true
|
30
packages/slate/test/interfaces/CustomTypes/custom-types.ts
Normal file
30
packages/slate/test/interfaces/CustomTypes/custom-types.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Descendant, Element, Text, CustomTypes } from 'slate'
|
||||
|
||||
export interface HeadingElement {
|
||||
type: 'heading'
|
||||
level: number
|
||||
children: Descendant[]
|
||||
}
|
||||
|
||||
export interface ListItemElement {
|
||||
type: 'list-item'
|
||||
depth: number
|
||||
children: Descendant[]
|
||||
}
|
||||
|
||||
export interface CustomText {
|
||||
placeholder: string
|
||||
text: string
|
||||
}
|
||||
|
||||
export interface BoldCustomText {
|
||||
bold: boolean
|
||||
text: string
|
||||
}
|
||||
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Element: HeadingElement | ListItemElement
|
||||
Text: CustomText | BoldCustomText
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
import { Text } from 'slate'
|
||||
import { isCustomText } from './type-guards'
|
||||
|
||||
export const input: Text = {
|
||||
bold: true,
|
||||
text: 'mytext',
|
||||
}
|
||||
|
||||
export const test = isCustomText
|
||||
|
||||
export const output = false
|
@@ -0,0 +1,11 @@
|
||||
import { Text } from 'slate'
|
||||
import { isCustomText } from './type-guards'
|
||||
|
||||
export const input: Text = {
|
||||
placeholder: 'mystring',
|
||||
text: 'mytext',
|
||||
}
|
||||
|
||||
export const test = isCustomText
|
||||
|
||||
export const output = true
|
@@ -0,0 +1,12 @@
|
||||
import { Element } from 'slate'
|
||||
import { isHeadingElement } from './type-guards'
|
||||
|
||||
export const input: Element = {
|
||||
type: 'list-item',
|
||||
depth: 5,
|
||||
children: [],
|
||||
}
|
||||
|
||||
export const test = isHeadingElement
|
||||
|
||||
export const output = false
|
@@ -0,0 +1,12 @@
|
||||
import { Element } from 'slate'
|
||||
import { isHeadingElement } from './type-guards'
|
||||
|
||||
export const input: Element = {
|
||||
type: 'heading',
|
||||
level: 5,
|
||||
children: [],
|
||||
}
|
||||
|
||||
export const test = isHeadingElement
|
||||
|
||||
export const output = true
|
11
packages/slate/test/interfaces/CustomTypes/type-guards.ts
Normal file
11
packages/slate/test/interfaces/CustomTypes/type-guards.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Element, Text } from 'slate'
|
||||
import { BoldCustomText, CustomText, HeadingElement } from './custom-types'
|
||||
|
||||
export const isBoldText = (text: Text): text is BoldCustomText =>
|
||||
!!(text as BoldCustomText).bold
|
||||
|
||||
export const isCustomText = (text: Text): text is CustomText =>
|
||||
!!(text as CustomText).placeholder
|
||||
|
||||
export const isHeadingElement = (element: Element): element is HeadingElement =>
|
||||
element.type === 'heading'
|
19
packages/slate/test/interfaces/Editor/after/path-void.tsx
Normal file
19
packages/slate/test/interfaces/Editor/after/path-void.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>
|
||||
<text>one</text>
|
||||
<text>two</text>
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.after(editor, [0, 0], { voids: true })
|
||||
}
|
||||
|
||||
export const output = { path: [0, 1], offset: 0 }
|
16
packages/slate/test/interfaces/Editor/after/point-void.tsx
Normal file
16
packages/slate/test/interfaces/Editor/after/point-void.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.after(editor, { path: [0, 0], offset: 1 }, { voids: true })
|
||||
}
|
||||
|
||||
export const output = { path: [0, 0], offset: 2 }
|
24
packages/slate/test/interfaces/Editor/after/range-void.tsx
Normal file
24
packages/slate/test/interfaces/Editor/after/range-void.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
<block void>two</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.after(
|
||||
editor,
|
||||
{
|
||||
anchor: { path: [0, 0], offset: 1 },
|
||||
focus: { path: [1, 0], offset: 2 },
|
||||
},
|
||||
{ voids: true }
|
||||
)
|
||||
}
|
||||
|
||||
export const output = { path: [1, 0], offset: 3 }
|
17
packages/slate/test/interfaces/Editor/before/path-void.tsx
Normal file
17
packages/slate/test/interfaces/Editor/before/path-void.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
<block void>two</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.before(editor, [1, 0], { voids: true })
|
||||
}
|
||||
|
||||
export const output = { path: [0, 0], offset: 3 }
|
16
packages/slate/test/interfaces/Editor/before/point-void.tsx
Normal file
16
packages/slate/test/interfaces/Editor/before/point-void.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.before(editor, { path: [0, 0], offset: 1 }, { voids: true })
|
||||
}
|
||||
|
||||
export const output = { path: [0, 0], offset: 0 }
|
24
packages/slate/test/interfaces/Editor/before/range-void.tsx
Normal file
24
packages/slate/test/interfaces/Editor/before/range-void.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
<block void>two</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.before(
|
||||
editor,
|
||||
{
|
||||
anchor: { path: [0, 0], offset: 1 },
|
||||
focus: { path: [0, 1], offset: 2 },
|
||||
},
|
||||
{ voids: true }
|
||||
)
|
||||
}
|
||||
|
||||
export const output = { path: [0, 0], offset: 0 }
|
@@ -0,0 +1,20 @@
|
||||
/** @jsx jsx */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
</editor>
|
||||
)
|
||||
export const test = editor => {
|
||||
return Array.from(
|
||||
Editor.positions(editor, { at: [], reverse: true, voids: true })
|
||||
)
|
||||
}
|
||||
export const output = [
|
||||
{ path: [0, 0], offset: 3 },
|
||||
{ path: [0, 0], offset: 2 },
|
||||
{ path: [0, 0], offset: 1 },
|
||||
{ path: [0, 0], offset: 0 },
|
||||
]
|
@@ -0,0 +1,18 @@
|
||||
/** @jsx jsx */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
</editor>
|
||||
)
|
||||
export const test = editor => {
|
||||
return Array.from(Editor.positions(editor, { at: [], voids: true }))
|
||||
}
|
||||
export const output = [
|
||||
{ path: [0, 0], offset: 0 },
|
||||
{ path: [0, 0], offset: 1 },
|
||||
{ path: [0, 0], offset: 2 },
|
||||
{ path: [0, 0], offset: 3 },
|
||||
]
|
@@ -0,0 +1,32 @@
|
||||
/** @jsx jsx */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>
|
||||
one<inline>two</inline>three
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
export const test = editor => {
|
||||
return Array.from(
|
||||
Editor.positions(editor, { at: [], reverse: true, voids: true })
|
||||
)
|
||||
}
|
||||
export const output = [
|
||||
{ path: [0, 2], offset: 5 },
|
||||
{ path: [0, 2], offset: 4 },
|
||||
{ path: [0, 2], offset: 3 },
|
||||
{ path: [0, 2], offset: 2 },
|
||||
{ path: [0, 2], offset: 1 },
|
||||
{ path: [0, 2], offset: 0 },
|
||||
{ path: [0, 1, 0], offset: 3 },
|
||||
{ path: [0, 1, 0], offset: 2 },
|
||||
{ path: [0, 1, 0], offset: 1 },
|
||||
{ path: [0, 1, 0], offset: 0 },
|
||||
{ path: [0, 0], offset: 3 },
|
||||
{ path: [0, 0], offset: 2 },
|
||||
{ path: [0, 0], offset: 1 },
|
||||
{ path: [0, 0], offset: 0 },
|
||||
]
|
@@ -0,0 +1,30 @@
|
||||
/** @jsx jsx */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>
|
||||
one<inline>two</inline>three
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
export const test = editor => {
|
||||
return Array.from(Editor.positions(editor, { at: [], voids: true }))
|
||||
}
|
||||
export const output = [
|
||||
{ path: [0, 0], offset: 0 },
|
||||
{ path: [0, 0], offset: 1 },
|
||||
{ path: [0, 0], offset: 2 },
|
||||
{ path: [0, 0], offset: 3 },
|
||||
{ path: [0, 1, 0], offset: 0 },
|
||||
{ path: [0, 1, 0], offset: 1 },
|
||||
{ path: [0, 1, 0], offset: 2 },
|
||||
{ path: [0, 1, 0], offset: 3 },
|
||||
{ path: [0, 2], offset: 0 },
|
||||
{ path: [0, 2], offset: 1 },
|
||||
{ path: [0, 2], offset: 2 },
|
||||
{ path: [0, 2], offset: 3 },
|
||||
{ path: [0, 2], offset: 4 },
|
||||
{ path: [0, 2], offset: 5 },
|
||||
]
|
@@ -0,0 +1,16 @@
|
||||
/** @jsx jsx */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block void>
|
||||
<text>one</text>
|
||||
<text>two</text>
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
export const test = editor => {
|
||||
return Editor.string(editor, [0], { voids: true })
|
||||
}
|
||||
export const output = `onetwo`
|
@@ -4,4 +4,5 @@ export const input = true
|
||||
export const test = value => {
|
||||
return Element.isElement(value)
|
||||
}
|
||||
|
||||
export const output = false
|
||||
|
6
packages/slate/test/jsx.d.ts
vendored
Normal file
6
packages/slate/test/jsx.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// This allows tests to include Slate Nodes written in JSX without TypeScript complaining.
|
||||
declare namespace jsx.JSX {
|
||||
interface IntrinsicElements {
|
||||
[elemName: string]: any // eslint-disable-line
|
||||
}
|
||||
}
|
@@ -4,10 +4,13 @@ import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>one</block>
|
||||
<block>
|
||||
<text>bar</text>
|
||||
<text>foo</text>
|
||||
</block>
|
||||
<block>
|
||||
<cursor />
|
||||
two
|
||||
baz
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
@@ -17,12 +20,14 @@ export const run = editor => {
|
||||
export const output = (
|
||||
<editor>
|
||||
<block>
|
||||
<text />
|
||||
<text>foo</text>
|
||||
</block>
|
||||
<block>
|
||||
one
|
||||
<cursor />
|
||||
two
|
||||
<text>
|
||||
bar
|
||||
<cursor />
|
||||
baz
|
||||
</text>
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
|
@@ -6,20 +6,22 @@ export const input = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
<block void>two</block>
|
||||
<block void>three</block>
|
||||
</editor>
|
||||
)
|
||||
export const run = editor => {
|
||||
Transforms.moveNodes(editor, {
|
||||
at: [0, 0],
|
||||
to: [1, 0],
|
||||
at: [1, 0],
|
||||
to: [2, 0],
|
||||
voids: true,
|
||||
})
|
||||
}
|
||||
export const output = (
|
||||
<editor>
|
||||
<block void>one</block>
|
||||
<block void>
|
||||
<text />
|
||||
</block>
|
||||
<block void>onetwo</block>
|
||||
<block void>twothree</block>
|
||||
</editor>
|
||||
)
|
||||
|
Reference in New Issue
Block a user