UNPKG

@portabletext/editor

Version:

Portable Text Editor made in React

1,034 lines 714 kB
import { jsx, jsxs, Fragment } from "react/jsx-runtime"; import { c } from "react/compiler-runtime"; import { useSelector, useActorRef } from "@xstate/react"; import React, { useRef, useEffect, useLayoutEffect, useState, createContext, useContext, useReducer, useCallback, useMemo, memo, forwardRef, Component, startTransition } from "react"; import rawDebug from "debug"; import { isSpan, isTextBlock, compileSchema } from "@portabletext/schema"; import { defineSchema } from "@portabletext/schema"; import { isTypedObject, isListBlock, getBlockEndPoint, getBlockStartPoint, getBlockKeyFromSelectionPoint, isSelectionCollapsed, isKeyedSegment, isEqualSelectionPoints, getChildKeyFromSelectionPoint, blockOffsetToSpanSelectionPoint, defaultKeyGenerator, parseBlocks, parseBlock, getSelectionStartPoint as getSelectionStartPoint$1, getSelectionEndPoint as getSelectionEndPoint$1, parseAnnotation, parseMarkDefs, parseSpan, parseInlineObject, isEqualPathSegments } from "./_chunks-es/util.slice-blocks.js"; import scrollIntoView from "scroll-into-view-if-needed"; import { createKeyboardShortcut, code, underline, italic as italic$1, bold as bold$1, undo as undo$1, redo as redo$1 } from "@portabletext/keyboard-shortcuts"; import { ResizeObserver } from "@juggle/resize-observer"; import { isEmptyTextBlock, sliceTextBlock, getTextBlockText } from "./_chunks-es/util.slice-text-block.js"; import { setup, fromCallback, assign, and, enqueueActions, emit, assertEvent, raise as raise$1, not, createActor } from "xstate"; import { isSelectionCollapsed as isSelectionCollapsed$1, getFocusChild as getFocusChild$1, getSelectedChildren, getSelectionStartPoint, getSelectionEndPoint, getFocusInlineObject, getFocusTextBlock, getFocusSpan as getFocusSpan$1, getSelectedBlocks, isSelectionExpanded, getSelectionStartBlock, getSelectionEndBlock, isOverlappingSelection, getFocusBlock as getFocusBlock$1, isSelectingEntireBlocks, getSelectedValue, isActiveAnnotation, getActiveAnnotationsMarks, getActiveDecorators, getSelectionStartChild, getSelectionEndChild, getPreviousSpan, getNextSpan, getCaretWordSelection, getFocusBlockObject, getPreviousBlock, getNextBlock, getMarkState, isAtTheEndOfBlock, isAtTheStartOfBlock, getFocusListBlock, isActiveDecorator, getActiveAnnotations, getLastBlock as getLastBlock$1, getSelectedTextBlocks, isActiveListItem, isActiveStyle } from "./_chunks-es/selector.is-selecting-entire-blocks.js"; import { defineBehavior, forward, raise, effect } from "./behaviors/index.js"; import { htmlToPortableText } from "@portabletext/html"; import { toHTML } from "@portabletext/to-html"; import { markdownToPortableText, portableTextToMarkdown } from "@portabletext/markdown"; import { applyAll, set, unset, insert, setIfMissing, diffMatchPatch as diffMatchPatch$1 } from "@portabletext/patches"; import { EditorContext as EditorContext$1 } from "./_chunks-es/use-editor.js"; import { useEditor } from "./_chunks-es/use-editor.js"; const rootName = "pte:"; function createDebugger(name) { const namespace = `${rootName}${name}`; return rawDebug && rawDebug.enabled(namespace) ? rawDebug(namespace) : rawDebug(rootName); } const debug$1 = { behaviors: createDebugger("behaviors"), history: createDebugger("history"), mutation: createDebugger("mutation"), normalization: createDebugger("normalization"), operation: createDebugger("operation"), selection: createDebugger("selection"), setup: createDebugger("setup"), state: createDebugger("state"), syncValue: createDebugger("sync:value"), syncPatch: createDebugger("sync:patch") }; function safeStringify(value, space) { try { return JSON.stringify(value, null, space); } catch (error) { return console.error(error), "JSON.stringify failed"; } } function safeParse(text) { try { return JSON.parse(text); } catch (error) { return console.error(error), "JSON.parse failed"; } } function isObjectNode(context, node2) { return isTypedObject(node2) && node2._type !== context.schema.block.name && node2._type !== context.schema.span.name; } function isLeaf(node2, schema) { return isSpan({ schema }, node2) || isObjectNode({ schema }, node2); } function getNodeIf(root, path2, schema) { if (path2.length === 0) return; let node2 = root; for (let i = 0; i < path2.length; i++) { const p = path2[i]; if (isLeaf(node2, schema)) return; const children = node2.children; if (!children[p]) return; node2 = children[p]; } return node2; } function getNode(root, path2, schema) { const node2 = getNodeIf(root, path2, schema); if (node2 === void 0) throw new Error(`Cannot find a descendant at path [${path2}] in node: ${safeStringify(root)}`); return node2; } function getFirst(root, path2, schema) { const p = path2.slice(); let n2; if (path2.length === 0) { if (isLeaf(root, schema) || root.children.length === 0) throw new Error("Cannot get the first descendant of a leaf or empty root"); n2 = root.children[0], p.push(0); } else n2 = getNode(root, p, schema); for (; n2 && !isLeaf(n2, schema); ) { const ancestorChildren = n2.children; if (ancestorChildren.length === 0) break; n2 = ancestorChildren[0], p.push(0); } return [n2, p]; } function getLast(root, path2, schema) { const p = path2.slice(); let n2; if (path2.length === 0) { if (isLeaf(root, schema) || root.children.length === 0) throw new Error("Cannot get the last descendant of a leaf or empty root"); const i = root.children.length - 1; n2 = root.children[i], p.push(i); } else n2 = getNode(root, p, schema); for (; n2 && !isLeaf(n2, schema); ) { const ancestorChildren = n2.children; if (ancestorChildren.length === 0) break; const i = ancestorChildren.length - 1; n2 = ancestorChildren[i], p.push(i); } return [n2, p]; } function isPath(value) { return Array.isArray(value) && (value.length === 0 || typeof value[0] == "number"); } const isObject = (value) => typeof value == "object" && value !== null; function isPoint(value) { return isObject(value) && typeof value.offset == "number" && isPath(value.path); } function isRange(value) { return isObject(value) && isPoint(value.anchor) && isPoint(value.focus); } function comparePaths(path2, another) { const min = Math.min(path2.length, another.length); for (let i = 0; i < min; i++) { if (path2[i] < another[i]) return -1; if (path2[i] > another[i]) return 1; } return 0; } function comparePoints(point2, another) { const result = comparePaths(point2.path, another.path); return result === 0 ? point2.offset < another.offset ? -1 : point2.offset > another.offset ? 1 : 0 : result; } function isAfterPoint(point2, another) { return comparePoints(point2, another) === 1; } function isBackwardRange(range2) { const { anchor, focus } = range2; return isAfterPoint(anchor, focus); } function rangeEdges(range2, options = {}) { const { reverse = !1 } = options, { anchor, focus } = range2; return isBackwardRange(range2) === reverse ? [anchor, focus] : [focus, anchor]; } const EDITOR_BRAND = /* @__PURE__ */ Symbol.for("slate-editor"); function isEditor(value) { return isObject(value) && value[EDITOR_BRAND] === !0; } function point(editor, at, options = {}) { const { edge = "start" } = options; if (isPath(at)) { let path2; if (edge === "end") { const [, lastPath] = getLast(editor, at, editor.schema); path2 = lastPath; } else { const [, firstPath] = getFirst(editor, at, editor.schema); path2 = firstPath; } const node2 = getNode(editor, path2, editor.schema); if (!isSpan({ schema: editor.schema }, node2) && !isTextBlock({ schema: editor.schema }, node2) && !isEditor(node2)) return { path: path2, offset: 0 }; if (!isSpan({ schema: editor.schema }, node2)) throw new Error(`Cannot get the ${edge} point in the node at path [${at}] because it has no ${edge} text node.`); return { path: path2, offset: edge === "end" ? node2.text.length : 0 }; } if (isRange(at)) { const [start2, end2] = rangeEdges(at); return edge === "start" ? start2 : end2; } return at; } function end(editor, at) { return point(editor, at, { edge: "end" }); } function isAncestorPath(path2, another) { return path2.length < another.length && comparePaths(path2, another) === 0; } function pathEquals(path2, another) { return path2.length === another.length && path2.every((n2, i) => n2 === another[i]); } const getCharacterDistance = (str, isRTL = !1) => { const isLTR = !isRTL, codepoints = isRTL ? codepointsIteratorRTL(str) : str; let left = CodepointType.None, right = CodepointType.None, distance = 0, gb11 = null, gb12Or13 = null; for (const char of codepoints) { const code2 = char.codePointAt(0); if (!code2) break; const type = getCodepointType(char, code2); if ([left, right] = isLTR ? [right, type] : [type, left], intersects(left, CodepointType.ZWJ) && intersects(right, CodepointType.ExtPict) && (isLTR ? gb11 = endsWithEmojiZWJ(str.substring(0, distance)) : gb11 = endsWithEmojiZWJ(str.substring(0, str.length - distance)), !gb11) || intersects(left, CodepointType.RI) && intersects(right, CodepointType.RI) && (gb12Or13 !== null ? gb12Or13 = !gb12Or13 : isLTR ? gb12Or13 = !0 : gb12Or13 = endsWithOddNumberOfRIs(str.substring(0, str.length - distance)), !gb12Or13) || left !== CodepointType.None && right !== CodepointType.None && isBoundaryPair(left, right)) break; distance += char.length; } return distance || 1; }, SPACE = /\s/, PUNCTUATION = /[\u002B\u0021-\u0023\u0025-\u002A\u002C-\u002F\u003A\u003B\u003F\u0040\u005B-\u005D\u005F\u007B\u007D\u00A1\u00A7\u00AB\u00B6\u00B7\u00BB\u00BF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E3B\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]/, CHAMELEON = /['\u2018\u2019]/, getWordDistance = (text, isRTL = !1) => { let dist = 0, started = !1; for (; text.length > 0; ) { const charDist = getCharacterDistance(text, isRTL), [char, remaining] = splitByCharacterDistance(text, charDist, isRTL); if (isWordCharacter(char, remaining, isRTL)) started = !0, dist += charDist; else if (!started) dist += charDist; else break; text = remaining; } return dist; }, splitByCharacterDistance = (str, dist, isRTL) => { if (isRTL) { const at = str.length - dist; return [str.slice(at, str.length), str.slice(0, at)]; } return [str.slice(0, dist), str.slice(dist)]; }, isWordCharacter = (char, remaining, isRTL = !1) => { if (SPACE.test(char)) return !1; if (CHAMELEON.test(char)) { const charDist = getCharacterDistance(remaining, isRTL), [nextChar, nextRemaining] = splitByCharacterDistance(remaining, charDist, isRTL); if (isWordCharacter(nextChar, nextRemaining, isRTL)) return !0; } return !PUNCTUATION.test(char); }, codepointsIteratorRTL = function* (str) { const end2 = str.length - 1; for (let i = 0; i < str.length; i++) { const char1 = str.charAt(end2 - i); if (isLowSurrogate$1(char1.charCodeAt(0))) { const char2 = str.charAt(end2 - i - 1); if (isHighSurrogate$1(char2.charCodeAt(0))) { yield char2 + char1, i++; continue; } } yield char1; } }, isHighSurrogate$1 = (charCode) => charCode >= 55296 && charCode <= 56319, isLowSurrogate$1 = (charCode) => charCode >= 56320 && charCode <= 57343, CodepointType = { None: 0, Extend: 1, ZWJ: 2, RI: 4, Prepend: 8, SpacingMark: 16, L: 32, V: 64, T: 128, LV: 256, LVT: 512, ExtPict: 1024, Any: 2048 }, reExtend = /^[\p{Gr_Ext}\p{EMod}]$/u, rePrepend = /^[\u0600-\u0605\u06DD\u070F\u0890-\u0891\u08E2\u0D4E\u{110BD}\u{110CD}\u{111C2}-\u{111C3}\u{1193F}\u{11941}\u{11A3A}\u{11A84}-\u{11A89}\u{11D46}]$/u, reSpacingMark = /^[\u0903\u093B\u093E-\u0940\u0949-\u094C\u094E-\u094F\u0982-\u0983\u09BF-\u09C0\u09C7-\u09C8\u09CB-\u09CC\u0A03\u0A3E-\u0A40\u0A83\u0ABE-\u0AC0\u0AC9\u0ACB-\u0ACC\u0B02-\u0B03\u0B40\u0B47-\u0B48\u0B4B-\u0B4C\u0BBF\u0BC1-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0C01-\u0C03\u0C41-\u0C44\u0C82-\u0C83\u0CBE\u0CC0-\u0CC1\u0CC3-\u0CC4\u0CC7-\u0CC8\u0CCA-\u0CCB\u0D02-\u0D03\u0D3F-\u0D40\u0D46-\u0D48\u0D4A-\u0D4C\u0D82-\u0D83\u0DD0-\u0DD1\u0DD8-\u0DDE\u0DF2-\u0DF3\u0E33\u0EB3\u0F3E-\u0F3F\u0F7F\u1031\u103B-\u103C\u1056-\u1057\u1084\u1715\u1734\u17B6\u17BE-\u17C5\u17C7-\u17C8\u1923-\u1926\u1929-\u192B\u1930-\u1931\u1933-\u1938\u1A19-\u1A1A\u1A55\u1A57\u1A6D-\u1A72\u1B04\u1B3B\u1B3D-\u1B41\u1B43-\u1B44\u1B82\u1BA1\u1BA6-\u1BA7\u1BAA\u1BE7\u1BEA-\u1BEC\u1BEE\u1BF2-\u1BF3\u1C24-\u1C2B\u1C34-\u1C35\u1CE1\u1CF7\uA823-\uA824\uA827\uA880-\uA881\uA8B4-\uA8C3\uA952-\uA953\uA983\uA9B4-\uA9B5\uA9BA-\uA9BB\uA9BE-\uA9C0\uAA2F-\uAA30\uAA33-\uAA34\uAA4D\uAAEB\uAAEE-\uAAEF\uAAF5\uABE3-\uABE4\uABE6-\uABE7\uABE9-\uABEA\uABEC\u{11000}\u{11002}\u{11082}\u{110B0}-\u{110B2}\u{110B7}-\u{110B8}\u{1112C}\u{11145}-\u{11146}\u{11182}\u{111B3}-\u{111B5}\u{111BF}-\u{111C0}\u{111CE}\u{1122C}-\u{1122E}\u{11232}-\u{11233}\u{11235}\u{112E0}-\u{112E2}\u{11302}-\u{11303}\u{1133F}\u{11341}-\u{11344}\u{11347}-\u{11348}\u{1134B}-\u{1134D}\u{11362}-\u{11363}\u{11435}-\u{11437}\u{11440}-\u{11441}\u{11445}\u{114B1}-\u{114B2}\u{114B9}\u{114BB}-\u{114BC}\u{114BE}\u{114C1}\u{115B0}-\u{115B1}\u{115B8}-\u{115BB}\u{115BE}\u{11630}-\u{11632}\u{1163B}-\u{1163C}\u{1163E}\u{116AC}\u{116AE}-\u{116AF}\u{116B6}\u{11726}\u{1182C}-\u{1182E}\u{11838}\u{11931}-\u{11935}\u{11937}-\u{11938}\u{1193D}\u{11940}\u{11942}\u{119D1}-\u{119D3}\u{119DC}-\u{119DF}\u{119E4}\u{11A39}\u{11A57}-\u{11A58}\u{11A97}\u{11C2F}\u{11C3E}\u{11CA9}\u{11CB1}\u{11CB4}\u{11D8A}-\u{11D8E}\u{11D93}-\u{11D94}\u{11D96}\u{11EF5}-\u{11EF6}\u{16F51}-\u{16F87}\u{16FF0}-\u{16FF1}\u{1D166}\u{1D16D}]$/u, reL = /^[\u1100-\u115F\uA960-\uA97C]$/u, reV = /^[\u1160-\u11A7\uD7B0-\uD7C6]$/u, reT = /^[\u11A8-\u11FF\uD7CB-\uD7FB]$/u, reLV = /^[\uAC00\uAC1C\uAC38\uAC54\uAC70\uAC8C\uACA8\uACC4\uACE0\uACFC\uAD18\uAD34\uAD50\uAD6C\uAD88\uADA4\uADC0\uADDC\uADF8\uAE14\uAE30\uAE4C\uAE68\uAE84\uAEA0\uAEBC\uAED8\uAEF4\uAF10\uAF2C\uAF48\uAF64\uAF80\uAF9C\uAFB8\uAFD4\uAFF0\uB00C\uB028\uB044\uB060\uB07C\uB098\uB0B4\uB0D0\uB0EC\uB108\uB124\uB140\uB15C\uB178\uB194\uB1B0\uB1CC\uB1E8\uB204\uB220\uB23C\uB258\uB274\uB290\uB2AC\uB2C8\uB2E4\uB300\uB31C\uB338\uB354\uB370\uB38C\uB3A8\uB3C4\uB3E0\uB3FC\uB418\uB434\uB450\uB46C\uB488\uB4A4\uB4C0\uB4DC\uB4F8\uB514\uB530\uB54C\uB568\uB584\uB5A0\uB5BC\uB5D8\uB5F4\uB610\uB62C\uB648\uB664\uB680\uB69C\uB6B8\uB6D4\uB6F0\uB70C\uB728\uB744\uB760\uB77C\uB798\uB7B4\uB7D0\uB7EC\uB808\uB824\uB840\uB85C\uB878\uB894\uB8B0\uB8CC\uB8E8\uB904\uB920\uB93C\uB958\uB974\uB990\uB9AC\uB9C8\uB9E4\uBA00\uBA1C\uBA38\uBA54\uBA70\uBA8C\uBAA8\uBAC4\uBAE0\uBAFC\uBB18\uBB34\uBB50\uBB6C\uBB88\uBBA4\uBBC0\uBBDC\uBBF8\uBC14\uBC30\uBC4C\uBC68\uBC84\uBCA0\uBCBC\uBCD8\uBCF4\uBD10\uBD2C\uBD48\uBD64\uBD80\uBD9C\uBDB8\uBDD4\uBDF0\uBE0C\uBE28\uBE44\uBE60\uBE7C\uBE98\uBEB4\uBED0\uBEEC\uBF08\uBF24\uBF40\uBF5C\uBF78\uBF94\uBFB0\uBFCC\uBFE8\uC004\uC020\uC03C\uC058\uC074\uC090\uC0AC\uC0C8\uC0E4\uC100\uC11C\uC138\uC154\uC170\uC18C\uC1A8\uC1C4\uC1E0\uC1FC\uC218\uC234\uC250\uC26C\uC288\uC2A4\uC2C0\uC2DC\uC2F8\uC314\uC330\uC34C\uC368\uC384\uC3A0\uC3BC\uC3D8\uC3F4\uC410\uC42C\uC448\uC464\uC480\uC49C\uC4B8\uC4D4\uC4F0\uC50C\uC528\uC544\uC560\uC57C\uC598\uC5B4\uC5D0\uC5EC\uC608\uC624\uC640\uC65C\uC678\uC694\uC6B0\uC6CC\uC6E8\uC704\uC720\uC73C\uC758\uC774\uC790\uC7AC\uC7C8\uC7E4\uC800\uC81C\uC838\uC854\uC870\uC88C\uC8A8\uC8C4\uC8E0\uC8FC\uC918\uC934\uC950\uC96C\uC988\uC9A4\uC9C0\uC9DC\uC9F8\uCA14\uCA30\uCA4C\uCA68\uCA84\uCAA0\uCABC\uCAD8\uCAF4\uCB10\uCB2C\uCB48\uCB64\uCB80\uCB9C\uCBB8\uCBD4\uCBF0\uCC0C\uCC28\uCC44\uCC60\uCC7C\uCC98\uCCB4\uCCD0\uCCEC\uCD08\uCD24\uCD40\uCD5C\uCD78\uCD94\uCDB0\uCDCC\uCDE8\uCE04\uCE20\uCE3C\uCE58\uCE74\uCE90\uCEAC\uCEC8\uCEE4\uCF00\uCF1C\uCF38\uCF54\uCF70\uCF8C\uCFA8\uCFC4\uCFE0\uCFFC\uD018\uD034\uD050\uD06C\uD088\uD0A4\uD0C0\uD0DC\uD0F8\uD114\uD130\uD14C\uD168\uD184\uD1A0\uD1BC\uD1D8\uD1F4\uD210\uD22C\uD248\uD264\uD280\uD29C\uD2B8\uD2D4\uD2F0\uD30C\uD328\uD344\uD360\uD37C\uD398\uD3B4\uD3D0\uD3EC\uD408\uD424\uD440\uD45C\uD478\uD494\uD4B0\uD4CC\uD4E8\uD504\uD520\uD53C\uD558\uD574\uD590\uD5AC\uD5C8\uD5E4\uD600\uD61C\uD638\uD654\uD670\uD68C\uD6A8\uD6C4\uD6E0\uD6FC\uD718\uD734\uD750\uD76C\uD788]$/u, reLVT = /^[\uAC01-\uAC1B\uAC1D-\uAC37\uAC39-\uAC53\uAC55-\uAC6F\uAC71-\uAC8B\uAC8D-\uACA7\uACA9-\uACC3\uACC5-\uACDF\uACE1-\uACFB\uACFD-\uAD17\uAD19-\uAD33\uAD35-\uAD4F\uAD51-\uAD6B\uAD6D-\uAD87\uAD89-\uADA3\uADA5-\uADBF\uADC1-\uADDB\uADDD-\uADF7\uADF9-\uAE13\uAE15-\uAE2F\uAE31-\uAE4B\uAE4D-\uAE67\uAE69-\uAE83\uAE85-\uAE9F\uAEA1-\uAEBB\uAEBD-\uAED7\uAED9-\uAEF3\uAEF5-\uAF0F\uAF11-\uAF2B\uAF2D-\uAF47\uAF49-\uAF63\uAF65-\uAF7F\uAF81-\uAF9B\uAF9D-\uAFB7\uAFB9-\uAFD3\uAFD5-\uAFEF\uAFF1-\uB00B\uB00D-\uB027\uB029-\uB043\uB045-\uB05F\uB061-\uB07B\uB07D-\uB097\uB099-\uB0B3\uB0B5-\uB0CF\uB0D1-\uB0EB\uB0ED-\uB107\uB109-\uB123\uB125-\uB13F\uB141-\uB15B\uB15D-\uB177\uB179-\uB193\uB195-\uB1AF\uB1B1-\uB1CB\uB1CD-\uB1E7\uB1E9-\uB203\uB205-\uB21F\uB221-\uB23B\uB23D-\uB257\uB259-\uB273\uB275-\uB28F\uB291-\uB2AB\uB2AD-\uB2C7\uB2C9-\uB2E3\uB2E5-\uB2FF\uB301-\uB31B\uB31D-\uB337\uB339-\uB353\uB355-\uB36F\uB371-\uB38B\uB38D-\uB3A7\uB3A9-\uB3C3\uB3C5-\uB3DF\uB3E1-\uB3FB\uB3FD-\uB417\uB419-\uB433\uB435-\uB44F\uB451-\uB46B\uB46D-\uB487\uB489-\uB4A3\uB4A5-\uB4BF\uB4C1-\uB4DB\uB4DD-\uB4F7\uB4F9-\uB513\uB515-\uB52F\uB531-\uB54B\uB54D-\uB567\uB569-\uB583\uB585-\uB59F\uB5A1-\uB5BB\uB5BD-\uB5D7\uB5D9-\uB5F3\uB5F5-\uB60F\uB611-\uB62B\uB62D-\uB647\uB649-\uB663\uB665-\uB67F\uB681-\uB69B\uB69D-\uB6B7\uB6B9-\uB6D3\uB6D5-\uB6EF\uB6F1-\uB70B\uB70D-\uB727\uB729-\uB743\uB745-\uB75F\uB761-\uB77B\uB77D-\uB797\uB799-\uB7B3\uB7B5-\uB7CF\uB7D1-\uB7EB\uB7ED-\uB807\uB809-\uB823\uB825-\uB83F\uB841-\uB85B\uB85D-\uB877\uB879-\uB893\uB895-\uB8AF\uB8B1-\uB8CB\uB8CD-\uB8E7\uB8E9-\uB903\uB905-\uB91F\uB921-\uB93B\uB93D-\uB957\uB959-\uB973\uB975-\uB98F\uB991-\uB9AB\uB9AD-\uB9C7\uB9C9-\uB9E3\uB9E5-\uB9FF\uBA01-\uBA1B\uBA1D-\uBA37\uBA39-\uBA53\uBA55-\uBA6F\uBA71-\uBA8B\uBA8D-\uBAA7\uBAA9-\uBAC3\uBAC5-\uBADF\uBAE1-\uBAFB\uBAFD-\uBB17\uBB19-\uBB33\uBB35-\uBB4F\uBB51-\uBB6B\uBB6D-\uBB87\uBB89-\uBBA3\uBBA5-\uBBBF\uBBC1-\uBBDB\uBBDD-\uBBF7\uBBF9-\uBC13\uBC15-\uBC2F\uBC31-\uBC4B\uBC4D-\uBC67\uBC69-\uBC83\uBC85-\uBC9F\uBCA1-\uBCBB\uBCBD-\uBCD7\uBCD9-\uBCF3\uBCF5-\uBD0F\uBD11-\uBD2B\uBD2D-\uBD47\uBD49-\uBD63\uBD65-\uBD7F\uBD81-\uBD9B\uBD9D-\uBDB7\uBDB9-\uBDD3\uBDD5-\uBDEF\uBDF1-\uBE0B\uBE0D-\uBE27\uBE29-\uBE43\uBE45-\uBE5F\uBE61-\uBE7B\uBE7D-\uBE97\uBE99-\uBEB3\uBEB5-\uBECF\uBED1-\uBEEB\uBEED-\uBF07\uBF09-\uBF23\uBF25-\uBF3F\uBF41-\uBF5B\uBF5D-\uBF77\uBF79-\uBF93\uBF95-\uBFAF\uBFB1-\uBFCB\uBFCD-\uBFE7\uBFE9-\uC003\uC005-\uC01F\uC021-\uC03B\uC03D-\uC057\uC059-\uC073\uC075-\uC08F\uC091-\uC0AB\uC0AD-\uC0C7\uC0C9-\uC0E3\uC0E5-\uC0FF\uC101-\uC11B\uC11D-\uC137\uC139-\uC153\uC155-\uC16F\uC171-\uC18B\uC18D-\uC1A7\uC1A9-\uC1C3\uC1C5-\uC1DF\uC1E1-\uC1FB\uC1FD-\uC217\uC219-\uC233\uC235-\uC24F\uC251-\uC26B\uC26D-\uC287\uC289-\uC2A3\uC2A5-\uC2BF\uC2C1-\uC2DB\uC2DD-\uC2F7\uC2F9-\uC313\uC315-\uC32F\uC331-\uC34B\uC34D-\uC367\uC369-\uC383\uC385-\uC39F\uC3A1-\uC3BB\uC3BD-\uC3D7\uC3D9-\uC3F3\uC3F5-\uC40F\uC411-\uC42B\uC42D-\uC447\uC449-\uC463\uC465-\uC47F\uC481-\uC49B\uC49D-\uC4B7\uC4B9-\uC4D3\uC4D5-\uC4EF\uC4F1-\uC50B\uC50D-\uC527\uC529-\uC543\uC545-\uC55F\uC561-\uC57B\uC57D-\uC597\uC599-\uC5B3\uC5B5-\uC5CF\uC5D1-\uC5EB\uC5ED-\uC607\uC609-\uC623\uC625-\uC63F\uC641-\uC65B\uC65D-\uC677\uC679-\uC693\uC695-\uC6AF\uC6B1-\uC6CB\uC6CD-\uC6E7\uC6E9-\uC703\uC705-\uC71F\uC721-\uC73B\uC73D-\uC757\uC759-\uC773\uC775-\uC78F\uC791-\uC7AB\uC7AD-\uC7C7\uC7C9-\uC7E3\uC7E5-\uC7FF\uC801-\uC81B\uC81D-\uC837\uC839-\uC853\uC855-\uC86F\uC871-\uC88B\uC88D-\uC8A7\uC8A9-\uC8C3\uC8C5-\uC8DF\uC8E1-\uC8FB\uC8FD-\uC917\uC919-\uC933\uC935-\uC94F\uC951-\uC96B\uC96D-\uC987\uC989-\uC9A3\uC9A5-\uC9BF\uC9C1-\uC9DB\uC9DD-\uC9F7\uC9F9-\uCA13\uCA15-\uCA2F\uCA31-\uCA4B\uCA4D-\uCA67\uCA69-\uCA83\uCA85-\uCA9F\uCAA1-\uCABB\uCABD-\uCAD7\uCAD9-\uCAF3\uCAF5-\uCB0F\uCB11-\uCB2B\uCB2D-\uCB47\uCB49-\uCB63\uCB65-\uCB7F\uCB81-\uCB9B\uCB9D-\uCBB7\uCBB9-\uCBD3\uCBD5-\uCBEF\uCBF1-\uCC0B\uCC0D-\uCC27\uCC29-\uCC43\uCC45-\uCC5F\uCC61-\uCC7B\uCC7D-\uCC97\uCC99-\uCCB3\uCCB5-\uCCCF\uCCD1-\uCCEB\uCCED-\uCD07\uCD09-\uCD23\uCD25-\uCD3F\uCD41-\uCD5B\uCD5D-\uCD77\uCD79-\uCD93\uCD95-\uCDAF\uCDB1-\uCDCB\uCDCD-\uCDE7\uCDE9-\uCE03\uCE05-\uCE1F\uCE21-\uCE3B\uCE3D-\uCE57\uCE59-\uCE73\uCE75-\uCE8F\uCE91-\uCEAB\uCEAD-\uCEC7\uCEC9-\uCEE3\uCEE5-\uCEFF\uCF01-\uCF1B\uCF1D-\uCF37\uCF39-\uCF53\uCF55-\uCF6F\uCF71-\uCF8B\uCF8D-\uCFA7\uCFA9-\uCFC3\uCFC5-\uCFDF\uCFE1-\uCFFB\uCFFD-\uD017\uD019-\uD033\uD035-\uD04F\uD051-\uD06B\uD06D-\uD087\uD089-\uD0A3\uD0A5-\uD0BF\uD0C1-\uD0DB\uD0DD-\uD0F7\uD0F9-\uD113\uD115-\uD12F\uD131-\uD14B\uD14D-\uD167\uD169-\uD183\uD185-\uD19F\uD1A1-\uD1BB\uD1BD-\uD1D7\uD1D9-\uD1F3\uD1F5-\uD20F\uD211-\uD22B\uD22D-\uD247\uD249-\uD263\uD265-\uD27F\uD281-\uD29B\uD29D-\uD2B7\uD2B9-\uD2D3\uD2D5-\uD2EF\uD2F1-\uD30B\uD30D-\uD327\uD329-\uD343\uD345-\uD35F\uD361-\uD37B\uD37D-\uD397\uD399-\uD3B3\uD3B5-\uD3CF\uD3D1-\uD3EB\uD3ED-\uD407\uD409-\uD423\uD425-\uD43F\uD441-\uD45B\uD45D-\uD477\uD479-\uD493\uD495-\uD4AF\uD4B1-\uD4CB\uD4CD-\uD4E7\uD4E9-\uD503\uD505-\uD51F\uD521-\uD53B\uD53D-\uD557\uD559-\uD573\uD575-\uD58F\uD591-\uD5AB\uD5AD-\uD5C7\uD5C9-\uD5E3\uD5E5-\uD5FF\uD601-\uD61B\uD61D-\uD637\uD639-\uD653\uD655-\uD66F\uD671-\uD68B\uD68D-\uD6A7\uD6A9-\uD6C3\uD6C5-\uD6DF\uD6E1-\uD6FB\uD6FD-\uD717\uD719-\uD733\uD735-\uD74F\uD751-\uD76B\uD76D-\uD787\uD789-\uD7A3]$/u, reExtPict = new RegExp("^\\p{ExtPict}$", "u"), getCodepointType = (char, code2) => { let type = CodepointType.Any; return char.search(reExtend) !== -1 && (type |= CodepointType.Extend), code2 === 8205 && (type |= CodepointType.ZWJ), code2 >= 127462 && code2 <= 127487 && (type |= CodepointType.RI), char.search(rePrepend) !== -1 && (type |= CodepointType.Prepend), char.search(reSpacingMark) !== -1 && (type |= CodepointType.SpacingMark), char.search(reL) !== -1 && (type |= CodepointType.L), char.search(reV) !== -1 && (type |= CodepointType.V), char.search(reT) !== -1 && (type |= CodepointType.T), char.search(reLV) !== -1 && (type |= CodepointType.LV), char.search(reLVT) !== -1 && (type |= CodepointType.LVT), char.search(reExtPict) !== -1 && (type |= CodepointType.ExtPict), type; }; function intersects(x, y) { return (x & y) !== 0; } const NonBoundaryPairs = [ // GB6 [CodepointType.L, CodepointType.L | CodepointType.V | CodepointType.LV | CodepointType.LVT], // GB7 [CodepointType.LV | CodepointType.V, CodepointType.V | CodepointType.T], // GB8 [CodepointType.LVT | CodepointType.T, CodepointType.T], // GB9 [CodepointType.Any, CodepointType.Extend | CodepointType.ZWJ], // GB9a [CodepointType.Any, CodepointType.SpacingMark], // GB9b [CodepointType.Prepend, CodepointType.Any], // GB11 [CodepointType.ZWJ, CodepointType.ExtPict], // GB12 and GB13 [CodepointType.RI, CodepointType.RI] ]; function isBoundaryPair(left, right) { return NonBoundaryPairs.findIndex((r) => intersects(left, r[0]) && intersects(right, r[1])) === -1; } const endingEmojiZWJ = new RegExp("\\p{ExtPict}[\\p{Gr_Ext}\\p{EMod}]*\\u200D$", "u"), endsWithEmojiZWJ = (str) => str.search(endingEmojiZWJ) !== -1, endingRIs = new RegExp("\\p{RI}+$", "gu"), endsWithOddNumberOfRIs = (str) => { const match2 = str.match(endingRIs); return match2 === null ? !1 : match2[0].length / 2 % 2 === 1; }; function hasInlines(editor, element) { return element.children.some((n2) => isSpan({ schema: editor.schema }, n2) ? !0 : editor.isInline(n2)); } const Span = { isSpan(value) { return Array.isArray(value) && value.length === 2 && value.every(isPath); } }; function isAfterPath(path2, another) { return comparePaths(path2, another) === 1; } function isBeforePath(path2, another) { return comparePaths(path2, another) === -1; } function nextPath(path2) { if (path2.length === 0) throw new Error(`Cannot get the next path of a root path [${path2}], because it has no next index.`); const last = path2[path2.length - 1]; return path2.slice(0, -1).concat(last + 1); } function parentPath(path2) { if (path2.length === 0) throw new Error(`Cannot get the parent path of the root path [${path2}].`); return path2.slice(0, -1); } function previousPath(path2) { if (path2.length === 0) throw new Error(`Cannot get the previous path of a root path [${path2}], because it has no previous index.`); const last = path2[path2.length - 1]; if (last <= 0) throw new Error(`Cannot get the previous path of a first child path [${path2}] because it would result in a negative index.`); return path2.slice(0, -1).concat(last - 1); } function hasNode(root, path2, schema) { let node2 = root; for (let i = 0; i < path2.length; i++) { const p = path2[i]; if (isLeaf(node2, schema)) return !1; const children = node2.children; if (!children[p]) return !1; node2 = children[p]; } return !0; } function* getNodes(root, schema, options = {}) { const { pass, reverse = !1 } = options, { from = [], to } = options, visited = /* @__PURE__ */ new Set(); let p = [], n2 = root; for (; !(to && (reverse ? isBeforePath(p, to) : isAfterPath(p, to))); ) { if (visited.has(n2) || (yield [n2, p]), !visited.has(n2) && !isLeaf(n2, schema) && n2.children.length !== 0 && (pass == null || pass([n2, p]) === !1)) { visited.add(n2); const children = n2.children; let nextIndex = reverse ? children.length - 1 : 0; isAncestorPath(p, from) && (nextIndex = from[p.length]), p = p.concat(nextIndex), n2 = getNode(root, p, schema); continue; } if (p.length === 0) break; if (!reverse) { const newPath = nextPath(p); if (hasNode(root, newPath, schema)) { p = newPath, n2 = getNode(root, p, schema); continue; } } if (reverse && p[p.length - 1] !== 0) { p = previousPath(p), n2 = getNode(root, p, schema); continue; } p = parentPath(p), n2 = p.length === 0 ? root : getNode(root, p, schema), visited.add(n2); } } function commonPath(path2, another) { const common = []; for (let i = 0; i < path2.length && i < another.length; i++) { const av = path2[i], bv = another[i]; if (av !== bv) break; common.push(av); } return common; } function rangeEnd(range2) { const [, end2] = rangeEdges(range2); return end2; } function rangeStart(range2) { const [start2] = rangeEdges(range2); return start2; } function path(editor, at, options = {}) { const { depth, edge } = options; if (isPath(at)) { if (edge === "start") { const [, firstPath] = getFirst(editor, at, editor.schema); at = firstPath; } else if (edge === "end") { const [, lastPath] = getLast(editor, at, editor.schema); at = lastPath; } } return isRange(at) && (edge === "start" ? at = rangeStart(at) : edge === "end" ? at = rangeEnd(at) : at = commonPath(at.anchor.path, at.focus.path)), isPoint(at) && (at = at.path), depth != null && (at = at.slice(0, depth)), at; } function* nodes(editor, options = {}) { const { at = editor.selection, mode, reverse = !1, includeObjectNodes = !1 } = options; let { match: match2 } = options; if (match2 || (match2 = () => !0), !at) return; let from, to; if (Span.isSpan(at)) from = at[0], to = at[1]; else { const first = path(editor, at, { edge: "start" }), last = path(editor, at, { edge: "end" }); from = reverse ? last : first, to = reverse ? first : last; } const nodeEntries = getNodes(editor, editor.schema, { reverse, from, to, pass: ([node2]) => isTextBlock({ schema: editor.schema }, node2) ? !!(!includeObjectNodes && editor.isElementReadOnly(node2)) : !1 }); let hit; for (const [node2, path2] of nodeEntries) { const isLower = hit && comparePaths(path2, hit[1]) === 0; if (mode === "highest" && isLower || !match2(node2, path2)) continue; if (!mode) { yield [node2, path2], hit = [node2, path2]; continue; } if (mode === "lowest" && isLower) { hit = [node2, path2]; continue; } const emit2 = mode === "lowest" ? hit : [node2, path2]; emit2 && (yield emit2), hit = [node2, path2]; } mode === "lowest" && hit && (yield hit); } function start(editor, at) { return point(editor, at, { edge: "start" }); } function range(editor, at, to) { if (isRange(at) && !to) return at; const rangeStart2 = start(editor, at), rangeEnd2 = end(editor, to || at); return { anchor: rangeStart2, focus: rangeEnd2 }; } function string(editor, at, options = {}) { const { includeObjectNodes = !1 } = options, editorRange = range(editor, at), [start2, end2] = rangeEdges(editorRange); let text = ""; for (const [node2, path2] of nodes(editor, { at: editorRange, match: (n2) => isSpan({ schema: editor.schema }, n2), includeObjectNodes })) { let t = node2.text; pathEquals(path2, end2.path) && (t = t.slice(0, end2.offset)), pathEquals(path2, start2.path) && (t = t.slice(start2.offset)), text += t; } return text; } function* positions(editor, options = {}) { const { at = editor.selection, unit = "offset", reverse = !1, includeObjectNodes = !1 } = options; if (!at) return; const editorRange = range(editor, at), [start$1, end$1] = rangeEdges(editorRange), first = reverse ? end$1 : start$1; let isNewBlock = !1, blockText = "", distance = 0, leafTextRemaining = 0, leafTextOffset = 0; for (const [node2, nodePath] of nodes(editor, { at, reverse, includeObjectNodes })) { if (isTextBlock({ schema: editor.schema }, node2)) { if (!includeObjectNodes && editor.isElementReadOnly(node2)) { yield start(editor, nodePath); continue; } if (editor.isInline(node2)) continue; if (hasInlines(editor, node2)) { const e = isAncestorPath(nodePath, end$1.path) ? end$1 : end(editor, nodePath), s = isAncestorPath(nodePath, start$1.path) ? start$1 : start(editor, nodePath); blockText = string(editor, { anchor: s, focus: e }, { includeObjectNodes }), isNewBlock = !0; } } if (isObjectNode({ schema: editor.schema }, node2)) { yield { path: nodePath, offset: 0 }; continue; } if (!isEditor(node2) && !isTextBlock({ schema: editor.schema }, node2) && !isSpan({ schema: editor.schema }, node2)) { yield { path: nodePath, offset: 0 }; continue; } if (isSpan({ schema: editor.schema }, node2)) { const isFirst = pathEquals(nodePath, first.path); for (isFirst ? (leafTextRemaining = reverse ? first.offset : node2.text.length - first.offset, leafTextOffset = first.offset) : (leafTextRemaining = node2.text.length, leafTextOffset = reverse ? leafTextRemaining : 0), (isFirst || isNewBlock || unit === "offset") && (yield { path: nodePath, offset: leafTextOffset }, isNewBlock = !1); ; ) { if (distance === 0) { if (blockText === "") break; distance = calcDistance(blockText, unit, reverse), blockText = splitByCharacterDistance(blockText, distance, reverse)[1]; } if (leafTextOffset = reverse ? leafTextOffset - distance : leafTextOffset + distance, leafTextRemaining = leafTextRemaining - distance, leafTextRemaining < 0) { distance = -leafTextRemaining; break; } distance = 0, yield { path: nodePath, offset: leafTextOffset }; } } } function calcDistance(text, unit2, reverse2) { return unit2 === "character" ? getCharacterDistance(text, reverse2) : unit2 === "word" ? getWordDistance(text, reverse2) : unit2 === "line" || unit2 === "block" ? text.length : 1; } } function after(editor, at, options = {}) { const anchor = point(editor, at, { edge: "end" }), focus = end(editor, []), range2 = { anchor, focus }, { distance = 1 } = options; let d = 0, target; for (const p of positions(editor, { ...options, at: range2 })) { if (d > distance) break; d !== 0 && (target = p), d++; } return target; } function before(editor, at, options = {}) { const anchor = start(editor, []), focus = point(editor, at, { edge: "start" }), range2 = { anchor, focus }, { distance = 1 } = options; let d = 0, target; for (const p of positions(editor, { ...options, at: range2, reverse: !0 })) { if (d > distance) break; d !== 0 && (target = p), d++; } return target; } function pathLevels(path2, options = {}) { const { reverse = !1 } = options, list = []; for (let i = 0; i <= path2.length; i++) list.push(path2.slice(0, i)); return reverse && list.reverse(), list; } function* getLevels(root, path2, schema, options = {}) { for (const p of pathLevels(path2, options)) { if (p.length === 0) { yield [root, p]; continue; } yield [getNode(root, p, schema), p]; } } function* levels(editor, options = {}) { const { at = editor.selection, reverse = !1 } = options; let { match: match2 } = options; if (match2 == null && (match2 = () => !0), !at) return; const levels2 = [], fromPath = path(editor, at); for (const [n2, p] of getLevels(editor, fromPath, editor.schema)) match2(n2, p) && levels2.push([n2, p]); reverse && levels2.reverse(), yield* levels2; } function above(editor, options) { const { mode = "lowest", at = editor.selection, match: match2 } = options; if (!at) return; let fromPath = path(editor, at); if (!isRange(at) || pathEquals(at.focus.path, at.anchor.path)) { if (fromPath.length === 0) return; fromPath = parentPath(fromPath); } const reverse = mode === "lowest", [firstMatch] = levels(editor, { at: fromPath, match: match2, reverse }); return firstMatch; } function getObjectNode(editor, options = {}) { const { at = editor.selection } = options; if (!at) return; const nodePath = path(editor, at), node2 = getNode(editor, nodePath, editor.schema); return isObjectNode({ schema: editor.schema }, node2) ? [node2, nodePath] : above(editor, { ...options, match: (n2) => isObjectNode({ schema: editor.schema }, n2) }); } function hasPath(editor, path2) { return hasNode(editor, path2, editor.schema); } function node(editor, at, options = {}) { const nodePath = path(editor, at, options); return [getNode(editor, nodePath, editor.schema), nodePath]; } function pathHasPrevious(path2) { return path2[path2.length - 1] > 0; } function pointEquals(point2, another) { return point2.offset === another.offset && pathEquals(point2.path, another.path); } function isCollapsedRange(range2) { const { anchor, focus } = range2; return pointEquals(anchor, focus); } function unhangRange(editor, range2, options = {}) { const { includeObjectNodes = !1 } = options; let [start$1, end2] = rangeEdges(range2); if (start$1.offset !== 0 || end2.offset !== 0 || isCollapsedRange(range2) || pathHasPrevious(end2.path)) return range2; const endBlock = above(editor, { at: end2, match: (n2) => isTextBlock({ schema: editor.schema }, n2) }), blockPath = endBlock ? endBlock[1] : [], before2 = { anchor: start(editor, start$1), focus: end2 }; let skip = !0; for (const [node2, path2] of nodes(editor, { at: before2, match: (n2) => isSpan({ schema: editor.schema }, n2), reverse: !0, includeObjectNodes })) { if (skip) { skip = !1; continue; } if (node2.text !== "" || isBeforePath(path2, blockPath)) { end2 = { path: path2, offset: node2.text.length }; break; } } return { anchor: start$1, focus: end2 }; } function isExpandedRange(range2) { return !isCollapsedRange(range2); } function isForwardRange(range2) { return !isBackwardRange(range2); } const DOMText = globalThis.Text, getDefaultView = (value) => value && value.ownerDocument && value.ownerDocument.defaultView || null, isDOMComment = (value) => isDOMNode(value) && value.nodeType === 8, isDOMElement = (value) => isDOMNode(value) && value.nodeType === 1, isDOMNode = (value) => { const window2 = getDefaultView(value); return !!window2 && value instanceof window2.Node; }, isDOMSelection = (value) => { const window2 = value && value.anchorNode && getDefaultView(value.anchorNode); return !!window2 && value instanceof window2.Selection; }, isPlainTextOnlyPaste = (event) => event.clipboardData && event.clipboardData.getData("text/plain") !== "" && event.clipboardData.types.length === 1, normalizeDOMPoint = (domPoint) => { let [node2, offset] = domPoint; if (isDOMElement(node2) && node2.childNodes.length) { let isLast = offset === node2.childNodes.length, index = isLast ? offset - 1 : offset; for ([node2, index] = getEditableChildAndIndex(node2, index, isLast ? "backward" : "forward"), isLast = index < offset; isDOMElement(node2) && node2.childNodes.length; ) { const i = isLast ? node2.childNodes.length - 1 : 0; node2 = getEditableChild(node2, i, isLast ? "backward" : "forward"); } offset = isLast && node2.textContent != null ? node2.textContent.length : 0; } return [node2, offset]; }, hasShadowRoot = (node2) => { let parent2 = node2 && node2.parentNode; for (; parent2; ) { if (parent2.toString() === "[object ShadowRoot]") return !0; parent2 = parent2.parentNode; } return !1; }, getEditableChildAndIndex = (parent2, index, direction) => { const { childNodes } = parent2; let child = childNodes[index], i = index, triedForward = !1, triedBackward = !1; for (; (isDOMComment(child) || isDOMElement(child) && child.childNodes.length === 0 || isDOMElement(child) && child.getAttribute("contenteditable") === "false") && !(triedForward && triedBackward); ) { if (i >= childNodes.length) { triedForward = !0, i = index - 1, direction = "backward"; continue; } if (i < 0) { triedBackward = !0, i = index + 1, direction = "forward"; continue; } child = childNodes[i], index = i, i += direction === "forward" ? 1 : -1; } return [child, index]; }, getEditableChild = (parent2, index, direction) => { const [child] = getEditableChildAndIndex(parent2, index, direction); return child; }, getSelection = (root) => "getSelection" in root && typeof root.getSelection == "function" ? root.getSelection() : document.getSelection(), isTrackedMutation = (editor, mutation, batch) => { const { target } = mutation; if (isDOMElement(target) && target.matches('[contentEditable="false"]')) return !1; const { document: document2 } = DOMEditor.getWindow(editor); if (containsShadowAware(document2, target)) return DOMEditor.hasDOMNode(editor, target, { editable: !0 }); const parentMutation = batch.find(({ addedNodes, removedNodes }) => { for (const node2 of addedNodes) if (node2 === target || containsShadowAware(node2, target)) return !0; for (const node2 of removedNodes) if (node2 === target || containsShadowAware(node2, target)) return !0; return !1; }); return !parentMutation || parentMutation === mutation ? !1 : isTrackedMutation(editor, parentMutation, batch); }, getActiveElement = () => { let activeElement = document.activeElement; for (; activeElement?.shadowRoot && activeElement.shadowRoot?.activeElement; ) activeElement = activeElement?.shadowRoot?.activeElement; return activeElement; }, isBefore = (node2, otherNode) => !!(node2.compareDocumentPosition(otherNode) & Node.DOCUMENT_POSITION_PRECEDING), isAfter = (node2, otherNode) => !!(node2.compareDocumentPosition(otherNode) & Node.DOCUMENT_POSITION_FOLLOWING), closestShadowAware = (element, selector) => { if (!element) return null; let current = element; for (; current; ) { if (current.matches && current.matches(selector)) return current; if (current.parentElement) current = current.parentElement; else if (current.parentNode && "host" in current.parentNode) current = current.parentNode.host; else return null; } return null; }, containsShadowAware = (parent2, child) => { if (!parent2 || !child) return !1; if (parent2.contains(child)) return !0; let current = child; for (; current; ) { if (current === parent2) return !0; if (current.parentNode) "host" in current.parentNode ? current = current.parentNode.host : current = current.parentNode; else return !1; } return !1; }, IS_IOS = typeof navigator < "u" && typeof window < "u" && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream, IS_ANDROID = typeof navigator < "u" && /Android/.test(navigator.userAgent), IS_FIREFOX = typeof navigator < "u" && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent), IS_WEBKIT = typeof navigator < "u" && /AppleWebKit(?!.*Chrome)/i.test(navigator.userAgent), IS_EDGE_LEGACY = typeof navigator < "u" && /Edge?\/(?:[0-6][0-9]|[0-7][0-8])(?:\.)/i.test(navigator.userAgent), IS_CHROME = typeof navigator < "u" && /Chrome/i.test(navigator.userAgent), IS_CHROME_LEGACY = typeof navigator < "u" && /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])(?:\.)/i.test(navigator.userAgent), IS_ANDROID_CHROME_LEGACY = IS_ANDROID && typeof navigator < "u" && /Chrome?\/(?:[0-5]?\d)(?:\.)/i.test(navigator.userAgent), IS_FIREFOX_LEGACY = typeof navigator < "u" && /^(?!.*Seamonkey)(?=.*Firefox\/(?:[0-7][0-9]|[0-8][0-6])(?:\.)).*/i.test(navigator.userAgent), IS_UC_MOBILE = typeof navigator < "u" && /.*UCBrowser/.test(navigator.userAgent), IS_WECHATBROWSER = typeof navigator < "u" && /.*Wechat/.test(navigator.userAgent) && !/.*MacWechat/.test(navigator.userAgent) && // avoid lookbehind (buggy in safari < 16.4) (!IS_CHROME || IS_CHROME_LEGACY), CAN_USE_DOM = typeof window < "u" && typeof window.document < "u" && typeof window.document.createElement < "u", HAS_BEFORE_INPUT_SUPPORT = (!IS_CHROME_LEGACY || !IS_ANDROID_CHROME_LEGACY) && !IS_EDGE_LEGACY && // globalThis is undefined in older browsers typeof globalThis < "u" && globalThis.InputEvent && typeof globalThis.InputEvent.prototype.getTargetRanges == "function"; let n = 0; class Key { constructor() { this.id = `${n++}`; } } const DOMEditor = { blur: (editor) => { const el = DOMEditor.toDOMNode(editor, editor), root = DOMEditor.findDocumentOrShadowRoot(editor); editor.focused = !1, root.activeElement === el && el.blur(); }, findDocumentOrShadowRoot: (editor) => { const el = DOMEditor.toDOMNode(editor, editor), root = el.getRootNode(); return root instanceof Document || root instanceof ShadowRoot ? root : el.ownerDocument; }, findEventRange: (editor, event) => { "nativeEvent" in event && (event = event.nativeEvent); const { clientX: x, clientY: y, target } = event; if (x == null || y == null) throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`); const node2 = DOMEditor.toSlateNode(editor, event.target), path2 = DOMEditor.findPath(editor, node2); if (isObjectNode({ schema: editor.schema }, node2)) { const rect = target.getBoundingClientRect(), isPrev = path2.length > 1 ? x - rect.left < rect.left + rect.width - x : y - rect.top < rect.top + rect.height - y, edge = point(editor, path2, { edge: isPrev ? "start" : "end" }), point$1 = isPrev ? before(editor, edge) : after(editor, edge); if (point$1) return range(editor, point$1); } let domRange = null; const { document: document2 } = DOMEditor.getWindow(editor); if (document2.caretRangeFromPoint) domRange = document2.caretRangeFromPoint(x, y); else { const position = document2.caretPositionFromPoint(x, y); position && (domRange = document2.createRange(), domRange.setStart(position.offsetNode, position.offset), domRange.setEnd(position.offsetNode, position.offset)); } if (!domRange) throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`); return DOMEditor.toSlateRange(editor, domRange, { exactMatch: !1, suppressThrow: !1 }); }, findKey: (editor, node2) => { let key = editor.nodeToKey.get(node2); return key || (key = new Key(), editor.nodeToKey.set(node2, key)), key; }, findPath: (editor, node2) => { const path2 = []; let child = node2; for (; ; ) { const parent2 = editor.nodeToParent.get(child); if (parent2 == null) { if (isEditor(child)) return path2; break; } const i = editor.nodeToIndex.get(child); if (i == null) break; path2.unshift(i), child = parent2; } throw new Error(`Unable to find the path for Slate node: ${safeStringify(node2)}`); }, focus: (editor, options = { retries: 5 }) => { if (editor.focused || !editor.domElement) return; if (options.retries <= 0) throw new Error("Could not set focus, editor seems stuck with pending operations"); if (editor.operations.length > 0) { setTimeout(() => { DOMEditor.focus(editor, { retries: options.retries - 1 }); }, 10); return; } const el = DOMEditor.toDOMNode(editor, editor), root = DOMEditor.findDocumentOrShadowRoot(editor); if (root.activeElement !== el) { if (editor.selection && root instanceof Document) { const domSelection = getSelection(root), domRange = DOMEditor.toDOMRange(editor, editor.selection); domSelection?.removeAllRanges(), domSelection?.addRange(domRange); } editor.selection || editor.select(start(editor, [])), editor.focused = !0, el.focus({ preventScroll: !0 }); } }, getWindow: (editor) => { const window2 = editor.domWindow; if (!window2) throw new Error("Unable to find a host window element for this editor"); return window2; }, hasDOMNode: (editor, target, options = {}) => { const { editable = !1 } = options, editorEl = DOMEditor.toDOMNode(editor, editor); let targetEl = null; try { targetEl = isDOMElement(target) ? target : target.parentElement; } catch (err) { if (err instanceof Error && !err.message.includes('Permission denied to access property "nodeType"')) throw err; } return targetEl ? closestShadowAware(targetEl, "[data-slate-editor]") === editorEl && (!editable || targetEl.isContentEditable ? !0 : typeof targetEl.isContentEditable == "boolean" && // isContentEditable exists only on HTMLElement, and on other nodes it will be undefined // this is the core logic that lets you know you got the right editor.selection instead of null when editor is contenteditable="false"(readOnly) closestShadowAware(targetEl, '[contenteditable="false"]') === editorEl || !!targetEl.getAttribute("data-slate-zero-width")) : !1; }, hasEditableTarget: (editor, target) => isDOMNode(target) && DOMEditor.hasDOMNode(editor, target, { editable: !0 }), hasRange: (editor, range2) => { const { anchor, focus } = range2; return hasPath(editor, anchor.path) && hasPath(editor, focus.path); }, hasSelectableTarget: (editor, target) => DOMEditor.hasEditableTarget(editor, target) || DOMEditor.isTargetInsideNonReadonlyVoid(editor, target), hasTarget: (editor, target) => isDOMNode(target) && DOMEditor.hasDOMNode(editor, target), isComposing: (editor) => !!editor.composing, isFocused: (editor) => !!editor.focused, isTargetInsideNonReadonlyVoid: (editor, target) => { if (editor.readOnly) return !1; const slateNode = DOMEditor.hasTarget(editor, target) && DOMEditor.toSlateNode(editor, target); return !!slateNode && isObjectNode({ schema: editor.schema }, slateNode); }, toDOMNode: (editor, node2) => { const domNode = isEditor(node2) ? editor.domElement : editor.keyToElement?.get(DOMEditor.findKey(editor, node2)); if (!domNode) throw new Error(`Cannot resolve a DOM node from Slate node: ${safeStringify(node2)}`); return domNode; }, toDOMPoint: (editor, point2) => { const [node$1] = node(editor, point2.path), el = DOMEditor.toDOMNode(editor, node$1); let domPoint; if (isObjectNode({ schema: editor.schema }, node$1)) { const spacer = el.querySele