UNPKG

slate

Version:

A completely customizable framework for building rich text editors.

1 lines 477 kB
{"version":3,"file":"index.es.js","sources":["../src/interfaces/path-ref.ts","../src/interfaces/point-ref.ts","../src/interfaces/range-ref.ts","../src/utils/weak-maps.ts","../src/interfaces/path.ts","../../../../../../.yarn/berry/cache/@babel-runtime-npm-7.23.2-d013d6cf7e-10.zip/node_modules/@babel/runtime/helpers/esm/typeof.js","../../../../../../.yarn/berry/cache/@babel-runtime-npm-7.23.2-d013d6cf7e-10.zip/node_modules/@babel/runtime/helpers/esm/toPrimitive.js","../../../../../../.yarn/berry/cache/@babel-runtime-npm-7.23.2-d013d6cf7e-10.zip/node_modules/@babel/runtime/helpers/esm/toPropertyKey.js","../../../../../../.yarn/berry/cache/@babel-runtime-npm-7.23.2-d013d6cf7e-10.zip/node_modules/@babel/runtime/helpers/esm/defineProperty.js","../src/interfaces/transforms/general.ts","../src/interfaces/transforms/node.ts","../src/interfaces/transforms/selection.ts","../src/utils/is-object.ts","../src/utils/deep-equal.ts","../../../../../../.yarn/berry/cache/@babel-runtime-npm-7.23.2-d013d6cf7e-10.zip/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js","../../../../../../.yarn/berry/cache/@babel-runtime-npm-7.23.2-d013d6cf7e-10.zip/node_modules/@babel/runtime/helpers/esm/objectWithoutProperties.js","../src/interfaces/range.ts","../src/interfaces/element.ts","../src/interfaces/node.ts","../src/interfaces/operation.ts","../src/editor/is-editor.ts","../src/interfaces/editor.ts","../src/interfaces/location.ts","../src/interfaces/point.ts","../src/interfaces/scrubber.ts","../src/interfaces/text.ts","../src/utils/get-default-insert-location.ts","../src/utils/match-path.ts","../src/utils/string.ts","../src/interfaces/transforms/text.ts","../src/interfaces/transforms/index.ts","../src/core/batch-dirty-paths.ts","../src/core/update-dirty-paths.ts","../src/core/apply.ts","../src/core/get-dirty-paths.ts","../src/core/get-fragment.ts","../src/core/normalize-node.ts","../src/core/should-normalize.ts","../src/editor/above.ts","../src/editor/add-mark.ts","../src/editor/after.ts","../src/editor/before.ts","../src/editor/delete-backward.ts","../src/editor/delete-forward.ts","../src/editor/delete-fragment.ts","../src/editor/edges.ts","../src/editor/element-read-only.ts","../src/editor/end.ts","../src/editor/first.ts","../src/editor/fragment.ts","../src/editor/get-void.ts","../src/editor/has-blocks.ts","../src/editor/has-inlines.ts","../src/editor/has-path.ts","../src/editor/has-texts.ts","../src/editor/insert-break.ts","../src/editor/insert-node.ts","../src/editor/insert-soft-break.ts","../src/editor/insert-text.ts","../src/editor/is-block.ts","../src/editor/is-edge.ts","../src/editor/is-empty.ts","../src/editor/is-end.ts","../src/editor/is-normalizing.ts","../src/editor/is-start.ts","../src/editor/last.ts","../src/editor/leaf.ts","../src/editor/levels.ts","../src/editor/marks.ts","../src/editor/next.ts","../src/editor/node.ts","../src/editor/nodes.ts","../src/editor/normalize.ts","../src/editor/parent.ts","../src/editor/path-ref.ts","../src/editor/path-refs.ts","../src/editor/path.ts","../src/editor/point-ref.ts","../src/editor/point-refs.ts","../src/editor/point.ts","../src/editor/positions.ts","../src/editor/previous.ts","../src/editor/range-ref.ts","../src/editor/range-refs.ts","../src/editor/range.ts","../src/editor/remove-mark.ts","../src/editor/set-normalizing.ts","../src/editor/start.ts","../src/editor/string.ts","../src/editor/unhang-range.ts","../src/editor/without-normalizing.ts","../src/editor/should-merge-nodes-remove-prev-node.ts","../src/transforms-text/delete-text.ts","../src/transforms-text/insert-fragment.ts","../src/transforms-selection/collapse.ts","../src/transforms-selection/deselect.ts","../src/transforms-selection/move.ts","../src/transforms-selection/select.ts","../src/transforms-selection/set-point.ts","../src/transforms-selection/set-selection.ts","../src/transforms-node/insert-nodes.ts","../src/transforms-node/lift-nodes.ts","../src/transforms-node/merge-nodes.ts","../src/transforms-node/move-nodes.ts","../src/transforms-node/remove-nodes.ts","../src/transforms-node/set-nodes.ts","../src/transforms-node/split-nodes.ts","../src/transforms-node/unset-nodes.ts","../src/transforms-node/unwrap-nodes.ts","../src/transforms-node/wrap-nodes.ts","../src/create-editor.ts"],"sourcesContent":["import { Operation, Path } from '..'\n\n/**\n * `PathRef` objects keep a specific path in a document synced over time as new\n * operations are applied to the editor. You can access their `current` property\n * at any time for the up-to-date path value.\n */\n\nexport interface PathRef {\n current: Path | null\n affinity: 'forward' | 'backward' | null\n unref(): Path | null\n}\n\nexport interface PathRefInterface {\n /**\n * Transform the path ref's current value by an operation.\n */\n transform: (ref: PathRef, op: Operation) => void\n}\n\n// eslint-disable-next-line no-redeclare\nexport const PathRef: PathRefInterface = {\n transform(ref: PathRef, op: Operation): void {\n const { current, affinity } = ref\n\n if (current == null) {\n return\n }\n\n const path = Path.transform(current, op, { affinity })\n ref.current = path\n\n if (path == null) {\n ref.unref()\n }\n },\n}\n","import { Operation, Point } from '..'\nimport { TextDirection } from '../types/types'\n\n/**\n * `PointRef` objects keep a specific point in a document synced over time as new\n * operations are applied to the editor. You can access their `current` property\n * at any time for the up-to-date point value.\n */\n\nexport interface PointRef {\n current: Point | null\n affinity: TextDirection | null\n unref(): Point | null\n}\n\nexport interface PointRefInterface {\n /**\n * Transform the point ref's current value by an operation.\n */\n transform: (ref: PointRef, op: Operation) => void\n}\n\n// eslint-disable-next-line no-redeclare\nexport const PointRef: PointRefInterface = {\n transform(ref: PointRef, op: Operation): void {\n const { current, affinity } = ref\n\n if (current == null) {\n return\n }\n\n const point = Point.transform(current, op, { affinity })\n ref.current = point\n\n if (point == null) {\n ref.unref()\n }\n },\n}\n","import { Operation, Range } from '..'\n\n/**\n * `RangeRef` objects keep a specific range in a document synced over time as new\n * operations are applied to the editor. You can access their `current` property\n * at any time for the up-to-date range value.\n */\n\nexport interface RangeRef {\n current: Range | null\n affinity: 'forward' | 'backward' | 'outward' | 'inward' | null\n unref(): Range | null\n}\n\nexport interface RangeRefInterface {\n /**\n * Transform the range ref's current value by an operation.\n */\n transform: (ref: RangeRef, op: Operation) => void\n}\n\n// eslint-disable-next-line no-redeclare\nexport const RangeRef: RangeRefInterface = {\n transform(ref: RangeRef, op: Operation): void {\n const { current, affinity } = ref\n\n if (current == null) {\n return\n }\n\n const path = Range.transform(current, op, { affinity })\n ref.current = path\n\n if (path == null) {\n ref.unref()\n }\n },\n}\n","import { Editor, Path, PathRef, PointRef, RangeRef } from '..'\n\nexport const DIRTY_PATHS: WeakMap<Editor, Path[]> = new WeakMap()\nexport const DIRTY_PATH_KEYS: WeakMap<Editor, Set<string>> = new WeakMap()\nexport const FLUSHING: WeakMap<Editor, boolean> = new WeakMap()\nexport const NORMALIZING: WeakMap<Editor, boolean> = new WeakMap()\nexport const PATH_REFS: WeakMap<Editor, Set<PathRef>> = new WeakMap()\nexport const POINT_REFS: WeakMap<Editor, Set<PointRef>> = new WeakMap()\nexport const RANGE_REFS: WeakMap<Editor, Set<RangeRef>> = new WeakMap()\n","import {\n InsertNodeOperation,\n MergeNodeOperation,\n MoveNodeOperation,\n Operation,\n RemoveNodeOperation,\n SplitNodeOperation,\n} from '..'\nimport { TextDirection } from '../types/types'\n\n/**\n * `Path` arrays are a list of indexes that describe a node's exact position in\n * a Slate node tree. Although they are usually relative to the root `Editor`\n * object, they can be relative to any `Node` object.\n */\n\nexport type Path = number[]\n\nexport interface PathAncestorsOptions {\n reverse?: boolean\n}\n\nexport interface PathLevelsOptions {\n reverse?: boolean\n}\n\nexport interface PathTransformOptions {\n affinity?: TextDirection | null\n}\n\nexport interface PathInterface {\n /**\n * Get a list of ancestor paths for a given path.\n *\n * The paths are sorted from shallowest to deepest ancestor. However, if the\n * `reverse: true` option is passed, they are reversed.\n */\n ancestors: (path: Path, options?: PathAncestorsOptions) => Path[]\n\n /**\n * Get the common ancestor path of two paths.\n */\n common: (path: Path, another: Path) => Path\n\n /**\n * Compare a path to another, returning an integer indicating whether the path\n * was before, at, or after the other.\n *\n * Note: Two paths of unequal length can still receive a `0` result if one is\n * directly above or below the other. If you want exact matching, use\n * [[Path.equals]] instead.\n */\n compare: (path: Path, another: Path) => -1 | 0 | 1\n\n /**\n * Check if a path ends after one of the indexes in another.\n */\n endsAfter: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path ends at one of the indexes in another.\n */\n endsAt: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path ends before one of the indexes in another.\n */\n endsBefore: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path is exactly equal to another.\n */\n equals: (path: Path, another: Path) => boolean\n\n /**\n * Check if the path of previous sibling node exists\n */\n hasPrevious: (path: Path) => boolean\n\n /**\n * Check if a path is after another.\n */\n isAfter: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path is an ancestor of another.\n */\n isAncestor: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path is before another.\n */\n isBefore: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path is a child of another.\n */\n isChild: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path is equal to or an ancestor of another.\n */\n isCommon: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path is a descendant of another.\n */\n isDescendant: (path: Path, another: Path) => boolean\n\n /**\n * Check if a path is the parent of another.\n */\n isParent: (path: Path, another: Path) => boolean\n\n /**\n * Check is a value implements the `Path` interface.\n */\n isPath: (value: any) => value is Path\n\n /**\n * Check if a path is a sibling of another.\n */\n isSibling: (path: Path, another: Path) => boolean\n\n /**\n * Get a list of paths at every level down to a path. Note: this is the same\n * as `Path.ancestors`, but including the path itself.\n *\n * The paths are sorted from shallowest to deepest. However, if the `reverse:\n * true` option is passed, they are reversed.\n */\n levels: (path: Path, options?: PathLevelsOptions) => Path[]\n\n /**\n * Given a path, get the path to the next sibling node.\n */\n next: (path: Path) => Path\n\n /**\n * Returns whether this operation can affect paths or not. Used as an\n * optimization when updating dirty paths during normalization\n *\n * NOTE: This *must* be kept in sync with the implementation of 'transform'\n * below\n */\n operationCanTransformPath: (\n operation: Operation\n ) => operation is\n | InsertNodeOperation\n | RemoveNodeOperation\n | MergeNodeOperation\n | SplitNodeOperation\n | MoveNodeOperation\n\n /**\n * Given a path, return a new path referring to the parent node above it.\n */\n parent: (path: Path) => Path\n\n /**\n * Given a path, get the path to the previous sibling node.\n */\n previous: (path: Path) => Path\n\n /**\n * Get a path relative to an ancestor.\n */\n relative: (path: Path, ancestor: Path) => Path\n\n /**\n * Transform a path by an operation.\n */\n transform: (\n path: Path,\n operation: Operation,\n options?: PathTransformOptions\n ) => Path | null\n}\n\n// eslint-disable-next-line no-redeclare\nexport const Path: PathInterface = {\n ancestors(path: Path, options: PathAncestorsOptions = {}): Path[] {\n const { reverse = false } = options\n let paths = Path.levels(path, options)\n\n if (reverse) {\n paths = paths.slice(1)\n } else {\n paths = paths.slice(0, -1)\n }\n\n return paths\n },\n\n common(path: Path, another: Path): Path {\n const common: Path = []\n\n for (let i = 0; i < path.length && i < another.length; i++) {\n const av = path[i]\n const bv = another[i]\n\n if (av !== bv) {\n break\n }\n\n common.push(av)\n }\n\n return common\n },\n\n compare(path: Path, another: Path): -1 | 0 | 1 {\n const min = Math.min(path.length, another.length)\n\n for (let i = 0; i < min; i++) {\n if (path[i] < another[i]) return -1\n if (path[i] > another[i]) return 1\n }\n\n return 0\n },\n\n endsAfter(path: Path, another: Path): boolean {\n const i = path.length - 1\n const as = path.slice(0, i)\n const bs = another.slice(0, i)\n const av = path[i]\n const bv = another[i]\n return Path.equals(as, bs) && av > bv\n },\n\n endsAt(path: Path, another: Path): boolean {\n const i = path.length\n const as = path.slice(0, i)\n const bs = another.slice(0, i)\n return Path.equals(as, bs)\n },\n\n endsBefore(path: Path, another: Path): boolean {\n const i = path.length - 1\n const as = path.slice(0, i)\n const bs = another.slice(0, i)\n const av = path[i]\n const bv = another[i]\n return Path.equals(as, bs) && av < bv\n },\n\n equals(path: Path, another: Path): boolean {\n return (\n path.length === another.length && path.every((n, i) => n === another[i])\n )\n },\n\n hasPrevious(path: Path): boolean {\n return path[path.length - 1] > 0\n },\n\n isAfter(path: Path, another: Path): boolean {\n return Path.compare(path, another) === 1\n },\n\n isAncestor(path: Path, another: Path): boolean {\n return path.length < another.length && Path.compare(path, another) === 0\n },\n\n isBefore(path: Path, another: Path): boolean {\n return Path.compare(path, another) === -1\n },\n\n isChild(path: Path, another: Path): boolean {\n return (\n path.length === another.length + 1 && Path.compare(path, another) === 0\n )\n },\n\n isCommon(path: Path, another: Path): boolean {\n return path.length <= another.length && Path.compare(path, another) === 0\n },\n\n isDescendant(path: Path, another: Path): boolean {\n return path.length > another.length && Path.compare(path, another) === 0\n },\n\n isParent(path: Path, another: Path): boolean {\n return (\n path.length + 1 === another.length && Path.compare(path, another) === 0\n )\n },\n\n isPath(value: any): value is Path {\n return (\n Array.isArray(value) &&\n (value.length === 0 || typeof value[0] === 'number')\n )\n },\n\n isSibling(path: Path, another: Path): boolean {\n if (path.length !== another.length) {\n return false\n }\n\n const as = path.slice(0, -1)\n const bs = another.slice(0, -1)\n const al = path[path.length - 1]\n const bl = another[another.length - 1]\n return al !== bl && Path.equals(as, bs)\n },\n\n levels(path: Path, options: PathLevelsOptions = {}): Path[] {\n const { reverse = false } = options\n const list: Path[] = []\n\n for (let i = 0; i <= path.length; i++) {\n list.push(path.slice(0, i))\n }\n\n if (reverse) {\n list.reverse()\n }\n\n return list\n },\n\n next(path: Path): Path {\n if (path.length === 0) {\n throw new Error(\n `Cannot get the next path of a root path [${path}], because it has no next index.`\n )\n }\n\n const last = path[path.length - 1]\n return path.slice(0, -1).concat(last + 1)\n },\n\n operationCanTransformPath(\n operation: Operation\n ): operation is\n | InsertNodeOperation\n | RemoveNodeOperation\n | MergeNodeOperation\n | SplitNodeOperation\n | MoveNodeOperation {\n switch (operation.type) {\n case 'insert_node':\n case 'remove_node':\n case 'merge_node':\n case 'split_node':\n case 'move_node':\n return true\n default:\n return false\n }\n },\n\n parent(path: Path): Path {\n if (path.length === 0) {\n throw new Error(`Cannot get the parent path of the root path [${path}].`)\n }\n\n return path.slice(0, -1)\n },\n\n previous(path: Path): Path {\n if (path.length === 0) {\n throw new Error(\n `Cannot get the previous path of a root path [${path}], because it has no previous index.`\n )\n }\n\n const last = path[path.length - 1]\n\n if (last <= 0) {\n throw new Error(\n `Cannot get the previous path of a first child path [${path}] because it would result in a negative index.`\n )\n }\n\n return path.slice(0, -1).concat(last - 1)\n },\n\n relative(path: Path, ancestor: Path): Path {\n if (!Path.isAncestor(ancestor, path) && !Path.equals(path, ancestor)) {\n throw new Error(\n `Cannot get the relative path of [${path}] inside ancestor [${ancestor}], because it is not above or equal to the path.`\n )\n }\n\n return path.slice(ancestor.length)\n },\n\n transform(\n path: Path | null,\n operation: Operation,\n options: PathTransformOptions = {}\n ): Path | null {\n if (!path) return null\n\n // PERF: use destructing instead of immer\n const p = [...path]\n const { affinity = 'forward' } = options\n\n // PERF: Exit early if the operation is guaranteed not to have an effect.\n if (path.length === 0) {\n return p\n }\n\n switch (operation.type) {\n case 'insert_node': {\n const { path: op } = operation\n\n if (\n Path.equals(op, p) ||\n Path.endsBefore(op, p) ||\n Path.isAncestor(op, p)\n ) {\n p[op.length - 1] += 1\n }\n\n break\n }\n\n case 'remove_node': {\n const { path: op } = operation\n\n if (Path.equals(op, p) || Path.isAncestor(op, p)) {\n return null\n } else if (Path.endsBefore(op, p)) {\n p[op.length - 1] -= 1\n }\n\n break\n }\n\n case 'merge_node': {\n const { path: op, position } = operation\n\n if (Path.equals(op, p) || Path.endsBefore(op, p)) {\n p[op.length - 1] -= 1\n } else if (Path.isAncestor(op, p)) {\n p[op.length - 1] -= 1\n p[op.length] += position\n }\n\n break\n }\n\n case 'split_node': {\n const { path: op, position } = operation\n\n if (Path.equals(op, p)) {\n if (affinity === 'forward') {\n p[p.length - 1] += 1\n } else if (affinity === 'backward') {\n // Nothing, because it still refers to the right path.\n } else {\n return null\n }\n } else if (Path.endsBefore(op, p)) {\n p[op.length - 1] += 1\n } else if (Path.isAncestor(op, p) && path[op.length] >= position) {\n p[op.length - 1] += 1\n p[op.length] -= position\n }\n\n break\n }\n\n case 'move_node': {\n const { path: op, newPath: onp } = operation\n\n // If the old and new path are the same, it's a no-op.\n if (Path.equals(op, onp)) {\n return p\n }\n\n if (Path.isAncestor(op, p) || Path.equals(op, p)) {\n const copy = onp.slice()\n\n if (Path.endsBefore(op, onp) && op.length < onp.length) {\n copy[op.length - 1] -= 1\n }\n\n return copy.concat(p.slice(op.length))\n } else if (\n Path.isSibling(op, onp) &&\n (Path.isAncestor(onp, p) || Path.equals(onp, p))\n ) {\n if (Path.endsBefore(op, p)) {\n p[op.length - 1] -= 1\n } else {\n p[op.length - 1] += 1\n }\n } else if (\n Path.endsBefore(onp, p) ||\n Path.equals(onp, p) ||\n Path.isAncestor(onp, p)\n ) {\n if (Path.endsBefore(op, p)) {\n p[op.length - 1] -= 1\n }\n\n p[onp.length - 1] += 1\n } else if (Path.endsBefore(op, p)) {\n if (Path.equals(onp, p)) {\n p[onp.length - 1] += 1\n }\n\n p[op.length - 1] -= 1\n }\n\n break\n }\n }\n\n return p\n },\n}\n","export default function _typeof(o) {\n \"@babel/helpers - typeof\";\n\n return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o;\n }, _typeof(o);\n}","import _typeof from \"./typeof.js\";\nexport default function _toPrimitive(input, hint) {\n if (_typeof(input) !== \"object\" || input === null) return input;\n var prim = input[Symbol.toPrimitive];\n if (prim !== undefined) {\n var res = prim.call(input, hint || \"default\");\n if (_typeof(res) !== \"object\") return res;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (hint === \"string\" ? String : Number)(input);\n}","import _typeof from \"./typeof.js\";\nimport toPrimitive from \"./toPrimitive.js\";\nexport default function _toPropertyKey(arg) {\n var key = toPrimitive(arg, \"string\");\n return _typeof(key) === \"symbol\" ? key : String(key);\n}","import toPropertyKey from \"./toPropertyKey.js\";\nexport default function _defineProperty(obj, key, value) {\n key = toPropertyKey(key);\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n return obj;\n}","import {\n Ancestor,\n Descendant,\n Editor,\n Element,\n Node,\n NodeEntry,\n Operation,\n Path,\n Point,\n Range,\n Scrubber,\n Selection,\n Text,\n} from '../../index'\n\nexport interface GeneralTransforms {\n /**\n * Transform the editor by an operation.\n */\n transform: (editor: Editor, op: Operation) => void\n}\n\nconst insertChildren = <T>(xs: T[], index: number, ...newValues: T[]) => [\n ...xs.slice(0, index),\n ...newValues,\n ...xs.slice(index),\n]\n\nconst replaceChildren = <T>(\n xs: T[],\n index: number,\n removeCount: number,\n ...newValues: T[]\n) => [...xs.slice(0, index), ...newValues, ...xs.slice(index + removeCount)]\n\nconst removeChildren = replaceChildren\n\n/**\n * Replace a descendant with a new node, replacing all ancestors\n */\nconst modifyDescendant = <N extends Descendant>(\n editor: Editor,\n path: Path,\n f: (node: N) => N\n) => {\n if (path.length === 0) {\n throw new Error('Cannot modify the editor')\n }\n\n const node = Node.get(editor, path) as N\n const slicedPath = path.slice()\n let modifiedNode: Node = f(node)\n\n while (slicedPath.length > 1) {\n const index = slicedPath.pop()!\n const ancestorNode = Node.get(editor, slicedPath) as Ancestor\n\n modifiedNode = {\n ...ancestorNode,\n children: replaceChildren(ancestorNode.children, index, 1, modifiedNode),\n }\n }\n\n const index = slicedPath.pop()!\n editor.children = replaceChildren(editor.children, index, 1, modifiedNode)\n}\n\n/**\n * Replace the children of a node, replacing all ancestors\n */\nconst modifyChildren = (\n editor: Editor,\n path: Path,\n f: (children: Descendant[]) => Descendant[]\n) => {\n if (path.length === 0) {\n editor.children = f(editor.children)\n } else {\n modifyDescendant<Element>(editor, path, node => {\n if (Text.isText(node)) {\n throw new Error(\n `Cannot get the element at path [${path}] because it refers to a leaf node: ${Scrubber.stringify(\n node\n )}`\n )\n }\n\n return { ...node, children: f(node.children) }\n })\n }\n}\n\n/**\n * Replace a leaf, replacing all ancestors\n */\nconst modifyLeaf = (editor: Editor, path: Path, f: (leaf: Text) => Text) =>\n modifyDescendant(editor, path, node => {\n if (!Text.isText(node)) {\n throw new Error(\n `Cannot get the leaf node at path [${path}] because it refers to a non-leaf node: ${Scrubber.stringify(\n node\n )}`\n )\n }\n\n return f(node)\n })\n\n// eslint-disable-next-line no-redeclare\nexport const GeneralTransforms: GeneralTransforms = {\n transform(editor: Editor, op: Operation): void {\n let transformSelection = false\n\n switch (op.type) {\n case 'insert_node': {\n const { path, node } = op\n\n modifyChildren(editor, Path.parent(path), children => {\n const index = path[path.length - 1]\n\n if (index > children.length) {\n throw new Error(\n `Cannot apply an \"insert_node\" operation at path [${path}] because the destination is past the end of the node.`\n )\n }\n\n return insertChildren(children, index, node)\n })\n\n transformSelection = true\n break\n }\n\n case 'insert_text': {\n const { path, offset, text } = op\n if (text.length === 0) break\n\n modifyLeaf(editor, path, node => {\n const before = node.text.slice(0, offset)\n const after = node.text.slice(offset)\n\n return {\n ...node,\n text: before + text + after,\n }\n })\n\n transformSelection = true\n break\n }\n\n case 'merge_node': {\n const { path } = op\n const index = path[path.length - 1]\n const prevPath = Path.previous(path)\n const prevIndex = prevPath[prevPath.length - 1]\n\n modifyChildren(editor, Path.parent(path), children => {\n const node = children[index]\n const prev = children[prevIndex]\n let newNode: Descendant\n\n if (Text.isText(node) && Text.isText(prev)) {\n newNode = { ...prev, text: prev.text + node.text }\n } else if (!Text.isText(node) && !Text.isText(prev)) {\n newNode = { ...prev, children: prev.children.concat(node.children) }\n } else {\n throw new Error(\n `Cannot apply a \"merge_node\" operation at path [${path}] to nodes of different interfaces: ${Scrubber.stringify(\n node\n )} ${Scrubber.stringify(prev)}`\n )\n }\n\n return replaceChildren(children, prevIndex, 2, newNode)\n })\n\n transformSelection = true\n break\n }\n\n case 'move_node': {\n const { path, newPath } = op\n const index = path[path.length - 1]\n\n if (Path.isAncestor(path, newPath)) {\n throw new Error(\n `Cannot move a path [${path}] to new path [${newPath}] because the destination is inside itself.`\n )\n }\n\n const node = Node.get(editor, path)\n\n modifyChildren(editor, Path.parent(path), children =>\n removeChildren(children, index, 1)\n )\n\n // This is tricky, but since the `path` and `newPath` both refer to\n // the same snapshot in time, there's a mismatch. After either\n // removing the original position, the second step's path can be out\n // of date. So instead of using the `op.newPath` directly, we\n // transform `op.path` to ascertain what the `newPath` would be after\n // the operation was applied.\n const truePath = Path.transform(path, op)!\n const newIndex = truePath[truePath.length - 1]\n\n modifyChildren(editor, Path.parent(truePath), children =>\n insertChildren(children, newIndex, node)\n )\n\n transformSelection = true\n break\n }\n\n case 'remove_node': {\n const { path } = op\n const index = path[path.length - 1]\n\n modifyChildren(editor, Path.parent(path), children =>\n removeChildren(children, index, 1)\n )\n\n // Transform all the points in the value, but if the point was in the\n // node that was removed we need to update the range or remove it.\n if (editor.selection) {\n let selection: Selection = { ...editor.selection }\n\n for (const [point, key] of Range.points(selection)) {\n const result = Point.transform(point, op)\n\n if (selection != null && result != null) {\n selection[key] = result\n } else {\n let prev: NodeEntry<Text> | undefined\n let next: NodeEntry<Text> | undefined\n\n for (const [n, p] of Node.texts(editor)) {\n if (Path.compare(p, path) === -1) {\n prev = [n, p]\n } else {\n next = [n, p]\n break\n }\n }\n\n let preferNext = false\n if (prev && next) {\n if (Path.equals(next[1], path)) {\n preferNext = !Path.hasPrevious(next[1])\n } else {\n preferNext =\n Path.common(prev[1], path).length <\n Path.common(next[1], path).length\n }\n }\n\n if (prev && !preferNext) {\n selection![key] = { path: prev[1], offset: prev[0].text.length }\n } else if (next) {\n selection![key] = { path: next[1], offset: 0 }\n } else {\n selection = null\n }\n }\n }\n\n editor.selection = selection\n }\n\n break\n }\n\n case 'remove_text': {\n const { path, offset, text } = op\n if (text.length === 0) break\n\n modifyLeaf(editor, path, node => {\n const before = node.text.slice(0, offset)\n const after = node.text.slice(offset + text.length)\n\n return {\n ...node,\n text: before + after,\n }\n })\n\n transformSelection = true\n break\n }\n\n case 'set_node': {\n const { path, properties, newProperties } = op\n\n if (path.length === 0) {\n throw new Error(`Cannot set properties on the root node!`)\n }\n\n modifyDescendant(editor, path, node => {\n const newNode = { ...node }\n\n for (const key in newProperties) {\n if (key === 'children' || key === 'text') {\n throw new Error(`Cannot set the \"${key}\" property of nodes!`)\n }\n\n const value = newProperties[<keyof Node>key]\n\n if (value == null) {\n delete newNode[<keyof Node>key]\n } else {\n newNode[<keyof Node>key] = value\n }\n }\n\n // properties that were previously defined, but are now missing, must be deleted\n for (const key in properties) {\n if (!newProperties.hasOwnProperty(key)) {\n delete newNode[<keyof Node>key]\n }\n }\n\n return newNode\n })\n\n break\n }\n\n case 'set_selection': {\n const { newProperties } = op\n\n if (newProperties == null) {\n editor.selection = null\n break\n }\n\n if (editor.selection == null) {\n if (!Range.isRange(newProperties)) {\n throw new Error(\n `Cannot apply an incomplete \"set_selection\" operation properties ${Scrubber.stringify(\n newProperties\n )} when there is no current selection.`\n )\n }\n\n editor.selection = { ...newProperties }\n break\n }\n\n const selection = { ...editor.selection }\n\n for (const key in newProperties) {\n const value = newProperties[<keyof Range>key]\n\n if (value == null) {\n if (key === 'anchor' || key === 'focus') {\n throw new Error(`Cannot remove the \"${key}\" selection property`)\n }\n\n delete selection[<keyof Range>key]\n } else {\n selection[<keyof Range>key] = value\n }\n }\n\n editor.selection = selection\n\n break\n }\n\n case 'split_node': {\n const { path, position, properties } = op\n const index = path[path.length - 1]\n\n if (path.length === 0) {\n throw new Error(\n `Cannot apply a \"split_node\" operation at path [${path}] because the root node cannot be split.`\n )\n }\n\n modifyChildren(editor, Path.parent(path), children => {\n const node = children[index]\n let newNode: Descendant\n let nextNode: Descendant\n\n if (Text.isText(node)) {\n const before = node.text.slice(0, position)\n const after = node.text.slice(position)\n newNode = {\n ...node,\n text: before,\n }\n nextNode = {\n ...(properties as Partial<Text>),\n text: after,\n }\n } else {\n const before = node.children.slice(0, position)\n const after = node.children.slice(position)\n newNode = {\n ...node,\n children: before,\n }\n nextNode = {\n ...(properties as Partial<Element>),\n children: after,\n }\n }\n\n return replaceChildren(children, index, 1, newNode, nextNode)\n })\n\n transformSelection = true\n break\n }\n }\n\n if (transformSelection && editor.selection) {\n const selection = { ...editor.selection }\n\n for (const [point, key] of Range.points(selection)) {\n selection[key] = Point.transform(point, op)!\n }\n\n editor.selection = selection\n }\n },\n}\n","import { Editor, Element, Location, Node, Path } from '../../index'\nimport { NodeMatch, PropsCompare, PropsMerge } from '../editor'\nimport { MaximizeMode, RangeMode } from '../../types/types'\n\nexport interface NodeInsertNodesOptions<T extends Node> {\n at?: Location\n match?: NodeMatch<T>\n mode?: RangeMode\n hanging?: boolean\n select?: boolean\n voids?: boolean\n batchDirty?: boolean\n}\n\nexport interface NodeTransforms {\n /**\n * Insert nodes in the editor\n * at the specified location or (if not defined) the current selection or (if not defined) the end of the document.\n */\n insertNodes: <T extends Node>(\n editor: Editor,\n nodes: Node | Node[],\n options?: NodeInsertNodesOptions<T>\n ) => void\n\n /**\n * Lift nodes at a specific location upwards in the document tree, splitting\n * their parent in two if necessary.\n */\n liftNodes: <T extends Node>(\n editor: Editor,\n options?: {\n at?: Location\n match?: NodeMatch<T>\n mode?: MaximizeMode\n voids?: boolean\n }\n ) => void\n\n /**\n * Merge a node at a location with the previous node of the same depth,\n * removing any empty containing nodes after the merge if necessary.\n */\n mergeNodes: <T extends Node>(\n editor: Editor,\n options?: {\n at?: Location\n match?: NodeMatch<T>\n mode?: RangeMode\n hanging?: boolean\n voids?: boolean\n }\n ) => void\n\n /**\n * Move the nodes at a location to a new location.\n */\n moveNodes: <T extends Node>(\n editor: Editor,\n options: {\n at?: Location\n match?: NodeMatch<T>\n mode?: MaximizeMode\n to: Path\n voids?: boolean\n }\n ) => void\n\n /**\n * Remove the nodes at a specific location in the document.\n */\n removeNodes: <T extends Node>(\n editor: Editor,\n options?: {\n at?: Location\n match?: NodeMatch<T>\n mode?: RangeMode\n hanging?: boolean\n voids?: boolean\n }\n ) => void\n\n /**\n * Set new properties on the nodes at a location.\n */\n setNodes: <T extends Node>(\n editor: Editor,\n props: Partial<T>,\n options?: {\n at?: Location\n match?: NodeMatch<T>\n mode?: MaximizeMode\n hanging?: boolean\n split?: boolean\n voids?: boolean\n compare?: PropsCompare\n merge?: PropsMerge\n }\n ) => void\n\n /**\n * Split the nodes at a specific location.\n */\n splitNodes: <T extends Node>(\n editor: Editor,\n options?: {\n at?: Location\n match?: NodeMatch<T>\n mode?: RangeMode\n always?: boolean\n height?: number\n voids?: boolean\n }\n ) => void\n\n /**\n * Unset properties on the nodes at a location.\n */\n unsetNodes: <T extends Node>(\n editor: Editor,\n props: string | string[],\n options?: {\n at?: Location\n match?: NodeMatch<T>\n mode?: MaximizeMode\n hanging?: boolean\n split?: boolean\n voids?: boolean\n }\n ) => void\n\n /**\n * Unwrap the nodes at a location from a parent node, splitting the parent if\n * necessary to ensure that only the content in the range is unwrapped.\n */\n unwrapNodes: <T extends Node>(\n editor: Editor,\n options?: {\n at?: Location\n match?: NodeMatch<T>\n mode?: MaximizeMode\n split?: boolean\n voids?: boolean\n }\n ) => void\n\n /**\n * Wrap the nodes at a location in a new container node, splitting the edges\n * of the range first to ensure that only the content in the range is wrapped.\n */\n wrapNodes: <T extends Node>(\n editor: Editor,\n element: Element,\n options?: {\n at?: Location\n match?: NodeMatch<T>\n mode?: MaximizeMode\n split?: boolean\n voids?: boolean\n }\n ) => void\n}\n\n// eslint-disable-next-line no-redeclare\nexport const NodeTransforms: NodeTransforms = {\n insertNodes(editor, nodes, options) {\n editor.insertNodes(nodes, options)\n },\n liftNodes(editor, options) {\n editor.liftNodes(options)\n },\n mergeNodes(editor, options) {\n editor.mergeNodes(options)\n },\n moveNodes(editor, options) {\n editor.moveNodes(options)\n },\n removeNodes(editor, options) {\n editor.removeNodes(options)\n },\n setNodes(editor, props, options) {\n editor.setNodes(props, options)\n },\n splitNodes(editor, options) {\n editor.splitNodes(options)\n },\n unsetNodes(editor, props, options) {\n editor.unsetNodes(props, options)\n },\n unwrapNodes(editor, options) {\n editor.unwrapNodes(options)\n },\n wrapNodes(editor, element, options) {\n editor.wrapNodes(element, options)\n },\n}\n","import { Editor, Location, Point, Range } from '../../index'\nimport { MoveUnit, SelectionEdge } from '../../types/types'\n\nexport interface SelectionCollapseOptions {\n edge?: SelectionEdge\n}\n\nexport interface SelectionMoveOptions {\n distance?: number\n unit?: MoveUnit\n reverse?: boolean\n edge?: SelectionEdge\n}\n\nexport interface SelectionSetPointOptions {\n edge?: SelectionEdge\n}\n\nexport interface SelectionTransforms {\n /**\n * Collapse the selection.\n */\n collapse: (editor: Editor, options?: SelectionCollapseOptions) => void\n\n /**\n * Unset the selection.\n */\n deselect: (editor: Editor) => void\n\n /**\n * Move the selection's point forward or backward.\n */\n move: (editor: Editor, options?: SelectionMoveOptions) => void\n\n /**\n * Set the selection to a new value.\n */\n select: (editor: Editor, target: Location) => void\n\n /**\n * Set new properties on one of the selection's points.\n */\n setPoint: (\n editor: Editor,\n props: Partial<Point>,\n options?: SelectionSetPointOptions\n ) => void\n\n /**\n * Set new properties on the selection.\n */\n setSelection: (editor: Editor, props: Partial<Range>) => void\n}\n\n// eslint-disable-next-line no-redeclare\nexport const SelectionTransforms: SelectionTransforms = {\n collapse(editor, options) {\n editor.collapse(options)\n },\n deselect(editor) {\n editor.deselect()\n },\n move(editor, options) {\n editor.move(options)\n },\n select(editor, target) {\n editor.select(target)\n },\n setPoint(editor, props, options) {\n editor.setPoint(props, options)\n },\n setSelection(editor, props) {\n editor.setSelection(props)\n },\n}\n","export const isObject = (value: any) =>\n typeof value === 'object' && value !== null\n","import { isObject } from './is-object'\n\n/*\n Custom deep equal comparison for Slate nodes.\n\n We don't need general purpose deep equality;\n Slate only supports plain values, Arrays, and nested objects.\n Complex values nested inside Arrays are not supported.\n\n Slate objects are designed to be serialised, so\n missing keys are deliberately normalised to undefined.\n */\nexport const isDeepEqual = (\n node: Record<string, any>,\n another: Record<string, any>\n): boolean => {\n for (const key in node) {\n const a = node[key]\n const b = another[key]\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false\n }\n } else if (isObject(a) && isObject(b)) {\n if (!isDeepEqual(a, b)) return false\n } else if (a !== b) {\n return false\n }\n }\n\n /*\n Deep object equality is only necessary in one direction; in the reverse direction\n we are only looking for keys that are missing.\n As above, undefined keys are normalised to missing.\n */\n\n for (const key in another) {\n if (node[key] === undefined && another[key] !== undefined) {\n return false\n }\n }\n\n return true\n}\n","export default function _objectWithoutPropertiesLoose(source, excluded) {\n if (source == null) return {};\n var target = {};\n var sourceKeys = Object.keys(source);\n var key, i;\n for (i = 0; i < sourceKeys.length; i++) {\n key = sourceKeys[i];\n if (excluded.indexOf(key) >= 0) continue;\n target[key] = source[key];\n }\n return target;\n}","import objectWithoutPropertiesLoose from \"./objectWithoutPropertiesLoose.js\";\nexport default function _objectWithoutProperties(source, excluded) {\n if (source == null) return {};\n var target = objectWithoutPropertiesLoose(source, excluded);\n var key, i;\n if (Object.getOwnPropertySymbols) {\n var sourceSymbolKeys = Object.getOwnPropertySymbols(source);\n for (i = 0; i < sourceSymbolKeys.length; i++) {\n key = sourceSymbolKeys[i];\n if (excluded.indexOf(key) >= 0) continue;\n if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;\n target[key] = source[key];\n }\n }\n return target;\n}","import { ExtendedType, Operation, Path, Point, PointEntry, isObject } from '..'\nimport { RangeDirection } from '../types/types'\n\n/**\n * `Range` objects are a set of points that refer to a specific span of a Slate\n * document. They can define a span inside a single node or a can span across\n * multiple nodes.\n */\n\nexport interface BaseRange {\n anchor: Point\n focus: Point\n}\n\nexport type Range = ExtendedType<'Range', BaseRange>\n\nexport interface RangeEdgesOptions {\n reverse?: boolean\n}\n\nexport interface RangeTransformOptions {\n affinity?: RangeDirection | null\n}\n\nexport interface RangeInterface {\n /**\n * Get the start and end points of a range, in the order in which they appear\n * in the document.\n */\n edges: (range: Range, options?: RangeEdgesOptions) => [Point, Point]\n\n /**\n * Get the end point of a range.\n */\n end: (range: Range) => Point\n\n /**\n * Check if a range is exactly equal to another.\n */\n equals: (range: Range, another: Range) => boolean\n\n /**\n * Check if a range includes a path, a point or part of another range.\n */\n includes: (range: Range, target: Path | Point | Range) => boolean\n\n /**\n * Check if a range includes another range.\n */\n surrounds: (range: Range, target: Range) => boolean\n\n /**\n * Get the intersection of a range with another.\n */\n intersection: (range: Range, another: Range) => Range | null\n\n /**\n * Check if a range is backward, meaning that its anchor point appears in the\n * document _after_ its focus point.\n */\n isBackward: (range: Range) => boolean\n\n /**\n * Check if a range is collapsed, meaning that both its anchor and focus\n * points refer to the exact same position in the document.\n */\n isCollapsed: (range: Range) => boolean\n\n /**\n * Check if a range is expanded.\n *\n * This is the opposite of [[Range.isCollapsed]] and is provided for legibility.\n */\n isExpanded: (range: Range) => boolean\n\n /**\n * Check if a range is forward.\n *\n * This is the opposite of [[Range.isBackward]] and is provided for legibility.\n */\n isForward: (range: Range) => boolean\n\n /**\n * Check if a value implements the [[Range]] interface.\n */\n isRange: (value: any) => value is Range\n\n /**\n * Iterate through all of the point entries in a range.\n */\n points: (range: Range) => Generator<PointEntry, void, undefined>\n\n /**\n * Get the start point of a range.\n */\n start: (range: Range) => Point\n\n /**\n * Transform a range by an operation.\n */\n transform: (\n range: Range,\n op: Operation,\n options?: RangeTransformOptions\n ) => Range | null\n}\n\n// eslint-disable-next-line no-redeclare\nexport const Range: RangeInterface = {\n edges(range: Range, options: RangeEdgesOptions = {}): [Point, Point] {\n const { reverse = false } = options\n const { anchor, focus } = range\n return Range.isBackward(range) === reverse\n ? [anchor, focus]\n : [focus, anchor]\n },\n\n end(range: Range): Point {\n const [, end] = Range.edges(range)\n return end\n },\n\n equals(range: Range, another: Range): boolean {\n return (\n Point.equals(range.anchor, another.anchor) &&\n Point.equals(range.focus, another.focus)\n )\n },\n\n surrounds(range: Range, target: Range): boolean {\n const intersectionRange = Range.intersection(range, target)\n if (!intersectionRange) {\n return false\n }\n return Range.equals(intersectionRange, target)\n },\n\n includes(range: Range, target: Path | Point | Range): boolean {\n if (Range.isRange(target)) {\n if (\n Range.includes(range, target.anchor) ||\n Range.includes(range, target.focus)\n ) {\n return true\n }\n\n const [rs, re] = Range.edges(range)\n const [ts, te] = Range.edges(target)\n return Point.isBefore(rs, ts) && Point.isAfter(re, te)\n }\n\n const [start, end] = Range.edges(range)\n let isAfterStart = false\n let isBeforeEnd = false\n\n if (Point.isPoint(target)) {\n isAfterStart = Point.compare(target, start) >= 0\n isBeforeEnd = Point.compare(target, end) <= 0\n } else {\n isAfterStart = Path.compare(target, start.path) >= 0\n isBeforeEnd = Path.compare(target, end.path) <= 0\n }\n\n return isAfterStart && isBeforeEnd\n },\n\n intersection(range: Range, another: Range): Range | null {\n const { anchor, focus, ...rest } = range\n const [s1, e1] = Range.edges(range)\n const [s2, e2] = Range.edges(another)\n const start = Point.isBefore(s1, s2) ? s2 : s1\n const end = Point.isBefore(e1, e2) ? e1 : e2\n\n if (Point.isBefore(end, start)) {\n return null\n } else {\n return { anchor: start, focus: end, ...rest }\n }\n },\n\n isBackward(range: Range): boolean {\n const { anchor, focus } = range\n return Point.isAfter(anchor, focus)\n },\n\n isCollapsed(range: Range): boolean {\n const { anchor, focus } = range\n return Point.equals(anchor, focus)\n },\n\n isExpanded(range: Range): boolean {\n return !Range.isCollapsed(range)\n },\n\n isForward(range: Range): boolean {\n return !Range.isBackward(range)\n },\n\n isRange(value: any): value is Range {\n return (\n isObject(value) &&\n Point.isPoint(value.anchor) &&\n Point.isPoint(value.focus)\n )\n },\n\n *points(range: Range): Generator<PointEntry, void, undefined> {\n yield [range.anchor, 'anchor']\n yield [range.focus, 'focus']\n },\n\n start(range: Range): Point {\n const [start] = Range.edges(range)\n return start\n },\n\n transform(\n range: Range | null,\n op: Operation,\n options: RangeTransformOptions = {}\n ): Range | null {\n if (range === null) {\n return null\n }\n\n const { affinity = 'inward' } = options\n let affinityAnchor: 'forward' | 'backward' | null\n let affinityFocus: 'forward' | 'backward' | null\n\n if (affinity === 'inward') {\n // If the range is collapsed, make sure to use the same affinity to\n // avoid the two points passing each other and expanding in the opposite\n // direction\n const isCollapsed = Range.isCollapsed(range)\n if (Range.isForward(range)) {\n affinityAnchor = 'forward'\n affinityFocus = isCollapsed ? affinityAnchor : 'backward'\n } else {\n affinityAnchor = 'backward'\n affinityFocus = isCollapsed ? affinityAnchor : 'forward'\n }\n } else if (affinity === 'outward') {\n if (Range.isForward(range)) {\n affinityAnchor = 'backward'\n