{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "api-slate-editor-transforms-docs",
  "title": "Editor Transforms",
  "description": "API reference for editor transformation operations in Plate.",
  "files": [
    {
      "path": "../../content/docs/api/slate/editor-transforms.mdx",
      "content": "---\ntitle: Editor Transforms\ndescription: API reference for editor transformation operations in Plate.\n---\n\nTransforms are helper functions that manipulate a Plate document.\n\n## Node Operations\n\n### `duplicateNodes`\n\nDuplicates nodes at a location and inserts them after that location.\n\n<API name=\"duplicateNodes\">\n<APIOptions type=\"DuplicateNodesOptions\">\n  <APIItem name=\"...options\" type=\"InsertNodesOptions\" optional>\n    `insertNodes` options.\n  </APIItem>\n  <APIItem name=\"at\" type=\"At\" optional>\n    Location to duplicate from and insert after. Defaults to selection.\n  </APIItem>\n  <APIItem name=\"block\" type=\"boolean\" optional>\n    If true, duplicates blocks above location. Ignored if `nodes` provided.\n  </APIItem>\n  <APIItem name=\"nodes\" type=\"NodeEntry[]\" optional>\n    Specific nodes to duplicate. Takes precedence over `block`.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `insertFragment`\n\nInsert a fragment of nodes at a location.\n\n<API name=\"insertFragment\">\n<APIParameters>\n  <APIItem name=\"fragment\" type=\"N[]\">\n    Fragment of nodes to insert.\n  </APIItem>\n  <APIItem name=\"options\" type=\"InsertFragmentOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"InsertFragmentOptions\">\n  <APIItem name=\"at\" type=\"At\" optional>\n    Location to insert at. Defaults to selection.\n  </APIItem>\n  <APIItem name=\"hanging\" type=\"boolean\" optional>\n    Whether range is hanging.\n  </APIItem>\n  <APIItem name=\"voids\" type=\"boolean\" optional>\n    Allow insertion in void nodes.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `insertNode`\n\nInsert a single node atomically.\n\n<API name=\"insertNode\">\n<APIParameters>\n  <APIItem name=\"node\" type=\"N\">\n    Node to insert.\n  </APIItem>\n  <APIItem name=\"options\" type=\"InsertNodesOptions\" optional />\n</APIParameters>\n</API>\n\n### `insertNodes`\n\nInsert one or more nodes atomically.\n\n<API name=\"insertNodes\">\n<APIParameters>\n  <APIItem name=\"nodes\" type=\"N | N[]\">\n    Node(s) to insert.\n  </APIItem>\n  <APIItem name=\"options\" type=\"InsertNodesOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"InsertNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional>\n    Common query options.\n  </APIItem>\n  <APIItem name=\"batchDirty\" type=\"boolean\" optional />\n  <APIItem name=\"hanging\" type=\"boolean\" optional />\n  <APIItem name=\"nextBlock\" type=\"boolean\" optional>\n    Insert after the current block if `removeEmpty` caused it to be removed.\n  </APIItem>\n  <APIItem name=\"removeEmpty\" type=\"QueryNodeOptions | boolean\" optional>\n    Remove the current block if empty. Defaults to removing an empty paragraph, but can be customized.\n  </APIItem>\n  <APIItem name=\"select\" type=\"boolean\" optional>\n    Select inserted nodes.\n  </APIItem>\n  <APIItem name=\"voids\" type=\"boolean\" optional>\n    Allow insertion in void nodes.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `liftNodes`\n\nLift nodes at the specified location upwards in the document tree. If necessary, the parent node is split.\n\n<API name=\"liftNodes\">\n<APIOptions type=\"LiftNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"mode\" type=\"'highest' | 'lowest'\" optional />\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `mergeNodes`\n\nMerge a node at the specified location with the previous node at the same depth. Resulting empty container nodes are removed.\n\n<API name=\"mergeNodes\">\n<APIOptions type=\"MergeNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"hanging\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `moveNodes`\n\nMove the nodes from an origin to a destination.\n\n<API name=\"moveNodes\">\n<APIOptions type=\"MoveNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"to\" type=\"Path\">\n    Destination path.\n  </APIItem>\n  <APIItem name=\"children\" type=\"boolean\" optional>\n    Move only children of the node at the location.\n  </APIItem>\n  <APIItem name=\"fromIndex\" type=\"number\" optional>\n    Start index of the children to move. Default is 0.\n  </APIItem>\n  <APIItem name=\"mode\" type=\"'highest' | 'lowest'\" optional />\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `removeNodes`\n\nRemove nodes at a location.\n\n<API name=\"removeNodes\">\n<APIOptions type=\"RemoveNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"children\" type=\"boolean\" optional>\n    When true, remove all children of the node at the specified location.\n  </APIItem>\n  <APIItem name=\"hanging\" type=\"boolean\" optional />\n  <APIItem name=\"previousEmptyBlock\" type=\"boolean\" optional>\n    Remove the previous empty block if it exists.\n  </APIItem>\n  <APIItem name=\"mode\" type=\"'highest' | 'lowest'\" optional />\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `replaceNodes`\n\nReplace nodes at a location with new nodes.\n\n<API name=\"replaceNodes\">\n<APIParameters>\n  <APIItem name=\"nodes\" type=\"N | N[]\">\n    The new node(s) to insert.\n  </APIItem>\n  <APIItem name=\"options\" type=\"ReplaceNodesOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"ReplaceNodesOptions\">\n  <APIItem name=\"...options\" type=\"InsertNodesOptions\" optional>\n    `insertNodes` options.\n  </APIItem>\n  <APIItem name=\"children\" type=\"boolean\" optional>\n    Replace all children of the node at the specified location instead of the node itself.\n  </APIItem>\n  <APIItem name=\"removeNodes\" type=\"Omit<RemoveNodesOptions, 'at'>\" optional>\n    Options for removing nodes before the replacement.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `reset`\n\nReset the editor state including history, selection and children.\n\n<API name=\"reset\">\n<APIOptions type=\"ResetOptions\">\n  <APIItem name=\"...options\" type=\"ReplaceNodesOptions\" optional>\n    `replaceNodes` options.\n  </APIItem>\n  <APIItem name=\"children\" type=\"boolean\" optional>\n    When true, only reset the children without clearing history/operations.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `setNodes`\n\nSet properties on nodes.\n\n<API name=\"setNodes\">\n<APIParameters>\n  <APIItem name=\"props\" type=\"Partial<NodeProps<N>>\">\n    Properties to set. Use `undefined` to unset.\n  </APIItem>\n  <APIItem name=\"options\" type=\"SetNodesOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"SetNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"compare\" type=\"(prop: Partial<Descendant>, node: Partial<Descendant>) => boolean\" optional />\n  <APIItem name=\"hanging\" type=\"boolean\" optional />\n  <APIItem name=\"marks\" type=\"boolean\" optional>\n    When true, only apply to text nodes in non-void or markable void nodes.\n  </APIItem>\n  <APIItem name=\"merge\" type=\"(prop: Partial<Descendant>, node: Partial<Descendant>) => object\" optional />\n  <APIItem name=\"mode\" type=\"'highest' | 'lowest'\" optional />\n  <APIItem name=\"split\" type=\"boolean\" optional />\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `splitNodes`\n\nSplit nodes at a location.\n\n<API name=\"splitNodes\">\n<APIOptions type=\"SplitNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"always\" type=\"boolean\" optional />\n  <APIItem name=\"height\" type=\"number\" optional />\n  <APIItem name=\"mode\" type=\"'highest' | 'lowest'\" optional />\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `toggleBlock`\n\nToggle the block type at a location.\n\n<API name=\"toggleBlock\">\n<APIParameters>\n  <APIItem name=\"type\" type=\"string\">\n    The block type to toggle.\n  </APIItem>\n  <APIItem name=\"options\" type=\"ToggleBlockOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"ToggleBlockOptions\">\n  <APIItem name=\"...options\" type=\"SetNodesOptions\" optional>\n    Options to pass to `setNodes`.\n  </APIItem>\n  <APIItem name=\"defaultType\" type=\"string\" optional>\n    The default block type when untoggling. Defaults to paragraph.\n  </APIItem>\n  <APIItem name=\"someOptions\" type=\"EditorNodesOptions\" optional>\n    Options for determining if the block is active.\n  </APIItem>\n  <APIItem name=\"wrap\" type=\"boolean\" optional>\n    If true, toggles wrapping with `type`. Otherwise, sets the block type directly.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `unsetNodes`\n\nRemove properties from nodes.\n\n<API name=\"unsetNodes\">\n<APIParameters>\n  <APIItem name=\"props\" type=\"string | string[]\">\n    Property key(s) to remove.\n  </APIItem>\n  <APIItem name=\"options\" type=\"UnsetNodesOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"UnsetNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"hanging\" type=\"boolean\" optional />\n  <APIItem name=\"mode\" type=\"'highest' | 'lowest'\" optional />\n  <APIItem name=\"split\" type=\"boolean\" optional />\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `unwrapNodes`\n\nUnwrap a node at a location. If necessary, the parent node is split.\n\n<API name=\"unwrapNodes\">\n<APIOptions type=\"UnwrapNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"hanging\" type=\"boolean\" optional />\n  <APIItem name=\"split\" type=\"boolean\" optional />\n  <APIItem name=\"mode\" type=\"'highest' | 'lowest'\" optional />\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `wrapNodes`\n\nWrap nodes at a location in the `element` container.\n\n<API name=\"wrapNodes\">\n<APIParameters>\n  <APIItem name=\"element\" type=\"N\">\n    The wrapper element.\n  </APIItem>\n  <APIItem name=\"options\" type=\"WrapNodesOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"WrapNodesOptions\">\n  <APIItem name=\"...options\" type=\"QueryOptions\" optional />\n  <APIItem name=\"children\" type=\"boolean\" optional>\n    When true, wrap all children into a single container element.\n  </APIItem>\n  <APIItem name=\"hanging\" type=\"boolean\" optional />\n  <APIItem name=\"mode\" type=\"'highest' | 'lowest'\" optional />\n  <APIItem name=\"split\" type=\"boolean\" optional />\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n## Text Operations\n\n### `delete`\n\nDelete text at a location.\n\n<API name=\"delete\">\n<APIOptions type=\"DeleteTextOptions\">\n  <APIItem name=\"at\" type=\"At\" optional />\n  <APIItem name=\"distance\" type=\"number\" optional>\n    Number of characters (or other unit) to delete. Default is 1.\n  </APIItem>\n  <APIItem name=\"hanging\" type=\"boolean\" optional />\n  <APIItem name=\"reverse\" type=\"boolean\" optional>\n    If true, delete backward.\n  </APIItem>\n  <APIItem name=\"unit\" type=\"'character' | 'word' | 'line' | 'block'\" optional>\n    Unit to delete by.\n  </APIItem>\n  <APIItem name=\"voids\" type=\"boolean\" optional />\n</APIOptions>\n</API>\n\n### `deleteBackward`\n\nDelete text backward.\n\n<API name=\"deleteBackward\">\n<APIParameters>\n  <APIItem name=\"unit\" type=\"'character' | 'word' | 'line' | 'block'\" optional>\n    Defaults to `'character'`.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `deleteForward`\n\nDelete text forward.\n\n<API name=\"deleteForward\">\n<APIParameters>\n  <APIItem name=\"unit\" type=\"'character' | 'word' | 'line' | 'block'\" optional>\n    Defaults to `'character'`.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `deleteFragment`\n\nDelete a fragment of nodes.\n\n<API name=\"deleteFragment\">\n<APIOptions type=\"EditorFragmentDeletionOptions\">\n  <APIItem name=\"direction\" type=\"'forward' | 'backward'\" optional>\n    Direction to delete.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `insertText`\n\nInsert text at a location, optionally with marks. The behavior depends on the provided options:\n\n1. If `at` is specified in options, inserts at that location regardless of selection\n2. Otherwise, if there's a selection:\n   - If `marks` is true (default) and editor has marks, inserts text with those marks\n   - If no marks, inserts plain text\n3. If neither `at` nor selection exists, no text is inserted\n\n<API name=\"insertText\">\n<APIParameters>\n  <APIItem name=\"text\" type=\"string\">\n    Text to insert.\n  </APIItem>\n  <APIItem name=\"options\" type=\"InsertTextOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"InsertTextOptions\">\n  <APIItem name=\"at\" type=\"TLocation\" optional>\n    Location to insert text at. Takes precedence over current selection.\n  </APIItem>\n  <APIItem name=\"voids\" type=\"boolean\" optional>\n    Whether to allow insertion in void nodes.\n  </APIItem>\n  <APIItem name=\"marks\" type=\"boolean\" optional>\n    - **Default:** `true`\n    When true and editor has marks, the inserted text will include those marks.\n    When false, inserts plain text without marks.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `insertBreak`\n\nInsert a block break at the current selection.\n\n### `insertSoftBreak`\n\nInsert a soft break at the current selection. A soft break is a new line in the current block.\n\n### `deselect`\n\nUnset the selection.\n\n### `move`\n\nMove the selection's point forward or backward.\n\n<API name=\"move\">\n<APIOptions type=\"object\">\n  <APIItem name=\"distance\" type=\"number\" optional>\n    How many units to move. Defaults to 1.\n  </APIItem>\n  <APIItem name=\"unit\" type=\"'offset' | 'character' | 'word' | 'line'\" optional>\n    Defaults to `'character'`.\n  </APIItem>\n  <APIItem name=\"reverse\" type=\"boolean\" optional>\n    Move backward if true.\n  </APIItem>\n  <APIItem name=\"edge\" type=\"'anchor' | 'focus' | 'start' | 'end'\" optional>\n    Which edge to move.\n  </APIItem>\n</APIOptions>\n</API>\n\n## Mark Operations\n\n### `addMark`\n\nAdd a custom property to the leaf text nodes within non-void nodes or void nodes that `editor.markableVoid()` allows in the current selection. If the selection is currently collapsed, the marks will be added to the `editor.marks` property instead, and applied when text is inserted next.\n\n<API name=\"addMark\">\n<APIParameters>\n  <APIItem name=\"key\" type=\"string\">\n    Mark key to add.\n  </APIItem>\n  <APIItem name=\"value\" type=\"any\">\n    Value for the mark.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `addMarks`\n\nAdd multiple marks to the current selection.\n\n```ts\neditor.tf.addMarks({ bold: true, italic: true })\neditor.tf.addMarks({ bold: subscript }, { remove: 'superscript' })\neditor.tf.addMarks({ bold: true }, { remove: ['italic', 'underline'] })\n```\n\n<API name=\"addMarks\">\n<APIParameters>\n  <APIItem name=\"marks\" type=\"Record<string, any>\">\n    Key-value pairs of mark props.\n  </APIItem>\n  <APIItem name=\"options\" type=\"AddMarksOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"AddMarksOptions\">\n  <APIItem name=\"remove\" type=\"string[] | string\" optional>\n    Mark keys to remove first. For mutually exclusive marks, e.g. subscript/superscript.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `removeMark`\n\nRemove a mark from text in the selection.\n\n<API name=\"removeMark\">\n<APIParameters>\n  <APIItem name=\"key\" type=\"string\">\n    Mark key to remove.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `removeMarks`\n\nRemove marks from text nodes in the current selection or from `editor.marks`. The behavior depends on the selection state and options:\n\n1. If selection is expanded or is in a markable void node:\n   - Remove specified mark keys from text nodes\n2. If selection is collapsed and no custom range provided:\n   - Remove specified keys from `editor.marks`\n   - If no keys specified, clear all marks from `editor.marks`\n3. If custom range provided (`at` option):\n   - Only remove marks from text nodes in that range\n\n```ts\neditor.tf.removeMarks()             // remove all marks\neditor.tf.removeMarks('bold')       // remove the 'bold' mark\neditor.tf.removeMarks(['bold','italic'])\neditor.tf.removeMarks('bold', { at: range })\n```\n\n<API name=\"removeMarks\">\n<APIParameters>\n  <APIItem name=\"keys\" type=\"string | string[]\" optional>\n    Mark key(s) to remove. If not provided and selection is collapsed, clears all marks from `editor.marks`.\n  </APIItem>\n  <APIItem name=\"options\" type=\"RemoveMarksOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"RemoveMarksOptions\">\n  <APIItem name=\"...options\" type=\"UnsetNodesOptions\" optional />\n  <APIItem name=\"at\" type=\"TRange\" optional>\n    Custom range to remove marks from. Takes precedence over current selection.\n  </APIItem>\n  <APIItem name=\"shouldChange\" type=\"boolean\" optional>\n    - **Default:** `true`\n    Whether to trigger onChange when modifying editor.marks.\n  </APIItem>\n  <APIItem name=\"split\" type=\"boolean\" optional>\n    Whether to split nodes when removing marks.\n  </APIItem>\n  <APIItem name=\"match\" type=\"(node: Node, path: Path) => boolean\" optional>\n    Custom function to filter which nodes to remove marks from.\n  </APIItem>\n  <APIItem name=\"voids\" type=\"boolean\" optional>\n    Whether to allow removing marks from void nodes.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `toggleMark`\n\nToggle a mark on or off in the current selection. If the mark exists, removes it. If it doesn't exist:\n1. Removes any specified marks in the `remove` option \n2. Adds the mark with value `true`\n\n```ts\neditor.tf.toggleMark('bold')                                // Toggle bold on/off\neditor.tf.toggleMark('subscript', { remove: 'superscript'}) // Remove superscript before adding subscript\n```\n\n<API name=\"toggleMark\">\n<APIParameters>\n  <APIItem name=\"key\" type=\"string\">\n    The mark key to toggle.\n  </APIItem>\n  <APIItem name=\"options\" type=\"ToggleMarkOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"ToggleMarkOptions\">\n  <APIItem name=\"remove\" type=\"string[] | string\" optional>\n    Mark key(s) to remove before adding the mark. Useful for mutually exclusive marks like subscript/superscript.\n    The specified mark key is always removed in addition to these marks.\n  </APIItem>\n</APIOptions>\n</API>\n\n## Selection\n\n### `collapse`\n\nCollapse the selection to a point.\n\n<API name=\"collapse\">\n<APIOptions type=\"object\">\n  <APIItem name=\"edge\" type=\"'anchor' | 'focus' | 'start' | 'end'\" optional>\n    Edge to collapse to. Defaults to `'anchor'`.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `deselect`\n\nUnset the current selection.\n\n### `move`\n\nMove the selection's point.\n\n<API name=\"move\">\n<APIOptions type=\"object\">\n  <APIItem name=\"distance\" type=\"number\" optional>\n    Defaults to 1.\n  </APIItem>\n  <APIItem name=\"unit\" type=\"'offset' | 'character' | 'word' | 'line'\" optional>\n    Defaults to `'character'`.\n  </APIItem>\n  <APIItem name=\"reverse\" type=\"boolean\" optional>\n    If true, move backward.\n  </APIItem>\n  <APIItem name=\"edge\" type=\"'anchor' | 'focus' | 'start' | 'end'\" optional>\n    Which edge to move.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `select`\n\nSet the selection to a new value specified by `at`. When a selection already exists, this method just calls `setSelection`.\n\n```ts\neditor.tf.select(at)\neditor.tf.select(at, { edge: 'end' })\neditor.tf.select(at, { edge: 'start' })\n```\n\n<API name=\"select\">\n<APIParameters>\n  <APIItem name=\"at\" type=\"At\">\n    Location to select.\n  </APIItem>\n  <APIItem name=\"options\" type=\"SelectOptions\" optional />\n</APIParameters>\n\n<APIOptions type=\"SelectOptions\">\n  <APIItem name=\"edge\" type=\"'start' | 'end'\" optional>\n    Select the start or end edge above `at`.\n  </APIItem>\n  <APIItem name=\"focus\" type=\"boolean\" optional>\n    Focus the editor before selecting.\n  </APIItem>\n  <APIItem name=\"next\" type=\"boolean\" optional>\n    Select the start of the next sibling.\n  </APIItem>\n  <APIItem name=\"previous\" type=\"boolean\" optional>\n    Select the end of the previous sibling.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `setPoint`\n\nSet new properties on one of the selection's points.\n\n<API name=\"setPoint\">\n<APIParameters>\n  <APIItem name=\"props\" type=\"Partial<Point>\">\n    Point properties to update.\n  </APIItem>\n  <APIItem name=\"options\" type=\"object\" optional />\n</APIParameters>\n\n<APIOptions type=\"object\">\n  <APIItem name=\"edge\" type=\"'anchor' | 'focus' | 'start' | 'end'\" optional>\n    Which edge of the selection to set.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `setSelection`\n\nSet new properties on an active selection. Since the value is a `Partial<Range>`, this method can only handle updates to an existing selection. If there is no active selection the operation will be void. Use `select` if you'd like to create a selection when there is none.\n\n<API name=\"setSelection\">\n<APIParameters>\n  <APIItem name=\"props\" type=\"Partial<TRange>\">\n    A partial range to update existing selection properties.\n  </APIItem>\n</APIParameters>\n</API>\n\n## DOM Operations\n\n### `blur`\n\nBlur the editor.\n\n### `deselectDOM`\n\nDeselect the editor's DOM selection in addition to `deselect`.\n\n### `focus`\n\nFocus the editor.\n\n```ts\neditor.tf.focus()\neditor.tf.focus({ edge: 'end' })\neditor.tf.focus({ edge: 'endEditor' })\n```\n\n<API name=\"focus\">\n<APIOptions type=\"FocusOptions\">\n  <APIItem name=\"at\" type=\"At\" optional>\n    Select this location before focusing.\n  </APIItem>\n  <APIItem name=\"edge\" type=\"'start' | 'startEditor' | 'end' | 'endEditor'\" optional>\n    Focus at the edge of the location or the editor.\n  </APIItem>\n  <APIItem name=\"retries\" type=\"number\" optional>\n    Number of attempts to refocus.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `insertData`\n\nInsert data from a `DataTransfer` into the editor. Calls:\n\n1. `insertFragmentData(editor: ReactEditor, data: DataTransfer)`\n2. `insertTextData(editor: ReactEditor, data: DataTransfer)`\n\n<API name=\"insertData\">\n<APIParameters>\n  <APIItem name=\"data\" type=\"DataTransfer\">\n    Data to insert from clipboard or drag event.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `insertFragmentData`\n\nInsert fragment data from a `DataTransfer` into the editor.\n\n<API name=\"insertFragmentData\">\n<APIParameters>\n  <APIItem name=\"data\" type=\"DataTransfer\">\n    Data to parse as fragment.\n  </APIItem>\n</APIParameters>\n\n<APIReturns type=\"boolean\" />\n</API>\n\n### `insertTextData`\n\nInsert text data from a `DataTransfer` into the editor.\n\n<API name=\"insertTextData\">\n<APIParameters>\n  <APIItem name=\"data\" type=\"DataTransfer\">\n    Text data to insert.\n  </APIItem>\n</APIParameters>\n\n<APIReturns type=\"boolean\" />\n</API>\n\n### `setFragmentData`\n\nSets data from the currently selected fragment on a `DataTransfer`.\n\n<API name=\"setFragmentData\">\n<APIParameters>\n  <APIItem name=\"data\" type=\"DataTransfer\">\n    DataTransfer to store the fragment.\n  </APIItem>\n</APIParameters>\n</API>\n\n## History Operations\n\n### `redo`\n\nRedo to the next saved state.\n\n### `undo`\n\nUndo to the previous saved state.\n\n### `setSplittingOnce`\n\n<API name=\"setSplittingOnce\">\n<APIParameters>\n  <APIItem name=\"value\" type=\"boolean\">\n    Whether the next operation should split into a new batch in history.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `withMerging`\n\nApply a series of changes inside a synchronous `fn`, These operations will\nbe merged into the previous history.\n\n<API name=\"withMerging\">\n<APIParameters>\n  <APIItem name=\"fn\" type=\"() => void\">\n    Batched changes to merge into the previous history point.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `withNewBatch`\n\nApply a series of changes inside a synchronous `fn`, ensuring that the first\noperation starts a new batch in the history. Subsequent operations will be\nmerged as usual.\n\n<API name=\"withNewBatch\">\n<APIParameters>\n  <APIItem name=\"fn\" type=\"() => void\">\n    Batched changes in a new history point.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `withoutMerging`\n\nApply a series of changes inside a synchronous `fn`, without merging any of\nthe new operations into previous save point in the history.\n\n<API name=\"withoutMerging\">\n<APIParameters>\n  <APIItem name=\"fn\" type=\"() => void\">\n    Changes not merged into any existing history point.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `withoutSaving`\n\nApply a series of changes inside a synchronous `fn`, without saving any of\ntheir operations into the history.\n\n<API name=\"withoutSaving\">\n<APIParameters>\n  <APIItem name=\"fn\" type=\"() => void\">\n    Changes not saved into history at all.\n  </APIItem>\n</APIParameters>\n</API>\n\n## Core Operations\n\n### `apply`\n\nApply an operation in the editor.\n\n<API name=\"apply\">\n<APIParameters>\n  <APIItem name=\"operation\" type=\"Operation<N>\">\n    Operation to apply.\n  </APIItem>\n</APIParameters>\n</API>\n\n### `normalizeNode`\n\nNormalize a node according to the editor's schema.\n\n<API name=\"normalizeNode\">\n<APIParameters>\n  <APIItem name=\"entry\" type=\"NodeEntry<N>\">\n    The node entry to normalize.\n  </APIItem>\n  <APIItem name=\"options\" type=\"{ operation?: Operation }\" optional />\n</APIParameters>\n\n<APIOptions type=\"{ operation?: Operation }\">\n  <APIItem name=\"operation\" type=\"Operation\" optional>\n    The triggering operation.\n  </APIItem>\n</APIOptions>\n</API>\n\n### `normalize`\n\nNormalize dirty nodes in the editor.\n\n<API name=\"normalize\">\n<APIOptions type=\"EditorNormalizeOptions\">\n  <APIItem name=\"force\" type=\"boolean\" optional>\n    When true, forcibly re-normalize all nodes.\n  </APIItem>\n  <APIItem name=\"operation\" type=\"Operation\" optional />\n</APIOptions>\n</API>\n\n### `withoutNormalizing`\n\nCall a function, deferring normalization until after it completes.\n\n<API name=\"withoutNormalizing\">\n<APIParameters>\n  <APIItem name=\"fn\" type=\"() => void\">\n    A synchronous function to execute without normalization in between operations.\n  </APIItem>\n</APIParameters>\n\n<APIReturns type=\"boolean\">\n  True if normalization was performed afterwards.\n</APIReturns>\n</API>\n\n## Keyboard Shortcuts\n\n### `moveLine`\n\nHandle `ArrowUp` and `ArrowDown` keyboard events.\n\n<API name=\"moveLine\">\n<APIParameters>\n  <APIItem name=\"options\" type=\"{ reverse: boolean }\">\n    - `reverse: true` for `ArrowUp`\n    - `reverse: false` for `ArrowDown`\n  </APIItem>\n</APIParameters>\n\n<APIReturns type=\"boolean | void\">\n  Return `true` to prevent default browser behavior, `false` to allow it.\n</APIReturns>\n</API>\n\n**Default behavior:** Returns `false` (allows Plate's default line movement).\n\n**Usage:**\n```ts\nconst plugin = createPlatePlugin({\n  key: 'myPlugin',\n}).overrideEditor(() => ({\n  transforms: {\n    moveLine: ({ reverse }) => {\n      // Custom line movement logic\n      if (reverse) {\n        // Handle ArrowUp\n      } else {\n        // Handle ArrowDown  \n      }\n      return true; // Prevent default\n    },\n  },\n}));\n```\n\n### `tab`\n\nHandle `Tab` and `Shift+Tab` keyboard events.\n\n<API name=\"tab\">\n<APIParameters>\n  <APIItem name=\"options\" type=\"{ reverse: boolean }\">\n    - `reverse: false` for `Tab`\n    - `reverse: true` for `Shift+Tab`\n  </APIItem>\n</APIParameters>\n\n<APIReturns type=\"boolean | void\">\n  Return `true` to prevent default browser behavior, `false` to allow it.\n</APIReturns>\n</API>\n\n**Default behavior:** Returns `false` (allows default browser tab navigation).\n\n**Usage:**\n```ts\nconst plugin = createPlatePlugin({\n  key: 'myPlugin',\n}).overrideEditor(() => ({\n  transforms: {\n    tab: ({ reverse }) => {\n      if (reverse) {\n        // Handle Shift+Tab (usually outdent)\n        editor.tf.outdent();\n      } else {\n        // Handle Tab (usually indent)\n        editor.tf.indent();\n      }\n      return true; // Prevent default\n    },\n  },\n}));\n```\n\n### `selectAll`\n\nHandle `Cmd+A` / `Ctrl+A` keyboard events.\n\n<API name=\"selectAll\">\n<APIReturns type=\"boolean | void\">\n  Return `true` to prevent default browser behavior, `false` to allow it.\n</APIReturns>\n</API>\n\n**Default behavior:** Returns `false` (allows default browser select all).\n\n**Usage:**\n```ts\nconst plugin = createPlatePlugin({\n  key: 'myPlugin',\n}).overrideEditor(() => ({\n  transforms: {\n    selectAll: () => {\n      // Custom select all logic\n      const blockEntry = editor.api.block();\n      if (blockEntry) {\n        editor.tf.select(blockEntry[1]);\n        return true; // Prevent default\n      }\n      return false; // Allow default\n    },\n  },\n}));\n```\n\n### `escape`\n\nHandle `Escape` keyboard events.\n\n<API name=\"escape\">\n<APIReturns type=\"boolean | void\">\n  Return `true` to prevent default browser behavior, `false` to allow it.\n</APIReturns>\n</API>\n\n**Default behavior:** Returns `false` (allows default browser escape handling).\n\n**Usage:**\n```ts\nconst plugin = createPlatePlugin({\n  key: 'myPlugin',\n}).overrideEditor(() => ({\n  transforms: {\n    escape: () => {\n      // Custom escape logic (e.g., exit special mode)\n      if (editor.api.inSpecialMode()) {\n        editor.tf.exitSpecialMode();\n        return true; // Prevent default\n      }\n      return false; // Allow default\n    },\n  },\n}));\n```\n",
      "type": "registry:file",
      "target": "content/docs/plate/api/slate/editor-transforms.mdx"
    }
  ],
  "type": "registry:file"
}