@haklex/rich-editor 0.0.103 → 0.0.105
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/{AlertQuoteEditNode-C_Cb063D.js → AlertQuoteEditNode-CPb1jFUY.js} +1 -1
- package/dist/{MermaidPlugin-DI86n71x.js → MermaidPlugin-CJ0tqr0F.js} +8 -4
- package/dist/{SubmitShortcutPlugin-CDqj7KHO.js → SubmitShortcutPlugin-BmTJ4o1C.js} +665 -8
- package/dist/commands-entry.mjs +3 -3
- package/dist/components/RichEditor.d.ts.map +1 -1
- package/dist/components/RichEditorShell.d.ts.map +1 -1
- package/dist/{config-mAejoug-.js → config-DjJiU65k.js} +1 -1
- package/dist/context/TextSelectionContext.d.ts +18 -0
- package/dist/context/TextSelectionContext.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +38 -171
- package/dist/{node-registry-BOSH1oBi.js → node-registry-CJe4Pjdm.js} +3 -3
- package/dist/nodes/KaTeXBlockNode.d.ts +7 -2
- package/dist/nodes/KaTeXBlockNode.d.ts.map +1 -1
- package/dist/nodes/KaTeXInlineNode.d.ts +7 -2
- package/dist/nodes/KaTeXInlineNode.d.ts.map +1 -1
- package/dist/nodes-entry.mjs +4 -4
- package/dist/plugins/KaTeXPlugin.d.ts.map +1 -1
- package/dist/plugins/TextSelectionPlugin.d.ts +2 -0
- package/dist/plugins/TextSelectionPlugin.d.ts.map +1 -0
- package/dist/plugins/text-selection.css.d.ts +3 -0
- package/dist/plugins/text-selection.css.d.ts.map +1 -0
- package/dist/plugins-entry.d.ts +1 -0
- package/dist/plugins-entry.d.ts.map +1 -1
- package/dist/plugins-entry.mjs +3 -2
- package/dist/rich-editor.css +1 -1
- package/dist/static-entry.mjs +3 -3
- package/dist/{theme-CrJbATnf.js → theme-I0pMTSBW.js} +78 -10
- package/dist/utils/getRegisteredNodeKlass.d.ts +3 -0
- package/dist/utils/getRegisteredNodeKlass.d.ts.map +1 -0
- package/dist/utils/katex-defaults.d.ts +5 -0
- package/dist/utils/katex-defaults.d.ts.map +1 -0
- package/dist/utils/text-selection-constants.d.ts +3 -0
- package/dist/utils/text-selection-constants.d.ts.map +1 -0
- package/dist/utils/text-selection.d.ts +22 -0
- package/dist/utils/text-selection.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -6,24 +6,24 @@ import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin
|
|
|
6
6
|
import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
|
|
7
7
|
import { createLinkMatcherWithRegExp, registerAutoLink, LinkNode, AutoLinkNode } from "@lexical/link";
|
|
8
8
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
9
|
-
import { useEffect, createContext, use, useRef, useState, useMemo, useCallback } from "react";
|
|
9
|
+
import { useEffect, createContext, use, useRef, useState, useMemo, useCallback, useSyncExternalStore } from "react";
|
|
10
10
|
import { $isQuoteNode, QuoteNode, $createQuoteNode, DRAG_DROP_PASTE } from "@lexical/rich-text";
|
|
11
|
-
import { KEY_ARROW_RIGHT_COMMAND, $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, KEY_ARROW_DOWN_COMMAND, $isDecoratorNode, $isElementNode, $isRootNode, $isParagraphNode, $createParagraphNode, KEY_ENTER_COMMAND, $isNodeSelection, KEY_BACKSPACE_COMMAND, COMMAND_PRIORITY_HIGH, KEY_DELETE_COMMAND, KEY_ARROW_UP_COMMAND, $isTextNode, IS_CODE, $createNodeSelection, $setSelection, $getRoot, $getNodeByKey, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, $createTextNode, $createLineBreakNode, PASTE_COMMAND, $insertNodes, createEditor, $parseSerializedNode, createState, $getState, $addUpdateTag, $setState, $nodesOfType } from "lexical";
|
|
12
|
-
import { b as setCodeBlockCursorIntent, g as getResolvedEditNodes, $ as $createBannerEditNode, d as $createCodeBlockEditNode } from "./node-registry-
|
|
11
|
+
import { KEY_ARROW_RIGHT_COMMAND, $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, KEY_ARROW_DOWN_COMMAND, $isDecoratorNode, $isElementNode, $isRootNode, $isParagraphNode, $createParagraphNode, KEY_ENTER_COMMAND, $isNodeSelection, KEY_BACKSPACE_COMMAND, COMMAND_PRIORITY_HIGH, KEY_DELETE_COMMAND, KEY_ARROW_UP_COMMAND, $isTextNode, IS_CODE, $createNodeSelection, $setSelection, $getRoot, $getNodeByKey, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, $createTextNode, $createLineBreakNode, PASTE_COMMAND, $insertNodes, createEditor, $parseSerializedNode, createState, $getState, $addUpdateTag, $setState, $isLineBreakNode, $createRangeSelection, SELECTION_CHANGE_COMMAND, $nodesOfType } from "lexical";
|
|
12
|
+
import { b as setCodeBlockCursorIntent, g as getResolvedEditNodes, $ as $createBannerEditNode, d as $createCodeBlockEditNode } from "./node-registry-CJe4Pjdm.js";
|
|
13
13
|
import { HorizontalRuleNode, $createHorizontalRuleNode, INSERT_HORIZONTAL_RULE_COMMAND } from "@lexical/extension";
|
|
14
14
|
import { HORIZONTAL_RULE_BLOCK_TRANSFORMER as HORIZONTAL_RULE_BLOCK_TRANSFORMER$1, GIT_ALERT_TRANSFORMER as GIT_ALERT_TRANSFORMER$1, COMMENT_TRANSFORMER as COMMENT_TRANSFORMER$1, CONTAINER_TRANSFORMER as CONTAINER_TRANSFORMER$1, FOOTNOTE_TRANSFORMER as FOOTNOTE_TRANSFORMER$1, FOOTNOTE_SECTION_TRANSFORMER as FOOTNOTE_SECTION_TRANSFORMER$1, KATEX_INLINE_TRANSFORMER as KATEX_INLINE_TRANSFORMER$1, KATEX_BLOCK_TRANSFORMER as KATEX_BLOCK_TRANSFORMER$1, MENTION_TRANSFORMER as MENTION_TRANSFORMER$1, RUBY_TRANSFORMER as RUBY_TRANSFORMER$1, SPOILER_TRANSFORMER as SPOILER_TRANSFORMER$1, INSERT_TRANSFORMER, SUPERSCRIPT_TRANSFORMER, SUBSCRIPT_TRANSFORMER, IMAGE_BLOCK_TRANSFORMER, VIDEO_BLOCK_TRANSFORMER, CODE_BLOCK_NODE_TRANSFORMER, LINK_CARD_BLOCK_TRANSFORMER, MERMAID_BLOCK_TRANSFORMER, TABLE_BLOCK_TRANSFORMER } from "@haklex/rich-headless/transformers";
|
|
15
15
|
import { CHECK_LIST, TRANSFORMERS, QUOTE, CODE, $convertFromMarkdownString } from "@lexical/markdown";
|
|
16
|
-
import { $ as $createAlertQuoteEditNode } from "./AlertQuoteEditNode-
|
|
17
|
-
import { v as AlertQuoteNode, F as FootnoteNode, y as $createFootnoteNode, k as KaTeXInlineNode, K as KaTeXBlockNode, w as $createKaTeXInlineNode, x as $createKaTeXBlockNode, M as MentionNode, a as $createMentionNode, o as extractTextContent, S as SpoilerNode, q as $createSpoilerNode, $ as $createImageNode, O as OPEN_IMAGE_UPLOAD_DIALOG_COMMAND } from "./theme-
|
|
18
|
-
import { v as CodeBlockNode, C as CommentNode, w as $createCommentPlaceholderNode, $ as $createCommentNode, q as BannerNode, D as DetailsNode, x as $createDetailsNode, F as FootnoteSectionNode, f as $isFootnoteSectionNode, a as $createFootnoteSectionNode, g as $isGridContainerNode, R as RubyNode, d as $createRubyNode } from "./config-
|
|
16
|
+
import { $ as $createAlertQuoteEditNode } from "./AlertQuoteEditNode-CPb1jFUY.js";
|
|
17
|
+
import { v as AlertQuoteNode, F as FootnoteNode, y as $createFootnoteNode, k as KaTeXInlineNode, K as KaTeXBlockNode, w as $createKaTeXInlineNode, x as $createKaTeXBlockNode, M as MentionNode, a as $createMentionNode, o as extractTextContent, S as SpoilerNode, q as $createSpoilerNode, $ as $createImageNode, O as OPEN_IMAGE_UPLOAD_DIALOG_COMMAND } from "./theme-I0pMTSBW.js";
|
|
18
|
+
import { v as CodeBlockNode, C as CommentNode, w as $createCommentPlaceholderNode, $ as $createCommentNode, q as BannerNode, D as DetailsNode, x as $createDetailsNode, F as FootnoteSectionNode, f as $isFootnoteSectionNode, a as $createFootnoteSectionNode, g as $isGridContainerNode, R as RubyNode, d as $createRubyNode } from "./config-DjJiU65k.js";
|
|
19
19
|
import { $createTableNode, $createTableRowNode, $createTableCellNode, TableCellHeaderStates } from "@lexical/table";
|
|
20
20
|
import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
|
|
21
|
-
import { nanoid } from "nanoid";
|
|
22
21
|
import { Dialog, DialogPopup, DialogTitle, SegmentedControl, ActionButton, ActionBar } from "@haklex/rich-editor-ui";
|
|
23
22
|
import { Check, Info, Upload, Link2 } from "lucide-react";
|
|
24
23
|
import { i as computeImageMeta, F as FootnoteDefinitionsProvider } from "./KaTeXRenderer-CQyQzNTJ.js";
|
|
25
24
|
import "./katex.css-Csc-7N7u.js";
|
|
26
25
|
import { g as getHostname, p as probeFavicon, n as normalizeSerializedEditorState } from "./normalizeSerializedEditorState-k5G4xSi9.js";
|
|
26
|
+
import { nanoid } from "nanoid";
|
|
27
27
|
const URL_REGEX = /https?:\/\/(?:www\.)?[\w#%+.:=@~-]{1,256}\.[A-Za-z]{2}[\w#%&()+./:=?@~-]*/;
|
|
28
28
|
const EMAIL_REGEX = /(?:[\w%+.-]+@[\d.a-z-]+\.[a-z]{2,})/i;
|
|
29
29
|
const URL_MATCHER = createLinkMatcherWithRegExp(URL_REGEX);
|
|
@@ -1587,6 +1587,644 @@ function LinkFaviconPlugin() {
|
|
|
1587
1587
|
}, [editor]);
|
|
1588
1588
|
return null;
|
|
1589
1589
|
}
|
|
1590
|
+
function areSnapshotsEqual(a, b) {
|
|
1591
|
+
if (a === b) return true;
|
|
1592
|
+
if (!a || !b) return false;
|
|
1593
|
+
return a.text === b.text && a.anchorBlockId === b.anchorBlockId && a.anchorOffset === b.anchorOffset && a.focusBlockId === b.focusBlockId && a.focusOffset === b.focusOffset;
|
|
1594
|
+
}
|
|
1595
|
+
function createTextSelectionStore(initialState = { snapshot: null }) {
|
|
1596
|
+
let state = initialState;
|
|
1597
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1598
|
+
const emit = () => {
|
|
1599
|
+
for (const listener of listeners) {
|
|
1600
|
+
listener();
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
return {
|
|
1604
|
+
getState: () => state,
|
|
1605
|
+
subscribe: (listener) => {
|
|
1606
|
+
listeners.add(listener);
|
|
1607
|
+
return () => {
|
|
1608
|
+
listeners.delete(listener);
|
|
1609
|
+
};
|
|
1610
|
+
},
|
|
1611
|
+
setSnapshot: (snapshot) => {
|
|
1612
|
+
if (areSnapshotsEqual(state.snapshot, snapshot)) {
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
state = { ...state, snapshot };
|
|
1616
|
+
emit();
|
|
1617
|
+
},
|
|
1618
|
+
clearSnapshot: () => {
|
|
1619
|
+
if (state.snapshot === null) {
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
state = { ...state, snapshot: null };
|
|
1623
|
+
emit();
|
|
1624
|
+
}
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
const TextSelectionStoreContext = createContext(null);
|
|
1628
|
+
function TextSelectionStoreProvider({ children }) {
|
|
1629
|
+
const storeRef = useRef(null);
|
|
1630
|
+
if (!storeRef.current) {
|
|
1631
|
+
storeRef.current = createTextSelectionStore();
|
|
1632
|
+
}
|
|
1633
|
+
return /* @__PURE__ */ jsx(TextSelectionStoreContext.Provider, { value: storeRef.current, children });
|
|
1634
|
+
}
|
|
1635
|
+
function useTextSelectionStore() {
|
|
1636
|
+
const store = use(TextSelectionStoreContext);
|
|
1637
|
+
if (!store) {
|
|
1638
|
+
throw new Error("useTextSelectionStore must be used within TextSelectionStoreProvider");
|
|
1639
|
+
}
|
|
1640
|
+
return store;
|
|
1641
|
+
}
|
|
1642
|
+
function useTextSelectionSnapshot() {
|
|
1643
|
+
const store = useTextSelectionStore();
|
|
1644
|
+
return useSyncExternalStore(
|
|
1645
|
+
store.subscribe,
|
|
1646
|
+
() => store.getState().snapshot,
|
|
1647
|
+
() => store.getState().snapshot
|
|
1648
|
+
);
|
|
1649
|
+
}
|
|
1650
|
+
function computeBlockFingerprint(block) {
|
|
1651
|
+
const text = block.getTextContent();
|
|
1652
|
+
const input = text.slice(0, 200) + String(text.length);
|
|
1653
|
+
let hash = 5381;
|
|
1654
|
+
for (let i = 0; i < input.length; i++) {
|
|
1655
|
+
hash = (hash << 5) + hash + (input.codePointAt(i) ?? 0) | 0;
|
|
1656
|
+
}
|
|
1657
|
+
return (hash >>> 0).toString(16);
|
|
1658
|
+
}
|
|
1659
|
+
function $getRootBlock(node) {
|
|
1660
|
+
const root = $getRoot();
|
|
1661
|
+
let current = node;
|
|
1662
|
+
while (current) {
|
|
1663
|
+
const parent = current.getParent();
|
|
1664
|
+
if (parent === root && "getChildren" in current) {
|
|
1665
|
+
return current;
|
|
1666
|
+
}
|
|
1667
|
+
current = parent;
|
|
1668
|
+
}
|
|
1669
|
+
return null;
|
|
1670
|
+
}
|
|
1671
|
+
function $resolveSelectionPoint(selection, which) {
|
|
1672
|
+
const point = selection[which];
|
|
1673
|
+
const node = point.getNode();
|
|
1674
|
+
if ($isElementNode(node)) {
|
|
1675
|
+
const children = node.getChildren();
|
|
1676
|
+
if (point.offset < children.length) {
|
|
1677
|
+
return { node: children[point.offset], offset: 0 };
|
|
1678
|
+
}
|
|
1679
|
+
const last = children.at(-1);
|
|
1680
|
+
if (last && $isTextNode(last)) {
|
|
1681
|
+
return { node: last, offset: last.getTextContentSize() };
|
|
1682
|
+
}
|
|
1683
|
+
return { node, offset: 0 };
|
|
1684
|
+
}
|
|
1685
|
+
return { node, offset: point.offset };
|
|
1686
|
+
}
|
|
1687
|
+
function $getTextOffsetInBlock(block, targetNode, targetOffset) {
|
|
1688
|
+
let offset = 0;
|
|
1689
|
+
function walk(node) {
|
|
1690
|
+
if (node.is(targetNode)) {
|
|
1691
|
+
offset += targetOffset;
|
|
1692
|
+
return true;
|
|
1693
|
+
}
|
|
1694
|
+
if ($isTextNode(node)) {
|
|
1695
|
+
offset += node.getTextContentSize();
|
|
1696
|
+
} else if ($isLineBreakNode(node)) {
|
|
1697
|
+
offset += 1;
|
|
1698
|
+
} else if ($isElementNode(node)) {
|
|
1699
|
+
for (const child of node.getChildren()) {
|
|
1700
|
+
if (walk(child)) return true;
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
return false;
|
|
1704
|
+
}
|
|
1705
|
+
for (const child of block.getChildren()) {
|
|
1706
|
+
if (walk(child)) break;
|
|
1707
|
+
}
|
|
1708
|
+
return offset;
|
|
1709
|
+
}
|
|
1710
|
+
function $buildBlockAnchorData(block) {
|
|
1711
|
+
const blockId = $getState(block, blockIdState);
|
|
1712
|
+
if (!blockId) {
|
|
1713
|
+
return { ok: false, error: "no-block-id" };
|
|
1714
|
+
}
|
|
1715
|
+
return {
|
|
1716
|
+
ok: true,
|
|
1717
|
+
anchor: {
|
|
1718
|
+
mode: "block",
|
|
1719
|
+
blockId,
|
|
1720
|
+
blockType: block.getType(),
|
|
1721
|
+
blockFingerprint: computeBlockFingerprint(block),
|
|
1722
|
+
snapshotText: block.getTextContent().slice(0, 300)
|
|
1723
|
+
}
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
function buildBlockAnchor(editor, blockKey) {
|
|
1727
|
+
return editor.read(() => {
|
|
1728
|
+
if (blockKey) {
|
|
1729
|
+
const node = $getRoot().getChildren().find((c) => c.getKey() === blockKey);
|
|
1730
|
+
if (!node || !("getChildren" in node)) {
|
|
1731
|
+
return { ok: false, error: "not-root-block" };
|
|
1732
|
+
}
|
|
1733
|
+
return $buildBlockAnchorData(node);
|
|
1734
|
+
}
|
|
1735
|
+
const selection = $getSelection();
|
|
1736
|
+
if (!$isRangeSelection(selection)) {
|
|
1737
|
+
return { ok: false, error: "no-selection" };
|
|
1738
|
+
}
|
|
1739
|
+
const anchorNode = selection.anchor.getNode();
|
|
1740
|
+
const block = $getRootBlock(anchorNode);
|
|
1741
|
+
if (!block) {
|
|
1742
|
+
return { ok: false, error: "not-root-block" };
|
|
1743
|
+
}
|
|
1744
|
+
return $buildBlockAnchorData(block);
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
function buildRangeAnchor(editor) {
|
|
1748
|
+
return editor.read(() => {
|
|
1749
|
+
const selection = $getSelection();
|
|
1750
|
+
if (!$isRangeSelection(selection)) {
|
|
1751
|
+
return { ok: false, error: "no-selection" };
|
|
1752
|
+
}
|
|
1753
|
+
if (selection.isCollapsed()) {
|
|
1754
|
+
return { ok: false, error: "collapsed" };
|
|
1755
|
+
}
|
|
1756
|
+
const anchorBlock = $getRootBlock(selection.anchor.getNode());
|
|
1757
|
+
const focusBlock = $getRootBlock(selection.focus.getNode());
|
|
1758
|
+
if (!anchorBlock || !focusBlock) {
|
|
1759
|
+
return { ok: false, error: "not-root-block" };
|
|
1760
|
+
}
|
|
1761
|
+
if (anchorBlock !== focusBlock) {
|
|
1762
|
+
return { ok: false, error: "cross-block" };
|
|
1763
|
+
}
|
|
1764
|
+
const block = anchorBlock;
|
|
1765
|
+
const blockId = $getState(block, blockIdState);
|
|
1766
|
+
if (!blockId) {
|
|
1767
|
+
return { ok: false, error: "no-block-id" };
|
|
1768
|
+
}
|
|
1769
|
+
const anchorPoint = $resolveSelectionPoint(selection, "anchor");
|
|
1770
|
+
const focusPoint = $resolveSelectionPoint(selection, "focus");
|
|
1771
|
+
let startOffset = $getTextOffsetInBlock(block, anchorPoint.node, anchorPoint.offset);
|
|
1772
|
+
let endOffset = $getTextOffsetInBlock(block, focusPoint.node, focusPoint.offset);
|
|
1773
|
+
if (startOffset > endOffset) {
|
|
1774
|
+
[startOffset, endOffset] = [endOffset, startOffset];
|
|
1775
|
+
}
|
|
1776
|
+
const text = block.getTextContent();
|
|
1777
|
+
const quote = text.slice(startOffset, endOffset);
|
|
1778
|
+
const prefix = text.slice(Math.max(0, startOffset - 50), startOffset);
|
|
1779
|
+
const suffix = text.slice(endOffset, endOffset + 50);
|
|
1780
|
+
return {
|
|
1781
|
+
ok: true,
|
|
1782
|
+
anchor: {
|
|
1783
|
+
mode: "range",
|
|
1784
|
+
blockId,
|
|
1785
|
+
blockType: block.getType(),
|
|
1786
|
+
blockFingerprint: computeBlockFingerprint(block),
|
|
1787
|
+
snapshotText: text.slice(0, 300),
|
|
1788
|
+
quote,
|
|
1789
|
+
prefix,
|
|
1790
|
+
suffix,
|
|
1791
|
+
startOffset,
|
|
1792
|
+
endOffset
|
|
1793
|
+
}
|
|
1794
|
+
};
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
const TEXT_SELECTION_HIGHLIGHT_NAME = "rich-editor-text-selection";
|
|
1798
|
+
const TEXT_SELECTION_INACTIVE_HIGHLIGHT_NAME = "rich-editor-text-selection-inactive";
|
|
1799
|
+
function clampOffset(offset, max) {
|
|
1800
|
+
return Math.max(0, Math.min(offset, max));
|
|
1801
|
+
}
|
|
1802
|
+
function getTopLevelBlockById(blockId) {
|
|
1803
|
+
for (const child of $getRoot().getChildren()) {
|
|
1804
|
+
if ($getState(child, blockIdState) === blockId && $isElementNode(child)) {
|
|
1805
|
+
return child;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
return null;
|
|
1809
|
+
}
|
|
1810
|
+
function getTextLengthOfDomNode(node) {
|
|
1811
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
1812
|
+
return node.textContent?.length ?? 0;
|
|
1813
|
+
}
|
|
1814
|
+
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
1815
|
+
return 0;
|
|
1816
|
+
}
|
|
1817
|
+
const element = node;
|
|
1818
|
+
if (element.tagName === "BR") {
|
|
1819
|
+
return 1;
|
|
1820
|
+
}
|
|
1821
|
+
let length = 0;
|
|
1822
|
+
for (const child of node.childNodes) {
|
|
1823
|
+
length += getTextLengthOfDomNode(child);
|
|
1824
|
+
}
|
|
1825
|
+
return length;
|
|
1826
|
+
}
|
|
1827
|
+
function compareBlockElements(a, b) {
|
|
1828
|
+
if (a === b) return 0;
|
|
1829
|
+
const position = a.compareDocumentPosition(b);
|
|
1830
|
+
if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
1831
|
+
return -1;
|
|
1832
|
+
}
|
|
1833
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING) {
|
|
1834
|
+
return 1;
|
|
1835
|
+
}
|
|
1836
|
+
return 0;
|
|
1837
|
+
}
|
|
1838
|
+
function buildDomRectFromClientRects(rects) {
|
|
1839
|
+
if (!rects.length) return null;
|
|
1840
|
+
let left = rects[0].left;
|
|
1841
|
+
let top = rects[0].top;
|
|
1842
|
+
let right = rects[0].right;
|
|
1843
|
+
let bottom = rects[0].bottom;
|
|
1844
|
+
for (const rect of rects.slice(1)) {
|
|
1845
|
+
left = Math.min(left, rect.left);
|
|
1846
|
+
top = Math.min(top, rect.top);
|
|
1847
|
+
right = Math.max(right, rect.right);
|
|
1848
|
+
bottom = Math.max(bottom, rect.bottom);
|
|
1849
|
+
}
|
|
1850
|
+
return new DOMRect(left, top, right - left, bottom - top);
|
|
1851
|
+
}
|
|
1852
|
+
function resolveLexicalSelectionTarget(block, requestedOffset) {
|
|
1853
|
+
const offset = clampOffset(requestedOffset, block.getTextContent().length);
|
|
1854
|
+
let remaining = offset;
|
|
1855
|
+
let lastTarget = {
|
|
1856
|
+
key: block.getKey(),
|
|
1857
|
+
offset: block.getChildrenSize(),
|
|
1858
|
+
type: "element"
|
|
1859
|
+
};
|
|
1860
|
+
function walk(node) {
|
|
1861
|
+
if ($isTextNode(node)) {
|
|
1862
|
+
const length = node.getTextContentSize();
|
|
1863
|
+
lastTarget = { key: node.getKey(), offset: length, type: "text" };
|
|
1864
|
+
if (remaining <= length) {
|
|
1865
|
+
return { key: node.getKey(), offset: remaining, type: "text" };
|
|
1866
|
+
}
|
|
1867
|
+
remaining -= length;
|
|
1868
|
+
return null;
|
|
1869
|
+
}
|
|
1870
|
+
if ($isLineBreakNode(node)) {
|
|
1871
|
+
const parent = node.getParent();
|
|
1872
|
+
if (!parent) {
|
|
1873
|
+
return null;
|
|
1874
|
+
}
|
|
1875
|
+
const index = node.getIndexWithinParent();
|
|
1876
|
+
if (remaining === 0) {
|
|
1877
|
+
return { key: parent.getKey(), offset: index, type: "element" };
|
|
1878
|
+
}
|
|
1879
|
+
if (remaining === 1) {
|
|
1880
|
+
return { key: parent.getKey(), offset: index + 1, type: "element" };
|
|
1881
|
+
}
|
|
1882
|
+
remaining -= 1;
|
|
1883
|
+
lastTarget = { key: parent.getKey(), offset: index + 1, type: "element" };
|
|
1884
|
+
return null;
|
|
1885
|
+
}
|
|
1886
|
+
if (!$isElementNode(node)) {
|
|
1887
|
+
return null;
|
|
1888
|
+
}
|
|
1889
|
+
if (node.getChildrenSize() === 0) {
|
|
1890
|
+
lastTarget = { key: node.getKey(), offset: 0, type: "element" };
|
|
1891
|
+
return null;
|
|
1892
|
+
}
|
|
1893
|
+
for (const child of node.getChildren()) {
|
|
1894
|
+
const resolved = walk(child);
|
|
1895
|
+
if (resolved) {
|
|
1896
|
+
return resolved;
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
lastTarget = { key: node.getKey(), offset: node.getChildrenSize(), type: "element" };
|
|
1900
|
+
return null;
|
|
1901
|
+
}
|
|
1902
|
+
return walk(block) ?? lastTarget;
|
|
1903
|
+
}
|
|
1904
|
+
function $captureTextSelectionFromRangeSelection(selection) {
|
|
1905
|
+
if (selection.isCollapsed()) {
|
|
1906
|
+
return null;
|
|
1907
|
+
}
|
|
1908
|
+
const anchorBlock = $getRootBlock(selection.anchor.getNode());
|
|
1909
|
+
const focusBlock = $getRootBlock(selection.focus.getNode());
|
|
1910
|
+
if (!anchorBlock || !focusBlock) {
|
|
1911
|
+
return null;
|
|
1912
|
+
}
|
|
1913
|
+
const anchorBlockId = $getState(anchorBlock, blockIdState);
|
|
1914
|
+
const focusBlockId = $getState(focusBlock, blockIdState);
|
|
1915
|
+
if (!anchorBlockId || !focusBlockId) {
|
|
1916
|
+
return null;
|
|
1917
|
+
}
|
|
1918
|
+
const anchorPoint = $resolveSelectionPoint(selection, "anchor");
|
|
1919
|
+
const focusPoint = $resolveSelectionPoint(selection, "focus");
|
|
1920
|
+
return {
|
|
1921
|
+
text: selection.getTextContent(),
|
|
1922
|
+
anchorBlockId,
|
|
1923
|
+
anchorOffset: $getTextOffsetInBlock(anchorBlock, anchorPoint.node, anchorPoint.offset),
|
|
1924
|
+
focusBlockId,
|
|
1925
|
+
focusOffset: $getTextOffsetInBlock(focusBlock, focusPoint.node, focusPoint.offset)
|
|
1926
|
+
};
|
|
1927
|
+
}
|
|
1928
|
+
function $captureTextSelection() {
|
|
1929
|
+
const selection = $getSelection();
|
|
1930
|
+
if (!$isRangeSelection(selection)) {
|
|
1931
|
+
return null;
|
|
1932
|
+
}
|
|
1933
|
+
return $captureTextSelectionFromRangeSelection(selection);
|
|
1934
|
+
}
|
|
1935
|
+
function $restoreTextSelection(snapshot) {
|
|
1936
|
+
const anchorBlock = getTopLevelBlockById(snapshot.anchorBlockId);
|
|
1937
|
+
const focusBlock = getTopLevelBlockById(snapshot.focusBlockId);
|
|
1938
|
+
if (!anchorBlock || !focusBlock) {
|
|
1939
|
+
return false;
|
|
1940
|
+
}
|
|
1941
|
+
const anchor = resolveLexicalSelectionTarget(anchorBlock, snapshot.anchorOffset);
|
|
1942
|
+
const focus = resolveLexicalSelectionTarget(focusBlock, snapshot.focusOffset);
|
|
1943
|
+
const selection = $createRangeSelection();
|
|
1944
|
+
selection.anchor.set(anchor.key, anchor.offset, anchor.type);
|
|
1945
|
+
selection.focus.set(focus.key, focus.offset, focus.type);
|
|
1946
|
+
$setSelection(selection);
|
|
1947
|
+
return true;
|
|
1948
|
+
}
|
|
1949
|
+
function getTextOffsetFromDOMPoint(container, targetNode, targetOffset) {
|
|
1950
|
+
let offset = 0;
|
|
1951
|
+
function walk(node) {
|
|
1952
|
+
if (node === targetNode) {
|
|
1953
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
1954
|
+
offset += Math.min(targetOffset, node.textContent?.length ?? 0);
|
|
1955
|
+
return true;
|
|
1956
|
+
}
|
|
1957
|
+
const childNodes = Array.from(node.childNodes);
|
|
1958
|
+
const boundary = Math.min(targetOffset, childNodes.length);
|
|
1959
|
+
for (let i = 0; i < boundary; i++) {
|
|
1960
|
+
offset += getTextLengthOfDomNode(childNodes[i]);
|
|
1961
|
+
}
|
|
1962
|
+
return true;
|
|
1963
|
+
}
|
|
1964
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
1965
|
+
offset += node.textContent?.length ?? 0;
|
|
1966
|
+
return false;
|
|
1967
|
+
}
|
|
1968
|
+
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
1969
|
+
return false;
|
|
1970
|
+
}
|
|
1971
|
+
const element = node;
|
|
1972
|
+
if (element.tagName === "BR") {
|
|
1973
|
+
offset += 1;
|
|
1974
|
+
return false;
|
|
1975
|
+
}
|
|
1976
|
+
for (const child of node.childNodes) {
|
|
1977
|
+
if (walk(child)) {
|
|
1978
|
+
return true;
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
return false;
|
|
1982
|
+
}
|
|
1983
|
+
walk(container);
|
|
1984
|
+
return offset;
|
|
1985
|
+
}
|
|
1986
|
+
function findDOMPointByTextOffset(container, requestedOffset) {
|
|
1987
|
+
const targetOffset = clampOffset(requestedOffset, getTextLengthOfDomNode(container));
|
|
1988
|
+
let consumed = 0;
|
|
1989
|
+
function walk(node) {
|
|
1990
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
1991
|
+
const length = node.textContent?.length ?? 0;
|
|
1992
|
+
if (targetOffset <= consumed + length) {
|
|
1993
|
+
return { node, offset: targetOffset - consumed };
|
|
1994
|
+
}
|
|
1995
|
+
consumed += length;
|
|
1996
|
+
return null;
|
|
1997
|
+
}
|
|
1998
|
+
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
1999
|
+
return null;
|
|
2000
|
+
}
|
|
2001
|
+
const element = node;
|
|
2002
|
+
if (element.tagName === "BR") {
|
|
2003
|
+
const parent = element.parentNode;
|
|
2004
|
+
if (!parent) {
|
|
2005
|
+
return null;
|
|
2006
|
+
}
|
|
2007
|
+
const index = Array.from(parent.childNodes).indexOf(element);
|
|
2008
|
+
if (targetOffset === consumed) {
|
|
2009
|
+
return { node: parent, offset: index };
|
|
2010
|
+
}
|
|
2011
|
+
if (targetOffset === consumed + 1) {
|
|
2012
|
+
return { node: parent, offset: index + 1 };
|
|
2013
|
+
}
|
|
2014
|
+
consumed += 1;
|
|
2015
|
+
return null;
|
|
2016
|
+
}
|
|
2017
|
+
for (const child of node.childNodes) {
|
|
2018
|
+
const resolved = walk(child);
|
|
2019
|
+
if (resolved) {
|
|
2020
|
+
return resolved;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
return null;
|
|
2024
|
+
}
|
|
2025
|
+
return walk(container) ?? { node: container, offset: container.childNodes.length };
|
|
2026
|
+
}
|
|
2027
|
+
function getBlockElementById(rootElement, blockId) {
|
|
2028
|
+
return rootElement.querySelector(`[data-block-id="${blockId}"]`);
|
|
2029
|
+
}
|
|
2030
|
+
function createDOMRangeFromTextSelection(rootElement, snapshot) {
|
|
2031
|
+
const anchorBlock = getBlockElementById(rootElement, snapshot.anchorBlockId);
|
|
2032
|
+
const focusBlock = getBlockElementById(rootElement, snapshot.focusBlockId);
|
|
2033
|
+
if (!anchorBlock || !focusBlock) {
|
|
2034
|
+
return null;
|
|
2035
|
+
}
|
|
2036
|
+
const anchor = findDOMPointByTextOffset(anchorBlock, snapshot.anchorOffset);
|
|
2037
|
+
const focus = findDOMPointByTextOffset(focusBlock, snapshot.focusOffset);
|
|
2038
|
+
if (!anchor || !focus) {
|
|
2039
|
+
return null;
|
|
2040
|
+
}
|
|
2041
|
+
const anchorComesFirst = anchorBlock === focusBlock ? snapshot.anchorOffset <= snapshot.focusOffset : compareBlockElements(anchorBlock, focusBlock) <= 0;
|
|
2042
|
+
const start = anchorComesFirst ? anchor : focus;
|
|
2043
|
+
const end = anchorComesFirst ? focus : anchor;
|
|
2044
|
+
try {
|
|
2045
|
+
const range = document.createRange();
|
|
2046
|
+
range.setStart(start.node, start.offset);
|
|
2047
|
+
range.setEnd(end.node, end.offset);
|
|
2048
|
+
return range;
|
|
2049
|
+
} catch {
|
|
2050
|
+
return null;
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
function getDOMRectFromTextSelection(rootElement, snapshot) {
|
|
2054
|
+
const range = createDOMRangeFromTextSelection(rootElement, snapshot);
|
|
2055
|
+
if (!range) {
|
|
2056
|
+
return null;
|
|
2057
|
+
}
|
|
2058
|
+
const rect = range.getBoundingClientRect();
|
|
2059
|
+
if (rect.width > 0 || rect.height > 0) {
|
|
2060
|
+
return rect;
|
|
2061
|
+
}
|
|
2062
|
+
return buildDomRectFromClientRects(Array.from(range.getClientRects()));
|
|
2063
|
+
}
|
|
2064
|
+
var nativeSelectionActive = "gr1ebt0";
|
|
2065
|
+
var nativeSelectionInactive = "gr1ebt1";
|
|
2066
|
+
let activeHighlightOwner = null;
|
|
2067
|
+
function getHighlightRegistry() {
|
|
2068
|
+
if (typeof CSS === "undefined" || !("highlights" in CSS) || typeof Highlight === "undefined") {
|
|
2069
|
+
return null;
|
|
2070
|
+
}
|
|
2071
|
+
return CSS.highlights;
|
|
2072
|
+
}
|
|
2073
|
+
function clearManagedHighlight(rootElement) {
|
|
2074
|
+
if (rootElement && rootElement !== activeHighlightOwner) {
|
|
2075
|
+
rootElement.classList.remove(nativeSelectionActive, nativeSelectionInactive);
|
|
2076
|
+
return;
|
|
2077
|
+
}
|
|
2078
|
+
const registry = getHighlightRegistry();
|
|
2079
|
+
registry?.delete(TEXT_SELECTION_HIGHLIGHT_NAME);
|
|
2080
|
+
registry?.delete(TEXT_SELECTION_INACTIVE_HIGHLIGHT_NAME);
|
|
2081
|
+
activeHighlightOwner?.classList.remove(nativeSelectionActive, nativeSelectionInactive);
|
|
2082
|
+
activeHighlightOwner = null;
|
|
2083
|
+
}
|
|
2084
|
+
function TextSelectionPlugin() {
|
|
2085
|
+
const [editor] = useLexicalComposerContext();
|
|
2086
|
+
const store = useTextSelectionStore();
|
|
2087
|
+
const snapshot = useTextSelectionSnapshot();
|
|
2088
|
+
const [isEditorFocused, setIsEditorFocused] = useState(false);
|
|
2089
|
+
const frameRef = useRef(null);
|
|
2090
|
+
const focusFrameRef = useRef(null);
|
|
2091
|
+
useEffect(() => {
|
|
2092
|
+
const syncSnapshot = () => {
|
|
2093
|
+
const rootElement2 = editor.getRootElement();
|
|
2094
|
+
if (!rootElement2) {
|
|
2095
|
+
store.clearSnapshot();
|
|
2096
|
+
return;
|
|
2097
|
+
}
|
|
2098
|
+
const nextSnapshot = editor.getEditorState().read(() => $captureTextSelection());
|
|
2099
|
+
store.setSnapshot(nextSnapshot);
|
|
2100
|
+
};
|
|
2101
|
+
const syncFocusState = () => {
|
|
2102
|
+
const rootElement2 = editor.getRootElement();
|
|
2103
|
+
const activeElement = rootElement2?.ownerDocument.activeElement;
|
|
2104
|
+
setIsEditorFocused(
|
|
2105
|
+
Boolean(rootElement2 && activeElement && rootElement2.contains(activeElement))
|
|
2106
|
+
);
|
|
2107
|
+
};
|
|
2108
|
+
const scheduleFocusStateSync = () => {
|
|
2109
|
+
if (focusFrameRef.current !== null) {
|
|
2110
|
+
cancelAnimationFrame(focusFrameRef.current);
|
|
2111
|
+
}
|
|
2112
|
+
focusFrameRef.current = requestAnimationFrame(() => {
|
|
2113
|
+
focusFrameRef.current = null;
|
|
2114
|
+
syncFocusState();
|
|
2115
|
+
});
|
|
2116
|
+
};
|
|
2117
|
+
const unregisterSelectionChange = editor.registerCommand(
|
|
2118
|
+
SELECTION_CHANGE_COMMAND,
|
|
2119
|
+
() => {
|
|
2120
|
+
syncSnapshot();
|
|
2121
|
+
return false;
|
|
2122
|
+
},
|
|
2123
|
+
COMMAND_PRIORITY_LOW
|
|
2124
|
+
);
|
|
2125
|
+
const unregisterUpdate = editor.registerUpdateListener(() => {
|
|
2126
|
+
syncSnapshot();
|
|
2127
|
+
});
|
|
2128
|
+
const rootElement = editor.getRootElement();
|
|
2129
|
+
if (rootElement) {
|
|
2130
|
+
const onFocusIn = (event) => {
|
|
2131
|
+
const target = event.target;
|
|
2132
|
+
if (!target) return;
|
|
2133
|
+
const nestedEditable = target.closest('[contenteditable="true"]');
|
|
2134
|
+
if (nestedEditable && nestedEditable !== rootElement) {
|
|
2135
|
+
store.clearSnapshot();
|
|
2136
|
+
scheduleFocusStateSync();
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
scheduleFocusStateSync();
|
|
2140
|
+
syncSnapshot();
|
|
2141
|
+
};
|
|
2142
|
+
const onFocusOut = () => {
|
|
2143
|
+
scheduleFocusStateSync();
|
|
2144
|
+
syncSnapshot();
|
|
2145
|
+
};
|
|
2146
|
+
rootElement.addEventListener("focusin", onFocusIn);
|
|
2147
|
+
rootElement.addEventListener("focusout", onFocusOut);
|
|
2148
|
+
syncFocusState();
|
|
2149
|
+
syncSnapshot();
|
|
2150
|
+
return () => {
|
|
2151
|
+
unregisterSelectionChange();
|
|
2152
|
+
unregisterUpdate();
|
|
2153
|
+
if (focusFrameRef.current !== null) {
|
|
2154
|
+
cancelAnimationFrame(focusFrameRef.current);
|
|
2155
|
+
focusFrameRef.current = null;
|
|
2156
|
+
}
|
|
2157
|
+
rootElement.removeEventListener("focusin", onFocusIn);
|
|
2158
|
+
rootElement.removeEventListener("focusout", onFocusOut);
|
|
2159
|
+
store.clearSnapshot();
|
|
2160
|
+
};
|
|
2161
|
+
}
|
|
2162
|
+
syncFocusState();
|
|
2163
|
+
syncSnapshot();
|
|
2164
|
+
return () => {
|
|
2165
|
+
unregisterSelectionChange();
|
|
2166
|
+
unregisterUpdate();
|
|
2167
|
+
if (focusFrameRef.current !== null) {
|
|
2168
|
+
cancelAnimationFrame(focusFrameRef.current);
|
|
2169
|
+
focusFrameRef.current = null;
|
|
2170
|
+
}
|
|
2171
|
+
store.clearSnapshot();
|
|
2172
|
+
};
|
|
2173
|
+
}, [editor, store]);
|
|
2174
|
+
useEffect(() => {
|
|
2175
|
+
const registry = getHighlightRegistry();
|
|
2176
|
+
const cancelScheduledSync = () => {
|
|
2177
|
+
if (frameRef.current !== null) {
|
|
2178
|
+
cancelAnimationFrame(frameRef.current);
|
|
2179
|
+
frameRef.current = null;
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
const syncManagedHighlight = () => {
|
|
2183
|
+
cancelScheduledSync();
|
|
2184
|
+
frameRef.current = requestAnimationFrame(() => {
|
|
2185
|
+
frameRef.current = null;
|
|
2186
|
+
const rootElement = editor.getRootElement();
|
|
2187
|
+
if (!rootElement) {
|
|
2188
|
+
clearManagedHighlight();
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2191
|
+
if (!snapshot) {
|
|
2192
|
+
clearManagedHighlight(rootElement);
|
|
2193
|
+
return;
|
|
2194
|
+
}
|
|
2195
|
+
if (activeHighlightOwner && activeHighlightOwner !== rootElement) {
|
|
2196
|
+
activeHighlightOwner.classList.remove(
|
|
2197
|
+
nativeSelectionActive,
|
|
2198
|
+
nativeSelectionInactive
|
|
2199
|
+
);
|
|
2200
|
+
}
|
|
2201
|
+
const activeSelectionClass = isEditorFocused ? nativeSelectionActive : nativeSelectionInactive;
|
|
2202
|
+
const inactiveSelectionClass = isEditorFocused ? nativeSelectionInactive : nativeSelectionActive;
|
|
2203
|
+
const highlightName = isEditorFocused ? TEXT_SELECTION_HIGHLIGHT_NAME : TEXT_SELECTION_INACTIVE_HIGHLIGHT_NAME;
|
|
2204
|
+
const staleHighlightName = isEditorFocused ? TEXT_SELECTION_INACTIVE_HIGHLIGHT_NAME : TEXT_SELECTION_HIGHLIGHT_NAME;
|
|
2205
|
+
rootElement.classList.remove(inactiveSelectionClass);
|
|
2206
|
+
rootElement.classList.add(activeSelectionClass);
|
|
2207
|
+
activeHighlightOwner = rootElement;
|
|
2208
|
+
if (!registry) {
|
|
2209
|
+
return;
|
|
2210
|
+
}
|
|
2211
|
+
const range = createDOMRangeFromTextSelection(rootElement, snapshot);
|
|
2212
|
+
if (!range) {
|
|
2213
|
+
clearManagedHighlight(rootElement);
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2216
|
+
registry.delete(staleHighlightName);
|
|
2217
|
+
registry.set(highlightName, new Highlight(range));
|
|
2218
|
+
});
|
|
2219
|
+
};
|
|
2220
|
+
syncManagedHighlight();
|
|
2221
|
+
return () => {
|
|
2222
|
+
cancelScheduledSync();
|
|
2223
|
+
clearManagedHighlight(editor.getRootElement());
|
|
2224
|
+
};
|
|
2225
|
+
}, [editor, isEditorFocused, snapshot]);
|
|
2226
|
+
return null;
|
|
2227
|
+
}
|
|
1590
2228
|
function AutoFocusPlugin() {
|
|
1591
2229
|
const [editor] = useLexicalComposerContext();
|
|
1592
2230
|
useEffect(() => {
|
|
@@ -1748,6 +2386,7 @@ function SubmitShortcutPlugin({ onSubmit }) {
|
|
|
1748
2386
|
return null;
|
|
1749
2387
|
}
|
|
1750
2388
|
export {
|
|
2389
|
+
$captureTextSelection as $,
|
|
1751
2390
|
ALL_TRANSFORMERS as A,
|
|
1752
2391
|
BlockExitPlugin as B,
|
|
1753
2392
|
CorePlugins as C,
|
|
@@ -1759,6 +2398,7 @@ export {
|
|
|
1759
2398
|
MarkdownPastePlugin as M,
|
|
1760
2399
|
OnChangePlugin as O,
|
|
1761
2400
|
SubmitShortcutPlugin as S,
|
|
2401
|
+
TextSelectionPlugin as T,
|
|
1762
2402
|
AutoFocusPlugin as a,
|
|
1763
2403
|
AutoLinkPlugin as b,
|
|
1764
2404
|
BlockIdPlugin as c,
|
|
@@ -1766,5 +2406,22 @@ export {
|
|
|
1766
2406
|
MarkdownShortcutsPlugin as e,
|
|
1767
2407
|
blockIdState as f,
|
|
1768
2408
|
defaultImageUpload as g,
|
|
1769
|
-
|
|
2409
|
+
TextSelectionStoreProvider as h,
|
|
2410
|
+
$captureTextSelectionFromRangeSelection as i,
|
|
2411
|
+
$getRootBlock as j,
|
|
2412
|
+
$getTextOffsetInBlock as k,
|
|
2413
|
+
$resolveSelectionPoint as l,
|
|
2414
|
+
$restoreTextSelection as m,
|
|
2415
|
+
TEXT_SELECTION_HIGHLIGHT_NAME as n,
|
|
2416
|
+
buildBlockAnchor as o,
|
|
2417
|
+
buildRangeAnchor as p,
|
|
2418
|
+
createDOMRangeFromTextSelection as q,
|
|
2419
|
+
createTextSelectionStore as r,
|
|
2420
|
+
findDOMPointByTextOffset as s,
|
|
2421
|
+
getBlockElementById as t,
|
|
2422
|
+
useImageUpload as u,
|
|
2423
|
+
getDOMRectFromTextSelection as v,
|
|
2424
|
+
getTextOffsetFromDOMPoint as w,
|
|
2425
|
+
useTextSelectionSnapshot as x,
|
|
2426
|
+
useTextSelectionStore as y
|
|
1770
2427
|
};
|