{"version":3,"file":"index.cjs","names":[],"sources":["../src/utils.ts","../src/doc/node.ts","../src/doc/utils.ts","../src/doc/operation.ts","../src/doc/position.ts","../src/queries.ts","../src/commands.ts","../src/dom/utils.ts","../src/dom/parser.ts","../src/dom/default.ts","../src/dom/index.ts","../src/dom/mutation.ts","../src/keyboard.ts","../src/plugins/history.ts","../src/editor.ts","../src/plugins/transfer/fileTransfer.ts","../src/plugins/transfer/plainTransfer.ts","../src/plugins/transfer/htmlTransfer.ts","../src/plugins/transfer/internalTransfer.ts","../src/plugins/blockLock.ts","../src/plugins/debug.ts","../src/plugins/keymap.ts","../src/plugins/scrollToSelection.ts","../src/plugins/selectionRect.ts","../src/plugins/singleline.ts","../src/presets/plain.ts"],"sourcesContent":["/**\n * @internal\n */\nexport const { min, max } = Math;\n\n/**\n * @internal\n */\nexport const { keys, is } = Object;\n\n/**\n * @internal\n */\nexport const isString = (n: unknown) => typeof n === \"string\";\n\n/**\n * @internal\n */\nexport const isFunction = (n: unknown) => typeof n === \"function\";\n\n/**\n * @internal\n */\nexport const microtask: (fn: () => void) => void = isFunction(queueMicrotask)\n  ? queueMicrotask\n  : (fn) => {\n      Promise.resolve().then(fn);\n    };\n","import { max, min } from \"../utils.js\";\nimport type {\n  InferInlineNode,\n  InferLeafBlockNode,\n  InferVoidNode,\n} from \"./types-infer.js\";\nimport type {\n  BlockNode,\n  DocNode,\n  Node,\n  Path,\n  TextNode,\n  DomPosition,\n  DomSelection,\n  Selection,\n  Fragment,\n  Range,\n} from \"./types.js\";\n\n/**\n * @internal\n */\nexport const isTextNode = (node: Node): node is TextNode => \"text\" in node;\n\n/**\n * @internal\n */\nexport const isBlockNode = (node: Node): node is BlockNode =>\n  \"children\" in node;\n\n/**\n * @internal\n */\nexport const hasBlockChildren = (\n  children: Fragment,\n): children is Extract<typeof children, readonly BlockNode[]> => {\n  return children.some(isBlockNode);\n};\n\nconst sizeCache = new WeakMap<BlockNode, number>();\n\nconst calcBlockSize = (\n  { children }: BlockNode,\n  start: number = 0,\n  end: number = children.length,\n): number => {\n  let size = 0;\n  let count = 0;\n  for (let i = start; i < end; i++) {\n    const n = children[i]!;\n    size += getNodeSize(n);\n    if (count !== 0 && isBlockNode(n)) {\n      size++;\n    }\n    count++;\n  }\n  return size;\n};\n\nexport const getNodeSize = (node: Node): number => {\n  if (isBlockNode(node)) {\n    let size = sizeCache.get(node);\n    if (size == null) {\n      sizeCache.set(node, (size = calcBlockSize(node)));\n    }\n    return size;\n  }\n  return isTextNode(node) ? node.text.length : 1;\n};\n\nexport const getChildAt = <T extends BlockNode>(\n  { children }: T,\n  offset: number,\n  isBackwardAffinity?: boolean,\n): [node: T[\"children\"][number], offset: number, index: number] | null => {\n  // TODO optimize\n  const length = children.length;\n  for (let i = 0; i < length; i++) {\n    const node = children[i]!;\n    const isBlock = isBlockNode(node);\n    let size = getNodeSize(node);\n    const isEmptyNode = size === 0;\n    if (isBlock) {\n      size++;\n    }\n    if (\n      size > offset ||\n      (size === offset && !isBlock && (isBackwardAffinity || isEmptyNode))\n    ) {\n      return [node, offset, i];\n    }\n    offset -= size;\n  }\n  return null;\n};\n\nexport const getLeafBlockAt = <T extends DocNode | BlockNode>(\n  node: T,\n  offset: number,\n): [node: InferLeafBlockNode<T>, offset: number, path: Path] => {\n  const path: number[] = [];\n  while (node) {\n    const found = getChildAt(node, offset);\n    if (!found) {\n      break;\n    }\n    const nextNode = found[0];\n    if (!isBlockNode(nextNode)) {\n      break;\n    }\n    offset = found[1];\n    node = nextNode as T;\n    path.push(found[2]);\n  }\n  return [node as InferLeafBlockNode<T>, offset, path];\n};\n\nexport const getLeafAt = <T extends DocNode | BlockNode>(\n  node: T,\n  offset: number,\n  isBackwardAffinity?: boolean,\n): [node: InferInlineNode<T>, offset: number, path: Path] | null => {\n  const [blockNode, blockOffset, path] = getLeafBlockAt(node, offset);\n  const inline = getChildAt(blockNode, blockOffset, isBackwardAffinity);\n  if (inline) {\n    (path as number[]).push(inline[2]);\n    return [inline[0] as InferInlineNode<T>, inline[1], path];\n  }\n  return null;\n};\n\nexport const getNodeOffset = (\n  root: DocNode | BlockNode,\n  target: Node,\n): number | null => {\n  // TODO optimize\n  let offset = 0;\n  let count = 0;\n  for (const child of root.children) {\n    const isBlock = isBlockNode(child);\n    if (isBlock && count !== 0) {\n      offset++;\n    }\n    if (child === target) {\n      return offset;\n    }\n    if (isBlock) {\n      const found = getNodeOffset(child, target);\n      if (found != null) {\n        return offset + found;\n      }\n    }\n    offset += getNodeSize(child);\n    count++;\n  }\n  return null;\n};\n\n/**\n * @internal\n */\nexport const splitBlock = <T extends DocNode | BlockNode>(\n  node: T,\n  pos: number,\n): [T, T] => {\n  const children = node.children;\n  const target = getChildAt(node, pos);\n  if (target) {\n    const [child, offsetAtChild, i] = target;\n    if (isBlockNode(child)) {\n      const [childBefore, childAfter] = splitBlock(child, offsetAtChild);\n      const before = children.slice(0, i);\n      const after = children.slice(i + 1);\n      before.push(childBefore);\n      after.unshift(childAfter);\n      return [\n        { ...node, children: before },\n        { ...node, children: after },\n      ];\n    } else {\n      const before = children.slice(0, i);\n      const after = children.slice(i + 1);\n      if (isTextNode(child)) {\n        const beforeText = child.text.slice(0, offsetAtChild);\n        const afterText = child.text.slice(offsetAtChild);\n        if (beforeText || !before.length) {\n          before.push({ ...child, text: beforeText });\n        }\n        if (afterText || !after.length) {\n          after.unshift({ ...child, text: afterText });\n        }\n      } else {\n        // node size must be 1\n        after.unshift(child);\n      }\n      return [\n        { ...node, children: before },\n        { ...node, children: after },\n      ];\n    }\n  }\n  const last = children[children.length - 1]!;\n  return [\n    node,\n    { ...node, children: isTextNode(last) ? [{ ...last, text: \"\" }] : [] },\n  ];\n};\n\n/**\n * @internal\n */\nexport const positionToOffset = (\n  node: DocNode | BlockNode,\n  [path, offset]: DomPosition,\n): number => {\n  let size = 0;\n  for (const p of path) {\n    size += calcBlockSize(node, 0, p);\n    if (p !== 0) {\n      size++;\n    }\n    node = node.children[p]! as BlockNode;\n  }\n  return size + offset;\n};\n\nexport const offsetToPosition = (\n  node: DocNode | BlockNode,\n  offset: number,\n): DomPosition => {\n  const [, blockOffset, path] = getLeafBlockAt(node, offset);\n  return [path, blockOffset];\n};\n\n/**\n * @internal\n */\nexport const domSelectionToSelection = (\n  doc: DocNode,\n  [anchor, focus]: DomSelection,\n): Selection => {\n  return [positionToOffset(doc, anchor), positionToOffset(doc, focus)];\n};\n\n/**\n * @internal\n */\nexport const selectionToDomSelection = (\n  doc: DocNode,\n  [anchor, focus]: Selection,\n): DomSelection => {\n  return [offsetToPosition(doc, anchor), offsetToPosition(doc, focus)];\n};\n\nfunction* iterChildren<T extends Node>(\n  node: T,\n  [start, end]: Range,\n): Generator<[node: Node, offset: number], void, void> {\n  if (start >= end) {\n    return;\n  }\n  if (!isBlockNode(node)) {\n    return;\n  }\n  const res = getChildAt(node, start);\n  if (res) {\n    let offset = start - res[1];\n    let i = res[2];\n    const children = node.children;\n    const length = children.length;\n    while (offset <= end && i < length) {\n      const targetNode = children[i]!;\n      yield [targetNode, offset];\n\n      i++;\n      offset += getNodeSize(targetNode);\n      if (isBlockNode(targetNode)) {\n        offset++;\n      }\n    }\n  }\n}\n\nexport function* iterLeafBlocks<T extends Node>(\n  node: T,\n  range: Range,\n): Generator<[node: InferLeafBlockNode<T>, offset: number], void, void> {\n  if (isBlockNode(node) && !hasBlockChildren(node.children)) {\n    yield [node as InferLeafBlockNode<T>, 0];\n    return;\n  }\n  for (const n of iterChildren(node, range)) {\n    const [child, offset] = n;\n    for (const r of iterLeafBlocks(child, [0, getNodeSize(child)])) {\n      r[1] += offset;\n      yield r as [InferLeafBlockNode<T>, number];\n    }\n  }\n}\n\nexport function* iterLeaves<T extends Node>(\n  node: T,\n  range: Range,\n): Generator<[node: InferInlineNode<T>, offset: number], void, void> {\n  if (!isBlockNode(node)) {\n    yield [node as InferInlineNode<T>, 0];\n    return;\n  }\n  for (const [child, offset] of iterChildren(node, range)) {\n    for (const leaf of iterLeaves(child, [0, getNodeSize(child)])) {\n      leaf[1] += offset;\n      yield leaf as [InferInlineNode<T>, number];\n    }\n  }\n}\n\nexport const sliceText = <T extends Node>(\n  node: T,\n  start: number = 0,\n  end: number = Infinity,\n  voidToString?: (node: InferVoidNode<T>) => string,\n): string => {\n  let str = \"\";\n  let offset = start;\n  for (const [leaf, leafStart] of iterLeaves(node, [start, end])) {\n    for (let i = leafStart - offset; i > 0; i--) {\n      str += \"\\n\";\n    }\n\n    const size = getNodeSize(leaf);\n    const leafEnd = leafStart + size;\n    if (isTextNode(leaf)) {\n      const textStart = max(leafStart, start) - leafStart;\n      const textEnd = min(leafEnd, end) - leafStart;\n      str +=\n        textStart === 0 && textEnd === size\n          ? leaf.text\n          : leaf.text.slice(textStart, textEnd);\n    } else {\n      if (voidToString) {\n        str += voidToString(leaf as InferVoidNode<T>);\n      }\n    }\n    offset = leafEnd;\n  }\n\n  for (let i = min(end, getNodeSize(node)) - offset; i > 0; i--) {\n    str += \"\\n\";\n  }\n  return str;\n};\n\n/**\n * @internal\n */\nexport const sliceFragment = <T extends DocNode>(\n  doc: T,\n  start: number,\n  end: number,\n): T[\"children\"] => {\n  if (start >= end) {\n    return [];\n  }\n\n  return splitBlock(splitBlock(doc, end)[0], start)[1].children;\n};\n","import { type BlockNode, type TextNode } from \"./types.js\";\n\n/**\n * @internal\n */\nexport const stringToFragment = <T extends TextNode, B extends BlockNode>(\n  text: string,\n  node?: T,\n  block?: B,\n) => {\n  return text\n    .split(\"\\n\")\n    .map((l) => ({ ...block, children: [{ ...node, text: l } as T] }));\n};\n","import { is, keys } from \"../utils.js\";\nimport {\n  getLeafBlockAt,\n  getChildAt,\n  getNodeSize,\n  hasBlockChildren,\n  isBlockNode,\n  isTextNode,\n  sliceFragment,\n  splitBlock,\n} from \"./node.js\";\nimport type {\n  DocNode,\n  Fragment,\n  InlineNode,\n  Selection,\n  TextNode,\n  Path,\n  BlockNode,\n  Node,\n  Range,\n} from \"./types.js\";\nimport { stringToFragment } from \"./utils.js\";\n\nconst OP_DELETE = \"delete\";\ntype DeleteOperation = Readonly<{\n  type: typeof OP_DELETE;\n  range: Range;\n}>;\n\nconst OP_INSERT_TEXT = \"insert_text\";\ntype InsertTextOperation = Readonly<{\n  type: typeof OP_INSERT_TEXT;\n  at: number;\n  text: string;\n}>;\n\nconst OP_INSERT_NODE = \"insert_node\";\ntype InsertNodeOperation = Readonly<{\n  type: typeof OP_INSERT_NODE;\n  at: number;\n  fragment: Fragment;\n}>;\n\nconst OP_FORMAT = \"format\";\ntype FormatOperation = Readonly<{\n  type: typeof OP_FORMAT;\n  range: Range;\n  key: string;\n  value: unknown;\n}>;\n\nconst OP_PATCH_NODE = \"patch_node\";\ntype PatchNodeOperation = Readonly<{\n  type: typeof OP_PATCH_NODE;\n  path: Path;\n  key: string;\n  value: unknown;\n}>;\n\nexport type Operation =\n  | DeleteOperation\n  | InsertTextOperation\n  | InsertNodeOperation\n  | FormatOperation\n  | PatchNodeOperation;\n\n/**\n * @internal\n */\nexport const isUnsafeOperation = ({ type }: Operation): boolean =>\n  type !== OP_INSERT_TEXT && type !== OP_DELETE;\n\nconst isSameNode = (a: InlineNode, b: InlineNode): boolean => {\n  const aKeys = keys(a);\n  if (aKeys.length !== keys(b).length) {\n    return false;\n  }\n  return aKeys.every((k) => {\n    if (!(k in b)) {\n      return false;\n    }\n    return k === \"text\" || is((a as any)[k], (b as any)[k]);\n  });\n};\n\nconst normalizeInline = (\n  array: InlineNode[],\n  start: number = 0,\n  end: number = array.length - 1,\n): void => {\n  let i = start + 1;\n  while (i <= end) {\n    const prev = array[i - 1]!;\n    const curr = array[i]!;\n    // merge text nodes with same attrs\n    if (isTextNode(prev) && isTextNode(curr) && isSameNode(prev, curr)) {\n      array[i - 1] = { ...prev, text: prev.text + curr.text };\n      array.splice(i, 1);\n      end--;\n    } else {\n      i++;\n    }\n  }\n\n  // remove empty text nodes, leaving at least one node per block\n  i = start;\n  while (i <= end) {\n    const node = array[i]!;\n    if (isTextNode(node) && !node.text && array.length > 1) {\n      array.splice(i, 1);\n      end--;\n    } else {\n      i++;\n    }\n  }\n};\n\nconst normalizeBlock = (\n  array: BlockNode[],\n  start: number = 0,\n  end: number = array.length - 1,\n): void => {\n  let i = start + 1;\n  while (i <= end) {\n    const prev = array[i - 1]!;\n    const curr = array[i]!;\n    // merge block nodes\n    array[i - 1] = joinBlocks(prev, curr);\n    array.splice(i, 1);\n    end--;\n  }\n};\n\nconst concat = <T extends Node>(a: T[], b: readonly T[]): void => {\n  if (b.length) {\n    const prevLength = a.length;\n    a.push(...b);\n    if (prevLength) {\n      const aLastIndex = prevLength - 1;\n      const aLastNode = a[aLastIndex]!;\n      const bFirstNode = a[prevLength]!;\n      const isALastBlock = isBlockNode(aLastNode);\n      const isBFirstBlock = isBlockNode(bFirstNode);\n      if (isALastBlock) {\n        if (isBFirstBlock) {\n          normalizeBlock(a as BlockNode[], prevLength - 1, prevLength);\n        }\n      } else if (!isALastBlock) {\n        if (!isBFirstBlock) {\n          normalizeInline(a as TextNode[], prevLength - 1, prevLength);\n        }\n      }\n    }\n  }\n  if (!a.length) {\n    a.push({ text: \"\" } as T);\n  }\n};\n\n/**\n * @internal\n */\nexport const joinBlocks = <T extends BlockNode>(...blocks: T[]): T => {\n  return {\n    ...blocks[0]!,\n    children: blocks.reduce((acc, b) => {\n      concat(acc, b.children);\n      return acc;\n    }, []),\n  };\n};\n\nconst getNodeAtPath = (\n  node: DocNode | BlockNode,\n  path: Path,\n): BlockNode | DocNode => {\n  for (let i = 0; i < path.length; i++) {\n    node = node.children[path[i]!]! as BlockNode; // TODO improve\n  }\n  return node;\n};\n\nconst replaceNodeAt = <T extends DocNode | BlockNode>(\n  node: T,\n  path: Path,\n  afterNode: Node,\n  i: number = 0,\n): T => {\n  if (i < path.length) {\n    const index = path[i]!;\n    const children = node.children;\n    const sliced = children.slice();\n    sliced.splice(\n      index,\n      1,\n      replaceNodeAt(children[index]! as T, path, afterNode, i + 1),\n    );\n    return { ...node, children: sliced };\n  }\n  // TODO improve type\n  return afterNode as T;\n};\n\nconst replaceRange = <T extends DocNode>(\n  doc: T,\n  start: number,\n  end: number,\n  inserted: Fragment,\n): T => {\n  const [before, maybeAfter] = splitBlock(doc, start);\n  const after = start < end ? splitBlock(doc, end)[1] : maybeAfter;\n\n  const isDocBlock = hasBlockChildren(doc.children);\n  if (hasBlockChildren(inserted)) {\n    if (!isDocBlock) {\n      inserted = joinBlocks(...inserted).children;\n    }\n  } else {\n    if (isDocBlock) {\n      inserted = [{ children: inserted }];\n    }\n  }\n  const array = before.children.slice();\n  concat(array, inserted);\n  concat(array, after.children);\n\n  return { ...doc, children: array };\n};\n\nconst isValidPosition = (doc: DocNode, offset: number): boolean => {\n  return offset >= 0 && offset <= getNodeSize(doc);\n};\n\n/**\n * @internal\n */\nexport const mapPositionWithOps = (\n  position: number,\n  ops: readonly Operation[],\n): number => {\n  return ops.reduce((acc, op) => mapPosition(acc, op), position);\n};\n\n/**\n * Remap a position through the given operation.\n * @param stickBefore `true` to keep the position in place when content is inserted at it, instead of moving it after the inserted content.\n */\nexport const mapPosition = (\n  position: number,\n  op: Operation,\n  stickBefore?: boolean,\n): number => {\n  switch (op.type) {\n    case OP_DELETE: {\n      const [start, end] = op.range;\n\n      if (position >= start) {\n        // start <= position\n        if (end >= position) {\n          // start <= position <= end\n          return start;\n        }\n        // start <= end < position\n        return position + start - end;\n      }\n      break;\n    }\n    case OP_INSERT_TEXT: {\n      const { at, text } = op;\n\n      if (stickBefore ? position > at : position >= at) {\n        // at <= position\n        return position + text.length;\n      }\n      break;\n    }\n    case OP_INSERT_NODE: {\n      const { at, fragment } = op;\n\n      if (stickBefore ? position > at : position >= at) {\n        // at <= position\n        return position + getNodeSize({ children: fragment });\n      }\n      break;\n    }\n  }\n  return position;\n};\n\nconst rebaseSelection = (\n  [anchor, focus]: Selection,\n  op: Operation,\n): Selection => {\n  return [mapPosition(anchor, op), mapPosition(focus, op)];\n};\n\n/**\n * @internal\n */\nexport const isValidSelection = (\n  doc: DocNode,\n  [anchor, focus]: Selection,\n): boolean => {\n  return isValidPosition(doc, anchor) && isValidPosition(doc, focus);\n};\n\n/**\n * @internal\n */\nexport const applyOperation = <T extends DocNode>(\n  doc: T,\n  selection: Selection,\n  op: Operation,\n): [T, Selection] => {\n  switch (op.type) {\n    case OP_DELETE: {\n      const [start, end] = op.range;\n      if (\n        isValidPosition(doc, start) &&\n        isValidPosition(doc, end) &&\n        start < end\n      ) {\n        doc = replaceRange(doc, start, end, []);\n        selection = rebaseSelection(selection, op);\n      }\n      break;\n    }\n    case OP_INSERT_TEXT: {\n      const { at, text } = op;\n      if (isValidPosition(doc, at) && text) {\n        // inherit style from previous block/text node\n        const [block, offset] = getLeafBlockAt(doc, at);\n        const res = getChildAt(block, offset, true);\n        let anchorNode: TextNode | undefined;\n        if (res) {\n          const node = res[0];\n          if (isTextNode(node)) {\n            anchorNode = node;\n          }\n        }\n\n        doc = replaceRange(\n          doc,\n          at,\n          at,\n          stringToFragment(text, anchorNode, block),\n        );\n        selection = rebaseSelection(selection, op);\n      }\n      break;\n    }\n    case OP_INSERT_NODE: {\n      const { at, fragment } = op;\n      if (isValidPosition(doc, at) && fragment.length) {\n        doc = replaceRange(doc, at, at, fragment);\n        selection = rebaseSelection(selection, op);\n      }\n      break;\n    }\n    case OP_FORMAT: {\n      const {\n        range: [start, end],\n        key,\n        value,\n      } = op;\n      if (\n        isValidPosition(doc, start) &&\n        isValidPosition(doc, end) &&\n        start <= end\n      ) {\n        if (start === end) {\n          const [{ children }, , path] = getLeafBlockAt(doc, start);\n          if (children.length === 1) {\n            const maybeText = children[0]!;\n            if (isTextNode(maybeText) && !maybeText.text) {\n              doc = replaceNodeAt(\n                doc,\n                [...path, 0], // TODO imporve\n                { ...maybeText, [key]: value },\n              );\n            }\n          }\n        } else {\n          const mapNode = <T extends Node>(node: T): T => {\n            if (isBlockNode(node)) {\n              return {\n                ...node,\n                children: node.children.map(mapNode),\n              };\n            } else if (isTextNode(node)) {\n              return { ...node, [key]: value };\n            }\n            return node;\n          };\n\n          doc = replaceRange(\n            doc,\n            start,\n            end,\n            sliceFragment(doc, start, end).map(mapNode),\n          );\n        }\n      }\n      break;\n    }\n    case OP_PATCH_NODE: {\n      const { path, key, value } = op;\n      const node = getNodeAtPath(doc, path);\n      if (node) {\n        doc = replaceNodeAt(doc, path, { ...node, [key]: value });\n      }\n      break;\n    }\n    default: {\n      op satisfies never;\n    }\n  }\n\n  return [doc, selection];\n};\n","import type { Range, Selection } from \"./types.js\";\n\n/**\n * @internal\n */\nexport const toRange = ([a, b]: Selection | Range): Range => {\n  return a > b ? [b, a] : [a, b];\n};\n\n/**\n * @internal\n */\nexport const isCollapsed = ([a, b]: Selection | Range): boolean => {\n  return a === b;\n};\n\n/**\n * @internal\n */\nexport const hasIntersection = (\n  [aStart, aEnd]: Range,\n  [bStart, bEnd]: Range,\n): boolean => {\n  // ignore edge for now\n  return aStart < bEnd && bStart < aEnd;\n};\n","import { getLeafAt, getNodeSize, iterLeaves } from \"./doc/node.js\";\nimport { hasIntersection, isCollapsed, toRange } from \"./doc/position.js\";\nimport type { InferInlineNode } from \"./doc/types-infer.js\";\nimport type { DocNode, Range } from \"./doc/types.js\";\nimport type { Editor } from \"./editor.js\";\n\n/**\n * Get leaf nodes that intersect with the selection or specified range.\n */\nexport function* LeavesInRange<T extends DocNode>(\n  editor: Editor<T>,\n  range: Range = toRange(editor.selection),\n): Generator<InferInlineNode<T>, void, void> {\n  if (isCollapsed(range)) {\n    const n = getLeafAt(editor.doc, range[0])?.[0];\n    if (n) {\n      yield n;\n    }\n  } else {\n    for (const [n, o] of iterLeaves(editor.doc, range)) {\n      if (hasIntersection(range, [o, o + getNodeSize(n)])) {\n        yield n;\n      }\n    }\n  }\n}\n","import { toRange } from \"./doc/position.js\";\nimport {\n  getLeafBlockAt,\n  getLeafAt,\n  getNodeSize,\n  isTextNode,\n} from \"./doc/node.js\";\nimport type { Editor } from \"./editor.js\";\nimport type { DocNode, Range } from \"./doc/types.js\";\nimport type {\n  ExtractAttrValue,\n  InferInlineNode,\n  InferLeafBlockNode,\n  InferTextNode,\n  InferVoidNode,\n} from \"./doc/types-infer.js\";\nimport { LeavesInRange } from \"./queries.js\";\n\n/**\n * Delete content in the selection or specified range.\n */\nexport function Delete(\n  editor: Editor,\n  range: Range = toRange(editor.selection),\n) {\n  editor.apply({ type: \"delete\", range });\n}\n\n/**\n * Insert text at the caret or specified position.\n */\nexport function InsertText(\n  editor: Editor,\n  text: string,\n  at: number = editor.selection[0],\n) {\n  editor.apply({ type: \"insert_text\", at, text });\n}\n\n/**\n * Insert node at the caret or specified position.\n */\nexport function InsertNode<T extends DocNode>(\n  editor: Editor<T>,\n  node: InferVoidNode<T>,\n  at: number = editor.selection[0],\n) {\n  editor.apply({\n    type: \"insert_node\",\n    at,\n    fragment: [{ children: [node] }],\n  });\n}\n\n/**\n * Insert multiple inline nodes as a single line fragment in one transaction.\n *\n * Fork-only command. Useful when a single insert needs to interleave text and\n * void nodes (e.g. mention chips) without splitting blocks.\n */\nexport function InsertNodes<T extends DocNode>(\n  editor: Editor<T>,\n  nodes: InferInlineNode<T>[],\n  position: number = editor.selection[0],\n) {\n  editor.apply({\n    type: \"insert_node\",\n    at: position,\n    fragment: [{ children: nodes }],\n  });\n}\n\n/**\n * Replace text in the selection or specified range.\n */\nexport function ReplaceText(\n  editor: Editor,\n  text: string,\n  range: Range = toRange(editor.selection),\n) {\n  editor\n    .apply({ type: \"delete\", range })\n    .apply({ type: \"insert_text\", at: range[0], text });\n}\n\n/**\n * Replace document in the editor.\n */\nexport function ReplaceDoc<T extends DocNode>(\n  editor: Editor<T>,\n  fragment: T[\"children\"],\n) {\n  // TODO revisit\n  editor.apply({\n    type: \"patch_node\",\n    path: [],\n    key: \"children\",\n    value: fragment,\n  });\n}\n\n/**\n * Replace the whole document content with a plain text string.\n *\n * Fork-only convenience command — splits on `\\n` into one block per line\n * (matching how plain editors render). Equivalent to:\n *\n * ```ts\n * editor.exec(ReplaceDoc, text.split(\"\\n\").map((t) => ({ children: [{ text: t }] })));\n * ```\n */\nexport function ReplaceAll(editor: Editor, text: string) {\n  editor\n    .apply({ type: \"delete\", range: [0, getNodeSize(editor.doc)] })\n    .apply({ type: \"insert_text\", at: 0, text });\n}\n\ntype ToggleableKey<T> = {\n  [K in keyof T]-?: T[K] extends boolean | undefined ? K : never;\n}[keyof T];\n\n/**\n * Format content in the selection or specified range.\n */\nexport function Format<\n  T extends DocNode,\n  N extends Omit<InferTextNode<T>, \"text\">,\n  K extends Extract<keyof N, string>,\n>(\n  editor: Editor<T>,\n  key: K,\n  value: N[K],\n  range: Range = toRange(editor.selection),\n) {\n  editor.apply({ type: \"format\", range, key, value });\n}\n\n/**\n * Toggle formatting in the selection or specified range.\n */\nexport function ToggleFormat<T extends DocNode>(\n  editor: Editor<T>,\n  key: Extract<ToggleableKey<Omit<InferTextNode<T>, \"text\">>, string>,\n  range: Range = toRange(editor.selection),\n) {\n  let shouldFormat = false;\n  let hasText = false;\n  for (const n of editor.exec(LeavesInRange, range)) {\n    if (isTextNode(n)) {\n      hasText = true;\n      if (!n[key as keyof typeof n]) {\n        shouldFormat = true;\n        break;\n      }\n    }\n  }\n\n  if (!hasText) {\n    return;\n  }\n\n  editor.apply({\n    type: \"format\",\n    range,\n    key,\n    value: shouldFormat,\n  });\n}\n\n/**\n * Set attr to a block node at the caret or specified position.\n */\nexport function SetBlockAttr<\n  T extends DocNode,\n  N extends InferLeafBlockNode<T>,\n  K extends string,\n>(\n  editor: Editor<T>,\n  key: K,\n  value: ExtractAttrValue<N, K>,\n  offset: number = editor.selection[0],\n) {\n  const path = getLeafBlockAt(editor.doc, offset)[2];\n  editor.apply({ type: \"patch_node\", path, key, value });\n}\n\n/**\n * Toggle attr of block node at the caret or specified position.\n */\nexport function ToggleBlockAttr<\n  T extends DocNode,\n  N extends InferLeafBlockNode<T>,\n  K extends string,\n>(\n  editor: Editor<T>,\n  key: K,\n  onValue: ExtractAttrValue<N, K>,\n  offValue: ExtractAttrValue<N, K>,\n  offset: number = editor.selection[0],\n) {\n  const [block, , path] = getLeafBlockAt(editor.doc, offset);\n  editor.apply({\n    type: \"patch_node\",\n    path,\n    key,\n    value: block[key as keyof typeof block] === onValue ? offValue : onValue,\n  });\n}\n\n/**\n * Set attr to a void node at the caret or specified position.\n */\nexport function SetVoidAttr<\n  T extends DocNode,\n  N extends InferVoidNode<T>,\n  K extends string,\n>(\n  editor: Editor<T>,\n  key: K,\n  value: ExtractAttrValue<N, K>,\n  offset: number = editor.selection[0],\n) {\n  const leaf = getLeafAt(editor.doc, offset, true);\n  if (leaf && !isTextNode(leaf[0])) {\n    editor.apply({ type: \"patch_node\", path: leaf[2], key, value });\n  }\n}\n","const ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\nconst COMMENT_NODE = 8;\nconst DOCUMENT_FRAGMENT_NODE = 11;\n\n/**\n * @internal\n */\nexport const isTextNode = (node: Node): node is Text => {\n  return node.nodeType === TEXT_NODE;\n};\n\n/**\n * @internal\n */\nexport const isElementNode = (node: Node): node is Element => {\n  return node.nodeType === ELEMENT_NODE;\n};\n\n/**\n * @internal\n */\nexport const isCommentNode = (node: Node): node is Comment => {\n  return node.nodeType === COMMENT_NODE;\n};\n\n/**\n * @internal\n */\nexport const isDocumentFragment = (node: Node): node is DocumentFragment => {\n  return node.nodeType === DOCUMENT_FRAGMENT_NODE;\n};\n","import { isDocumentFragment, isElementNode, isTextNode } from \"./utils.js\";\n\nconst LINE_BREAK_ELEMENT = 1;\nconst HIDDEN_ELEMENT = 2;\nconst STUB_ELEMENT = 3;\ntype ElementType =\n  | typeof LINE_BREAK_ELEMENT\n  | typeof HIDDEN_ELEMENT\n  | typeof STUB_ELEMENT;\n\ntype TagName = Uppercase<\n  | keyof HTMLElementTagNameMap\n  | keyof SVGElementTagNameMap\n  | keyof MathMLElementTagNameMap\n>;\n\nconst ELEMENT_TO_TYPE_MAP = new Map<string, ElementType>([\n  [\"BR\", LINE_BREAK_ELEMENT],\n  [\"WBR\", LINE_BREAK_ELEMENT],\n  // https://html.spec.whatwg.org/multipage/rendering.html#hidden-elements\n  [\"AREA\", HIDDEN_ELEMENT],\n  [\"BASE\", HIDDEN_ELEMENT],\n  // \"BASEFONT\",\n  [\"DATALIST\", HIDDEN_ELEMENT],\n  [\"HEAD\", HIDDEN_ELEMENT],\n  [\"LINK\", HIDDEN_ELEMENT],\n  [\"META\", HIDDEN_ELEMENT],\n  // \"NOEMBED\",\n  // \"NOFRAMES\",\n  // \"PARAM\",\n  [\"RP\", HIDDEN_ELEMENT],\n  [\"SCRIPT\", HIDDEN_ELEMENT],\n  [\"STYLE\", HIDDEN_ELEMENT],\n  [\"TEMPLATE\", HIDDEN_ELEMENT],\n  [\"TITLE\", HIDDEN_ELEMENT],\n  // https://html.spec.whatwg.org/multipage/rendering.html#tables-2\n  [\"COLGROUP\", HIDDEN_ELEMENT],\n  // https://html.spec.whatwg.org/#void-elements\n  // https://html.spec.whatwg.org/multipage/rendering.html#the-hr-element-2\n  [\"HR\", STUB_ELEMENT],\n  // https://html.spec.whatwg.org/multipage/dom.html#embedded-content-category\n  // https://html.spec.whatwg.org/multipage/rendering.html#replaced-elements\n  [\"AUDIO\", STUB_ELEMENT],\n  [\"CANVAS\", STUB_ELEMENT],\n  [\"EMBED\", STUB_ELEMENT],\n  [\"IFRAME\", STUB_ELEMENT],\n  [\"IMG\", STUB_ELEMENT],\n  [\"OBJECT\", STUB_ELEMENT],\n  [\"PICTURE\", STUB_ELEMENT],\n  [\"VIDEO\", STUB_ELEMENT],\n  [\"SVG\", STUB_ELEMENT],\n  [\"MATH\", STUB_ELEMENT],\n  // https://html.spec.whatwg.org/multipage/rendering.html#widgets\n  [\"BUTTON\", STUB_ELEMENT],\n  [\"INPUT\", STUB_ELEMENT],\n  [\"METER\", STUB_ELEMENT],\n  [\"PROGRESS\", STUB_ELEMENT],\n  [\"SELECT\", STUB_ELEMENT],\n  [\"TEXTAREA\", STUB_ELEMENT],\n] satisfies [TagName, ElementType][]) as ReadonlyMap<string, ElementType>;\n\nconst SHOW_ELEMENT = 0x1;\nconst SHOW_TEXT = 0x4;\n\nconst TOKEN_NULL = 0;\n/** @internal */\nexport const TOKEN_TEXT = 1;\n/** @internal */\nexport const TOKEN_VOID = 2;\n/** @internal */\nexport const TOKEN_SOFT_BREAK = 3;\n/** @internal */\nexport const TOKEN_BLOCK = 4;\nconst TOKEN_ANCHORABLE = 5;\nconst TOKEN_HIDDEN = 6;\n\ntype InternalTokenType =\n  | typeof TOKEN_NULL\n  | typeof TOKEN_TEXT\n  | typeof TOKEN_VOID\n  | typeof TOKEN_SOFT_BREAK\n  | typeof TOKEN_BLOCK\n  | typeof TOKEN_ANCHORABLE\n  | typeof TOKEN_HIDDEN;\n\n/**\n * @internal\n */\nexport type TokenType = Exclude<\n  InternalTokenType,\n  typeof TOKEN_NULL | typeof TOKEN_HIDDEN\n>;\n\ntype InferDomNode<T extends InternalTokenType> = T extends typeof TOKEN_TEXT\n  ? Text\n  : T extends typeof TOKEN_NULL | typeof TOKEN_HIDDEN\n    ? never\n    : Element;\n\n/**\n * @internal\n */\nexport const isHiddenNode = (node: Element): boolean => {\n  return ELEMENT_TO_TYPE_MAP.get(node.tagName) === HIDDEN_ELEMENT;\n};\n\ninterface ParserContext {\n  /**\n   * @internal\n   */\n  _next: () => TokenType | void;\n  /**\n   * @internal\n   */\n  _readToken: () => TokenType;\n  /**\n   * @internal\n   */\n  _domNode: <\n    T extends InternalTokenType | void = void,\n  >() => T extends InternalTokenType ? InferDomNode<T> : Node;\n  /**\n   * @internal\n   */\n  _nodeSize: () => number;\n  /**\n   * @internal\n   */\n  _moveTo: (node: Node) => void;\n  /**\n   * @internal\n   */\n  _prevBlock: () => void;\n  /**\n   * @internal\n   */\n  _nextBlock: () => void;\n  /**\n   * @internal\n   */\n  _parentBlock: () => void;\n}\n\n/**\n * @internal\n */\nexport const createParser = (\n  document: Document,\n  isBlock: (node: Element) => boolean,\n): Parser => {\n  let walker: TreeWalker | null = null;\n  let node: Node | null = null;\n  let _token: InternalTokenType | null = null;\n\n  const readToken = (): InternalTokenType => {\n    if (_token != null) {\n      return _token;\n    }\n\n    if (node) {\n      if (isTextNode(node)) {\n        const text = node.data;\n        // Ignore empty text nodes some frameworks may generate\n        if (text) {\n          return (_token =\n            // Especially Shift+Enter in Chrome\n            text === \"\\n\"\n              ? isValidSoftBreak()\n                ? TOKEN_SOFT_BREAK\n                : TOKEN_ANCHORABLE\n              : TOKEN_TEXT);\n        }\n      } else if (isElementNode(node)) {\n        if ((node as HTMLElement).contentEditable === \"false\") {\n          return (_token = TOKEN_VOID);\n        } else {\n          const elementType = ELEMENT_TO_TYPE_MAP.get(node.tagName);\n          if (elementType != null) {\n            return (_token =\n              elementType === LINE_BREAK_ELEMENT\n                ? isValidSoftBreak()\n                  ? // Especially Shift+Enter in Firefox\n                    TOKEN_SOFT_BREAK\n                  : // Returning <div><br/></div> is necessary to anchor selection\n                    TOKEN_ANCHORABLE\n                : elementType === STUB_ELEMENT\n                  ? TOKEN_VOID\n                  : TOKEN_HIDDEN);\n          } else if (isBlock(node)) {\n            return (_token = TOKEN_BLOCK);\n          }\n        }\n      } else if (isDocumentFragment(node)) {\n        // same as span\n      } else {\n        // e.g. Comment/ProcessingInstruction\n        return (_token = TOKEN_HIDDEN);\n      }\n    }\n    return (_token = TOKEN_NULL);\n  };\n\n  const nextNode = (): Node | null => {\n    const prevToken = readToken();\n    _token = null;\n\n    if (prevToken === TOKEN_VOID || prevToken === TOKEN_HIDDEN) {\n      const current = node!;\n      node = walker!.nextSibling();\n      if (!node) {\n        // to support case like <p><a><img /></a></p><p>hello</p> / <p><span contentEditable=\"false\">nested<span>tag</span></span></p>\n        while ((node = walker!.nextNode())) {\n          if (!current.contains(node)) {\n            break;\n          }\n        }\n      }\n      return node;\n    } else {\n      return (node = walker!.nextNode());\n    }\n  };\n\n  const isValidSoftBreak = (): boolean => {\n    // This function will return false if there are no nodes after soft break.\n    //\n    // In contenteditable, Shift+Enter will insert soft break. \\n in Chrome, <br/> in Firefox. Safari doesn't insert soft break.\n    // And \\n or <br/> has a special role that represents empty block in contenteditable.\n    // We have to distinguish real soft breaks from empty blocks.\n    //\n    // There are many possible markups for soft break ([] means text node):\n    // <div>[\\n][abc]</div>         Shift+Enter at start of line in Chrome\n    // <div><br/>[abc]</div>        Shift+Enter at start of line in Firefox\n    // <div>[ab][\\n][c]</div>       Shift+Enter at mid of line in Chrome\n    // <div>[ab]<br/>[c]</div>      Shift+Enter at mid of line in Firefox\n    // <div>[abc][\\n][\\n]</div>     Shift+Enter at end of line in Chrome\n    // <div>[abc]<br/><br/></div>   Shift+Enter at end of line in Firefox\n    // <div>[\\n]<br/></div>         Shift+Enter at empty line in Chrome\n    // <div><br/><br/></div>        Shift+Enter at empty line in Firefox\n    //\n    // And these do not include soft breaks:\n    // <div><br/></div>             empty line\n    // <div>[a]<br/></div>          type on empty line in Firefox\n    const parent = node!.parentNode!;\n    return parser(() => {\n      // To avoid \"RangeError: Maximum call stack size exceeded\"\n      _token = TOKEN_NULL;\n\n      while (nextNode()) {\n        if (readToken()) {\n          return true;\n        }\n        if (!parent.contains(node)) {\n          break;\n        }\n      }\n      return false;\n    });\n  };\n\n  const isInvisibleToken = (): boolean => {\n    const t = readToken();\n    return t === TOKEN_NULL || t === TOKEN_HIDDEN;\n  };\n\n  const moveToSibling = (backward: boolean, block?: boolean): boolean => {\n    while (\n      (_token = null) ||\n      (node = backward ? walker!.previousSibling() : walker!.nextSibling())\n    ) {\n      if (block ? readToken() === TOKEN_BLOCK : !isInvisibleToken()) {\n        return true;\n      }\n    }\n    return false;\n  };\n\n  const context: ParserContext = {\n    _next: (): TokenType | void => {\n      while (nextNode()) {\n        const t = readToken();\n        if (t && t !== TOKEN_HIDDEN) {\n          return t;\n        }\n      }\n    },\n    _readToken: readToken as () => TokenType,\n    _domNode: () => {\n      return node as any;\n    },\n    _nodeSize: () => {\n      const token = readToken();\n      return token === TOKEN_TEXT\n        ? (node as InferDomNode<typeof token>).data.length\n        : token === TOKEN_VOID\n          ? 1\n          : 0;\n    },\n    _moveTo: (nextNode) => {\n      _token = null;\n      walker!.currentNode = node = nextNode;\n      // https://github.com/inokawa/editate/pull/446\n      if (isInvisibleToken() && !moveToSibling(true)) {\n        _token = null;\n        walker!.currentNode = node = nextNode;\n        if (!moveToSibling(false)) {\n          _token = null;\n          walker!.currentNode = node = nextNode;\n        }\n      }\n    },\n    _prevBlock: () => {\n      moveToSibling(true, true);\n    },\n    _nextBlock: () => {\n      moveToSibling(false, true);\n    },\n    _parentBlock: () => {\n      while ((_token = null) || (node = walker!.parentNode())) {\n        if (readToken() === TOKEN_BLOCK) {\n          return;\n        }\n      }\n    },\n  };\n  const parser: Parser = <T>(\n    scopeFn: (ctx: ParserContext) => T,\n    root?: Node,\n  ): T => {\n    const prevWalker = walker;\n    const prevNode = node;\n    const prevToken = _token;\n    try {\n      if (!walker) {\n        walker = document.createTreeWalker(\n          (node = root!),\n          SHOW_TEXT | SHOW_ELEMENT,\n        );\n      }\n      return scopeFn(context);\n    } finally {\n      walker = prevWalker;\n      node = prevNode;\n      _token = prevToken;\n      if (walker && prevNode) {\n        walker.currentNode = prevNode;\n      }\n    }\n  };\n  return parser;\n};\n\nexport interface Parser {\n  <T>(scopeFn: (ctx: ParserContext) => T, root?: Node): T;\n}\n","const SINGLE_LINE_CONTAINER_NAMES = new Set([\n  // https://w3c.github.io/editing/docs/execCommand/#single-line-container\n  // non-list single-line container\n  \"DIV\",\n  \"H1\",\n  \"H2\",\n  \"H3\",\n  \"H4\",\n  \"H5\",\n  \"H6\",\n  \"P\",\n  \"PRE\",\n  // list single-line container\n  \"LI\",\n  \"DT\",\n  \"DD\",\n\n  // other elements for HTML paste\n  \"TH\",\n  \"TD\",\n]);\n\n/**\n * @internal\n */\nexport const defaultIsBlockNode = (node: Element): boolean => {\n  return SINGLE_LINE_CONTAINER_NAMES.has(node.tagName);\n};\n","import { type TokenType, type Parser, TOKEN_BLOCK } from \"./parser.js\";\nimport type {\n  DocNode,\n  Selection as JsSelection,\n  DomPosition,\n  DomSelection,\n  Path,\n} from \"../doc/types.js\";\nimport { selectionToDomSelection } from \"../doc/node.js\";\nimport { isCollapsed } from \"../doc/position.js\";\nimport { min } from \"../utils.js\";\nimport { isElementNode } from \"./utils.js\";\n\nexport {\n  createParser,\n  TOKEN_TEXT,\n  TOKEN_VOID,\n  TOKEN_SOFT_BREAK,\n  TOKEN_BLOCK,\n} from \"./parser.js\";\nexport { defaultIsBlockNode } from \"./default.js\";\n\n// const DOCUMENT_POSITION_DISCONNECTED = 0x01;\nconst DOCUMENT_POSITION_PRECEDING = 0x02;\nconst DOCUMENT_POSITION_FOLLOWING = 0x04;\n// const DOCUMENT_POSITION_CONTAINS = 0x08;\nconst DOCUMENT_POSITION_CONTAINED_BY = 0x10;\n// const DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;\n\nconst compareDomPosition = (a: Node, b: Node) => a.compareDocumentPosition(b);\n\n/**\n * @internal\n */\nexport const getCurrentDocument = (node: Element): Document =>\n  node.ownerDocument;\n\n/**\n * @internal\n */\nexport const getDOMSelection = (element: Element): Selection => {\n  // TODO support ShadowRoot\n  return getCurrentDocument(element).getSelection()!;\n};\n\n/**\n * @internal\n */\nexport const getSelectionRangeInEditor = (\n  selection: Selection,\n  root: Element,\n): Range | void => {\n  if (selection.rangeCount) {\n    const range = selection.getRangeAt(0);\n    if (root.contains(range.commonAncestorContainer)) {\n      return range;\n    }\n  }\n};\n\nexport const selectionToRange = (\n  root: Element,\n  parse: Parser,\n  doc: DocNode,\n  sel: JsSelection,\n): Range => {\n  const [anchor, focus] = selectionToDomSelection(doc, sel);\n\n  const document = getCurrentDocument(root);\n  const collapsed = isCollapsed(sel);\n  const backward = sel[0] - sel[1] > 0;\n  const start = backward ? focus : anchor;\n  const end = backward ? anchor : focus;\n\n  const domStart = findPosition(root, parse, start);\n  const domEnd = collapsed ? domStart : findPosition(root, parse, end);\n\n  const range = document.createRange();\n\n  const [startNode, startOffset] = domStart;\n  const [endNode, endOffset] = domEnd;\n\n  // embed or br\n  if (isElementNode(startNode) && root !== startNode) {\n    if (startOffset < 1) {\n      range.setStartBefore(startNode);\n    } else {\n      range.setStartAfter(startNode);\n    }\n  } else {\n    range.setStart(startNode, startOffset);\n  }\n\n  // embed or br\n  if (isElementNode(endNode) && root !== endNode) {\n    if (endOffset < 1) {\n      range.setEndBefore(endNode);\n    } else {\n      range.setEndAfter(endNode);\n    }\n  } else {\n    range.setEnd(endNode, endOffset);\n  }\n  return range;\n};\n\n/**\n * @internal\n */\nexport const setSelectionToDOM = (\n  root: Element,\n  parse: Parser,\n  doc: DocNode,\n  sel: JsSelection,\n  force?: boolean,\n): void => {\n  const selection = getDOMSelection(root);\n\n  if (force || getSelectionRangeInEditor(selection, root)) {\n    const range = selectionToRange(root, parse, doc, sel);\n    const backward = sel[0] - sel[1] > 0;\n\n    selection.removeAllRanges();\n    selection.addRange(range);\n    if (backward) {\n      selection.collapseToEnd();\n      selection.extend(range.startContainer, range.startOffset);\n    }\n  }\n};\n\n/**\n * @internal\n */\nexport type DomPoint = [node: Node, offsetAtNode: number];\n\n/**\n * @internal\n */\nexport const findPosition = (\n  root: Element,\n  parse: Parser,\n  [path, offset]: DomPosition,\n): DomPoint => {\n  return parse(\n    ({\n      _next: next,\n      _nextBlock: nextBlock,\n      _domNode: domNode,\n      _nodeSize: nodeSize,\n    }): DomPoint => {\n      let pathIndex = 0;\n      let type: TokenType | void;\n      while ((type = next())) {\n        if (type === TOKEN_BLOCK) {\n          if (pathIndex < path.length) {\n            for (\n              let blockIndex = path[pathIndex++]!;\n              blockIndex > 0;\n              blockIndex--\n            ) {\n              nextBlock();\n            }\n          }\n        } else {\n          const size = nodeSize();\n          if (offset <= size) {\n            return [domNode<typeof type>(), offset];\n          }\n          offset -= size;\n        }\n      }\n\n      // special path for empty content with empty selection, necessary for placeholder\n      return [root, 0];\n    },\n    root,\n  );\n};\n\n/**\n * @internal\n */\nexport const serializePosition = (\n  root: Element,\n  parse: Parser,\n  node: DomPoint[0],\n  offsetAtNode: DomPoint[1],\n): DomPosition => {\n  let excludeEnd = true;\n  if (root === node && !node.hasChildNodes()) {\n    // for placeholder\n    return [[], 0];\n  }\n\n  if (isElementNode(node) && node.hasChildNodes()) {\n    // If start/end of Range is not selectable node, it will have offset relative to its parent\n    //      0  1       2               3\n    // <div>aaaa<img /><span>bbbb</span></div>\n    //\n    // And there are other possible cases:\n    // - Selection with Ctrl+A in Firefox\n    // - getTargetRanges() when deleting contenteditable:false in Firefox\n    // - Selection.setBaseAndExtent(element, 0, element, 0)\n    const index = min(offsetAtNode, node.childNodes.length - 1);\n    node = node.childNodes[index]!;\n    excludeEnd = index === offsetAtNode;\n    offsetAtNode = 0;\n  }\n\n  return parse(\n    ({\n      _next: next,\n      _moveTo: moveTo,\n      _parentBlock: parentBlock,\n      _prevBlock: prevBlock,\n      _domNode: domNode,\n      _nodeSize: nodeSize,\n      _readToken: readToken,\n    }) => {\n      moveTo(node);\n      if (readToken() !== TOKEN_BLOCK) {\n        parentBlock();\n      }\n\n      const path = parse((): Path => {\n        const p: number[] = [];\n        while (readToken() && domNode() !== root) {\n          let i = 0;\n          while (true) {\n            prevBlock();\n            if (!readToken()) {\n              break;\n            }\n            i++;\n          }\n          p.unshift(i);\n          parentBlock();\n        }\n\n        return p;\n      });\n\n      let offset = 0;\n      while (next()) {\n        const comp = compareDomPosition(node, domNode());\n        if (\n          comp === 0 || // same object\n          comp & DOCUMENT_POSITION_CONTAINED_BY\n        ) {\n          if (excludeEnd) {\n            break;\n          }\n        } else if (comp & DOCUMENT_POSITION_FOLLOWING) {\n          break;\n        }\n        offset += nodeSize();\n      }\n      return [path, offset + offsetAtNode];\n    },\n    root,\n  );\n};\n\n/**\n * @internal\n */\nexport const serializeRange = (\n  root: Element,\n  parse: Parser,\n  { startOffset, startContainer, endOffset, endContainer }: AbstractRange,\n): [DomPosition, DomPosition] => {\n  const start = serializePosition(root, parse, startContainer, startOffset);\n  return [\n    start,\n    startContainer === endContainer && startOffset === endOffset\n      ? start\n      : serializePosition(root, parse, endContainer, endOffset),\n  ];\n};\n\n/**\n * @internal\n */\nexport const takeSelectionSnapshot = (\n  root: Element,\n  parse: Parser,\n): DomSelection => {\n  const selection = getDOMSelection(root);\n  const domRange = getSelectionRangeInEditor(selection, root);\n  if (!domRange) {\n    return [\n      [[0], 0],\n      [[0], 0],\n    ];\n  }\n\n  const range = serializeRange(root, parse, domRange);\n  const comp = compareDomPosition(selection.anchorNode!, selection.focusNode!);\n\n  // https://stackoverflow.com/questions/9180405/detect-direction-of-user-selection-with-javascript\n  return (\n    comp === 0 // same object\n      ? selection.anchorOffset > selection.focusOffset\n      : comp & DOCUMENT_POSITION_PRECEDING\n  )\n    ? [range[1], range[0]]\n    : range;\n};\n\n/**\n * @internal\n */\nexport const getPointedCaretPosition = (\n  root: Element,\n  parse: Parser,\n  { clientX, clientY }: MouseEvent,\n): DomPosition | void => {\n  const document = getCurrentDocument(root);\n  // https://developer.mozilla.org/en-US/docs/Web/API/Document/caretPositionFromPoint\n  // https://developer.mozilla.org/en-US/docs/Web/API/Document/caretRangeFromPoint\n  //          caretPositionFromPoint caretRangeFromPoint\n  // Chrome:  128                    4\n  // Firefox: 20                     -\n  // Safari:  26.2                   5\n  if (document.caretPositionFromPoint) {\n    const position = document.caretPositionFromPoint(clientX, clientY);\n    if (position) {\n      return serializePosition(\n        root,\n        parse,\n        position.offsetNode,\n        position.offset,\n      );\n    }\n  } else if (document.caretRangeFromPoint) {\n    const range = document.caretRangeFromPoint(clientX, clientY);\n    if (range) {\n      return serializePosition(\n        root,\n        parse,\n        range.startContainer,\n        range.startOffset,\n      );\n    }\n  }\n};\n","/**\n * @internal\n */\nexport const createMutationObserver = (\n  element: Element,\n  onMutationIgnored: () => void,\n  /**\n   * When true, DOM mutations outside composition recording and outside\n   * `_domUpdate(true)` are reverted. Imperative hosts must wrap their paint\n   * in `_domUpdate`; declarative React hosts should leave this false.\n   */\n  revertForeign = false,\n) => {\n  let isInputing = false;\n  let isDomUpdating = false;\n  let queue: MutationRecord[] = [];\n\n  const process = (records: MutationRecord[]) => {\n    if (isInputing || isDomUpdating) {\n      queue.push(...records);\n    }\n  };\n\n  const revertRecords = (records: MutationRecord[]) => {\n    let m: MutationRecord | undefined;\n    while ((m = records.pop())) {\n      if (m.type === \"childList\") {\n        const { target, removedNodes, addedNodes, nextSibling } = m;\n        for (let i = removedNodes.length - 1; i >= 0; i--) {\n          target.insertBefore(removedNodes[i]!, nextSibling);\n        }\n        for (let i = addedNodes.length - 1; i >= 0; i--) {\n          target.removeChild(addedNodes[i]!);\n        }\n      } else {\n        // characterData\n        (m.target as CharacterData).data = m.oldValue!;\n      }\n    }\n  };\n\n  // https://dom.spec.whatwg.org/#interface-mutationobserver\n  const mo = new MutationObserver((records) => {\n    if (isInputing || isDomUpdating) {\n      process(records);\n      return;\n    }\n\n    if (revertForeign && records.length) {\n      // Undo Translate / extension / spellcheck wrappers that rewrite the\n      // contenteditable tree. takeRecords() inside flush() swallows the\n      // side-effect mutations from the undo so they are not delivered again.\n      revertRecords(records.slice());\n      flush();\n    }\n\n    onMutationIgnored();\n  });\n\n  const sync = () => {\n    process(mo.takeRecords());\n  };\n\n  const flush = (): MutationRecord[] => {\n    sync();\n    const prev = queue;\n    queue = [];\n    return prev;\n  };\n\n  mo.observe(element, {\n    characterData: true,\n    characterDataOldValue: true,\n    childList: true,\n    subtree: true,\n  });\n\n  return {\n    _revert: (records: MutationRecord[]) => {\n      revertRecords(records);\n      flush();\n    },\n    _record: (enable: boolean) => {\n      if (!isInputing && enable) {\n        sync();\n      }\n      isInputing = enable;\n    },\n    /**\n     * Mark a host-driven DOM paint. Mutations inside are accepted (queued and\n     * discarded on disable). Required when `revertForeign` is true.\n     */\n    _domUpdate: (enable: boolean) => {\n      if (!isDomUpdating && enable) {\n        // Drop any pending unexpected records before accepting host paint.\n        mo.takeRecords();\n      }\n      if (isDomUpdating && !enable) {\n        flush();\n      }\n      isDomUpdating = enable;\n    },\n    _flush: flush,\n    _dispose: () => {\n      queue.length = 0;\n      mo.disconnect();\n    },\n  };\n};\n","import type { KeyboardHook } from \"./editor.js\";\n\ntype Modifier = \"Ctrl\" | \"Meta\" | \"Alt\" | \"Shift\" | \"Mod\";\n\n// TODO support more keys\ntype BaseKey =\n  | \"A\"\n  | \"B\"\n  | \"C\"\n  | \"D\"\n  | \"E\"\n  | \"F\"\n  | \"G\"\n  | \"H\"\n  | \"I\"\n  | \"J\"\n  | \"K\"\n  | \"L\"\n  | \"M\"\n  | \"N\"\n  | \"O\"\n  | \"P\"\n  | \"Q\"\n  | \"R\"\n  | \"S\"\n  | \"T\"\n  | \"U\"\n  | \"V\"\n  | \"W\"\n  | \"X\"\n  | \"Y\"\n  | \"Z\"\n  | \"0\"\n  | \"1\"\n  | \"2\"\n  | \"3\"\n  | \"4\"\n  | \"5\"\n  | \"6\"\n  | \"7\"\n  | \"8\"\n  | \"9\"\n  | \",\"\n  | \".\"\n  | \"/\"\n  | \"[\"\n  | \"]\"\n  | \"-\"\n  | \"=\"\n  | \"\\\\\"\n  | \"`\"\n  | \"Enter\"\n  | \"Escape\"\n  | \"Space\"\n  | \"Backspace\"\n  | \"Tab\"\n  | \"ArrowUp\"\n  | \"ArrowDown\"\n  | \"ArrowLeft\"\n  | \"ArrowRight\"\n  | \"Delete\"\n  | \"Home\"\n  | \"End\"\n  | \"PageUp\"\n  | \"PageDown\"\n  | \"F1\"\n  | \"F2\"\n  | \"F3\"\n  | \"F4\"\n  | \"F5\"\n  | \"F6\"\n  | \"F7\"\n  | \"F8\"\n  | \"F9\"\n  | \"F10\"\n  | \"F11\"\n  | \"F12\";\n\nexport type KeyString =\n  | BaseKey\n  | `${Modifier}+${BaseKey}`\n  | `${Modifier}+${Modifier}+${BaseKey}`\n  | `${Modifier}+${Modifier}+${Modifier}+${BaseKey}`;\n\nconst isMac =\n  typeof navigator !== \"undefined\" &&\n  /Mac|iP(hone|od|ad)/.test(navigator.platform);\n\nexport const keymap = (\n  key: KeyString,\n  cb: (e: KeyboardEvent) => void | false,\n): KeyboardHook => {\n  const isPlusKey = key.endsWith(\"+\");\n  const splitted = (isPlusKey ? key.slice(0, -2) : key).split(\"+\");\n  const rawTargetKey = isPlusKey ? \"+\" : splitted.pop()!;\n  const targetKey = rawTargetKey === \"Space\" ? \" \" : rawTargetKey.toLowerCase();\n  let shift = false;\n  let ctrl = false;\n  let meta = false;\n  let alt = false;\n  splitted.forEach((k) => {\n    switch (k as Modifier) {\n      case \"Ctrl\": {\n        ctrl = true;\n        break;\n      }\n      case \"Meta\": {\n        meta = true;\n        break;\n      }\n      case \"Mod\": {\n        if (isMac) {\n          meta = true;\n        } else {\n          ctrl = true;\n        }\n        break;\n      }\n      case \"Alt\": {\n        alt = true;\n        break;\n      }\n      case \"Shift\": {\n        shift = true;\n        break;\n      }\n    }\n  });\n\n  return (e): boolean | void => {\n    // TODO should we handle it e.code?\n    if (\n      e.key.toLowerCase() === targetKey &&\n      ctrl === e.ctrlKey &&\n      meta === e.metaKey &&\n      shift === e.shiftKey &&\n      alt === e.altKey\n    ) {\n      return cb(e) === false ? false : true;\n    }\n  };\n};\n","import { ReplaceDoc } from \"../commands.js\";\nimport { mapPositionWithOps, type Operation } from \"../doc/operation.js\";\nimport type { DocNode, Selection } from \"../doc/types.js\";\nimport type { Editor } from \"../editor.js\";\nimport { keymap } from \"../keyboard.js\";\nimport { keys } from \"../utils.js\";\n\nconst MAX_HISTORY_LENGTH = 500;\nconst BATCH_HISTORY_TIME = 500;\n\ninterface HistoryContext {\n  undo: () => void;\n  redo: () => void;\n  undoable: () => boolean;\n  redoable: () => boolean;\n  clear: () => void;\n}\n\n/**\n * @internal\n */\nexport function historyPlugin<T extends DocNode>(editor: Editor<T>) {\n  type History = [T, Selection, Operation[]];\n  let index = 0;\n  let prevTime = 0;\n  let undoOrRedoing = false;\n  const now = Date.now;\n  const histories: History[] = [[editor.doc, editor.selection, []]];\n\n  const get = () => histories[index]!;\n\n  const isUndoable = (): boolean => {\n    return index > 0;\n  };\n\n  const isRedoable = (): boolean => {\n    return index < histories.length - 1;\n  };\n\n  const restore = (doc: T) => {\n    editor.exec(ReplaceDoc, doc.children);\n\n    // TODO improve\n    const prev = doc as Record<string, unknown>;\n    const current = editor.doc as Record<string, unknown>;\n    for (const key of keys(prev)) {\n      if (key !== \"children\" && current[key] !== prev[key]) {\n        editor.apply({ type: \"patch_node\", path: [], key, value: prev[key] });\n      }\n    }\n    for (const key of keys(current)) {\n      if (key !== \"children\" && !(key in prev)) {\n        editor.apply({ type: \"patch_node\", path: [], key, value: undefined });\n      }\n    }\n  };\n\n  const undo = () => {\n    if (isUndoable()) {\n      const sel = get()[1];\n      index--;\n      const currentDoc = editor.doc;\n      undoOrRedoing = true;\n      restore(get()[0]);\n      undoOrRedoing = false;\n      if (currentDoc !== editor.doc) {\n        editor.selection = sel;\n      }\n    }\n  };\n  const redo = () => {\n    if (isRedoable()) {\n      index++;\n      const [doc, sel, ops] = get();\n      const currentDoc = editor.doc;\n      undoOrRedoing = true;\n      restore(doc);\n      undoOrRedoing = false;\n      if (currentDoc !== editor.doc) {\n        editor.selection = [\n          mapPositionWithOps(sel[0], ops),\n          mapPositionWithOps(sel[1], ops),\n        ];\n      }\n    }\n  };\n\n  const clear = () => {\n    histories.length = 0;\n    histories.push([editor.doc, editor.selection, []]);\n    index = 0;\n    prevTime = 0;\n  };\n\n  editor.hook(\"apply\", (op, next) => {\n    if (undoOrRedoing) return;\n    const doc = editor.doc;\n    const selection = editor.selection;\n    next(op);\n    const newDoc = editor.doc;\n\n    if (doc !== newDoc) {\n      const time = now();\n      if (index === 0 || time - prevTime >= BATCH_HISTORY_TIME) {\n        index++;\n        const history: History = [doc, selection, []];\n        if (index >= histories.length) {\n          histories.push(history);\n        } else {\n          histories[index] = history;\n        }\n      }\n      prevTime = time;\n      histories[index]![0] = newDoc;\n      histories[index]![2].push(op);\n      if (histories.length > index + 1) {\n        histories.length = index + 1;\n      }\n      if (index > MAX_HISTORY_LENGTH) {\n        index--;\n        histories.shift();\n      }\n    }\n  });\n\n  editor.hook(\"keyboard\", keymap(\"Mod+Z\", undo));\n  editor.hook(\"keyboard\", keymap(\"Shift+Mod+Z\", redo));\n\n  editor.set<HistoryContext>(historyPlugin, {\n    undo,\n    redo,\n    undoable: isUndoable,\n    redoable: isRedoable,\n    clear,\n  });\n}\n\n/**\n * Undos the last edit.\n */\nexport function Undo(editor: Editor) {\n  editor.get<HistoryContext>(historyPlugin).undo();\n}\n\n/**\n * Redos the last undone edit.\n */\nexport function Redo(editor: Editor) {\n  editor.get<HistoryContext>(historyPlugin).redo();\n}\n\n/**\n * Check if the history can be undone.\n */\nexport function Undoable(editor: Editor): boolean {\n  return editor.get<HistoryContext>(historyPlugin).undoable();\n}\n\n/**\n * Check if the history can be redone.\n */\nexport function Redoable(editor: Editor): boolean {\n  return editor.get<HistoryContext>(historyPlugin).redoable();\n}\n\n/**\n * Clears the history and makes the current document its oldest state.\n */\nexport function ClearHistory(editor: Editor) {\n  editor.get<HistoryContext>(historyPlugin).clear();\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport {\n  getCurrentDocument,\n  takeSelectionSnapshot,\n  setSelectionToDOM,\n  getPointedCaretPosition,\n  defaultIsBlockNode,\n  serializeRange,\n} from \"./dom/index.js\";\nimport { createMutationObserver } from \"./dom/mutation.js\";\nimport type { DocNode, Fragment, Selection } from \"./doc/types.js\";\nimport { is, isFunction, isString, microtask } from \"./utils.js\";\nimport {\n  domSelectionToSelection,\n  positionToOffset,\n  isBlockNode,\n  isTextNode,\n} from \"./doc/node.js\";\nimport {\n  applyOperation,\n  type Operation,\n  isUnsafeOperation,\n  isValidSelection,\n  mapPositionWithOps,\n} from \"./doc/operation.js\";\nimport { createParser } from \"./dom/index.js\";\nimport { isCollapsed, toRange } from \"./doc/position.js\";\nimport { historyPlugin } from \"./plugins/history.js\";\nimport type { Parser } from \"./dom/parser.js\";\n\nconst empty: unknown[] = [];\n\nconst noop = () => {};\n\nconst defaultOnError = (message: string): never => {\n  throw new Error(message);\n};\n\n/**\n * https://www.w3.org/TR/input-events-1/#interface-InputEvent-Attributes\n */\ntype InputType =\n  | \"insertText\" // insert typed plain text\n  | \"insertReplacementText\" // replace existing text by means of a spell checker, auto-correct or similar\n  | \"insertLineBreak\" // insert a line break\n  | \"insertParagraph\" // insert a paragraph break\n  | \"insertOrderedList\" // insert a numbered list\n  | \"insertUnorderedList\" // insert a bulleted list\n  | \"insertHorizontalRule\" // insert a horizontal rule\n  | \"insertFromYank\" // replace the current selection with content stored in a kill buffer\n  | \"insertFromDrop\" // insert content into the DOM by means of drop\n  | \"insertFromPaste\" // paste\n  | \"insertFromPasteAsQuotation\" // paste content as a quotation\n  | \"insertTranspose\" // transpose the last two characters that were entered\n  | \"insertCompositionText\" // replace the current composition string\n  | \"insertLink\" // insert a link\n  | \"deleteWordBackward\" // delete a word directly before the caret position\n  | \"deleteWordForward\" // delete a word directly after the caret position\n  | \"deleteSoftLineBackward\" // delete from the caret to the nearest visual line break before the caret position\n  | \"deleteSoftLineForward\" // delete from the caret to the nearest visual line break after the caret position\n  | \"deleteEntireSoftLine\" // delete from to the nearest visual line break before the caret position to the nearest visual line break after the caret position\n  | \"deleteHardLineBackward\" // delete from the caret to the nearest beginning of a block element or br element before the caret position\n  | \"deleteHardLineForward\" // delete from the caret to the nearest end of a block element or br element after the caret position\n  | \"deleteByDrag\" // remove content from the DOM by means of drag\n  | \"deleteByCut\" // remove the current selection as part of a cut\n  | \"deleteContent\" // delete the selection without specifying the direction of the deletion and this intention is not covered by another inputType\n  | \"deleteContentBackward\" // delete the content directly before the caret position and this intention is not covered by another inputType or delete the selection with the selection collapsing to its start after the deletion\n  | \"deleteContentForward\" // delete the content directly after the caret position and this intention is not covered by another inputType or delete the selection with the selection collapsing to its end after the deletion\n  | \"historyUndo\" // undo the last editing action\n  | \"historyRedo\" // to redo the last undone editing action\n  | \"formatBold\" // initiate bold text\n  | \"formatItalic\" // initiate italic text\n  | \"formatUnderline\" // initiate underline text\n  | \"formatStrikeThrough\" // initiate stricken through text\n  | \"formatSuperscript\" // initiate superscript text\n  | \"formatSubscript\" // initiate subscript text\n  | \"formatJustifyFull\" // make the current selection fully justified\n  | \"formatJustifyCenter\" // center align the current selection\n  | \"formatJustifyRight\" // right align the current selection\n  | \"formatJustifyLeft\" // left align the current selection\n  | \"formatIndent\" // indent the current selection\n  | \"formatOutdent\" // outdent the current selection\n  | \"formatRemove\" // remove all formatting from the current selection\n  | \"formatSetBlockTextDirection\" // set the text block direction\n  | \"formatSetInlineTextDirection\" // set the text inline direction\n  | \"formatBackColor\" // change the background color\n  | \"formatFontColor\" // change the font color\n  | \"formatFontName\" // change the font-family\n  // Legacy events older Chrome/Safari may dispatch\n  // https://github.com/w3c/input-events/pull/122\n  | \"deleteCompositionText\"\n  | \"deleteByComposition\"\n  | \"insertFromComposition\";\n\ntype EditorCommandOrPlugin<A extends unknown[], T extends DocNode = DocNode> = (\n  editor: Editor<T>,\n  ...args: A\n) => void | undefined;\n\ntype EditorQuery<A extends unknown[], V, T extends DocNode = DocNode> = (\n  editor: Editor<T>,\n  ...args: A\n) => V;\n\n/**\n * Options of {@link createEditor}.\n */\nexport interface EditorOptions<\n  T extends DocNode,\n  S extends StandardSchemaV1<T, T> | void = void,\n> {\n  /**\n   * Optional [Standard Schema](https://github.com/standard-schema/standard-schema) to validate unsafe edits.\n   */\n  schema?: S;\n  /**\n   * Initial document.\n   */\n  doc: T;\n  /**\n   * The state editable or not.\n   */\n  readonly?: boolean;\n  /**\n   * TODO\n   */\n  isBlock?: (node: HTMLElement) => boolean;\n  /**\n   * Keep the caret visible inside the mounted element after document\n   * changes, behaving like a native `<textarea>`:\n   *\n   * - If the caret is already visible (e.g. typing in the middle of a\n   *   long doc), nothing scrolls.\n   * - If the caret falls below the viewport, the element scrolls down\n   *   just enough to reveal it.\n   * - If the caret falls above the viewport, the element scrolls up\n   *   just enough to reveal it.\n   *\n   * Scroll work is coalesced via `requestAnimationFrame` and only reads\n   * the caret's bounding rect, never `scrollHeight`, so it does not\n   * force a full overflow-layout pass on each input.\n   *\n   * @default false\n   */\n  autoScroll?: boolean;\n  /**\n   * Revert DOM mutations that are not from IME composition and not inside\n   * {@link Editor.domUpdate}.\n   *\n   * Use with **imperative** view sync (host patches the contenteditable from\n   * `change`). Declarative React/Vue hosts that re-render from state should\n   * leave this `false` — their paint looks like a foreign mutation and would\n   * be undone.\n   *\n   * When enabled, wrap every host-driven DOM write in {@link Editor.domUpdate}\n   * so the paint is accepted. This defends against page translators,\n   * Grammarly-like extensions, and similar tools that rewrite the editable\n   * tree and desync it from the document model.\n   *\n   * @default false\n   */\n  revertForeignMutations?: boolean;\n  /**\n   * Callback invoked when errors happen.\n   *\n   * @default console.warn\n   */\n  onWarn?: (message: string) => void;\n  /**\n   * Callback invoked when errors happen.\n   *\n   * @default `throw new Error(message)`\n   */\n  onError?: (message: string) => never;\n}\n\nexport type EditorContext<_> = {};\n\ntype EditorEventMap = {\n  change: () => void;\n  selectionchange: () => void;\n  readonly: () => void;\n};\n\n/**\n * Functions to handle keyboard events.\n *\n * Return `true` if you want to stop propagation.\n */\nexport type KeyboardHook = (keyboard: KeyboardEvent) => boolean | void;\n\n/**\n * Functions to handle copy events\n */\nexport type CopyHook = (dataTransfer: DataTransfer) => void;\n\n/**\n * Functions to handle paste / drop events.\n *\n * Return `true` if you want to stop propagation.\n */\nexport type PasteHook = (\n  dataTransfer: DataTransfer,\n) => string | Fragment | true | null;\n\ntype EditorHookMap = {\n  /**\n   * Call `next(op)` to continue applying the operation, or `next()` with a nullish value to cancel it.\n   * If the hook returns without calling `next`, the operation is passed through as is.\n   */\n  apply: (op: Operation, next: (op?: Operation | null) => void) => void;\n  mount: (element: HTMLElement, parser: Parser) => void | (() => void);\n  keyboard: KeyboardHook;\n  copy: CopyHook;\n  paste: PasteHook;\n};\n\n/**\n * The editor instance.\n */\nexport interface Editor<T extends DocNode = DocNode> {\n  readonly doc: T;\n  /**\n   * Whether the document is empty (no text content, no void nodes).\n   * Recomputed once per commit so reads stay O(1).\n   */\n  readonly isEmpty: boolean;\n  selection: Selection;\n  /**\n   * The getter/setter for the editor's read-only state.\n   * `true` to read-only. `false` to editable.\n   */\n  readonly: boolean;\n  /**\n   * Enable/disable native-textarea-like auto-scroll: scroll the mounted\n   * element only when needed to keep the caret visible.\n   *\n   * @see {@link EditorOptions.autoScroll}\n   */\n  autoScroll: boolean;\n  /**\n   * Dispatches editing operations.\n   * @param op {@link Operation}\n   */\n  apply(op: Operation | Operation[]): this;\n  /**\n   * Executes a function with editor bound as context.\n   * @param fn {@link EditorCommandOrPlugin} or {@link EditorQuery}\n   * @param args arguments of the function\n   */\n  exec<const A extends unknown[]>(\n    fn: EditorCommandOrPlugin<A, T>,\n    ...args: A\n  ): this;\n  exec<const A extends unknown[], V>(fn: EditorQuery<A, V, T>, ...args: A): V;\n  /**\n   * A function to subscribe editor events.\n   * @returns cleanup function\n   */\n  on<K extends keyof EditorEventMap>(\n    key: K,\n    callback: EditorEventMap[K],\n  ): () => void;\n  /**\n   * A function to register editor hooks.\n   * @returns cleanup function\n   */\n  hook<K extends keyof EditorHookMap>(\n    key: K,\n    callback: EditorHookMap[K],\n  ): () => void;\n  /**\n   * Get a value from the context.\n   */\n  get<V>(key: EditorContext<V>): V;\n  /**\n   * Set a value for the context.\n   */\n  set<V>(key: EditorContext<V>, value: V): this;\n  /**\n   * A function to make DOM editable.\n   * @returns A function to stop subscribing DOM changes and restores previous DOM state.\n   */\n  input: (element: HTMLElement) => () => void;\n  /**\n   * Run a host-driven DOM paint. Mutations inside are accepted by the\n   * MutationObserver.\n   *\n   * Required when {@link EditorOptions.revertForeignMutations} is `true`.\n   * Safe to call when unmounted (runs `fn` only) or when the option is off.\n   */\n  domUpdate(fn: () => void): this;\n}\n\n/**\n * A function to initialize {@link Editor}.\n */\nexport const createEditor = <\n  T extends DocNode,\n  S extends StandardSchemaV1<T, T> | void = void,\n>({\n  doc,\n  readonly = false,\n  schema,\n  isBlock = defaultIsBlockNode,\n  autoScroll: _autoScroll = false,\n  revertForeignMutations = false,\n  onWarn = console.warn,\n  onError = defaultOnError,\n}: EditorOptions<T, S>): Editor<T> => {\n  let selection: Selection = [0, 0];\n  let mountedElement: HTMLElement | null = null;\n  let scrollRAF = 0;\n  /** Set while `input()` is active — host paints go through here. */\n  let runDomUpdate: ((fn: () => void) => void) | null = null;\n\n  const scheduleScroll = () => {\n    if (mountedElement && !scrollRAF) {\n      const element = mountedElement;\n      scrollRAF = requestAnimationFrame(() => {\n        scrollRAF = 0;\n        // Keep the caret visible inside the scroll container without jumping to\n        // the bottom on every change. We avoid reading `scrollHeight` here\n        // because it forces a full overflow layout pass; instead we measure the\n        // caret rect (cheap, incremental) and scroll only when it falls\n        // outside the visible viewport of the mounted element.\n        const win = element.ownerDocument.defaultView;\n        const domSel = win?.getSelection();\n        if (!domSel || domSel.rangeCount === 0) return;\n        const range = domSel.getRangeAt(0);\n        if (!element.contains(range.startContainer)) return;\n\n        let rect = range.getBoundingClientRect();\n        // Collapsed ranges next to void/inline-block siblings can report a\n        // zero rect in some browsers — fall back to the focus node's rect.\n        if (rect.top === 0 && rect.bottom === 0 && rect.height === 0) {\n          const node = range.startContainer;\n          const probe =\n            node.nodeType === 1 ? (node as Element) : node.parentElement;\n          if (!probe) return;\n          rect = probe.getBoundingClientRect();\n        }\n\n        const host = element.getBoundingClientRect();\n        const margin = 4;\n        if (rect.top < host.top + margin) {\n          element.scrollTop -= host.top + margin - rect.top;\n        } else if (rect.bottom > host.bottom - margin) {\n          element.scrollTop += rect.bottom - (host.bottom - margin);\n        }\n      });\n    }\n  };\n\n  // O(n) walk over the doc; cached after each commit so `editor.isEmpty`\n  // remains O(1) for callers. Supports both block docs and single-line\n  // (inline-children) docs from upstream.\n  const computeEmpty = (value: DocNode): boolean => {\n    for (const child of value.children) {\n      if (isBlockNode(child)) {\n        for (const node of child.children) {\n          if (!isTextNode(node) || node.text.length > 0) {\n            return false;\n          }\n        }\n      } else if (!isTextNode(child) || child.text.length > 0) {\n        return false;\n      }\n    }\n    return true;\n  };\n  let emptyDoc = computeEmpty(doc);\n\n  const validate = (value: T): boolean => {\n    if (!schema) {\n      onWarn(\n        \"An unsafe operation was detected. We recommend using schema option.\",\n      );\n      return true;\n    }\n    const result = schema[\"~standard\"].validate(value);\n    if (result instanceof Promise) {\n      onError(\"async validate is not supported\");\n    } else if (result.issues) {\n      onWarn(result.issues.map((i) => i.message).join(\"\\n\"));\n    } else {\n      return true;\n    }\n    return false;\n  };\n\n  if (schema && !validate(doc)) {\n    onError(\"Invalid document\");\n  }\n\n  const hooks = new Map<\n    keyof EditorHookMap,\n    EditorHookMap[keyof EditorHookMap][]\n  >();\n\n  const contexts = new WeakMap<EditorContext<unknown>, unknown>();\n\n  const getHook = <T extends keyof EditorHookMap>(\n    key: T,\n  ): readonly EditorHookMap[T][] => {\n    return (hooks.get(key) || empty) as unknown as EditorHookMap[T][];\n  };\n\n  const subs = new Map<\n    keyof EditorEventMap,\n    Set<EditorEventMap[keyof EditorEventMap]>\n  >();\n\n  const publishing = new Set<() => void>();\n\n  const publish = <K extends keyof EditorEventMap>(key: K) => {\n    const sub = subs.get(key);\n    if (sub) {\n      if (!publishing.size) {\n        microtask(() => {\n          publishing.forEach((cb) => {\n            cb();\n          });\n          publishing.clear();\n        });\n      }\n      sub.forEach((s) => {\n        publishing.add(s);\n      });\n    }\n  };\n\n  const apply = (op: Operation | Operation[]) => {\n    if (!readonly) {\n      if (Array.isArray(op)) {\n        for (const o of op) {\n          applyOp(o);\n        }\n      } else {\n        applyOp(op);\n      }\n    }\n    return editor;\n  };\n\n  const applyOp = (op: Operation) => {\n    const currentDoc = doc;\n    const applyHooks = getHook(\"apply\");\n    const length = applyHooks.length;\n\n    let index = 0;\n\n    const dispatch = () => {\n      if (index < length) {\n        const i = index;\n        applyHooks[index]!(op, next);\n        if (i === index) {\n          next(op);\n        }\n      } else if (index === length) {\n        index++;\n\n        try {\n          const [nextDoc, nextSelection] = applyOperation(doc, selection, op);\n          if (!isUnsafeOperation(op) || validate(nextDoc)) {\n            doc = nextDoc;\n            updateSelection(nextSelection);\n          }\n        } catch (e) {\n          // rollback\n          onWarn(\"rollback operation: \" + e);\n        }\n      }\n    };\n\n    const next = (o?: Operation | null): void => {\n      if (o == null) {\n        // cancel\n        index = length + 1;\n        return;\n      }\n      op = o;\n      index++;\n      dispatch();\n    };\n\n    dispatch();\n\n    if (!is(currentDoc, doc)) {\n      emptyDoc = computeEmpty(doc);\n      publish(\"change\");\n    }\n  };\n\n  const updateSelection = (s: Selection) => {\n    if (\n      isValidSelection(doc, s) &&\n      (selection[0] !== s[0] || selection[1] !== s[1])\n    ) {\n      selection = s;\n      publish(\"selectionchange\");\n    }\n  };\n\n  const editor: Editor<T> = {\n    get doc() {\n      return doc;\n    },\n    get isEmpty() {\n      return emptyDoc;\n    },\n    get selection() {\n      return selection;\n    },\n    set selection(value) {\n      updateSelection(value);\n    },\n    get readonly() {\n      return readonly;\n    },\n    set readonly(value) {\n      readonly = value;\n      publish(\"readonly\");\n    },\n    get autoScroll() {\n      return _autoScroll;\n    },\n    set autoScroll(value) {\n      _autoScroll = value;\n    },\n    apply,\n    on: (type, callback) => {\n      let sub = subs.get(type);\n      if (!sub) {\n        subs.set(type, (sub = new Set()));\n      }\n      sub.add(callback);\n      return () => {\n        sub.delete(callback);\n      };\n    },\n    hook: (type, callback) => {\n      let sub = hooks.get(type);\n      if (!sub) {\n        hooks.set(type, (sub = []));\n      }\n      sub.push(callback);\n      return () => {\n        const i = sub.indexOf(callback);\n        if (i !== -1) {\n          sub.splice(i, 1);\n        }\n      };\n    },\n    exec: (\n      fn: EditorCommandOrPlugin<any, T> | EditorQuery<any, unknown, T>,\n      ...args: unknown[]\n    ): any => {\n      const result = fn(editor, ...args);\n      if (typeof result === \"undefined\") {\n        return editor;\n      }\n      return result;\n    },\n    get: (key) => {\n      if (!contexts.has(key)) {\n        onError(\"No value found for key\");\n      }\n      return contexts.get(key) as any;\n    },\n    set: (key, value) => {\n      contexts.set(key, value);\n      return editor;\n    },\n    domUpdate: (fn) => {\n      if (runDomUpdate) {\n        runDomUpdate(fn);\n      } else {\n        fn();\n      }\n      return editor;\n    },\n    input: (element) => {\n      if (\n        !(window.InputEvent && isFunction(InputEvent.prototype.getTargetRanges))\n      ) {\n        onWarn(\"beforeinput event is not supported.\");\n        return noop;\n      }\n      mountedElement = element;\n\n      // https://w3c.github.io/contentEditable/\n      // https://w3c.github.io/editing/docs/execCommand/\n      // https://w3c.github.io/selection-api/\n      const {\n        contentEditable: prevContentEditable,\n        role: prevRole,\n        ariaMultiLine: prevAriaMultiLine,\n        ariaReadOnly: prevAriaReadOnly,\n      } = element;\n      const prevWhiteSpace = element.style.whiteSpace;\n\n      element.role = \"textbox\";\n      // https://html.spec.whatwg.org/multipage/interaction.html#best-practices-for-in-page-editors\n      element.style.whiteSpace = \"pre-wrap\";\n      element.ariaMultiLine = \"true\";\n\n      let disposed = false;\n      let inputTransaction: [Operation[], Selection] | null = null;\n      let isComposing = false;\n      let hasFocus = false;\n      let isDragging = false;\n      let domSelection: Selection = selection;\n      let syncDomSelectionTimer: ReturnType<typeof setTimeout> | null = null;\n\n      const document = getCurrentDocument(element);\n\n      const parser = createParser(\n        document,\n        isBlock as (node: Element) => boolean,\n      );\n\n      const setEditableState = () => {\n        element.contentEditable = readonly ? \"false\" : \"true\";\n        element.ariaReadOnly = readonly ? \"true\" : null;\n      };\n\n      setEditableState();\n\n      const syncFocus = () => {\n        if (!hasFocus) {\n          // Set focus imperatively to return focus to the editor after a command execution via click.\n          // It must be queued after the MO callback because that may cause an additional selectionchange event.\n          element.focus({ preventScroll: true });\n        }\n      };\n      const syncDomSelection = () => {\n        syncDomSelectionTimer = null;\n        if (\n          selection[0] !== domSelection[0] ||\n          selection[1] !== domSelection[1]\n        ) {\n          setSelectionToDOM(element, parser, doc, selection);\n          domSelection = selection;\n        }\n      };\n      const cancelSyncDomSelection = () => {\n        if (syncDomSelectionTimer != null) {\n          clearTimeout(syncDomSelectionTimer);\n        }\n      };\n\n      const cleanupOnChange = editor.on(\"change\", () => {\n        if (!hasFocus) {\n          requestAnimationFrame(syncFocus);\n        }\n      });\n      const cleanupOnSelectionChange = editor.on(\"selectionchange\", () => {\n        if (\n          selection[0] !== domSelection[0] ||\n          selection[1] !== domSelection[1]\n        ) {\n          cancelSyncDomSelection();\n          // Use setTimeout to ensure synchronization is done after the mutation caused by re-render, especially on Firefox\n          syncDomSelectionTimer = setTimeout(syncDomSelection, 50);\n        }\n      });\n      const cleanupOnReadonly = editor.on(\"readonly\", setEditableState);\n\n      const paste = (dataTransfer: DataTransfer): string | Fragment | void => {\n        for (const ex of getHook(\"paste\")) {\n          const pasted = ex(dataTransfer);\n          if (pasted) {\n            if (pasted === true) {\n              return;\n            }\n            return pasted;\n          }\n        }\n        onWarn(\"failed to serialize pasted data\");\n      };\n\n      const restoreDomSelection = () => {\n        cancelSyncDomSelection();\n        // TODO optimize\n        // Mutation to selected DOM may change selection, so restore it.\n        setSelectionToDOM(element, parser, doc, selection);\n      };\n\n      const observer = createMutationObserver(\n        element,\n        restoreDomSelection,\n        revertForeignMutations,\n      );\n\n      runDomUpdate = (fn) => {\n        observer._domUpdate(true);\n        try {\n          fn();\n        } finally {\n          observer._domUpdate(false);\n          restoreDomSelection();\n        }\n      };\n\n      const syncSelection = () => {\n        updateSelection(\n          (domSelection = domSelectionToSelection(\n            doc,\n            takeSelectionSnapshot(element, parser),\n          )),\n        );\n      };\n\n      const flushInput = () => {\n        const queue = observer._flush();\n\n        observer._record(false);\n\n        if (queue.length) {\n          observer._revert(queue);\n\n          // Restore previous selection\n          // Updating selection may schedule the next selectionchange event\n          // It should be ignored especially in firefox not to confuse editor state\n          document.removeEventListener(\"selectionchange\", onSelectionChange);\n          setSelectionToDOM(element, parser, doc, selection, true);\n          document.addEventListener(\"selectionchange\", onSelectionChange);\n        }\n\n        if (inputTransaction) {\n          updateSelection(inputTransaction[1]);\n          apply(inputTransaction[0]);\n          inputTransaction = null;\n        }\n        isComposing = false;\n      };\n\n      // spec compliant: keydown -> beforeinput -> input (-> keyup)\n      // Safari (IME)  : beforeinput -> input -> keydown (-> keyup)\n      // https://w3c.github.io/uievents/#events-keyboard-event-order\n      // https://bugs.webkit.org/show_bug.cgi?id=165004\n      const onKeyDown = (e: KeyboardEvent) => {\n        if (isComposing) return;\n\n        for (const handler of getHook(\"keyboard\")) {\n          if (handler(e)) {\n            e.preventDefault();\n            observer._record(false);\n            return;\n          }\n        }\n      };\n\n      const onInput = () => {\n        if (!isComposing) {\n          flushInput();\n        }\n      };\n      const onBeforeInput = (e: InputEvent) => {\n        e.preventDefault();\n\n        const inputType = e.inputType as InputType;\n\n        if (inputType.startsWith(\"format\")) {\n          // Ignore format inputs from document.execCommand() or shortcuts like mod+b.\n          return;\n        }\n        if (inputType === \"historyUndo\" || inputType === \"historyRedo\") {\n          // Cancel for now.\n          return;\n        }\n\n        if (isComposing) {\n          // Unfortunately, input events related to composition are not cancellable.\n          // So we record mutations to DOM and revert them after composition ended.\n          observer._record(true);\n        } else {\n          syncSelection();\n        }\n\n        const domRange = e.getTargetRanges()[0];\n        if (domRange) {\n          // Read input\n          let data =\n            inputType === \"insertParagraph\" || inputType === \"insertLineBreak\"\n              ? \"\\n\"\n              : e.data;\n          if (data == null) {\n            const dataTransfer = e.dataTransfer;\n            if (dataTransfer) {\n              // In some cases (e.g. insertReplacementText), dataTransfer contains text.\n              data = dataTransfer.getData(\"text/plain\");\n            }\n          }\n\n          if (!inputTransaction) {\n            inputTransaction = [[], selection];\n          }\n          const ops = inputTransaction[0];\n\n          const range = domSelectionToSelection(\n            doc,\n            serializeRange(element, parser, domRange),\n          );\n          if (!isCollapsed(range)) {\n            // replace or delete\n            ops.push({ type: \"delete\", range });\n          }\n          if (data) {\n            // replace or insert\n            ops.push({ type: \"insert_text\", at: range[0], text: data });\n          }\n        }\n\n        if (!isComposing) {\n          flushInput();\n        }\n      };\n      const onCompositionStart = () => {\n        if (!isComposing) {\n          syncSelection();\n        }\n        isComposing = true;\n      };\n      const onCompositionEnd = () => {\n        flushInput();\n      };\n\n      const onFocus = () => {\n        hasFocus = true;\n        syncSelection();\n      };\n      const onBlur = () => {\n        hasFocus = false;\n      };\n\n      const onSelectionChange = () => {\n        // Safari may dispatch selectionchange event after dragstart\n        if (hasFocus && !isComposing && !isDragging) {\n          syncSelection();\n        }\n      };\n\n      const copy = (dataTransfer: DataTransfer) => {\n        syncSelection();\n        if (!isCollapsed(selection)) {\n          for (const ex of getHook(\"copy\")) {\n            ex(dataTransfer);\n          }\n        }\n      };\n\n      const onCopy = (e: ClipboardEvent) => {\n        e.preventDefault();\n        copy(e.clipboardData!);\n      };\n      const onCut = (e: ClipboardEvent) => {\n        e.preventDefault();\n        if (!readonly) {\n          copy(e.clipboardData!);\n          apply({ type: \"delete\", range: toRange(selection) });\n        }\n      };\n      const onPaste = (e: ClipboardEvent) => {\n        e.preventDefault();\n        const pasted = paste(e.clipboardData!);\n        if (pasted) {\n          const range = toRange(selection);\n          const start = range[0];\n          const ops: Operation[] = [{ type: \"delete\", range }];\n          ops.push(\n            isString(pasted)\n              ? { type: \"insert_text\", at: start, text: pasted }\n              : { type: \"insert_node\", at: start, fragment: pasted },\n          );\n          apply(ops);\n        }\n      };\n\n      const onDrop = (e: DragEvent) => {\n        e.preventDefault();\n\n        const dataTransfer = e.dataTransfer;\n        const droppedPosition = getPointedCaretPosition(element, parser, e);\n        if (dataTransfer && droppedPosition) {\n          let afterSelection: Selection | undefined;\n          const ops: Operation[] = [];\n          if (isDragging) {\n            ops.push({ type: \"delete\", range: toRange(selection) });\n          }\n          const pasted = paste(dataTransfer);\n          if (pasted) {\n            const offset = positionToOffset(doc, droppedPosition);\n            const pos = mapPositionWithOps(offset, ops);\n            ops.push(\n              isString(pasted)\n                ? { type: \"insert_text\", at: pos, text: pasted }\n                : { type: \"insert_node\", at: pos, fragment: pasted },\n            );\n            afterSelection = [pos, mapPositionWithOps(offset, ops)];\n          }\n          apply(ops);\n          if (afterSelection) {\n            updateSelection(afterSelection);\n          }\n        }\n\n        // dragend event may not fire when the drop target node is re-rendered\n        isDragging = false;\n      };\n      const onDragStart = (e: DragEvent) => {\n        isDragging = true;\n        copy(e.dataTransfer!);\n      };\n      const onDragEnd = () => {\n        isDragging = false;\n      };\n\n      document.addEventListener(\"selectionchange\", onSelectionChange);\n      element.addEventListener(\"keydown\", onKeyDown);\n      element.addEventListener(\"input\", onInput);\n      element.addEventListener(\"beforeinput\", onBeforeInput);\n      element.addEventListener(\"compositionstart\", onCompositionStart);\n      element.addEventListener(\"compositionend\", onCompositionEnd);\n      element.addEventListener(\"focus\", onFocus);\n      element.addEventListener(\"blur\", onBlur);\n      element.addEventListener(\"copy\", onCopy);\n      element.addEventListener(\"cut\", onCut);\n      element.addEventListener(\"paste\", onPaste);\n      element.addEventListener(\"drop\", onDrop);\n      element.addEventListener(\"dragstart\", onDragStart);\n      element.addEventListener(\"dragend\", onDragEnd);\n\n      const unmountHooks: (() => void)[] = [];\n      getHook(\"mount\").forEach((mount) => {\n        const cb = mount(element, parser);\n        if (cb) {\n          unmountHooks.push(cb);\n        }\n      });\n\n      return () => {\n        if (disposed) return;\n        disposed = true;\n\n        cleanupOnChange();\n        cleanupOnSelectionChange();\n        cleanupOnReadonly();\n\n        if (scrollRAF) {\n          cancelAnimationFrame(scrollRAF);\n          scrollRAF = 0;\n        }\n        if (mountedElement === element) {\n          mountedElement = null;\n        }\n        if (runDomUpdate) {\n          runDomUpdate = null;\n        }\n\n        element.contentEditable = prevContentEditable;\n        element.role = prevRole;\n        element.ariaMultiLine = prevAriaMultiLine;\n        element.ariaReadOnly = prevAriaReadOnly;\n        element.style.whiteSpace = prevWhiteSpace;\n\n        observer._dispose();\n\n        document.removeEventListener(\"selectionchange\", onSelectionChange);\n        element.removeEventListener(\"keydown\", onKeyDown);\n        element.removeEventListener(\"input\", onInput);\n        element.removeEventListener(\"beforeinput\", onBeforeInput);\n        element.removeEventListener(\"compositionstart\", onCompositionStart);\n        element.removeEventListener(\"compositionend\", onCompositionEnd);\n        element.removeEventListener(\"focus\", onFocus);\n        element.removeEventListener(\"blur\", onBlur);\n        element.removeEventListener(\"copy\", onCopy);\n        element.removeEventListener(\"cut\", onCut);\n        element.removeEventListener(\"paste\", onPaste);\n        element.removeEventListener(\"drop\", onDrop);\n        element.removeEventListener(\"dragstart\", onDragStart);\n        element.removeEventListener(\"dragend\", onDragEnd);\n\n        unmountHooks.forEach((cb) => {\n          cb();\n        });\n      };\n    },\n  };\n\n  editor.exec(historyPlugin);\n\n  editor.on(\"change\", () => {\n    if (_autoScroll) {\n      scheduleScroll();\n    }\n  });\n\n  return editor;\n};\n","import type { InlineNode } from \"../../doc/types.js\";\nimport type { Editor } from \"../../editor.js\";\n\n/**\n * A plugin to handle pasting / dropping from File.\n */\nexport const fileTransferPlugin = (\n  editor: Editor,\n  handlerByMime: Record<string, (file: File) => InlineNode>,\n) => {\n  editor.hook(\"paste\", (dataTransfer) => {\n    for (const item of dataTransfer.items) {\n      if (item.kind === \"file\") {\n        const mapper = handlerByMime[item.type];\n        if (mapper) {\n          const file = item.getAsFile();\n          if (file) {\n            return [{ children: [mapper(file)] }];\n          }\n        }\n      }\n    }\n    return null;\n  });\n};\n","import { sliceText } from \"../../doc/node.js\";\nimport { toRange } from \"../../doc/position.js\";\nimport type { InferVoidNode } from \"../../doc/types-infer.js\";\nimport type { DocNode } from \"../../doc/types.js\";\nimport type { Editor } from \"../../editor.js\";\n\n/**\n * A plugin to handle copying / pasting plain text.\n */\nexport function plainTransferPlugin<T extends DocNode>(\n  editor: Editor<T>,\n  options?: {\n    voidToString?: (node: InferVoidNode<T>) => string;\n  },\n) {\n  const voidToString = options && options.voidToString;\n  editor.hook(\"copy\", (dataTransfer) => {\n    dataTransfer.setData(\n      \"text/plain\",\n      sliceText(editor.doc, ...toRange(editor.selection), voidToString),\n    );\n  });\n  editor.hook(\"paste\", (dataTransfer) => {\n    return dataTransfer.getData(\"text/plain\");\n  });\n}\n","import type { Editor } from \"../../editor.js\";\n\nimport {\n  getDOMSelection,\n  getSelectionRangeInEditor,\n  TOKEN_BLOCK,\n  TOKEN_TEXT,\n  TOKEN_SOFT_BREAK,\n  TOKEN_VOID,\n} from \"../../dom/index.js\";\nimport { isCommentNode } from \"../../dom/utils.js\";\nimport type {\n  BlockNode,\n  DocNode,\n  Fragment,\n  InlineNode,\n  TextNode,\n} from \"../../doc/types.js\";\nimport type { Parser, TokenType } from \"../../dom/parser.js\";\nimport type { InferInlineNode } from \"../../doc/types-infer.js\";\n\ntype HtmlSerializers<T extends DocNode> = Partial<{\n  [key in keyof HTMLElementTagNameMap]: (\n    node: HTMLElementTagNameMap[key],\n  ) => Exclude<InferInlineNode<T>, TextNode> | void;\n}> & {\n  text: (t: string) => Extract<InferInlineNode<T>, TextNode>;\n};\n\n/**\n * @internal\n */\nexport const htmlPaste = <T extends DocNode>(\n  html: string,\n  parse: Parser,\n  serializers: HtmlSerializers<T>,\n): Fragment => {\n  const serializeText = serializers[\"text\"];\n  const serializeVoid = (n: Element) => {\n    const s = serializers[n.tagName.toLowerCase() as keyof typeof serializers];\n    if (s) {\n      const node = s(n as any);\n      if (node) {\n        return node;\n      }\n    }\n\n    return;\n  };\n\n  let dom: Node = new DOMParser().parseFromString(html, \"text/html\").body;\n  let isWindowsCopy = false;\n  // https://github.com/w3c/clipboard-apis/issues/193\n  for (const n of [...dom.childNodes]) {\n    if (isCommentNode(n)) {\n      if (n.data === \"StartFragment\") {\n        isWindowsCopy = true;\n        dom = new DocumentFragment();\n      } else if (n.data === \"EndFragment\") {\n        isWindowsCopy = false;\n      }\n    } else if (isWindowsCopy) {\n      dom.appendChild(n);\n    }\n  }\n\n  return parse(({ _next: next, _domNode: domNode }) => {\n    let type: TokenType | void;\n    let row: InlineNode[] | null = null;\n    let text = \"\";\n    let hasContent = false;\n\n    const rows: BlockNode[] = [];\n\n    const completeText = () => {\n      if (text) {\n        if (!row) {\n          row = [];\n        }\n        row.push(serializeText(text));\n        text = \"\";\n      }\n    };\n    const completeRow = () => {\n      completeText();\n      if (!row && hasContent) {\n        row = [];\n      }\n      if (row) {\n        rows.push({ children: row });\n      }\n      row = null;\n      hasContent = false;\n    };\n\n    while ((type = next())) {\n      if (type === TOKEN_BLOCK) {\n        completeRow();\n      } else {\n        hasContent = true;\n\n        if (type === TOKEN_TEXT) {\n          text += domNode<typeof type>().data;\n        } else if (type === TOKEN_VOID) {\n          completeText();\n          const docNode = serializeVoid(domNode<typeof type>());\n          if (docNode) {\n            row!.push(docNode);\n          }\n        } else if (type === TOKEN_SOFT_BREAK) {\n          completeRow();\n        }\n      }\n    }\n    completeRow();\n\n    if (!rows.length) {\n      rows.push({ children: [] });\n    }\n\n    return rows;\n  }, dom);\n};\n\n/**\n * A plugin to handle copying / pasting HTML\n */\nexport function htmlTransferPlugin<T extends DocNode>(\n  editor: Editor<T>,\n  options: {\n    serializers: HtmlSerializers<T>;\n  },\n) {\n  editor.hook(\"mount\", (element, parser) => {\n    const cleanupCopy = editor.hook(\"copy\", (dataTransfer) => {\n      const wrapper = document.createElement(\"div\");\n      wrapper.appendChild(\n        // DOM range must exist here\n        getSelectionRangeInEditor(\n          getDOMSelection(element),\n          element,\n        )!.cloneContents(),\n      );\n      dataTransfer.setData(\"text/html\", wrapper.innerHTML);\n    });\n    const cleanupPaste = editor.hook(\"paste\", (dataTransfer) => {\n      const html = dataTransfer.getData(\"text/html\");\n      if (html) {\n        return htmlPaste(html, parser, options.serializers);\n      }\n      return null;\n    });\n    return () => {\n      cleanupCopy();\n      cleanupPaste();\n    };\n  });\n}\n","import { sliceFragment } from \"../../doc/node.js\";\nimport { toRange } from \"../../doc/position.js\";\nimport type { Editor } from \"../../editor.js\";\n\n/**\n * A plugin to handle copying / pasting between editor instances\n *\n * @param options.mime A MIME type to store the copied fragment in clipboard. Give an app specific one if the schema is not shared with other editate based apps.\n * @defaultValue `\"application/x-editate-editor\"`\n */\nexport function internalTransferPlugin(\n  editor: Editor,\n  options?: {\n    mime?: string;\n  },\n) {\n  const mime = (options && options.mime) || \"application/x-editate-editor\";\n  editor.hook(\"copy\", (dataTransfer) => {\n    dataTransfer.setData(\n      mime,\n      JSON.stringify(sliceFragment(editor.doc, ...toRange(editor.selection))),\n    );\n  });\n  editor.hook(\"paste\", (dataTransfer) => {\n    try {\n      return JSON.parse(dataTransfer.getData(mime));\n    } catch (e) {\n      return null;\n    }\n  });\n}\n","import {\n  getLeafBlockAt,\n  getNodeSize,\n  isBlockNode,\n  iterLeafBlocks,\n} from \"../doc/node.js\";\nimport { isCollapsed, toRange } from \"../doc/position.js\";\nimport type { InferLeafBlockNode } from \"../doc/types-infer.js\";\nimport type { BlockNode, DocNode, Node, Range } from \"../doc/types.js\";\nimport type { Editor } from \"../editor.js\";\nimport { microtask } from \"../utils.js\";\n\ninterface BlockLockContext {\n  locked: (range: Range) => boolean;\n}\n\n/**\n * A plugin to make specific blocks read-only.\n *\n * Locked blocks can still be selected and copied, but operations editing them are cancelled,\n * except ones that unlock the block and ones targeting the root (e.g. undo / redo).\n */\nexport function blockLockPlugin<T extends DocNode>(\n  editor: Editor<T>,\n  options: {\n    /**\n     * A function to check if the block is locked or not.\n     */\n    isLocked: (node: InferLeafBlockNode<T>) => boolean;\n  },\n) {\n  const isLockedNode = options.isLocked as (node: BlockNode) => boolean;\n\n  const isLockedAt = (offset: number): boolean => {\n    return isLockedNode(getLeafBlockAt(editor.doc, offset)[0]);\n  };\n\n  const hasLockedBlock = (range: Range, includesEdge: boolean): boolean => {\n    const [start, end] = range;\n    for (const [block, offset] of iterLeafBlocks(editor.doc, range)) {\n      const blockEnd = offset + getNodeSize(block);\n      if (\n        (includesEdge\n          ? end >= offset && start <= blockEnd\n          : end > offset && start < blockEnd) &&\n        isLockedNode(block)\n      ) {\n        return true;\n      }\n    }\n    return false;\n  };\n\n  let suppressInsert = false;\n\n  editor.hook(\"apply\", (op, next) => {\n    const wasSuppressed = suppressInsert;\n    suppressInsert = false;\n\n    switch (op.type) {\n      case \"delete\": {\n        if (hasLockedBlock(toRange(op.range), true)) {\n          // also cancel an insert paired with this delete (e.g. input and paste dispatch [delete, insert])\n          suppressInsert = true;\n          microtask(() => {\n            suppressInsert = false;\n          });\n          return next(null);\n        }\n        break;\n      }\n      case \"insert_text\":\n      case \"insert_node\": {\n        if (wasSuppressed || isLockedAt(op.at)) {\n          return next(null);\n        }\n        break;\n      }\n      case \"format\": {\n        const range = toRange(op.range);\n        if (\n          isCollapsed(range)\n            ? isLockedAt(range[0])\n            : hasLockedBlock(range, false)\n        ) {\n          return next(null);\n        }\n        break;\n      }\n      case \"patch_node\": {\n        const path = op.path;\n        let node: Node = editor.doc;\n        for (let i = 0; i < path.length; i++) {\n          const child: Node | undefined = (node as BlockNode).children?.[\n            path[i]!\n          ];\n          if (!child) {\n            break;\n          }\n          node = child;\n          if (i < path.length - 1 && isBlockNode(node) && isLockedNode(node)) {\n            return next(null);\n          }\n        }\n        if (node !== editor.doc && isBlockNode(node) && isLockedNode(node)) {\n          // allow only patches that unlock the block\n          if (isLockedNode({ ...node, [op.key]: op.value })) {\n            return next(null);\n          }\n        }\n        break;\n      }\n    }\n    next(op);\n  });\n\n  editor.set<BlockLockContext>(blockLockPlugin, {\n    locked: (range) =>\n      isCollapsed(range) ? isLockedAt(range[0]) : hasLockedBlock(range, true),\n  });\n}\n\n/**\n * Check if the selection or specified range touches a locked block, which means editing operations on it will be cancelled.\n */\nexport function LockedInRange(\n  editor: Editor,\n  range: Range = toRange(editor.selection),\n): boolean {\n  return editor.get<BlockLockContext>(blockLockPlugin).locked(range);\n}\n","import type { Editor } from \"../editor.js\";\n\nexport function debugPlugin(editor: Editor) {\n  editor.hook(\"apply\", (op) => {\n    console.log(\"apply\", op);\n  });\n  editor.on(\"change\", () => {\n    console.log(\"change\", editor.doc);\n  });\n  editor.on(\"selectionchange\", () => {\n    console.log(\"selectionchange\", editor.selection);\n  });\n}\n","import type { Editor } from \"../editor.js\";\nimport { keymap, type KeyString } from \"../keyboard.js\";\nimport { keys } from \"../utils.js\";\n\nexport function keymapPlugin<K extends KeyString>(\n  editor: Editor,\n  bindings: Record<K, () => void | false>,\n) {\n  keys(bindings).forEach((k) => {\n    const fn = bindings[k as keyof typeof bindings]!;\n    editor.hook(\"keyboard\", keymap(k as KeyString, fn));\n  });\n}\n","import { getCurrentDocument, selectionToRange } from \"../dom/index.js\";\nimport { isElementNode } from \"../dom/utils.js\";\nimport type { Editor } from \"../editor.js\";\n\n// `auto` parses to NaN and reserves nothing\nconst resolveScrollPadding = (value: string, size: number): number => {\n  const px = parseFloat(value);\n  return px ? (value.endsWith(\"%\") ? (px / 100) * size : px) : 0;\n};\n\nconst getBounds = (\n  start: number,\n  size: number,\n  paddingStart: string,\n  paddingEnd: string,\n): [start: number, end: number] => [\n  start + resolveScrollPadding(paddingStart, size),\n  start + size - resolveScrollPadding(paddingEnd, size),\n];\n\nconst isScrollable = (overflow: string): boolean =>\n  overflow === \"auto\" || overflow === \"scroll\" || overflow === \"overlay\";\n\n// Resolved once on mount, so this keys off the authored overflow rather than\n// whether the element currently overflows, which depends on the content. Both\n// axes matter: a vertical writing mode scrolls along x.\n// body/documentElement are left to the viewport scroll.\nconst getNearestScrollParent = (\n  root: HTMLElement,\n  document: Document,\n  window: Window,\n): HTMLElement | null => {\n  const { body, documentElement } = document;\n  let element: HTMLElement | null = root;\n  while (element && element !== body && element !== documentElement) {\n    const { overflowX, overflowY } = window.getComputedStyle(element);\n    if (isScrollable(overflowX) || isScrollable(overflowY)) {\n      return element;\n    }\n    element = element.parentElement;\n  }\n  return null;\n};\n\nconst overflow = (\n  start: number,\n  end: number,\n  [boundStart, boundEnd]: [number, number],\n): number =>\n  start < boundStart ? start - boundStart : end > boundEnd ? end - boundEnd : 0;\n\n// An axis flowing back toward the scroll origin is reached through negative\n// offsets, so scrollLeft runs [-scrollable, 0] under `rtl` or `vertical-rl`.\nconst isReversed = (style: CSSStyleDeclaration): [x: boolean, y: boolean] => {\n  const rtl = style.direction === \"rtl\";\n  switch (style.writingMode) {\n    case \"vertical-rl\":\n    case \"sideways-rl\":\n      return [true, rtl];\n    case \"vertical-lr\":\n      return [false, rtl];\n    // the one mode whose inline axis runs bottom-to-top while `ltr`\n    case \"sideways-lr\":\n      return [false, !rtl];\n    default:\n      return [rtl, false];\n  }\n};\n\n// Clamping keeps the applied offset known without reading back the scroll\n// position, which stays stale during a smooth scroll.\nconst clamp = (\n  diff: number,\n  scrolled: number,\n  scrollable: number,\n  reversed: boolean,\n): number => {\n  const min = reversed ? -scrollable : 0;\n  return Math.max(min - scrolled, Math.min(diff, min + scrollable - scrolled));\n};\n\nconst measureElement = (\n  scroller: HTMLElement,\n  style: CSSStyleDeclaration,\n  rect: DOMRect,\n): [x: number, y: number] => {\n  const {\n    scrollLeft,\n    scrollTop,\n    scrollWidth,\n    scrollHeight,\n    clientLeft,\n    clientTop,\n    clientWidth,\n    clientHeight,\n  } = scroller;\n  const box = scroller.getBoundingClientRect();\n  const [reversedX, reversedY] = isReversed(style);\n\n  // The scrollport is the padding box minus scrollbars, which is what client*\n  // describe. The border box would count borders and scrollbars as visible.\n  const top = clamp(\n    overflow(\n      rect.top,\n      rect.bottom,\n      getBounds(\n        box.top + clientTop,\n        clientHeight,\n        style.scrollPaddingTop,\n        style.scrollPaddingBottom,\n      ),\n    ),\n    scrollTop,\n    scrollHeight - clientHeight,\n    reversedY,\n  );\n  const left = clamp(\n    overflow(\n      rect.left,\n      rect.right,\n      getBounds(\n        box.left + clientLeft,\n        clientWidth,\n        style.scrollPaddingLeft,\n        style.scrollPaddingRight,\n      ),\n    ),\n    scrollLeft,\n    scrollWidth - clientWidth,\n    reversedX,\n  );\n\n  return [left, top];\n};\n\nconst measureWindow = (\n  documentElement: HTMLElement,\n  style: CSSStyleDeclaration,\n  rect: DOMRect,\n  [x, y]: [x: number, y: number],\n): [x: number, y: number] => {\n  // not innerWidth/Height, which include the scrollbars\n  const { clientWidth, clientHeight } = documentElement;\n\n  const top = overflow(\n    rect.top - y,\n    rect.bottom - y,\n    getBounds(\n      0,\n      clientHeight,\n      style.scrollPaddingTop,\n      style.scrollPaddingBottom,\n    ),\n  );\n  const left = overflow(\n    rect.left - x,\n    rect.right - x,\n    getBounds(\n      0,\n      clientWidth,\n      style.scrollPaddingLeft,\n      style.scrollPaddingRight,\n    ),\n  );\n\n  return [left, top];\n};\n\nconst scrollBy = (\n  target: Window | HTMLElement,\n  [left, top]: [x: number, y: number],\n  behavior: ScrollBehavior,\n): void => {\n  if (top || left) {\n    target.scrollBy({ top, left, behavior });\n  }\n};\n\n/**\n * A plugin to scroll to the selection on document change.\n */\nexport const scrollToSelectionPlugin = (editor: Editor) => {\n  const behavior: ScrollBehavior = \"auto\";\n  editor.hook(\"mount\", (element, parser) => {\n    const document = getCurrentDocument(element);\n    const window = document.defaultView!;\n    const { documentElement } = document;\n    const scroller = getNearestScrollParent(element, document, window);\n    // live declarations, so the lookup is paid once but the values stay current\n    const scrollerStyle = scroller && window.getComputedStyle(scroller);\n    const rootStyle = window.getComputedStyle(documentElement);\n\n    let timer: ReturnType<typeof setTimeout> | null = null;\n    // Moving the caret reveals it natively, leaving only document changes\n    const cleanup = editor.on(\"change\", () => {\n      if (timer != null) return;\n      // Defer until the host framework has re-rendered, since the native reveal\n      // ran against the layout before it. Matches the delay in editor.input().\n      timer = setTimeout(() => {\n        timer = null;\n        const range = selectionToRange(\n          element,\n          parser,\n          editor.doc,\n          editor.selection,\n        );\n        let rect = range.getBoundingClientRect();\n        // A collapsed range around a `<br>` reports an empty rect at (0, 0),\n        // which would scroll toward the start of the document. A caret itself\n        // is flat on one axis only, on y in a vertical writing mode.\n        if (!rect.width && !rect.height) {\n          const node = range.startContainer;\n          const el = isElementNode(node) ? node : node.parentElement;\n          if (el) {\n            rect = el.getBoundingClientRect();\n          }\n        }\n\n        // Walk the scroll chain inner -> outer like scrollIntoView(). Rects are\n        // viewport-relative, so fitting the caret in the scroller does not put\n        // it on screen; scrolling the scroller shifts those coords, hence\n        // subtracting the applied offset. The reverse never holds, so one pass\n        // converges. Only the nearest scroller is walked. Both passes measure\n        // before either scrolls, since a scroll would invalidate layout and\n        // force the later measurements to lay out again.\n        const scrolled: [number, number] =\n          scroller && scrollerStyle\n            ? measureElement(scroller, scrollerStyle, rect)\n            : [0, 0];\n        const scrolledWindow = measureWindow(\n          documentElement,\n          rootStyle,\n          rect,\n          scrolled,\n        );\n\n        if (scroller) {\n          scrollBy(scroller, scrolled, behavior);\n        }\n        scrollBy(window, scrolledWindow, behavior);\n      }, 50);\n    });\n\n    return () => {\n      if (timer != null) {\n        clearTimeout(timer);\n      }\n      cleanup();\n    };\n  });\n};\n","import { selectionToRange } from \"../dom/index.js\";\nimport type { Editor } from \"../editor.js\";\n\n/**\n * A plugin to get the bounding rect of selection on selection change\n */\nexport function selectionRectPlugin(\n  editor: Editor,\n  onSelectionChange: (getRect: () => DOMRect) => void,\n) {\n  editor.hook(\"mount\", (element, parser) => {\n    let mounted = true;\n    let scheduling = false;\n    const cleanup = editor.on(\"selectionchange\", () => {\n      if (scheduling) return;\n      scheduling = true;\n      requestAnimationFrame(() => {\n        scheduling = false;\n        if (!mounted) return;\n        onSelectionChange(() => {\n          const selection = editor.selection;\n          return selectionToRange(\n            element,\n            parser,\n            editor.doc,\n            selection,\n          ).getBoundingClientRect();\n        });\n      });\n    });\n    return () => {\n      mounted = false;\n      cleanup();\n    };\n  });\n}\n","import { hasBlockChildren } from \"../doc/node.js\";\nimport { joinBlocks } from \"../doc/operation.js\";\nimport type { Editor } from \"../editor.js\";\n\n/**\n * A plugin to restrict input to a single line\n */\nexport function singlelinePlugin(editor: Editor) {\n  editor.hook(\"mount\", (element) => {\n    element.ariaMultiLine = null;\n  });\n  editor.hook(\"apply\", (op, next) => {\n    if (op.type === \"insert_text\") {\n      op = {\n        ...op,\n        text: op.text.replaceAll(\"\\n\", \"\"),\n      };\n    } else if (op.type === \"insert_node\") {\n      const fragment = op.fragment;\n      op = {\n        ...op,\n        fragment: hasBlockChildren(fragment)\n          ? [joinBlocks(...fragment)]\n          : fragment,\n      };\n    }\n    next(op);\n  });\n}\n","import { sliceText, isTextNode } from \"../doc/node.js\";\nimport { stringToFragment } from \"../doc/utils.js\";\nimport { createEditor, type Editor, type EditorOptions } from \"../editor.js\";\nimport { plainTransferPlugin, singlelinePlugin } from \"../plugins/index.js\";\nimport type { BlockNode, InlineNode } from \"../doc/types.js\";\n\ntype PlainDoc = { children: { children: { text: string }[] }[] };\n\n/**\n * Describes which lines changed between two document snapshots.\n * Starting at line `start`, `oldCount` lines were replaced with `newCount` lines.\n * `lines` contains the text content of the new lines in the dirty window.\n */\nexport interface DirtyRange {\n  start: number;\n  oldCount: number;\n  newCount: number;\n  lines: string[];\n}\n\nexport interface PlainEditorOptions extends Omit<\n  EditorOptions<PlainDoc>,\n  \"doc\" | \"schema\" | \"onChange\"\n> {\n  /**\n   * Initial document text.\n   */\n  text: string;\n  /**\n   * TODO\n   */\n  singleline?: boolean;\n  /**\n   * Callback invoked when document changes.\n   */\n  onChange: (text: string, dirtyRange: DirtyRange) => void;\n}\n\nconst lineText = (nodes: readonly InlineNode[]): string => {\n  let s = \"\";\n  for (let i = 0; i < nodes.length; i++) {\n    const node = nodes[i]!;\n    if (isTextNode(node)) {\n      s += node.text;\n    }\n  }\n  return s;\n};\n\nconst computeDirtyRange = (\n  prev: readonly BlockNode[],\n  next: readonly BlockNode[],\n): DirtyRange => {\n  const oldLen = prev.length;\n  const newLen = next.length;\n  const scanEnd = Math.min(oldLen, newLen);\n\n  let front = 0;\n  while (front < scanEnd && prev[front] === next[front]) {\n    front++;\n  }\n\n  let oldBack = oldLen;\n  let newBack = newLen;\n  while (\n    oldBack > front &&\n    newBack > front &&\n    prev[oldBack - 1] === next[newBack - 1]\n  ) {\n    oldBack--;\n    newBack--;\n  }\n\n  const count = newBack - front;\n  const lines: string[] = new Array(count);\n  for (let i = 0; i < count; i++) {\n    lines[i] = lineText(next[front + i]!.children);\n  }\n\n  return { start: front, oldCount: oldBack - front, newCount: count, lines };\n};\n\n/**\n * A function to initialize editor with plaintext.\n */\nexport const createPlainEditor = ({\n  text,\n  singleline,\n  onChange,\n  ...opts\n}: PlainEditorOptions): Editor<PlainDoc> => {\n  const initialChildren = stringToFragment(text);\n  let prevChildren: readonly BlockNode[] = initialChildren;\n  const editor = createEditor<PlainDoc>({\n    ...opts,\n    doc: { children: initialChildren },\n  }).exec(plainTransferPlugin);\n  if (singleline) {\n    editor.exec(singlelinePlugin);\n  }\n  editor.on(\"change\", () => {\n    const doc = editor.doc;\n    const dirtyRange = computeDirtyRange(prevChildren, doc.children);\n    prevChildren = doc.children;\n    onChange(sliceText(doc), dirtyRange);\n  });\n  return editor;\n};\n"],"mappings":"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"}