@portabletext/editor
Version:
Portable Text Editor made in React
1,034 lines • 714 kB
JavaScript
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