@trafica/editor 1.0.32 → 1.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +1060 -345
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1062 -347
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useSyncExternalStore, useRef, useCallback, useState, useEffect, useLayoutEffect, useMemo } from 'react';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { createPortal } from 'react-dom';
|
|
4
4
|
|
|
5
5
|
// src/editor/core/DocumentModel.ts
|
|
@@ -1633,38 +1633,47 @@ var htmlSerializer = {
|
|
|
1633
1633
|
return parseHTMLBody(parsed.body);
|
|
1634
1634
|
}
|
|
1635
1635
|
};
|
|
1636
|
+
function alignAttrs(align, extraStyles = "") {
|
|
1637
|
+
const dataAlign = align ? ` data-align="${align}"` : "";
|
|
1638
|
+
const textAlign = align && align !== "left" ? `text-align:${align};` : "";
|
|
1639
|
+
const combined = textAlign + extraStyles;
|
|
1640
|
+
const style = combined ? ` style="${combined}"` : "";
|
|
1641
|
+
return dataAlign + style;
|
|
1642
|
+
}
|
|
1636
1643
|
function serializeBlock(node, idCounts = /* @__PURE__ */ new Map(), inCell = false) {
|
|
1637
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A;
|
|
1644
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B;
|
|
1638
1645
|
switch (node.type) {
|
|
1639
1646
|
case "paragraph": {
|
|
1640
|
-
const align = (
|
|
1641
|
-
const
|
|
1642
|
-
return `<p${align}
|
|
1647
|
+
const align = (_a = node.attrs) == null ? void 0 : _a.align;
|
|
1648
|
+
const extra = inCell ? "margin:0;min-height:1.2em;" : "";
|
|
1649
|
+
return `<p${alignAttrs(align, extra)}>${serializeChildren(node.children)}</p>`;
|
|
1643
1650
|
}
|
|
1644
1651
|
case "heading": {
|
|
1645
1652
|
const l = (_c = (_b = node.attrs) == null ? void 0 : _b.level) != null ? _c : 1;
|
|
1646
|
-
const align = (
|
|
1653
|
+
const align = (_d = node.attrs) == null ? void 0 : _d.align;
|
|
1647
1654
|
const rawText = node.children.filter((c) => "text" in c).map((c) => c.text).join("");
|
|
1648
1655
|
const base = slugify(rawText) || `heading-${l}`;
|
|
1649
1656
|
const count = (_e = idCounts.get(base)) != null ? _e : 0;
|
|
1650
1657
|
idCounts.set(base, count + 1);
|
|
1651
1658
|
const id = count === 0 ? base : `${base}-${count}`;
|
|
1652
|
-
return `<h${l} id="${id}"${align}>${serializeChildren(node.children)}</h${l}>`;
|
|
1659
|
+
return `<h${l} id="${id}"${alignAttrs(align)}>${serializeChildren(node.children)}</h${l}>`;
|
|
1653
1660
|
}
|
|
1654
1661
|
case "blockquote": {
|
|
1655
|
-
const align = (
|
|
1656
|
-
return `<blockquote${align}>${serializeChildren(node.children)}</blockquote>`;
|
|
1662
|
+
const align = (_f = node.attrs) == null ? void 0 : _f.align;
|
|
1663
|
+
return `<blockquote${alignAttrs(align)}>${serializeChildren(node.children)}</blockquote>`;
|
|
1657
1664
|
}
|
|
1658
1665
|
case "bullet_list":
|
|
1659
1666
|
return `<ul>${serializeChildren(node.children)}</ul>`;
|
|
1660
1667
|
case "ordered_list":
|
|
1661
1668
|
return `<ol>${serializeChildren(node.children)}</ol>`;
|
|
1662
|
-
case "list_item":
|
|
1663
|
-
|
|
1669
|
+
case "list_item": {
|
|
1670
|
+
const align = (_g = node.attrs) == null ? void 0 : _g.align;
|
|
1671
|
+
return `<li${alignAttrs(align)}>${serializeChildren(node.children)}</li>`;
|
|
1672
|
+
}
|
|
1664
1673
|
case "check_list":
|
|
1665
1674
|
return `<ul class="todo-list" data-type="checklist">${serializeChildren(node.children)}</ul>`;
|
|
1666
1675
|
case "check_list_item": {
|
|
1667
|
-
const checked = !!((
|
|
1676
|
+
const checked = !!((_h = node.attrs) == null ? void 0 : _h.checked);
|
|
1668
1677
|
const dataChecked = checked ? ' data-checked="true"' : "";
|
|
1669
1678
|
const itemClass = `todo-list__item${checked ? " todo-list__item_checked" : ""}`;
|
|
1670
1679
|
const checkedAttr = checked ? ' checked="checked"' : "";
|
|
@@ -1672,16 +1681,16 @@ function serializeBlock(node, idCounts = /* @__PURE__ */ new Map(), inCell = fal
|
|
|
1672
1681
|
return `<li class="${itemClass}"${dataChecked}><label class="todo-list__label"><input type="checkbox" disabled="disabled"${checkedAttr}><span class="todo-list__label__description">${innerContent}</span></label></li>`;
|
|
1673
1682
|
}
|
|
1674
1683
|
case "code_block": {
|
|
1675
|
-
const lang = ((
|
|
1684
|
+
const lang = ((_i = node.attrs) == null ? void 0 : _i.language) ? ` class="language-${node.attrs.language}"` : "";
|
|
1676
1685
|
const raw = node.children.map((c) => isTextNode(c) ? escapeHTML(c.text) : "").join("");
|
|
1677
1686
|
return `<pre><code${lang}>${raw}</code></pre>`;
|
|
1678
1687
|
}
|
|
1679
1688
|
case "image": {
|
|
1680
|
-
const src = escapeAttr((
|
|
1681
|
-
const alt = escapeAttr((
|
|
1682
|
-
const width = ((
|
|
1683
|
-
const align = ((
|
|
1684
|
-
const caption = ((
|
|
1689
|
+
const src = escapeAttr((_k = (_j = node.attrs) == null ? void 0 : _j.src) != null ? _k : "");
|
|
1690
|
+
const alt = escapeAttr((_m = (_l = node.attrs) == null ? void 0 : _l.alt) != null ? _m : "");
|
|
1691
|
+
const width = ((_n = node.attrs) == null ? void 0 : _n.width) ? ` width="${node.attrs.width}"` : "";
|
|
1692
|
+
const align = ((_o = node.attrs) == null ? void 0 : _o.align) ? ` data-align="${node.attrs.align}"` : "";
|
|
1693
|
+
const caption = ((_p = node.attrs) == null ? void 0 : _p.caption) ? escapeHTML(node.attrs.caption) : "";
|
|
1685
1694
|
if (caption) {
|
|
1686
1695
|
return `<figure${align}><img src="${src}" alt="${alt}"${width} /><figcaption>${caption}</figcaption></figure>`;
|
|
1687
1696
|
}
|
|
@@ -1691,7 +1700,7 @@ function serializeBlock(node, idCounts = /* @__PURE__ */ new Map(), inCell = fal
|
|
|
1691
1700
|
return "<hr />";
|
|
1692
1701
|
case "table": {
|
|
1693
1702
|
const rows = node.children.map((c) => serializeBlock(c)).join("");
|
|
1694
|
-
const colWidths = (
|
|
1703
|
+
const colWidths = (_r = (_q = node.attrs) == null ? void 0 : _q.colWidths) != null ? _r : [];
|
|
1695
1704
|
let colgroup = "";
|
|
1696
1705
|
if (colWidths.length > 0) {
|
|
1697
1706
|
const total = colWidths.reduce((s, w) => s + w, 0) || colWidths.length * 120;
|
|
@@ -1704,15 +1713,15 @@ function serializeBlock(node, idCounts = /* @__PURE__ */ new Map(), inCell = fal
|
|
|
1704
1713
|
return `<tr>${cells}</tr>`;
|
|
1705
1714
|
}
|
|
1706
1715
|
case "table_cell": {
|
|
1707
|
-
if ((
|
|
1708
|
-
const cs = ((
|
|
1709
|
-
const rs = ((
|
|
1716
|
+
if ((_s = node.attrs) == null ? void 0 : _s.covered) return "";
|
|
1717
|
+
const cs = ((_t = node.attrs) == null ? void 0 : _t.colspan) > 1 ? ` colspan="${(_u = node.attrs) == null ? void 0 : _u.colspan}"` : "";
|
|
1718
|
+
const rs = ((_v = node.attrs) == null ? void 0 : _v.rowspan) > 1 ? ` rowspan="${(_w = node.attrs) == null ? void 0 : _w.rowspan}"` : "";
|
|
1710
1719
|
return `<td${cs}${rs} style="border:1px solid #d1d5db;padding:0.5em 0.75em;vertical-align:top;min-width:40px;word-break:break-word;">${node.children.map((c) => serializeBlock(c, /* @__PURE__ */ new Map(), true)).join("")}</td>`;
|
|
1711
1720
|
}
|
|
1712
1721
|
case "table_header": {
|
|
1713
|
-
if ((
|
|
1714
|
-
const cs = ((
|
|
1715
|
-
const rs = ((
|
|
1722
|
+
if ((_x = node.attrs) == null ? void 0 : _x.covered) return "";
|
|
1723
|
+
const cs = ((_y = node.attrs) == null ? void 0 : _y.colspan) > 1 ? ` colspan="${(_z = node.attrs) == null ? void 0 : _z.colspan}"` : "";
|
|
1724
|
+
const rs = ((_A = node.attrs) == null ? void 0 : _A.rowspan) > 1 ? ` rowspan="${(_B = node.attrs) == null ? void 0 : _B.rowspan}"` : "";
|
|
1716
1725
|
return `<th${cs}${rs} style="border:1px solid #d1d5db;padding:0.5em 0.75em;vertical-align:top;min-width:40px;word-break:break-word;background:#f9fafb;font-weight:600;text-align:left;">${node.children.map((c) => serializeBlock(c, /* @__PURE__ */ new Map(), true)).join("")}</th>`;
|
|
1717
1726
|
}
|
|
1718
1727
|
default:
|
|
@@ -7831,7 +7840,7 @@ var jsonSerializer = {
|
|
|
7831
7840
|
}
|
|
7832
7841
|
}
|
|
7833
7842
|
};
|
|
7834
|
-
function
|
|
7843
|
+
function Editor({
|
|
7835
7844
|
engine,
|
|
7836
7845
|
placeholder = "Start writing...",
|
|
7837
7846
|
className = "",
|
|
@@ -7839,14 +7848,11 @@ function EditorCore({
|
|
|
7839
7848
|
onHTMLChange,
|
|
7840
7849
|
onJSONChange,
|
|
7841
7850
|
onOpenLinkPopup,
|
|
7842
|
-
onUploadImage: _onUploadImage
|
|
7843
|
-
onFocus: onFocusProp,
|
|
7844
|
-
onBlur: onBlurProp,
|
|
7845
|
-
hideToolbar = false,
|
|
7846
|
-
toolbarConfig
|
|
7851
|
+
onUploadImage: _onUploadImage
|
|
7847
7852
|
}) {
|
|
7848
7853
|
const containerRef = useRef(null);
|
|
7849
7854
|
const isRenderingRef = useRef(false);
|
|
7855
|
+
const skipRestoreSelectionRef = useRef(false);
|
|
7850
7856
|
const scrollCaretIntoView = useCallback(() => {
|
|
7851
7857
|
var _a, _b;
|
|
7852
7858
|
const sel = window.getSelection();
|
|
@@ -7959,8 +7965,14 @@ function EditorCore({
|
|
|
7959
7965
|
useLayoutEffect(() => {
|
|
7960
7966
|
const container = containerRef.current;
|
|
7961
7967
|
if (!container || !state.selection) return;
|
|
7968
|
+
if (skipRestoreSelectionRef.current) {
|
|
7969
|
+
skipRestoreSelectionRef.current = false;
|
|
7970
|
+
return;
|
|
7971
|
+
}
|
|
7972
|
+
isRenderingRef.current = true;
|
|
7962
7973
|
restoreSelection(container, state.selection);
|
|
7963
7974
|
scrollCaretIntoView();
|
|
7975
|
+
isRenderingRef.current = false;
|
|
7964
7976
|
}, [state.selection]);
|
|
7965
7977
|
useEffect(() => {
|
|
7966
7978
|
const container = containerRef.current;
|
|
@@ -8025,6 +8037,7 @@ function EditorCore({
|
|
|
8025
8037
|
if (currentSelection && JSON.stringify(currentSelection.anchor) === JSON.stringify(captured.anchor) && JSON.stringify(currentSelection.focus) === JSON.stringify(captured.focus)) {
|
|
8026
8038
|
return;
|
|
8027
8039
|
}
|
|
8040
|
+
skipRestoreSelectionRef.current = true;
|
|
8028
8041
|
const tr = createTransaction();
|
|
8029
8042
|
tr.steps.push(tr_setSelection(captured));
|
|
8030
8043
|
engine.dispatch(tr);
|
|
@@ -8051,11 +8064,7 @@ function EditorCore({
|
|
|
8051
8064
|
);
|
|
8052
8065
|
engine.dispatch(tr);
|
|
8053
8066
|
}
|
|
8054
|
-
|
|
8055
|
-
}, [engine, onFocusProp]);
|
|
8056
|
-
const handleBlur = useCallback(() => {
|
|
8057
|
-
onBlurProp == null ? void 0 : onBlurProp();
|
|
8058
|
-
}, [onBlurProp]);
|
|
8067
|
+
}, [engine]);
|
|
8059
8068
|
const handleKeyDown = useCallback(
|
|
8060
8069
|
(e) => {
|
|
8061
8070
|
var _a, _b, _c;
|
|
@@ -8407,6 +8416,7 @@ function EditorCore({
|
|
|
8407
8416
|
if (!container) return;
|
|
8408
8417
|
const selection = captureSelection(container);
|
|
8409
8418
|
if (!selection) return;
|
|
8419
|
+
skipRestoreSelectionRef.current = true;
|
|
8410
8420
|
const tr = createTransaction();
|
|
8411
8421
|
tr.steps.push(
|
|
8412
8422
|
tr_setSelection(selection)
|
|
@@ -8489,7 +8499,7 @@ function EditorCore({
|
|
|
8489
8499
|
className: `editor-root relative flex flex-col ${className}`,
|
|
8490
8500
|
style: editorHeight ? { minHeight: editorHeight } : void 0,
|
|
8491
8501
|
children: [
|
|
8492
|
-
!readOnly &&
|
|
8502
|
+
!readOnly && /* @__PURE__ */ jsx(
|
|
8493
8503
|
Toolbar,
|
|
8494
8504
|
{
|
|
8495
8505
|
engine,
|
|
@@ -8500,8 +8510,7 @@ function EditorCore({
|
|
|
8500
8510
|
linkPopupOpen,
|
|
8501
8511
|
onLinkPopupClose: () => setLinkPopupOpen(false),
|
|
8502
8512
|
isSourceMode,
|
|
8503
|
-
onToggleSource: handleToggleSource
|
|
8504
|
-
toolbarConfig
|
|
8513
|
+
onToggleSource: handleToggleSource
|
|
8505
8514
|
}
|
|
8506
8515
|
),
|
|
8507
8516
|
/* @__PURE__ */ jsx("div", { className: "relative", children: isSourceMode ? /* @__PURE__ */ jsx(
|
|
@@ -8528,7 +8537,7 @@ function EditorCore({
|
|
|
8528
8537
|
isVisualEmpty && /* @__PURE__ */ jsx(
|
|
8529
8538
|
"div",
|
|
8530
8539
|
{
|
|
8531
|
-
className: "\r\n absolute\r\n top-6\r\n left-6\r\n pointer-events-none\r\n select-none\r\n text-base\r\n text-gray-400\r\n \r\n ",
|
|
8540
|
+
className: "\r\n absolute\r\n top-6\r\n left-6\r\n pointer-events-none\r\n select-none\r\n text-base\r\n text-gray-400\r\n dark:text-gray-500\r\n ",
|
|
8532
8541
|
"aria-hidden": "true",
|
|
8533
8542
|
children: placeholder
|
|
8534
8543
|
}
|
|
@@ -8546,7 +8555,6 @@ function EditorCore({
|
|
|
8546
8555
|
onMouseDown: handleMouseDown,
|
|
8547
8556
|
onContextMenu: handleContextMenu,
|
|
8548
8557
|
onFocus: handleFocus,
|
|
8549
|
-
onBlur: handleBlur,
|
|
8550
8558
|
onClick: handleClick,
|
|
8551
8559
|
onKeyDown: handleKeyDown,
|
|
8552
8560
|
className: [
|
|
@@ -8558,7 +8566,7 @@ function EditorCore({
|
|
|
8558
8566
|
"text-base",
|
|
8559
8567
|
"leading-relaxed",
|
|
8560
8568
|
"text-gray-900",
|
|
8561
|
-
"",
|
|
8569
|
+
"dark:text-gray-100",
|
|
8562
8570
|
readOnly ? "cursor-default" : "cursor-text"
|
|
8563
8571
|
].join(" ")
|
|
8564
8572
|
}
|
|
@@ -8568,7 +8576,7 @@ function EditorCore({
|
|
|
8568
8576
|
{
|
|
8569
8577
|
role: "tooltip",
|
|
8570
8578
|
style: { left: linkTooltip.x, top: linkTooltip.y },
|
|
8571
|
-
className: "absolute z-50 pointer-events-none flex items-center gap-1.5 bg-gray-900
|
|
8579
|
+
className: "absolute z-50 pointer-events-none flex items-center gap-1.5 bg-gray-900 dark:bg-gray-700 text-white text-xs px-2.5 py-1.5 rounded shadow-lg max-w-xs",
|
|
8572
8580
|
children: [
|
|
8573
8581
|
/* @__PURE__ */ jsxs("svg", { width: "11", height: "11", viewBox: "0 0 16 16", fill: "none", className: "shrink-0 opacity-70", "aria-hidden": "true", children: [
|
|
8574
8582
|
/* @__PURE__ */ jsx("path", { d: "M6.5 3.5H4A2.5 2.5 0 0 0 4 8.5h2", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
|
|
@@ -8683,168 +8691,1020 @@ function prettyPrintHTML(html) {
|
|
|
8683
8691
|
}
|
|
8684
8692
|
return result.join("\n");
|
|
8685
8693
|
}
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
|
|
8730
|
-
return caretRect.top < containerRect.top + lineHeight;
|
|
8731
|
-
} else {
|
|
8732
|
-
return caretRect.bottom > containerRect.bottom - lineHeight;
|
|
8733
|
-
}
|
|
8734
|
-
}
|
|
8735
|
-
var TablePlugin = {
|
|
8736
|
-
name: "table",
|
|
8737
|
-
keyBindings: {
|
|
8738
|
-
Tab: (engine) => {
|
|
8739
|
-
var _a;
|
|
8740
|
-
const state = engine.getState();
|
|
8741
|
-
const sel = state.selection;
|
|
8742
|
-
if (!sel) return false;
|
|
8743
|
-
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
8744
|
-
if (!cellPos) return false;
|
|
8745
|
-
const { tablePath, row, col } = cellPos;
|
|
8746
|
-
const table = getNodeAtPath(state.doc, tablePath);
|
|
8747
|
-
const { rows, cols } = getTableDimensions(table);
|
|
8748
|
-
let nextRow = row;
|
|
8749
|
-
let nextCol = col + 1;
|
|
8750
|
-
while (nextRow < rows) {
|
|
8751
|
-
if (nextCol >= cols) {
|
|
8752
|
-
nextCol = 0;
|
|
8753
|
-
nextRow++;
|
|
8754
|
-
continue;
|
|
8755
|
-
}
|
|
8756
|
-
const c = getNodeAtPath(state.doc, [...tablePath, nextRow, nextCol]);
|
|
8757
|
-
if (!((_a = c == null ? void 0 : c.attrs) == null ? void 0 : _a.covered)) break;
|
|
8758
|
-
nextCol++;
|
|
8759
|
-
}
|
|
8760
|
-
if (nextRow >= rows) {
|
|
8761
|
-
const newTable = insertTableRowAfter(table, rows - 1);
|
|
8762
|
-
const newChildren = [...state.doc.children];
|
|
8763
|
-
newChildren[tablePath[0]] = newTable;
|
|
8764
|
-
const tempDoc = { type: "doc", children: newChildren };
|
|
8765
|
-
const tr2 = createTransaction();
|
|
8766
|
-
tr2.steps.push({ type: "delete_node", path: tablePath });
|
|
8767
|
-
tr2.steps.push({
|
|
8768
|
-
type: "insert_node",
|
|
8769
|
-
parentPath: tablePath.length > 1 ? tablePath.slice(0, -1) : [],
|
|
8770
|
-
index: tablePath[tablePath.length - 1],
|
|
8771
|
-
node: newTable
|
|
8772
|
-
});
|
|
8773
|
-
const pos2 = getCellFirstPosition(tempDoc, tablePath, rows, 0);
|
|
8774
|
-
if (pos2) tr2.steps.push(tr_setSelection(makeCollapsedSelection(pos2)));
|
|
8775
|
-
engine.dispatch(tr2);
|
|
8776
|
-
return true;
|
|
8694
|
+
function EditorCore({
|
|
8695
|
+
engine,
|
|
8696
|
+
placeholder = "Start writing...",
|
|
8697
|
+
className = "",
|
|
8698
|
+
readOnly = false,
|
|
8699
|
+
onHTMLChange,
|
|
8700
|
+
onJSONChange,
|
|
8701
|
+
onOpenLinkPopup,
|
|
8702
|
+
onUploadImage: _onUploadImage,
|
|
8703
|
+
onFocus: onFocusProp,
|
|
8704
|
+
onBlur: onBlurProp,
|
|
8705
|
+
hideToolbar = false,
|
|
8706
|
+
toolbarConfig
|
|
8707
|
+
}) {
|
|
8708
|
+
const containerRef = useRef(null);
|
|
8709
|
+
const isRenderingRef = useRef(false);
|
|
8710
|
+
const scrollCaretIntoView = useCallback(() => {
|
|
8711
|
+
var _a, _b;
|
|
8712
|
+
const sel = window.getSelection();
|
|
8713
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
8714
|
+
const range = sel.getRangeAt(0).cloneRange();
|
|
8715
|
+
range.collapse(true);
|
|
8716
|
+
const caretRect = range.getBoundingClientRect();
|
|
8717
|
+
let rect = caretRect;
|
|
8718
|
+
if (!rect || rect.top === 0 && rect.bottom === 0 && rect.left === 0) {
|
|
8719
|
+
const node = range.startContainer;
|
|
8720
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
8721
|
+
if (el) rect = el.getBoundingClientRect();
|
|
8722
|
+
}
|
|
8723
|
+
if (!rect || rect.bottom === 0) return;
|
|
8724
|
+
let scrollEl = (_b = (_a = containerRef.current) == null ? void 0 : _a.parentElement) != null ? _b : null;
|
|
8725
|
+
while (scrollEl) {
|
|
8726
|
+
const style = window.getComputedStyle(scrollEl);
|
|
8727
|
+
const overflow = style.overflow + style.overflowY;
|
|
8728
|
+
if (/auto|scroll/.test(overflow)) break;
|
|
8729
|
+
scrollEl = scrollEl.parentElement;
|
|
8730
|
+
}
|
|
8731
|
+
const PADDING = 24;
|
|
8732
|
+
if (scrollEl) {
|
|
8733
|
+
const containerRect = scrollEl.getBoundingClientRect();
|
|
8734
|
+
if (rect.bottom > containerRect.bottom - PADDING) {
|
|
8735
|
+
scrollEl.scrollBy({ top: rect.bottom - containerRect.bottom + PADDING, behavior: "smooth" });
|
|
8736
|
+
} else if (rect.top < containerRect.top + PADDING) {
|
|
8737
|
+
scrollEl.scrollBy({ top: rect.top - containerRect.top - PADDING, behavior: "smooth" });
|
|
8777
8738
|
}
|
|
8778
|
-
|
|
8779
|
-
if (
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
return true;
|
|
8784
|
-
},
|
|
8785
|
-
"ArrowRight": (engine) => {
|
|
8786
|
-
var _a;
|
|
8787
|
-
const state = engine.getState();
|
|
8788
|
-
const sel = state.selection;
|
|
8789
|
-
if (!sel) return false;
|
|
8790
|
-
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
8791
|
-
if (!cellPos) return false;
|
|
8792
|
-
const { tablePath, row, col } = cellPos;
|
|
8793
|
-
const cellPath = [...tablePath, row, col];
|
|
8794
|
-
const cellEl = getCellDOMElement(JSON.stringify(cellPath));
|
|
8795
|
-
if (!cellEl || !isCaretAtContainerEnd(cellEl)) return false;
|
|
8796
|
-
const table = getNodeAtPath(state.doc, tablePath);
|
|
8797
|
-
const { rows, cols } = getTableDimensions(table);
|
|
8798
|
-
let nextRow = row;
|
|
8799
|
-
let nextCol = col + 1;
|
|
8800
|
-
while (nextRow < rows) {
|
|
8801
|
-
if (nextCol >= cols) {
|
|
8802
|
-
nextCol = 0;
|
|
8803
|
-
nextRow++;
|
|
8804
|
-
continue;
|
|
8805
|
-
}
|
|
8806
|
-
const c = getNodeAtPath(state.doc, [...tablePath, nextRow, nextCol]);
|
|
8807
|
-
if (!((_a = c == null ? void 0 : c.attrs) == null ? void 0 : _a.covered)) break;
|
|
8808
|
-
nextCol++;
|
|
8739
|
+
} else {
|
|
8740
|
+
if (rect.bottom > window.innerHeight - PADDING) {
|
|
8741
|
+
window.scrollBy({ top: rect.bottom - window.innerHeight + PADDING, behavior: "smooth" });
|
|
8742
|
+
} else if (rect.top < PADDING) {
|
|
8743
|
+
window.scrollBy({ top: rect.top - PADDING, behavior: "smooth" });
|
|
8809
8744
|
}
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8745
|
+
}
|
|
8746
|
+
}, []);
|
|
8747
|
+
const isComposingRef = useRef(false);
|
|
8748
|
+
const stateRef = useRef(engine.getState());
|
|
8749
|
+
const [selectedImagePath, setSelectedImagePath] = useState(null);
|
|
8750
|
+
const [findReplaceOpen, setFindReplaceOpen] = useState(false);
|
|
8751
|
+
const [findReplaceMode, setFindReplaceMode] = useState("find");
|
|
8752
|
+
const [linkPopupOpen, setLinkPopupOpen] = useState(false);
|
|
8753
|
+
const [isSourceMode, setIsSourceMode] = useState(false);
|
|
8754
|
+
const [sourceHTML, setSourceHTML] = useState("");
|
|
8755
|
+
const [editorHeight, setEditorHeight] = useState(null);
|
|
8756
|
+
const editorRootRef = useRef(null);
|
|
8757
|
+
const resizeDragRef = useRef(null);
|
|
8758
|
+
const [linkTooltip, setLinkTooltip] = useState(null);
|
|
8759
|
+
const linkTooltipTimerRef = useRef(null);
|
|
8760
|
+
const handleToggleSource = useCallback(() => {
|
|
8761
|
+
if (!isSourceMode) {
|
|
8762
|
+
const html = htmlSerializer.serialize(engine.getState().doc);
|
|
8763
|
+
setSourceHTML(prettyPrintHTML2(html));
|
|
8764
|
+
setIsSourceMode(true);
|
|
8765
|
+
} else {
|
|
8766
|
+
const newDoc = htmlSerializer.deserialize(sourceHTML);
|
|
8813
8767
|
const tr = createTransaction();
|
|
8814
|
-
tr.steps.push(
|
|
8768
|
+
tr.steps.push(tr_replaceDoc(newDoc));
|
|
8815
8769
|
engine.dispatch(tr);
|
|
8816
|
-
|
|
8817
|
-
}
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
const
|
|
8822
|
-
if (!
|
|
8823
|
-
const
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
8837
|
-
|
|
8838
|
-
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8770
|
+
setIsSourceMode(false);
|
|
8771
|
+
}
|
|
8772
|
+
}, [isSourceMode, sourceHTML, engine]);
|
|
8773
|
+
useEffect(() => {
|
|
8774
|
+
const onMouseMove = (e) => {
|
|
8775
|
+
const drag = resizeDragRef.current;
|
|
8776
|
+
if (!drag) return;
|
|
8777
|
+
const newHeight = Math.max(120, drag.startHeight + (e.clientY - drag.startY));
|
|
8778
|
+
setEditorHeight(newHeight);
|
|
8779
|
+
};
|
|
8780
|
+
const onMouseUp = () => {
|
|
8781
|
+
resizeDragRef.current = null;
|
|
8782
|
+
};
|
|
8783
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
8784
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
8785
|
+
return () => {
|
|
8786
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
8787
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
8788
|
+
};
|
|
8789
|
+
}, []);
|
|
8790
|
+
const [tableContextMenu, setTableContextMenu] = useState(null);
|
|
8791
|
+
const [tableSelection, setTableSelection] = useState(null);
|
|
8792
|
+
const cellDragRef = useRef(null);
|
|
8793
|
+
const colResizeRef = useRef(null);
|
|
8794
|
+
const state = useEditorState(engine);
|
|
8795
|
+
const inTableCellPos = state.selection ? findCellPosition(state.doc, state.selection.anchor.path) : null;
|
|
8796
|
+
useLayoutEffect(() => {
|
|
8797
|
+
stateRef.current = state;
|
|
8798
|
+
}, [state]);
|
|
8799
|
+
useLayoutEffect(() => {
|
|
8800
|
+
const container = containerRef.current;
|
|
8801
|
+
if (!container) return;
|
|
8802
|
+
isRenderingRef.current = true;
|
|
8803
|
+
renderDocument(state.doc, container);
|
|
8804
|
+
if (!container.contains(document.activeElement)) {
|
|
8805
|
+
container.focus({ preventScroll: true });
|
|
8806
|
+
}
|
|
8807
|
+
if (state.selection) {
|
|
8808
|
+
restoreSelection(container, state.selection);
|
|
8809
|
+
scrollCaretIntoView();
|
|
8810
|
+
}
|
|
8811
|
+
isRenderingRef.current = false;
|
|
8812
|
+
if (onHTMLChange) {
|
|
8813
|
+
onHTMLChange(htmlSerializer.serialize(state.doc));
|
|
8814
|
+
}
|
|
8815
|
+
if (onJSONChange) {
|
|
8816
|
+
onJSONChange(jsonSerializer.serialize(state.doc));
|
|
8817
|
+
}
|
|
8818
|
+
}, [state.doc]);
|
|
8819
|
+
useLayoutEffect(() => {
|
|
8820
|
+
const container = containerRef.current;
|
|
8821
|
+
if (!container || !state.selection) return;
|
|
8822
|
+
restoreSelection(container, state.selection);
|
|
8823
|
+
scrollCaretIntoView();
|
|
8824
|
+
}, [state.selection]);
|
|
8825
|
+
useEffect(() => {
|
|
8826
|
+
const container = containerRef.current;
|
|
8827
|
+
if (!container || readOnly) return;
|
|
8828
|
+
return attachClipboardHandlers(container, engine);
|
|
8829
|
+
}, [engine, readOnly]);
|
|
8830
|
+
useEffect(() => {
|
|
8831
|
+
const container = containerRef.current;
|
|
8832
|
+
if (!container) return;
|
|
8833
|
+
container.querySelectorAll(".editor-cell-selected").forEach((el) => {
|
|
8834
|
+
el.classList.remove("editor-cell-selected");
|
|
8835
|
+
});
|
|
8836
|
+
if (!tableSelection) return;
|
|
8837
|
+
const { tablePath, anchorCell, focusCell } = tableSelection;
|
|
8838
|
+
const minRow = Math.min(anchorCell[0], focusCell[0]);
|
|
8839
|
+
const maxRow = Math.max(anchorCell[0], focusCell[0]);
|
|
8840
|
+
const minCol = Math.min(anchorCell[1], focusCell[1]);
|
|
8841
|
+
const maxCol = Math.max(anchorCell[1], focusCell[1]);
|
|
8842
|
+
for (let r = minRow; r <= maxRow; r++) {
|
|
8843
|
+
for (let c = minCol; c <= maxCol; c++) {
|
|
8844
|
+
const cellPath = [...tablePath, r, c];
|
|
8845
|
+
const td = container.querySelector(
|
|
8846
|
+
`[data-block-path="${JSON.stringify(cellPath)}"]`
|
|
8847
|
+
);
|
|
8848
|
+
if (td) td.classList.add("editor-cell-selected");
|
|
8849
|
+
}
|
|
8850
|
+
}
|
|
8851
|
+
}, [tableSelection, state.doc]);
|
|
8852
|
+
useEffect(() => {
|
|
8853
|
+
const container = containerRef.current;
|
|
8854
|
+
if (!container) return;
|
|
8855
|
+
container.querySelectorAll(".editor-cell-active").forEach((el) => {
|
|
8856
|
+
el.classList.remove("editor-cell-active");
|
|
8857
|
+
});
|
|
8858
|
+
if (!inTableCellPos) {
|
|
8859
|
+
setTableSelection(null);
|
|
8860
|
+
return;
|
|
8861
|
+
}
|
|
8862
|
+
if (tableSelection) {
|
|
8863
|
+
const { anchorCell, focusCell, tablePath } = tableSelection;
|
|
8864
|
+
const sameTable = JSON.stringify(tablePath) === JSON.stringify(inTableCellPos.tablePath);
|
|
8865
|
+
const singleCell = anchorCell[0] === focusCell[0] && anchorCell[1] === focusCell[1];
|
|
8866
|
+
if (!sameTable || singleCell) {
|
|
8867
|
+
setTableSelection(null);
|
|
8868
|
+
}
|
|
8869
|
+
}
|
|
8870
|
+
const cellPath = [...inTableCellPos.tablePath, inTableCellPos.row, inTableCellPos.col];
|
|
8871
|
+
const td = container.querySelector(
|
|
8872
|
+
`[data-block-path="${JSON.stringify(cellPath)}"]`
|
|
8873
|
+
);
|
|
8874
|
+
if (td) td.classList.add("editor-cell-active");
|
|
8875
|
+
}, [inTableCellPos, state.doc]);
|
|
8876
|
+
useEffect(() => {
|
|
8877
|
+
const onSelectionChange = () => {
|
|
8878
|
+
if (isRenderingRef.current) return;
|
|
8879
|
+
const container = containerRef.current;
|
|
8880
|
+
if (!container) return;
|
|
8881
|
+
if (!isSelectionInContainer(container)) return;
|
|
8882
|
+
const captured = captureSelection(container);
|
|
8883
|
+
if (!captured) return;
|
|
8884
|
+
const currentSelection = engine.getState().selection;
|
|
8885
|
+
if (currentSelection && JSON.stringify(currentSelection.anchor) === JSON.stringify(captured.anchor) && JSON.stringify(currentSelection.focus) === JSON.stringify(captured.focus)) {
|
|
8886
|
+
return;
|
|
8887
|
+
}
|
|
8888
|
+
const tr = createTransaction();
|
|
8889
|
+
tr.steps.push(tr_setSelection(captured));
|
|
8890
|
+
engine.dispatch(tr);
|
|
8891
|
+
};
|
|
8892
|
+
document.addEventListener(
|
|
8893
|
+
"selectionchange",
|
|
8894
|
+
onSelectionChange
|
|
8895
|
+
);
|
|
8896
|
+
return () => {
|
|
8897
|
+
document.removeEventListener(
|
|
8898
|
+
"selectionchange",
|
|
8899
|
+
onSelectionChange
|
|
8900
|
+
);
|
|
8901
|
+
};
|
|
8902
|
+
}, [engine]);
|
|
8903
|
+
const handleFocus = useCallback(() => {
|
|
8904
|
+
const currentState = engine.getState();
|
|
8905
|
+
if (!currentState.selection) {
|
|
8906
|
+
const tr = createTransaction();
|
|
8907
|
+
tr.steps.push(
|
|
8908
|
+
tr_setSelection(
|
|
8909
|
+
makeCollapsedSelection({ path: [0], offset: 0 })
|
|
8910
|
+
)
|
|
8911
|
+
);
|
|
8912
|
+
engine.dispatch(tr);
|
|
8913
|
+
}
|
|
8914
|
+
onFocusProp == null ? void 0 : onFocusProp();
|
|
8915
|
+
}, [engine, onFocusProp]);
|
|
8916
|
+
const handleBlur = useCallback(() => {
|
|
8917
|
+
onBlurProp == null ? void 0 : onBlurProp();
|
|
8918
|
+
}, [onBlurProp]);
|
|
8919
|
+
const handleKeyDown = useCallback(
|
|
8920
|
+
(e) => {
|
|
8921
|
+
var _a, _b, _c;
|
|
8922
|
+
if (readOnly) return;
|
|
8923
|
+
if ((e.ctrlKey || e.metaKey) && e.key === "f") {
|
|
8924
|
+
e.preventDefault();
|
|
8925
|
+
setFindReplaceMode("find");
|
|
8926
|
+
setFindReplaceOpen(true);
|
|
8927
|
+
return;
|
|
8928
|
+
}
|
|
8929
|
+
if ((e.ctrlKey || e.metaKey) && e.key === "h") {
|
|
8930
|
+
e.preventDefault();
|
|
8931
|
+
setFindReplaceMode("replace");
|
|
8932
|
+
setFindReplaceOpen(true);
|
|
8933
|
+
return;
|
|
8934
|
+
}
|
|
8935
|
+
if ((e.ctrlKey || e.metaKey) && e.key === "k") {
|
|
8936
|
+
e.preventDefault();
|
|
8937
|
+
setLinkPopupOpen(true);
|
|
8938
|
+
onOpenLinkPopup == null ? void 0 : onOpenLinkPopup();
|
|
8939
|
+
return;
|
|
8940
|
+
}
|
|
8941
|
+
if ((e.ctrlKey || e.metaKey) && (e.key === "a" || e.key === "A")) {
|
|
8942
|
+
e.preventDefault();
|
|
8943
|
+
const container = containerRef.current;
|
|
8944
|
+
if (container) {
|
|
8945
|
+
const spans = container.querySelectorAll("[data-path]");
|
|
8946
|
+
const first = spans[0];
|
|
8947
|
+
const last = spans[spans.length - 1];
|
|
8948
|
+
if (first && last) {
|
|
8949
|
+
const sel = window.getSelection();
|
|
8950
|
+
const range = document.createRange();
|
|
8951
|
+
range.setStart((_a = leafTextNode2(first, "first")) != null ? _a : first, 0);
|
|
8952
|
+
const lastLeaf = leafTextNode2(last, "last");
|
|
8953
|
+
range.setEnd(lastLeaf != null ? lastLeaf : last, (_c = (_b = lastLeaf == null ? void 0 : lastLeaf.textContent) == null ? void 0 : _b.length) != null ? _c : 0);
|
|
8954
|
+
sel == null ? void 0 : sel.removeAllRanges();
|
|
8955
|
+
sel == null ? void 0 : sel.addRange(range);
|
|
8956
|
+
}
|
|
8957
|
+
}
|
|
8958
|
+
return;
|
|
8959
|
+
}
|
|
8960
|
+
if (selectedImagePath && (e.key === "Delete" || e.key === "Backspace")) {
|
|
8961
|
+
e.preventDefault();
|
|
8962
|
+
deleteImageAtPath(selectedImagePath)(engine);
|
|
8963
|
+
setSelectedImagePath(null);
|
|
8964
|
+
return;
|
|
8965
|
+
}
|
|
8966
|
+
if (selectedImagePath) setSelectedImagePath(null);
|
|
8967
|
+
if (e.key === "Tab") {
|
|
8968
|
+
const { doc, selection: sel } = engine.getState();
|
|
8969
|
+
if (sel) {
|
|
8970
|
+
const bp = findContentBlockPath(doc, sel.anchor.path);
|
|
8971
|
+
const block = bp ? getNodeAtPath(doc, bp) : null;
|
|
8972
|
+
if ((block == null ? void 0 : block.type) === "code_block") {
|
|
8973
|
+
e.preventDefault();
|
|
8974
|
+
insertText(" ")(engine);
|
|
8975
|
+
return;
|
|
8976
|
+
}
|
|
8977
|
+
if ((block == null ? void 0 : block.type) === "list_item") {
|
|
8978
|
+
e.preventDefault();
|
|
8979
|
+
if (e.shiftKey) {
|
|
8980
|
+
outdentListItem(engine);
|
|
8981
|
+
} else {
|
|
8982
|
+
indentListItem(engine);
|
|
8983
|
+
}
|
|
8984
|
+
return;
|
|
8985
|
+
}
|
|
8986
|
+
if (findCellPosition(doc, sel.anchor.path)) {
|
|
8987
|
+
e.preventDefault();
|
|
8988
|
+
}
|
|
8989
|
+
}
|
|
8990
|
+
}
|
|
8991
|
+
const handled = engine.handleKeyDown(
|
|
8992
|
+
e.nativeEvent
|
|
8993
|
+
);
|
|
8994
|
+
if (handled) return;
|
|
8995
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
8996
|
+
e.preventDefault();
|
|
8997
|
+
handleEnter(engine);
|
|
8998
|
+
return;
|
|
8999
|
+
}
|
|
9000
|
+
if (e.key === "Backspace") {
|
|
9001
|
+
e.preventDefault();
|
|
9002
|
+
handleBackspace(engine);
|
|
9003
|
+
return;
|
|
9004
|
+
}
|
|
9005
|
+
if (e.key === "Delete") {
|
|
9006
|
+
e.preventDefault();
|
|
9007
|
+
handleDelete(engine);
|
|
9008
|
+
return;
|
|
9009
|
+
}
|
|
9010
|
+
if (e.key === "Enter" && e.shiftKey) {
|
|
9011
|
+
e.preventDefault();
|
|
9012
|
+
insertText("\n")(engine);
|
|
9013
|
+
return;
|
|
9014
|
+
}
|
|
9015
|
+
},
|
|
9016
|
+
[engine, readOnly, onOpenLinkPopup, selectedImagePath]
|
|
9017
|
+
);
|
|
9018
|
+
useEffect(() => {
|
|
9019
|
+
const container = containerRef.current;
|
|
9020
|
+
if (!container || readOnly) return;
|
|
9021
|
+
const onBeforeInput = (e) => {
|
|
9022
|
+
if (e.isComposing || isComposingRef.current) return;
|
|
9023
|
+
switch (e.inputType) {
|
|
9024
|
+
case "insertText":
|
|
9025
|
+
case "insertReplacementText": {
|
|
9026
|
+
if (!e.data) return;
|
|
9027
|
+
e.preventDefault();
|
|
9028
|
+
insertText(e.data)(engine);
|
|
9029
|
+
return;
|
|
9030
|
+
}
|
|
9031
|
+
case "insertParagraph": {
|
|
9032
|
+
e.preventDefault();
|
|
9033
|
+
handleEnter(engine);
|
|
9034
|
+
return;
|
|
9035
|
+
}
|
|
9036
|
+
case "insertLineBreak": {
|
|
9037
|
+
e.preventDefault();
|
|
9038
|
+
insertText("\n")(engine);
|
|
9039
|
+
return;
|
|
9040
|
+
}
|
|
9041
|
+
case "deleteContentBackward":
|
|
9042
|
+
case "deleteWordBackward":
|
|
9043
|
+
case "deleteSoftLineBackward": {
|
|
9044
|
+
e.preventDefault();
|
|
9045
|
+
handleBackspace(engine);
|
|
9046
|
+
return;
|
|
9047
|
+
}
|
|
9048
|
+
case "insertFromPaste":
|
|
9049
|
+
case "insertFromDrop":
|
|
9050
|
+
return;
|
|
9051
|
+
default:
|
|
9052
|
+
e.preventDefault();
|
|
9053
|
+
}
|
|
9054
|
+
};
|
|
9055
|
+
container.addEventListener("beforeinput", onBeforeInput);
|
|
9056
|
+
return () => container.removeEventListener("beforeinput", onBeforeInput);
|
|
9057
|
+
}, [engine, readOnly]);
|
|
9058
|
+
useEffect(() => {
|
|
9059
|
+
const container = containerRef.current;
|
|
9060
|
+
if (!container || readOnly) return;
|
|
9061
|
+
const onCompositionStart = () => {
|
|
9062
|
+
isComposingRef.current = true;
|
|
9063
|
+
};
|
|
9064
|
+
const onCompositionEnd = (e) => {
|
|
9065
|
+
isComposingRef.current = false;
|
|
9066
|
+
if (e.data) insertText(e.data)(engine);
|
|
9067
|
+
};
|
|
9068
|
+
container.addEventListener("compositionstart", onCompositionStart);
|
|
9069
|
+
container.addEventListener("compositionend", onCompositionEnd);
|
|
9070
|
+
return () => {
|
|
9071
|
+
container.removeEventListener("compositionstart", onCompositionStart);
|
|
9072
|
+
container.removeEventListener("compositionend", onCompositionEnd);
|
|
9073
|
+
};
|
|
9074
|
+
}, [engine, readOnly]);
|
|
9075
|
+
useEffect(() => {
|
|
9076
|
+
const container = containerRef.current;
|
|
9077
|
+
if (!container) return;
|
|
9078
|
+
const onMouseOver = (e) => {
|
|
9079
|
+
var _a;
|
|
9080
|
+
const anchor = e.target.closest("a.editor-link");
|
|
9081
|
+
if (!anchor) return;
|
|
9082
|
+
const href = (_a = anchor.getAttribute("href")) != null ? _a : "";
|
|
9083
|
+
if (!href) return;
|
|
9084
|
+
if (linkTooltipTimerRef.current) clearTimeout(linkTooltipTimerRef.current);
|
|
9085
|
+
linkTooltipTimerRef.current = setTimeout(() => {
|
|
9086
|
+
const rect = anchor.getBoundingClientRect();
|
|
9087
|
+
const containerRect = container.getBoundingClientRect();
|
|
9088
|
+
setLinkTooltip({
|
|
9089
|
+
href,
|
|
9090
|
+
x: rect.left - containerRect.left,
|
|
9091
|
+
y: rect.bottom - containerRect.top + 6
|
|
9092
|
+
});
|
|
9093
|
+
}, 200);
|
|
9094
|
+
};
|
|
9095
|
+
const onMouseOut = (e) => {
|
|
9096
|
+
const anchor = e.target.closest("a.editor-link");
|
|
9097
|
+
if (!anchor) return;
|
|
9098
|
+
if (linkTooltipTimerRef.current) clearTimeout(linkTooltipTimerRef.current);
|
|
9099
|
+
setLinkTooltip(null);
|
|
9100
|
+
};
|
|
9101
|
+
const onClick = (e) => {
|
|
9102
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
9103
|
+
const anchor = e.target.closest("a.editor-link");
|
|
9104
|
+
if (!anchor) return;
|
|
9105
|
+
e.preventDefault();
|
|
9106
|
+
const href = anchor.getAttribute("href");
|
|
9107
|
+
if (href) window.open(href, "_blank", "noopener,noreferrer");
|
|
9108
|
+
};
|
|
9109
|
+
container.addEventListener("mouseover", onMouseOver);
|
|
9110
|
+
container.addEventListener("mouseout", onMouseOut);
|
|
9111
|
+
container.addEventListener("click", onClick);
|
|
9112
|
+
return () => {
|
|
9113
|
+
container.removeEventListener("mouseover", onMouseOver);
|
|
9114
|
+
container.removeEventListener("mouseout", onMouseOut);
|
|
9115
|
+
container.removeEventListener("click", onClick);
|
|
9116
|
+
if (linkTooltipTimerRef.current) clearTimeout(linkTooltipTimerRef.current);
|
|
9117
|
+
};
|
|
9118
|
+
}, []);
|
|
9119
|
+
useEffect(() => {
|
|
9120
|
+
const onMouseMove = (e) => {
|
|
9121
|
+
const drag = colResizeRef.current;
|
|
9122
|
+
if (!drag) return;
|
|
9123
|
+
const delta = e.clientX - drag.startX;
|
|
9124
|
+
const newWidth = Math.max(40, drag.startWidth + delta);
|
|
9125
|
+
const container = containerRef.current;
|
|
9126
|
+
if (container) {
|
|
9127
|
+
const colEl = container.querySelector(
|
|
9128
|
+
`col[data-col-index="${drag.colIndex}"]`
|
|
9129
|
+
);
|
|
9130
|
+
if (colEl) colEl.style.width = `${newWidth}px`;
|
|
9131
|
+
}
|
|
9132
|
+
};
|
|
9133
|
+
const onMouseUp = (e) => {
|
|
9134
|
+
const drag = colResizeRef.current;
|
|
9135
|
+
if (!drag) return;
|
|
9136
|
+
const delta = e.clientX - drag.startX;
|
|
9137
|
+
const newWidth = Math.max(40, drag.startWidth + delta);
|
|
9138
|
+
colResizeRef.current = null;
|
|
9139
|
+
setColumnWidth(drag.tablePath, drag.colIndex, newWidth)(engine);
|
|
9140
|
+
};
|
|
9141
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
9142
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
9143
|
+
return () => {
|
|
9144
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
9145
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
9146
|
+
};
|
|
9147
|
+
}, [engine]);
|
|
9148
|
+
useEffect(() => {
|
|
9149
|
+
const onMouseMove = (e) => {
|
|
9150
|
+
var _a, _b;
|
|
9151
|
+
const drag = cellDragRef.current;
|
|
9152
|
+
if (!drag) return;
|
|
9153
|
+
const td = e.target.closest("[data-cell-row]");
|
|
9154
|
+
if (!td) return;
|
|
9155
|
+
const row = parseInt((_a = td.dataset.cellRow) != null ? _a : "0");
|
|
9156
|
+
const col = parseInt((_b = td.dataset.cellCol) != null ? _b : "0");
|
|
9157
|
+
const tdTablePath = td.dataset.cellTablePath ? JSON.parse(td.dataset.cellTablePath) : null;
|
|
9158
|
+
if (!tdTablePath || JSON.stringify(tdTablePath) !== JSON.stringify(drag.tablePath)) return;
|
|
9159
|
+
setTableSelection({
|
|
9160
|
+
tablePath: drag.tablePath,
|
|
9161
|
+
anchorCell: [drag.startRow, drag.startCol],
|
|
9162
|
+
focusCell: [row, col]
|
|
9163
|
+
});
|
|
9164
|
+
};
|
|
9165
|
+
const onMouseUp = () => {
|
|
9166
|
+
cellDragRef.current = null;
|
|
9167
|
+
};
|
|
9168
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
9169
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
9170
|
+
return () => {
|
|
9171
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
9172
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
9173
|
+
};
|
|
9174
|
+
}, []);
|
|
9175
|
+
const handleContextMenu = useCallback(
|
|
9176
|
+
(e) => {
|
|
9177
|
+
var _a, _b, _c, _d, _e, _f;
|
|
9178
|
+
const td = e.target.closest("[data-cell-row]");
|
|
9179
|
+
if (!td) return;
|
|
9180
|
+
e.preventDefault();
|
|
9181
|
+
const row = parseInt((_a = td.dataset.cellRow) != null ? _a : "0");
|
|
9182
|
+
const col = parseInt((_b = td.dataset.cellCol) != null ? _b : "0");
|
|
9183
|
+
const tablePath = td.dataset.cellTablePath ? JSON.parse(td.dataset.cellTablePath) : null;
|
|
9184
|
+
if (!tablePath) return;
|
|
9185
|
+
const cellNode = getNodeAtPath(
|
|
9186
|
+
engine.getState().doc,
|
|
9187
|
+
[...tablePath, row, col]
|
|
9188
|
+
);
|
|
9189
|
+
const isMerged = !!cellNode && (((_d = (_c = cellNode.attrs) == null ? void 0 : _c.colspan) != null ? _d : 1) > 1 || ((_f = (_e = cellNode.attrs) == null ? void 0 : _e.rowspan) != null ? _f : 1) > 1);
|
|
9190
|
+
setTableContextMenu({ x: e.clientX, y: e.clientY, tablePath, row, col, isMerged });
|
|
9191
|
+
},
|
|
9192
|
+
[engine]
|
|
9193
|
+
);
|
|
9194
|
+
const handleMouseDown = useCallback(
|
|
9195
|
+
(e) => {
|
|
9196
|
+
var _a, _b, _c, _d;
|
|
9197
|
+
if (readOnly) return;
|
|
9198
|
+
const target = e.target;
|
|
9199
|
+
if (target.dataset.resizeImagePath) {
|
|
9200
|
+
e.preventDefault();
|
|
9201
|
+
const imagePath = JSON.parse(target.dataset.resizeImagePath);
|
|
9202
|
+
const corner = (_a = target.dataset.resizeImagePos) != null ? _a : "se";
|
|
9203
|
+
const container = containerRef.current;
|
|
9204
|
+
let startWidth = 300;
|
|
9205
|
+
if (container) {
|
|
9206
|
+
const fig2 = container.querySelector(`[data-image-path="${JSON.stringify(imagePath)}"]`);
|
|
9207
|
+
const img = fig2 == null ? void 0 : fig2.querySelector("img");
|
|
9208
|
+
if (img) startWidth = img.getBoundingClientRect().width || 300;
|
|
9209
|
+
}
|
|
9210
|
+
imageResizeRef.current = {
|
|
9211
|
+
imagePath,
|
|
9212
|
+
corner,
|
|
9213
|
+
startX: e.clientX,
|
|
9214
|
+
startY: e.clientY,
|
|
9215
|
+
startWidth,
|
|
9216
|
+
startHeight: 0
|
|
9217
|
+
};
|
|
9218
|
+
return;
|
|
9219
|
+
}
|
|
9220
|
+
const fig = target.closest("[data-image-path]");
|
|
9221
|
+
if (fig == null ? void 0 : fig.dataset.imagePath) {
|
|
9222
|
+
e.preventDefault();
|
|
9223
|
+
setSelectedImagePath(JSON.parse(fig.dataset.imagePath));
|
|
9224
|
+
return;
|
|
9225
|
+
}
|
|
9226
|
+
setSelectedImagePath(null);
|
|
9227
|
+
if (target.dataset.resizeTable) {
|
|
9228
|
+
e.preventDefault();
|
|
9229
|
+
const tablePath = JSON.parse(target.dataset.resizeTable);
|
|
9230
|
+
const colIndex = parseInt((_b = target.dataset.resizeCol) != null ? _b : "0");
|
|
9231
|
+
const container = containerRef.current;
|
|
9232
|
+
let startWidth = 120;
|
|
9233
|
+
if (container) {
|
|
9234
|
+
const colEl = container.querySelector(
|
|
9235
|
+
`col[data-col-index="${colIndex}"]`
|
|
9236
|
+
);
|
|
9237
|
+
if (colEl) startWidth = colEl.getBoundingClientRect().width || 120;
|
|
9238
|
+
}
|
|
9239
|
+
colResizeRef.current = { tablePath, colIndex, startX: e.clientX, startWidth };
|
|
9240
|
+
return;
|
|
9241
|
+
}
|
|
9242
|
+
const td = target.closest("[data-cell-row]");
|
|
9243
|
+
if (!td) setTableSelection(null);
|
|
9244
|
+
if (td && !readOnly) {
|
|
9245
|
+
const row = parseInt((_c = td.dataset.cellRow) != null ? _c : "0");
|
|
9246
|
+
const col = parseInt((_d = td.dataset.cellCol) != null ? _d : "0");
|
|
9247
|
+
const tdTablePath = td.dataset.cellTablePath ? JSON.parse(td.dataset.cellTablePath) : null;
|
|
9248
|
+
if (tdTablePath) {
|
|
9249
|
+
cellDragRef.current = { tablePath: tdTablePath, startRow: row, startCol: col };
|
|
9250
|
+
setTableSelection({
|
|
9251
|
+
tablePath: tdTablePath,
|
|
9252
|
+
anchorCell: [row, col],
|
|
9253
|
+
focusCell: [row, col]
|
|
9254
|
+
});
|
|
9255
|
+
}
|
|
9256
|
+
}
|
|
9257
|
+
const checkTarget = target.dataset.checkPath ? target : target.closest("[data-check-path]");
|
|
9258
|
+
if (checkTarget == null ? void 0 : checkTarget.dataset.checkPath) {
|
|
9259
|
+
e.preventDefault();
|
|
9260
|
+
toggleCheckItemAt(JSON.parse(checkTarget.dataset.checkPath))(engine);
|
|
9261
|
+
}
|
|
9262
|
+
},
|
|
9263
|
+
[engine, readOnly]
|
|
9264
|
+
);
|
|
9265
|
+
const handleClick = useCallback(() => {
|
|
9266
|
+
const container = containerRef.current;
|
|
9267
|
+
if (!container) return;
|
|
9268
|
+
const selection = captureSelection(container);
|
|
9269
|
+
if (!selection) return;
|
|
9270
|
+
const tr = createTransaction();
|
|
9271
|
+
tr.steps.push(
|
|
9272
|
+
tr_setSelection(selection)
|
|
9273
|
+
);
|
|
9274
|
+
engine.dispatch(tr);
|
|
9275
|
+
}, [engine]);
|
|
9276
|
+
const imageResizeRef = useRef(null);
|
|
9277
|
+
useEffect(() => {
|
|
9278
|
+
const onMouseMove = (e) => {
|
|
9279
|
+
const drag = imageResizeRef.current;
|
|
9280
|
+
if (!drag) return;
|
|
9281
|
+
const deltaX = e.clientX - drag.startX;
|
|
9282
|
+
const isRight = drag.corner === "ne" || drag.corner === "se";
|
|
9283
|
+
const newWidth = Math.max(60, drag.startWidth + (isRight ? deltaX : -deltaX));
|
|
9284
|
+
const container = containerRef.current;
|
|
9285
|
+
if (container) {
|
|
9286
|
+
const fig = container.querySelector(
|
|
9287
|
+
`[data-image-path="${JSON.stringify(drag.imagePath)}"]`
|
|
9288
|
+
);
|
|
9289
|
+
const img = fig == null ? void 0 : fig.querySelector("img");
|
|
9290
|
+
if (img) img.style.width = `${newWidth}px`;
|
|
9291
|
+
}
|
|
9292
|
+
};
|
|
9293
|
+
const onMouseUp = (e) => {
|
|
9294
|
+
const drag = imageResizeRef.current;
|
|
9295
|
+
if (!drag) return;
|
|
9296
|
+
const deltaX = e.clientX - drag.startX;
|
|
9297
|
+
const isRight = drag.corner === "ne" || drag.corner === "se";
|
|
9298
|
+
const newWidth = Math.max(60, drag.startWidth + (isRight ? deltaX : -deltaX));
|
|
9299
|
+
imageResizeRef.current = null;
|
|
9300
|
+
setImageAttr(drag.imagePath, { width: newWidth })(engine);
|
|
9301
|
+
};
|
|
9302
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
9303
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
9304
|
+
return () => {
|
|
9305
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
9306
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
9307
|
+
};
|
|
9308
|
+
}, [engine]);
|
|
9309
|
+
useEffect(() => {
|
|
9310
|
+
const container = containerRef.current;
|
|
9311
|
+
if (!container) return;
|
|
9312
|
+
container.querySelectorAll("[data-image-path]").forEach((el) => {
|
|
9313
|
+
el.removeAttribute("data-selected");
|
|
9314
|
+
});
|
|
9315
|
+
if (selectedImagePath) {
|
|
9316
|
+
const fig = container.querySelector(
|
|
9317
|
+
`[data-image-path="${JSON.stringify(selectedImagePath)}"]`
|
|
9318
|
+
);
|
|
9319
|
+
if (fig) fig.setAttribute("data-selected", "true");
|
|
9320
|
+
}
|
|
9321
|
+
}, [selectedImagePath, state.doc]);
|
|
9322
|
+
useEffect(() => {
|
|
9323
|
+
const container = containerRef.current;
|
|
9324
|
+
if (!container || readOnly) return;
|
|
9325
|
+
const onDragOver = (e) => {
|
|
9326
|
+
var _a;
|
|
9327
|
+
if ((_a = e.dataTransfer) == null ? void 0 : _a.types.includes("Files")) e.preventDefault();
|
|
9328
|
+
};
|
|
9329
|
+
const onDrop = (e) => {
|
|
9330
|
+
var _a;
|
|
9331
|
+
e.preventDefault();
|
|
9332
|
+
const file = (_a = e.dataTransfer) == null ? void 0 : _a.files[0];
|
|
9333
|
+
if (!file || !file.type.startsWith("image/")) return;
|
|
9334
|
+
const blobUrl = URL.createObjectURL(file);
|
|
9335
|
+
insertImage(blobUrl, file.name.replace(/\.[^.]+$/, ""))(engine);
|
|
9336
|
+
};
|
|
9337
|
+
container.addEventListener("dragover", onDragOver);
|
|
9338
|
+
container.addEventListener("drop", onDrop);
|
|
9339
|
+
return () => {
|
|
9340
|
+
container.removeEventListener("dragover", onDragOver);
|
|
9341
|
+
container.removeEventListener("drop", onDrop);
|
|
9342
|
+
};
|
|
9343
|
+
}, [engine, readOnly]);
|
|
9344
|
+
const isVisualEmpty = state.doc.children.length === 1 && state.doc.children[0].type === "paragraph" && state.doc.children[0].children.length === 0;
|
|
9345
|
+
return /* @__PURE__ */ jsxs(
|
|
9346
|
+
"div",
|
|
9347
|
+
{
|
|
9348
|
+
ref: editorRootRef,
|
|
9349
|
+
className: `editor-root relative flex flex-col ${className}`,
|
|
9350
|
+
style: editorHeight ? { minHeight: editorHeight } : void 0,
|
|
9351
|
+
children: [
|
|
9352
|
+
!readOnly && !hideToolbar && /* @__PURE__ */ jsx(
|
|
9353
|
+
Toolbar,
|
|
9354
|
+
{
|
|
9355
|
+
engine,
|
|
9356
|
+
onFindReplace: (mode) => {
|
|
9357
|
+
setFindReplaceMode(mode);
|
|
9358
|
+
setFindReplaceOpen(true);
|
|
9359
|
+
},
|
|
9360
|
+
linkPopupOpen,
|
|
9361
|
+
onLinkPopupClose: () => setLinkPopupOpen(false),
|
|
9362
|
+
isSourceMode,
|
|
9363
|
+
onToggleSource: handleToggleSource,
|
|
9364
|
+
toolbarConfig
|
|
9365
|
+
}
|
|
9366
|
+
),
|
|
9367
|
+
/* @__PURE__ */ jsx("div", { className: "relative", children: isSourceMode ? /* @__PURE__ */ jsx(
|
|
9368
|
+
"textarea",
|
|
9369
|
+
{
|
|
9370
|
+
"aria-label": "HTML source editor",
|
|
9371
|
+
value: sourceHTML,
|
|
9372
|
+
onChange: (e) => {
|
|
9373
|
+
setSourceHTML(e.target.value);
|
|
9374
|
+
const t = e.target;
|
|
9375
|
+
t.style.height = "auto";
|
|
9376
|
+
t.style.height = t.scrollHeight + "px";
|
|
9377
|
+
},
|
|
9378
|
+
ref: (el) => {
|
|
9379
|
+
if (el) {
|
|
9380
|
+
el.style.height = "auto";
|
|
9381
|
+
el.style.height = el.scrollHeight + "px";
|
|
9382
|
+
}
|
|
9383
|
+
},
|
|
9384
|
+
spellCheck: false,
|
|
9385
|
+
className: "w-full block px-6 py-4 font-mono text-sm leading-relaxed bg-gray-950 text-green-300 outline-none resize-none border-0 overflow-hidden"
|
|
9386
|
+
}
|
|
9387
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9388
|
+
isVisualEmpty && /* @__PURE__ */ jsx(
|
|
9389
|
+
"div",
|
|
9390
|
+
{
|
|
9391
|
+
className: "\r\n absolute\r\n top-6\r\n left-6\r\n pointer-events-none\r\n select-none\r\n text-base\r\n text-gray-400\r\n \r\n ",
|
|
9392
|
+
"aria-hidden": "true",
|
|
9393
|
+
children: placeholder
|
|
9394
|
+
}
|
|
9395
|
+
),
|
|
9396
|
+
/* @__PURE__ */ jsx(
|
|
9397
|
+
"div",
|
|
9398
|
+
{
|
|
9399
|
+
ref: containerRef,
|
|
9400
|
+
contentEditable: !readOnly,
|
|
9401
|
+
suppressContentEditableWarning: true,
|
|
9402
|
+
role: "textbox",
|
|
9403
|
+
"aria-multiline": "true",
|
|
9404
|
+
"aria-label": "Rich text editor",
|
|
9405
|
+
spellCheck: true,
|
|
9406
|
+
onMouseDown: handleMouseDown,
|
|
9407
|
+
onContextMenu: handleContextMenu,
|
|
9408
|
+
onFocus: handleFocus,
|
|
9409
|
+
onBlur: handleBlur,
|
|
9410
|
+
onClick: handleClick,
|
|
9411
|
+
onKeyDown: handleKeyDown,
|
|
9412
|
+
className: [
|
|
9413
|
+
"editor-canvas",
|
|
9414
|
+
"min-h-[300px]",
|
|
9415
|
+
"px-6",
|
|
9416
|
+
"py-4",
|
|
9417
|
+
"outline-none",
|
|
9418
|
+
"text-base",
|
|
9419
|
+
"leading-relaxed",
|
|
9420
|
+
"text-gray-900",
|
|
9421
|
+
"",
|
|
9422
|
+
readOnly ? "cursor-default" : "cursor-text"
|
|
9423
|
+
].join(" ")
|
|
9424
|
+
}
|
|
9425
|
+
),
|
|
9426
|
+
linkTooltip && /* @__PURE__ */ jsxs(
|
|
9427
|
+
"div",
|
|
9428
|
+
{
|
|
9429
|
+
role: "tooltip",
|
|
9430
|
+
style: { left: linkTooltip.x, top: linkTooltip.y },
|
|
9431
|
+
className: "absolute z-50 pointer-events-none flex items-center gap-1.5 bg-gray-900 text-white text-xs px-2.5 py-1.5 rounded shadow-lg max-w-xs",
|
|
9432
|
+
children: [
|
|
9433
|
+
/* @__PURE__ */ jsxs("svg", { width: "11", height: "11", viewBox: "0 0 16 16", fill: "none", className: "shrink-0 opacity-70", "aria-hidden": "true", children: [
|
|
9434
|
+
/* @__PURE__ */ jsx("path", { d: "M6.5 3.5H4A2.5 2.5 0 0 0 4 8.5h2", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
|
|
9435
|
+
/* @__PURE__ */ jsx("path", { d: "M9.5 3.5H12A2.5 2.5 0 0 1 12 8.5h-2", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
|
|
9436
|
+
/* @__PURE__ */ jsx("path", { d: "M5.5 6h5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })
|
|
9437
|
+
] }),
|
|
9438
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: linkTooltip.href }),
|
|
9439
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 opacity-50 ml-1", children: "Ctrl+click to open" })
|
|
9440
|
+
]
|
|
9441
|
+
}
|
|
9442
|
+
)
|
|
9443
|
+
] }) }),
|
|
9444
|
+
inTableCellPos && !readOnly && /* @__PURE__ */ jsx(
|
|
9445
|
+
TableToolbar,
|
|
9446
|
+
{
|
|
9447
|
+
engine,
|
|
9448
|
+
tablePath: inTableCellPos.tablePath,
|
|
9449
|
+
cellPos: { row: inTableCellPos.row, col: inTableCellPos.col },
|
|
9450
|
+
tableSelection,
|
|
9451
|
+
editorContainer: containerRef
|
|
9452
|
+
}
|
|
9453
|
+
),
|
|
9454
|
+
tableContextMenu && /* @__PURE__ */ jsx(
|
|
9455
|
+
TableContextMenu,
|
|
9456
|
+
{
|
|
9457
|
+
x: tableContextMenu.x,
|
|
9458
|
+
y: tableContextMenu.y,
|
|
9459
|
+
tablePath: tableContextMenu.tablePath,
|
|
9460
|
+
row: tableContextMenu.row,
|
|
9461
|
+
col: tableContextMenu.col,
|
|
9462
|
+
isMerged: tableContextMenu.isMerged,
|
|
9463
|
+
tableSelection,
|
|
9464
|
+
engine,
|
|
9465
|
+
onClose: () => setTableContextMenu(null)
|
|
9466
|
+
}
|
|
9467
|
+
),
|
|
9468
|
+
findReplaceOpen && /* @__PURE__ */ jsx(
|
|
9469
|
+
FindReplaceModal,
|
|
9470
|
+
{
|
|
9471
|
+
engine,
|
|
9472
|
+
editorContainer: containerRef,
|
|
9473
|
+
initialMode: findReplaceMode,
|
|
9474
|
+
onClose: () => setFindReplaceOpen(false)
|
|
9475
|
+
}
|
|
9476
|
+
),
|
|
9477
|
+
selectedImagePath && !readOnly && /* @__PURE__ */ jsx(
|
|
9478
|
+
ImageToolbar,
|
|
9479
|
+
{
|
|
9480
|
+
engine,
|
|
9481
|
+
imagePath: selectedImagePath,
|
|
9482
|
+
editorContainer: containerRef,
|
|
9483
|
+
onClose: () => setSelectedImagePath(null)
|
|
9484
|
+
}
|
|
9485
|
+
),
|
|
9486
|
+
!readOnly && /* @__PURE__ */ jsx(
|
|
9487
|
+
"div",
|
|
9488
|
+
{
|
|
9489
|
+
title: "Drag to resize",
|
|
9490
|
+
onMouseDown: (e) => {
|
|
9491
|
+
e.preventDefault();
|
|
9492
|
+
const rootEl = editorRootRef.current;
|
|
9493
|
+
if (!rootEl) return;
|
|
9494
|
+
resizeDragRef.current = {
|
|
9495
|
+
startY: e.clientY,
|
|
9496
|
+
startHeight: rootEl.getBoundingClientRect().height
|
|
9497
|
+
};
|
|
9498
|
+
},
|
|
9499
|
+
className: "absolute bottom-0 right-0 w-4 h-4 cursor-s-resize flex items-end justify-end pr-0.5 pb-0.5 select-none",
|
|
9500
|
+
"aria-hidden": "true",
|
|
9501
|
+
children: /* @__PURE__ */ jsx("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M7 1L1 7M7 4L4 7M7 7L7 7", stroke: "#9ca3af", strokeWidth: "1.2", strokeLinecap: "round" }) })
|
|
9502
|
+
}
|
|
9503
|
+
)
|
|
9504
|
+
]
|
|
9505
|
+
}
|
|
9506
|
+
);
|
|
9507
|
+
}
|
|
9508
|
+
var BLOCK_TAGS2 = "p|h[1-6]|ul|ol|li|blockquote|pre|figure|table|thead|tbody|tr|th|td";
|
|
9509
|
+
var _OPEN_ONLY_RE2 = new RegExp(`^<(${BLOCK_TAGS2})(?:\\s[^>]*)?>$`, "i");
|
|
9510
|
+
var _CLOSE_ONLY_RE2 = new RegExp(`^<\\/(${BLOCK_TAGS2})>$`, "i");
|
|
9511
|
+
var _HR_RE2 = /^<hr(\s[^>]*)?\/?>$/i;
|
|
9512
|
+
function leafTextNode2(el, end) {
|
|
9513
|
+
let node = el;
|
|
9514
|
+
while (node.hasChildNodes()) {
|
|
9515
|
+
node = end === "first" ? node.firstChild : node.lastChild;
|
|
9516
|
+
}
|
|
9517
|
+
return node.nodeType === Node.TEXT_NODE ? node : null;
|
|
9518
|
+
}
|
|
9519
|
+
function prettyPrintHTML2(html) {
|
|
9520
|
+
const blockOpen = new RegExp(`(<(?:${BLOCK_TAGS2})(?:\\s[^>]*)?>)`, "gi");
|
|
9521
|
+
const blockClose = new RegExp(`(<\\/(?:${BLOCK_TAGS2})>)`, "gi");
|
|
9522
|
+
const spread = html.replace(blockOpen, "\n$1").replace(blockClose, "$1\n").replace(/<hr(\s[^>]*)?\/?>(\s*)/gi, "\n<hr />\n");
|
|
9523
|
+
let depth = 0;
|
|
9524
|
+
const result = [];
|
|
9525
|
+
for (const raw of spread.split("\n")) {
|
|
9526
|
+
const line = raw.trim();
|
|
9527
|
+
if (!line) continue;
|
|
9528
|
+
if (_HR_RE2.test(line)) {
|
|
9529
|
+
result.push(" ".repeat(depth) + line);
|
|
9530
|
+
continue;
|
|
9531
|
+
}
|
|
9532
|
+
if (_CLOSE_ONLY_RE2.test(line)) {
|
|
9533
|
+
depth = Math.max(0, depth - 1);
|
|
9534
|
+
result.push(" ".repeat(depth) + line);
|
|
9535
|
+
continue;
|
|
9536
|
+
}
|
|
9537
|
+
if (_OPEN_ONLY_RE2.test(line)) {
|
|
9538
|
+
result.push(" ".repeat(depth) + line);
|
|
9539
|
+
depth++;
|
|
9540
|
+
continue;
|
|
9541
|
+
}
|
|
9542
|
+
result.push(" ".repeat(depth) + line);
|
|
9543
|
+
}
|
|
9544
|
+
return result.join("\n");
|
|
9545
|
+
}
|
|
9546
|
+
|
|
9547
|
+
// src/editor/table/TablePlugin.ts
|
|
9548
|
+
function getCellDOMElement(cellPathJson) {
|
|
9549
|
+
return document.querySelector(`[data-block-path='${cellPathJson}']`);
|
|
9550
|
+
}
|
|
9551
|
+
function isCaretAtContainerStart(container) {
|
|
9552
|
+
const sel = window.getSelection();
|
|
9553
|
+
if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) return false;
|
|
9554
|
+
const range = sel.getRangeAt(0);
|
|
9555
|
+
if (range.startOffset !== 0) return false;
|
|
9556
|
+
let node = range.startContainer;
|
|
9557
|
+
while (node && node !== container) {
|
|
9558
|
+
if (node.previousSibling) return false;
|
|
9559
|
+
node = node.parentNode;
|
|
9560
|
+
}
|
|
9561
|
+
return node === container;
|
|
9562
|
+
}
|
|
9563
|
+
function isCaretAtContainerEnd(container) {
|
|
9564
|
+
var _a, _b;
|
|
9565
|
+
const sel = window.getSelection();
|
|
9566
|
+
if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) return false;
|
|
9567
|
+
const range = sel.getRangeAt(0);
|
|
9568
|
+
const endNode = range.endContainer;
|
|
9569
|
+
const endOffset = range.endOffset;
|
|
9570
|
+
const len = endNode.nodeType === Node.TEXT_NODE ? (_b = (_a = endNode.textContent) == null ? void 0 : _a.length) != null ? _b : 0 : endNode.childNodes.length;
|
|
9571
|
+
if (endOffset !== len) return false;
|
|
9572
|
+
let node = endNode;
|
|
9573
|
+
while (node && node !== container) {
|
|
9574
|
+
if (node.nextSibling) return false;
|
|
9575
|
+
node = node.parentNode;
|
|
9576
|
+
}
|
|
9577
|
+
return node === container;
|
|
9578
|
+
}
|
|
9579
|
+
function isCaretOnEdgeLine(container, direction) {
|
|
9580
|
+
const sel = window.getSelection();
|
|
9581
|
+
if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) return false;
|
|
9582
|
+
const caretRange = sel.getRangeAt(0).cloneRange();
|
|
9583
|
+
caretRange.collapse(true);
|
|
9584
|
+
const caretRects = caretRange.getClientRects();
|
|
9585
|
+
if (!caretRects.length) return true;
|
|
9586
|
+
const caretRect = caretRects[0];
|
|
9587
|
+
const containerRect = container.getBoundingClientRect();
|
|
9588
|
+
const lineHeight = parseFloat(getComputedStyle(container).lineHeight) || 20;
|
|
9589
|
+
if (direction === "up") {
|
|
9590
|
+
return caretRect.top < containerRect.top + lineHeight;
|
|
9591
|
+
} else {
|
|
9592
|
+
return caretRect.bottom > containerRect.bottom - lineHeight;
|
|
9593
|
+
}
|
|
9594
|
+
}
|
|
9595
|
+
var TablePlugin = {
|
|
9596
|
+
name: "table",
|
|
9597
|
+
keyBindings: {
|
|
9598
|
+
Tab: (engine) => {
|
|
9599
|
+
var _a;
|
|
9600
|
+
const state = engine.getState();
|
|
9601
|
+
const sel = state.selection;
|
|
9602
|
+
if (!sel) return false;
|
|
9603
|
+
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
9604
|
+
if (!cellPos) return false;
|
|
9605
|
+
const { tablePath, row, col } = cellPos;
|
|
9606
|
+
const table = getNodeAtPath(state.doc, tablePath);
|
|
9607
|
+
const { rows, cols } = getTableDimensions(table);
|
|
9608
|
+
let nextRow = row;
|
|
9609
|
+
let nextCol = col + 1;
|
|
9610
|
+
while (nextRow < rows) {
|
|
9611
|
+
if (nextCol >= cols) {
|
|
9612
|
+
nextCol = 0;
|
|
9613
|
+
nextRow++;
|
|
9614
|
+
continue;
|
|
9615
|
+
}
|
|
9616
|
+
const c = getNodeAtPath(state.doc, [...tablePath, nextRow, nextCol]);
|
|
9617
|
+
if (!((_a = c == null ? void 0 : c.attrs) == null ? void 0 : _a.covered)) break;
|
|
9618
|
+
nextCol++;
|
|
9619
|
+
}
|
|
9620
|
+
if (nextRow >= rows) {
|
|
9621
|
+
const newTable = insertTableRowAfter(table, rows - 1);
|
|
9622
|
+
const newChildren = [...state.doc.children];
|
|
9623
|
+
newChildren[tablePath[0]] = newTable;
|
|
9624
|
+
const tempDoc = { type: "doc", children: newChildren };
|
|
9625
|
+
const tr2 = createTransaction();
|
|
9626
|
+
tr2.steps.push({ type: "delete_node", path: tablePath });
|
|
9627
|
+
tr2.steps.push({
|
|
9628
|
+
type: "insert_node",
|
|
9629
|
+
parentPath: tablePath.length > 1 ? tablePath.slice(0, -1) : [],
|
|
9630
|
+
index: tablePath[tablePath.length - 1],
|
|
9631
|
+
node: newTable
|
|
9632
|
+
});
|
|
9633
|
+
const pos2 = getCellFirstPosition(tempDoc, tablePath, rows, 0);
|
|
9634
|
+
if (pos2) tr2.steps.push(tr_setSelection(makeCollapsedSelection(pos2)));
|
|
9635
|
+
engine.dispatch(tr2);
|
|
9636
|
+
return true;
|
|
9637
|
+
}
|
|
9638
|
+
const pos = getCellFirstPosition(state.doc, tablePath, nextRow, nextCol);
|
|
9639
|
+
if (!pos) return false;
|
|
9640
|
+
const tr = createTransaction();
|
|
9641
|
+
tr.steps.push(tr_setSelection(makeCollapsedSelection(pos)));
|
|
9642
|
+
engine.dispatch(tr);
|
|
9643
|
+
return true;
|
|
9644
|
+
},
|
|
9645
|
+
"ArrowRight": (engine) => {
|
|
9646
|
+
var _a;
|
|
9647
|
+
const state = engine.getState();
|
|
9648
|
+
const sel = state.selection;
|
|
9649
|
+
if (!sel) return false;
|
|
9650
|
+
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
9651
|
+
if (!cellPos) return false;
|
|
9652
|
+
const { tablePath, row, col } = cellPos;
|
|
9653
|
+
const cellPath = [...tablePath, row, col];
|
|
9654
|
+
const cellEl = getCellDOMElement(JSON.stringify(cellPath));
|
|
9655
|
+
if (!cellEl || !isCaretAtContainerEnd(cellEl)) return false;
|
|
9656
|
+
const table = getNodeAtPath(state.doc, tablePath);
|
|
9657
|
+
const { rows, cols } = getTableDimensions(table);
|
|
9658
|
+
let nextRow = row;
|
|
9659
|
+
let nextCol = col + 1;
|
|
9660
|
+
while (nextRow < rows) {
|
|
9661
|
+
if (nextCol >= cols) {
|
|
9662
|
+
nextCol = 0;
|
|
9663
|
+
nextRow++;
|
|
9664
|
+
continue;
|
|
9665
|
+
}
|
|
9666
|
+
const c = getNodeAtPath(state.doc, [...tablePath, nextRow, nextCol]);
|
|
9667
|
+
if (!((_a = c == null ? void 0 : c.attrs) == null ? void 0 : _a.covered)) break;
|
|
9668
|
+
nextCol++;
|
|
9669
|
+
}
|
|
9670
|
+
if (nextRow >= rows) return true;
|
|
9671
|
+
const pos = getCellFirstPosition(state.doc, tablePath, nextRow, nextCol);
|
|
9672
|
+
if (!pos) return false;
|
|
9673
|
+
const tr = createTransaction();
|
|
9674
|
+
tr.steps.push(tr_setSelection(makeCollapsedSelection(pos)));
|
|
9675
|
+
engine.dispatch(tr);
|
|
9676
|
+
return true;
|
|
9677
|
+
},
|
|
9678
|
+
"ArrowLeft": (engine) => {
|
|
9679
|
+
var _a;
|
|
9680
|
+
const state = engine.getState();
|
|
9681
|
+
const sel = state.selection;
|
|
9682
|
+
if (!sel) return false;
|
|
9683
|
+
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
9684
|
+
if (!cellPos) return false;
|
|
9685
|
+
const { tablePath, row, col } = cellPos;
|
|
9686
|
+
const cellPath = [...tablePath, row, col];
|
|
9687
|
+
const cellEl = getCellDOMElement(JSON.stringify(cellPath));
|
|
9688
|
+
if (!cellEl || !isCaretAtContainerStart(cellEl)) return false;
|
|
9689
|
+
const table = getNodeAtPath(state.doc, tablePath);
|
|
9690
|
+
const { cols } = getTableDimensions(table);
|
|
9691
|
+
let prevRow = row;
|
|
9692
|
+
let prevCol = col - 1;
|
|
9693
|
+
while (prevRow >= 0) {
|
|
9694
|
+
if (prevCol < 0) {
|
|
9695
|
+
prevCol = cols - 1;
|
|
9696
|
+
prevRow--;
|
|
9697
|
+
continue;
|
|
9698
|
+
}
|
|
9699
|
+
const c = getNodeAtPath(state.doc, [...tablePath, prevRow, prevCol]);
|
|
9700
|
+
if (!((_a = c == null ? void 0 : c.attrs) == null ? void 0 : _a.covered)) break;
|
|
9701
|
+
prevCol--;
|
|
9702
|
+
}
|
|
9703
|
+
if (prevRow < 0) return true;
|
|
9704
|
+
const pos = getCellLastPosition(state.doc, tablePath, prevRow, prevCol);
|
|
9705
|
+
if (!pos) return false;
|
|
9706
|
+
const tr = createTransaction();
|
|
9707
|
+
tr.steps.push(tr_setSelection(makeCollapsedSelection(pos)));
|
|
8848
9708
|
engine.dispatch(tr);
|
|
8849
9709
|
return true;
|
|
8850
9710
|
},
|
|
@@ -9146,151 +10006,6 @@ function execCommand(engine, command, ...args) {
|
|
|
9146
10006
|
function registerCommand(name, fn) {
|
|
9147
10007
|
REGISTRY[name] = fn;
|
|
9148
10008
|
}
|
|
9149
|
-
var Editor = forwardRef(function Editor2(props, ref) {
|
|
9150
|
-
var _a;
|
|
9151
|
-
const {
|
|
9152
|
-
value,
|
|
9153
|
-
defaultValue,
|
|
9154
|
-
onChange,
|
|
9155
|
-
placeholder,
|
|
9156
|
-
readOnly = false,
|
|
9157
|
-
toolbar = DEFAULT_TOOLBAR,
|
|
9158
|
-
theme = "light",
|
|
9159
|
-
plugins,
|
|
9160
|
-
onFocus,
|
|
9161
|
-
onBlur,
|
|
9162
|
-
onReady,
|
|
9163
|
-
onUploadImage,
|
|
9164
|
-
className,
|
|
9165
|
-
style,
|
|
9166
|
-
minHeight,
|
|
9167
|
-
maxHeight
|
|
9168
|
-
} = props;
|
|
9169
|
-
const engine = useEditorEngine();
|
|
9170
|
-
const pluginsRegisteredRef = useRef(false);
|
|
9171
|
-
if (!pluginsRegisteredRef.current && (plugins == null ? void 0 : plugins.length)) {
|
|
9172
|
-
pluginsRegisteredRef.current = true;
|
|
9173
|
-
for (const p of plugins) {
|
|
9174
|
-
engine.registerPlugin(p);
|
|
9175
|
-
}
|
|
9176
|
-
}
|
|
9177
|
-
const initializedRef = useRef(false);
|
|
9178
|
-
useEffect(() => {
|
|
9179
|
-
if (initializedRef.current) return;
|
|
9180
|
-
initializedRef.current = true;
|
|
9181
|
-
const initHTML = value != null ? value : defaultValue;
|
|
9182
|
-
if (!initHTML) return;
|
|
9183
|
-
const doc = htmlSerializer.deserialize(initHTML);
|
|
9184
|
-
const tr = createTransaction();
|
|
9185
|
-
tr.steps.push(tr_replaceDoc(doc));
|
|
9186
|
-
engine.dispatch(tr);
|
|
9187
|
-
}, []);
|
|
9188
|
-
const lastEmittedRef = useRef("");
|
|
9189
|
-
useEffect(() => {
|
|
9190
|
-
if (value === void 0) return;
|
|
9191
|
-
if (value === lastEmittedRef.current) return;
|
|
9192
|
-
const currentHTML = htmlSerializer.serialize(engine.getState().doc);
|
|
9193
|
-
if (value === currentHTML) return;
|
|
9194
|
-
const doc = htmlSerializer.deserialize(value);
|
|
9195
|
-
const tr = createTransaction();
|
|
9196
|
-
tr.steps.push(tr_replaceDoc(doc));
|
|
9197
|
-
engine.dispatch(tr);
|
|
9198
|
-
}, [value, engine]);
|
|
9199
|
-
const handleHTMLChange = useCallback((html) => {
|
|
9200
|
-
lastEmittedRef.current = html;
|
|
9201
|
-
onChange == null ? void 0 : onChange(html);
|
|
9202
|
-
}, [onChange]);
|
|
9203
|
-
const rootRef = useRef(null);
|
|
9204
|
-
const api = useMemo(() => ({
|
|
9205
|
-
getHTML: () => htmlSerializer.serialize(engine.getState().doc),
|
|
9206
|
-
setHTML: (html) => {
|
|
9207
|
-
const doc = htmlSerializer.deserialize(html);
|
|
9208
|
-
const tr = createTransaction();
|
|
9209
|
-
tr.steps.push(tr_replaceDoc(doc));
|
|
9210
|
-
engine.dispatch(tr);
|
|
9211
|
-
},
|
|
9212
|
-
getJSON: () => engine.getState().doc,
|
|
9213
|
-
getMarkdown: () => markdownSerializer.serialize(engine.getState().doc),
|
|
9214
|
-
focus: () => {
|
|
9215
|
-
var _a2;
|
|
9216
|
-
const ce = (_a2 = rootRef.current) == null ? void 0 : _a2.querySelector("[contenteditable]");
|
|
9217
|
-
ce == null ? void 0 : ce.focus();
|
|
9218
|
-
},
|
|
9219
|
-
blur: () => {
|
|
9220
|
-
var _a2;
|
|
9221
|
-
const ce = (_a2 = rootRef.current) == null ? void 0 : _a2.querySelector("[contenteditable]");
|
|
9222
|
-
ce == null ? void 0 : ce.blur();
|
|
9223
|
-
},
|
|
9224
|
-
clear: () => {
|
|
9225
|
-
const tr = createTransaction();
|
|
9226
|
-
tr.steps.push(tr_replaceDoc(createEmptyDocument()));
|
|
9227
|
-
engine.dispatch(tr);
|
|
9228
|
-
},
|
|
9229
|
-
undo: () => {
|
|
9230
|
-
engine.handleKeyDown(
|
|
9231
|
-
new KeyboardEvent("keydown", { key: "z", ctrlKey: true, bubbles: true })
|
|
9232
|
-
);
|
|
9233
|
-
},
|
|
9234
|
-
redo: () => {
|
|
9235
|
-
engine.handleKeyDown(
|
|
9236
|
-
new KeyboardEvent("keydown", { key: "y", ctrlKey: true, bubbles: true })
|
|
9237
|
-
);
|
|
9238
|
-
},
|
|
9239
|
-
execCommand: (command, ...args) => {
|
|
9240
|
-
return execCommand(engine, command, ...args);
|
|
9241
|
-
},
|
|
9242
|
-
registerCommand: (name, fn) => {
|
|
9243
|
-
registerCommand(name, fn);
|
|
9244
|
-
},
|
|
9245
|
-
getEngine: () => engine
|
|
9246
|
-
}), [engine]);
|
|
9247
|
-
useImperativeHandle(ref, () => api, [api]);
|
|
9248
|
-
useEffect(() => {
|
|
9249
|
-
onReady == null ? void 0 : onReady(api);
|
|
9250
|
-
}, []);
|
|
9251
|
-
const themeMode = typeof theme === "string" ? theme : (_a = theme.mode) != null ? _a : "light";
|
|
9252
|
-
const themeTokenOverrides = typeof theme === "object" && theme.tokens ? theme.tokens : void 0;
|
|
9253
|
-
const rootStyle = useMemo(() => {
|
|
9254
|
-
const base = { ...style };
|
|
9255
|
-
if (minHeight !== void 0)
|
|
9256
|
-
base.minHeight = typeof minHeight === "number" ? `${minHeight}px` : minHeight;
|
|
9257
|
-
if (maxHeight !== void 0) {
|
|
9258
|
-
base.maxHeight = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
|
|
9259
|
-
base.overflow = "auto";
|
|
9260
|
-
}
|
|
9261
|
-
if (themeTokenOverrides) {
|
|
9262
|
-
for (const [key, val] of Object.entries(themeTokenOverrides)) {
|
|
9263
|
-
const cssVar = `--editor-${key.replace(/([A-Z])/g, (m) => `-${m.toLowerCase()}`)}`;
|
|
9264
|
-
base[cssVar] = val;
|
|
9265
|
-
}
|
|
9266
|
-
}
|
|
9267
|
-
return base;
|
|
9268
|
-
}, [style, minHeight, maxHeight, themeTokenOverrides]);
|
|
9269
|
-
return /* @__PURE__ */ jsx(
|
|
9270
|
-
"div",
|
|
9271
|
-
{
|
|
9272
|
-
ref: rootRef,
|
|
9273
|
-
"data-editor-theme": themeMode,
|
|
9274
|
-
"data-traffica-editor": "",
|
|
9275
|
-
className,
|
|
9276
|
-
style: rootStyle,
|
|
9277
|
-
children: /* @__PURE__ */ jsx(
|
|
9278
|
-
EditorCore,
|
|
9279
|
-
{
|
|
9280
|
-
engine,
|
|
9281
|
-
placeholder,
|
|
9282
|
-
readOnly,
|
|
9283
|
-
hideToolbar: toolbar === false,
|
|
9284
|
-
toolbarConfig: toolbar !== false ? toolbar : void 0,
|
|
9285
|
-
onHTMLChange: handleHTMLChange,
|
|
9286
|
-
onFocus,
|
|
9287
|
-
onBlur,
|
|
9288
|
-
onUploadImage
|
|
9289
|
-
}
|
|
9290
|
-
)
|
|
9291
|
-
}
|
|
9292
|
-
);
|
|
9293
|
-
});
|
|
9294
10009
|
|
|
9295
10010
|
export { BASIC_TOOLBAR, DEFAULT_TOOLBAR, Editor, EditorCore, EditorEngine, MINIMAL_TOOLBAR, TablePlugin, Toolbar, addColumnLeft, addColumnRight, addMarkToNode, addRowAbove, addRowBelow, applyMarkToRange, applySearchHighlights, applyTransaction, attachClipboardHandlers, attachPasteHandler, captureSelection, clearSearchHighlights, collectText, comparePaths, comparePositions, createEmptyDocument, createHistoryManager, createHistoryPlugin, createParagraph, createPastePlugin, createTableCell, createTableNode, createTransaction, deleteColumn, deleteImageAtPath, deleteRange, deleteRow, deleteTable, deleteTableColumn, deleteTableRow, deleteTextAtPath, execCommand, findCellPosition, findContentBlockPath, findMatches, findTablePath, getActiveAlignment, getActiveBlockType, getActiveFontFamily, getActiveFontSize, getActiveHighlightColor, getActiveLinkHref, getActiveLinkRange, getActiveMarks, getActiveTextColor, getCellFirstPosition, getCellLastPosition, getDocumentLength, getDocumentMarkAttrValues, getNodeAtPath, getTableDimensions, getTextNodesBetween, htmlSerializer, insertImage, insertLink, insertTable, insertTableColumnAfter, insertTableColumnBefore, insertTableRowAfter, insertTableRowBefore, insertText, insertTextAtPath, isBlockNode, isContainerBlock, isSelectionInContainer, isTextNode, joinBlocks, jsonSerializer, makeCollapsedSelection, makePosition, markdownSerializer, marksEqual, mergeAdjacentTextNodesInDoc, mergeCells, mergeTableCells, normalizeRange, redo, registerCommand, removeMarkFromNode, removeMarkFromRange, renderDocument, replaceAllMatches, replaceMatch, restoreSelection, scrollMatchIntoView, setAlignment, setBlockType2 as setBlockType, setCodeBlockLanguage, setColumnWidth, setFontFamily, setFontSize, setHighlightColor, setImageAttr, setMarkOnRange, setTextColor, splitBlock, splitCell, splitTableCell, toggleCheckItemAt, toggleHeaderRow, toggleMark, undo, updateColumnWidth, useEditorEngine, useEditorState, walkDocument };
|
|
9296
10011
|
//# sourceMappingURL=index.mjs.map
|