@webiny/lexical-editor 6.0.0-beta.0 → 6.0.0-rc.0
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/README.md +6 -12
- package/commands/image.d.ts +2 -2
- package/commands/image.js +2 -8
- package/commands/image.js.map +1 -1
- package/commands/index.d.ts +5 -3
- package/commands/index.js +5 -38
- package/commands/index.js.map +1 -1
- package/commands/list.d.ts +2 -2
- package/commands/list.js +4 -10
- package/commands/list.js.map +1 -1
- package/commands/quote.d.ts +2 -2
- package/commands/quote.js +2 -8
- package/commands/quote.js.map +1 -1
- package/commands/toolbar.d.ts +1 -0
- package/commands/toolbar.js +4 -0
- package/commands/toolbar.js.map +1 -0
- package/commands/typography.d.ts +8 -0
- package/commands/typography.js +4 -0
- package/commands/typography.js.map +1 -0
- package/components/Editor/EnsureHeadingTagPlugin.d.ts +6 -0
- package/components/Editor/EnsureHeadingTagPlugin.js +20 -0
- package/components/Editor/EnsureHeadingTagPlugin.js.map +1 -0
- package/components/Editor/RichTextEditor.d.ts +29 -12
- package/components/Editor/RichTextEditor.js +89 -110
- package/components/Editor/RichTextEditor.js.map +1 -1
- package/components/Editor/normalizeInputValue.d.ts +6 -0
- package/components/Editor/normalizeInputValue.js +16 -0
- package/components/Editor/normalizeInputValue.js.map +1 -0
- package/components/LexicalEditorConfig/LexicalEditorConfig.d.ts +14 -16
- package/components/LexicalEditorConfig/LexicalEditorConfig.js +21 -69
- package/components/LexicalEditorConfig/LexicalEditorConfig.js.map +1 -1
- package/components/LexicalEditorConfig/components/Node.d.ts +1 -1
- package/components/LexicalEditorConfig/components/Node.js +17 -26
- package/components/LexicalEditorConfig/components/Node.js.map +1 -1
- package/components/LexicalEditorConfig/components/Plugin.js +17 -26
- package/components/LexicalEditorConfig/components/Plugin.js.map +1 -1
- package/components/LexicalEditorConfig/components/ToolbarElement.js +17 -26
- package/components/LexicalEditorConfig/components/ToolbarElement.js.map +1 -1
- package/components/LexicalHtmlRenderer.d.ts +5 -8
- package/components/LexicalHtmlRenderer.js +35 -50
- package/components/LexicalHtmlRenderer.js.map +1 -1
- package/components/Toolbar/StaticToolbar.css +416 -0
- package/components/Toolbar/StaticToolbar.d.ts +3 -1
- package/components/Toolbar/StaticToolbar.js +19 -23
- package/components/Toolbar/StaticToolbar.js.map +1 -1
- package/components/ToolbarActions/BoldAction.js +16 -21
- package/components/ToolbarActions/BoldAction.js.map +1 -1
- package/components/ToolbarActions/BulletListAction.js +25 -31
- package/components/ToolbarActions/BulletListAction.js.map +1 -1
- package/components/ToolbarActions/CodeHighlightAction.js +16 -21
- package/components/ToolbarActions/CodeHighlightAction.js.map +1 -1
- package/components/ToolbarActions/FontColorAction.d.ts +16 -4
- package/components/ToolbarActions/FontColorAction.js +32 -43
- package/components/ToolbarActions/FontColorAction.js.map +1 -1
- package/components/ToolbarActions/ImageAction.js +19 -34
- package/components/ToolbarActions/ImageAction.js.map +1 -1
- package/components/ToolbarActions/ItalicAction.js +16 -21
- package/components/ToolbarActions/ItalicAction.js.map +1 -1
- package/components/ToolbarActions/LinkAction.js +19 -24
- package/components/ToolbarActions/LinkAction.js.map +1 -1
- package/components/ToolbarActions/NumberedListAction.js +25 -36
- package/components/ToolbarActions/NumberedListAction.js.map +1 -1
- package/components/ToolbarActions/QuoteAction.js +20 -25
- package/components/ToolbarActions/QuoteAction.js.map +1 -1
- package/components/ToolbarActions/TextAlignmentAction.d.ts +16 -4
- package/components/ToolbarActions/TextAlignmentAction.js +36 -45
- package/components/ToolbarActions/TextAlignmentAction.js.map +1 -1
- package/components/ToolbarActions/TypographyAction.d.ts +16 -4
- package/components/ToolbarActions/TypographyAction.js +57 -79
- package/components/ToolbarActions/TypographyAction.js.map +1 -1
- package/components/ToolbarActions/UnderlineAction.js +16 -21
- package/components/ToolbarActions/UnderlineAction.js.map +1 -1
- package/context/FontColorActionContext.js +2 -9
- package/context/FontColorActionContext.js.map +1 -1
- package/context/RichTextEditorContext.d.ts +7 -8
- package/context/RichTextEditorContext.js +28 -26
- package/context/RichTextEditorContext.js.map +1 -1
- package/context/SharedHistoryContext.d.ts +3 -3
- package/context/SharedHistoryContext.js +12 -20
- package/context/SharedHistoryContext.js.map +1 -1
- package/context/TextAlignmentActionContextProps.d.ts +1 -1
- package/context/TextAlignmentActionContextProps.js +2 -9
- package/context/TextAlignmentActionContextProps.js.map +1 -1
- package/context/TypographyActionContext.d.ts +3 -2
- package/context/TypographyActionContext.js +2 -9
- package/context/TypographyActionContext.js.map +1 -1
- package/exports/admin/lexical.d.ts +15 -0
- package/exports/admin/lexical.js +23 -0
- package/exports/admin/lexical.js.map +1 -0
- package/hooks/index.d.ts +7 -8
- package/hooks/index.js +7 -93
- package/hooks/index.js.map +1 -1
- package/hooks/useCurrentElement.d.ts +3 -3
- package/hooks/useCurrentElement.js +11 -18
- package/hooks/useCurrentElement.js.map +1 -1
- package/hooks/useCurrentSelection.d.ts +2 -1
- package/hooks/useCurrentSelection.js +27 -40
- package/hooks/useCurrentSelection.js.map +1 -1
- package/hooks/useFontColorPicker.d.ts +1 -1
- package/hooks/useFontColorPicker.js +5 -11
- package/hooks/useFontColorPicker.js.map +1 -1
- package/hooks/useIsMounted.js +6 -14
- package/hooks/useIsMounted.js.map +1 -1
- package/hooks/useRichTextEditor.d.ts +1 -1
- package/hooks/useRichTextEditor.js +5 -11
- package/hooks/useRichTextEditor.js.map +1 -1
- package/hooks/useTextAlignmentAction.d.ts +1 -1
- package/hooks/useTextAlignmentAction.js +5 -11
- package/hooks/useTextAlignmentAction.js.map +1 -1
- package/hooks/useTypographyAction.d.ts +1 -1
- package/hooks/useTypographyAction.js +5 -11
- package/hooks/useTypographyAction.js.map +1 -1
- package/index.d.ts +33 -38
- package/index.js +44 -322
- package/index.js.map +1 -1
- package/package.json +18 -22
- package/plugins/BlurEventPlugin/BlurEventPlugin.d.ts +2 -2
- package/plugins/BlurEventPlugin/BlurEventPlugin.js +16 -22
- package/plugins/BlurEventPlugin/BlurEventPlugin.js.map +1 -1
- package/plugins/CodeHighlightPlugin/CodeHighlightPlugin.js +9 -14
- package/plugins/CodeHighlightPlugin/CodeHighlightPlugin.js.map +1 -1
- package/plugins/CodeHighlightPlugin/index.d.ts +1 -1
- package/plugins/CodeHighlightPlugin/index.js +1 -16
- package/plugins/CodeHighlightPlugin/index.js.map +1 -1
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditor.d.ts +10 -0
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditor.js +28 -0
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditor.js.map +1 -0
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditorController.d.ts +7 -0
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditorController.js +61 -0
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditorController.js.map +1 -0
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditorPlugin.css +2 -136
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditorPlugin.d.ts +4 -16
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditorPlugin.js +7 -180
- package/plugins/FloatingLinkEditorPlugin/FloatingLinkEditorPlugin.js.map +1 -1
- package/plugins/FloatingLinkEditorPlugin/index.d.ts +1 -1
- package/plugins/FloatingLinkEditorPlugin/index.js +1 -16
- package/plugins/FloatingLinkEditorPlugin/index.js.map +1 -1
- package/plugins/FloatingLinkEditorPlugin/isChildOfLinkEditor.js +2 -8
- package/plugins/FloatingLinkEditorPlugin/isChildOfLinkEditor.js.map +1 -1
- package/plugins/FloatingLinkEditorPlugin/types.d.ts +10 -0
- package/plugins/FloatingLinkEditorPlugin/types.js +3 -0
- package/plugins/FloatingLinkEditorPlugin/types.js.map +1 -0
- package/plugins/FloatingLinkEditorPlugin/useFloatingLinkEditor.d.ts +8 -2
- package/plugins/FloatingLinkEditorPlugin/useFloatingLinkEditor.js +119 -63
- package/plugins/FloatingLinkEditorPlugin/useFloatingLinkEditor.js.map +1 -1
- package/plugins/FontColorPlugin/FontColorPlugin.js +19 -28
- package/plugins/FontColorPlugin/FontColorPlugin.js.map +1 -1
- package/plugins/FontColorPlugin/applyColorToNode.d.ts +3 -0
- package/plugins/FontColorPlugin/applyColorToNode.js +8 -0
- package/plugins/FontColorPlugin/applyColorToNode.js.map +1 -0
- package/plugins/FontColorPlugin/applyColorToSelection.d.ts +3 -0
- package/plugins/FontColorPlugin/applyColorToSelection.js +66 -0
- package/plugins/FontColorPlugin/applyColorToSelection.js.map +1 -0
- package/plugins/ImagesPlugin/ImagesPlugin.d.ts +2 -3
- package/plugins/ImagesPlugin/ImagesPlugin.js +58 -60
- package/plugins/ImagesPlugin/ImagesPlugin.js.map +1 -1
- package/plugins/LinkPlugin/LinkPlugin.d.ts +1 -1
- package/plugins/LinkPlugin/LinkPlugin.js +29 -37
- package/plugins/LinkPlugin/LinkPlugin.js.map +1 -1
- package/plugins/ListPLugin/ListPlugin.js +52 -15
- package/plugins/ListPLugin/ListPlugin.js.map +1 -1
- package/plugins/QuoteNodePlugin/QuoteNodePlugin.js +19 -16
- package/plugins/QuoteNodePlugin/QuoteNodePlugin.js.map +1 -1
- package/plugins/StateHandlingPlugin.d.ts +8 -0
- package/plugins/StateHandlingPlugin.js +75 -0
- package/plugins/StateHandlingPlugin.js.map +1 -0
- package/plugins/TypographyPlugin/TypographyPlugin.js +17 -21
- package/plugins/TypographyPlugin/TypographyPlugin.js.map +1 -1
- package/types.d.ts +8 -8
- package/types.js +6 -38
- package/types.js.map +1 -1
- package/ui/ContentEditable.d.ts +0 -1
- package/ui/ContentEditable.js +7 -14
- package/ui/ContentEditable.js.map +1 -1
- package/ui/Divider.d.ts +0 -1
- package/ui/Divider.js +3 -10
- package/ui/Divider.js.map +1 -1
- package/ui/DropDown.d.ts +1 -1
- package/ui/DropDown.js +64 -90
- package/ui/DropDown.js.map +1 -1
- package/ui/ImageResizer.d.ts +0 -1
- package/ui/ImageResizer.js +84 -89
- package/ui/ImageResizer.js.map +1 -1
- package/ui/LinkPreview.d.ts +0 -1
- package/ui/LinkPreview.js +22 -29
- package/ui/LinkPreview.js.map +1 -1
- package/ui/Placeholder.d.ts +1 -1
- package/ui/Placeholder.js +10 -16
- package/ui/Placeholder.js.map +1 -1
- package/ui/TextInput.d.ts +1 -2
- package/ui/TextInput.js +11 -18
- package/ui/TextInput.js.map +1 -1
- package/ui/ToolbarActionDialog.js +30 -42
- package/ui/ToolbarActionDialog.js.map +1 -1
- package/utils/canUseDOM.js +1 -7
- package/utils/canUseDOM.js.map +1 -1
- package/utils/files.d.ts +6 -7
- package/utils/files.js +5 -56
- package/utils/files.js.map +1 -1
- package/utils/getDOMRangeRect.js +4 -10
- package/utils/getDOMRangeRect.js.map +1 -1
- package/utils/getSelectedNode.d.ts +1 -1
- package/utils/getSelectedNode.js +9 -16
- package/utils/getSelectedNode.js.map +1 -1
- package/utils/getTransparentImage.js +1 -7
- package/utils/getTransparentImage.js.map +1 -1
- package/utils/insertImage.d.ts +1 -1
- package/utils/insertImage.js +8 -14
- package/utils/insertImage.js.map +1 -1
- package/utils/isAnchorLink.js +1 -7
- package/utils/isAnchorLink.js.map +1 -1
- package/utils/isChildOfFloatingToolbar.js +2 -8
- package/utils/isChildOfFloatingToolbar.js.map +1 -1
- package/utils/isHTMLElement.js +1 -7
- package/utils/isHTMLElement.js.map +1 -1
- package/utils/isValidJSON.js +3 -9
- package/utils/isValidJSON.js.map +1 -1
- package/utils/isValidLexicalData.d.ts +3 -3
- package/utils/isValidLexicalData.js +6 -12
- package/utils/isValidLexicalData.js.map +1 -1
- package/utils/point.js +35 -60
- package/utils/point.js.map +1 -1
- package/utils/rect.d.ts +2 -2
- package/utils/rect.js +115 -149
- package/utils/rect.js.map +1 -1
- package/utils/sanitizeUrl.js +6 -13
- package/utils/sanitizeUrl.js.map +1 -1
- package/utils/setFloatingElemPosition.d.ts +1 -1
- package/utils/setFloatingElemPosition.js +29 -39
- package/utils/setFloatingElemPosition.js.map +1 -1
- package/components/Editor/HeadingEditor.d.ts +0 -7
- package/components/Editor/HeadingEditor.js +0 -29
- package/components/Editor/HeadingEditor.js.map +0 -1
- package/components/Editor/ParagraphEditor.d.ts +0 -7
- package/components/Editor/ParagraphEditor.js +0 -29
- package/components/Editor/ParagraphEditor.js.map +0 -1
- package/components/Toolbar/Toolbar.css +0 -647
- package/components/Toolbar/Toolbar.d.ts +0 -6
- package/components/Toolbar/Toolbar.js +0 -162
- package/components/Toolbar/Toolbar.js.map +0 -1
- package/components/ToolbarActions/FontSizeAction.d.ts +0 -2
- package/components/ToolbarActions/FontSizeAction.js +0 -88
- package/components/ToolbarActions/FontSizeAction.js.map +0 -1
- package/hooks/useList.d.ts +0 -2
- package/hooks/useList.js +0 -54
- package/hooks/useList.js.map +0 -1
- package/hooks/useQuote.d.ts +0 -2
- package/hooks/useQuote.js +0 -22
- package/hooks/useQuote.js.map +0 -1
- package/plugins/FloatingLinkEditorPlugin/LinkEditForm.d.ts +0 -9
- package/plugins/FloatingLinkEditorPlugin/LinkEditForm.js +0 -118
- package/plugins/FloatingLinkEditorPlugin/LinkEditForm.js.map +0 -1
- package/plugins/FloatingLinkEditorPlugin/LinkPreviewForm.d.ts +0 -9
- package/plugins/FloatingLinkEditorPlugin/LinkPreviewForm.js +0 -44
- package/plugins/FloatingLinkEditorPlugin/LinkPreviewForm.js.map +0 -1
- package/plugins/LexicalUpdateStatePlugin/UpdateStatePlugin.d.ts +0 -9
- package/plugins/LexicalUpdateStatePlugin/UpdateStatePlugin.js +0 -45
- package/plugins/LexicalUpdateStatePlugin/UpdateStatePlugin.js.map +0 -1
- package/plugins/LexicalUpdateStatePlugin/index.d.ts +0 -1
- package/plugins/LexicalUpdateStatePlugin/index.js +0 -18
- package/plugins/LexicalUpdateStatePlugin/index.js.map +0 -1
- package/utils/generateInitialLexicalValue.d.ts +0 -5
- package/utils/generateInitialLexicalValue.js +0 -33
- package/utils/generateInitialLexicalValue.js.map +0 -1
|
@@ -1,72 +1,128 @@
|
|
|
1
|
-
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, mergeRegister } from "lexical";
|
|
3
|
+
import { $isLinkNode, TOGGLE_LINK_COMMAND } from "@webiny/lexical-nodes";
|
|
4
|
+
import { getSelectedNode } from "../../utils/getSelectedNode.js";
|
|
5
|
+
import { setFloatingElemPosition } from "../../utils/setFloatingElemPosition.js";
|
|
6
|
+
import { sanitizeUrl } from "../../utils/sanitizeUrl.js";
|
|
7
|
+
const emptyLinkData = {
|
|
8
|
+
url: "",
|
|
9
|
+
target: null,
|
|
10
|
+
alt: null
|
|
11
|
+
};
|
|
12
|
+
function getSelectionKey(selection) {
|
|
13
|
+
if ($isRangeSelection(selection)) {
|
|
14
|
+
return `${selection.anchor.key}:${selection.anchor.offset}-${selection.focus.key}:${selection.focus.offset}`;
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
function getLinkDataFromSelection() {
|
|
19
|
+
const selection = $getSelection();
|
|
20
|
+
if (!$isRangeSelection(selection)) {
|
|
21
|
+
return emptyLinkData;
|
|
22
|
+
}
|
|
23
|
+
const node = getSelectedNode(selection);
|
|
24
|
+
const parent = node.getParent();
|
|
25
|
+
if ($isLinkNode(parent)) {
|
|
26
|
+
return {
|
|
27
|
+
url: parent.getURL(),
|
|
28
|
+
target: parent.getTarget(),
|
|
29
|
+
alt: parent.getAlt()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if ($isLinkNode(node)) {
|
|
33
|
+
return {
|
|
34
|
+
url: node.getURL(),
|
|
35
|
+
target: node.getTarget(),
|
|
36
|
+
alt: node.getAlt()
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return emptyLinkData;
|
|
40
|
+
}
|
|
41
|
+
export function useFloatingLinkEditor(editor) {
|
|
42
|
+
const editorRef = useRef(null);
|
|
43
|
+
const [linkData, setLinkData] = useState(emptyLinkData);
|
|
44
|
+
const [lastSelection, setLastSelection] = useState(null);
|
|
45
|
+
const suppressedSelectionKeyRef = useRef(null);
|
|
46
|
+
const updateLinkEditor = useCallback(() => {
|
|
47
|
+
const selection = $getSelection();
|
|
48
|
+
const selectionKey = getSelectionKey(selection);
|
|
2
49
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
var _debounce = _interopRequireDefault(require("lodash/debounce"));
|
|
17
|
-
var _lexical = require("lexical");
|
|
18
|
-
var _utils = require("@lexical/utils");
|
|
19
|
-
var _FloatingLinkEditorPlugin = require("./FloatingLinkEditorPlugin");
|
|
20
|
-
function useFloatingLinkEditor(anchorElem) {
|
|
21
|
-
var _useRichTextEditor = (0, _hooks.useRichTextEditor)(),
|
|
22
|
-
editor = _useRichTextEditor.editor;
|
|
23
|
-
var _useState = (0, _react.useState)(false),
|
|
24
|
-
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
25
|
-
isLink = _useState2[0],
|
|
26
|
-
setIsLink = _useState2[1];
|
|
27
|
-
var debounceSetIsLink = (0, _react.useCallback)((0, _debounce.default)(setIsLink, 50), []);
|
|
28
|
-
var updateToolbar = (0, _react.useCallback)(function () {
|
|
29
|
-
var selection = (0, _lexical.$getSelection)();
|
|
30
|
-
if (!(0, _lexical.$isRangeSelection)(selection)) {
|
|
31
|
-
return;
|
|
50
|
+
// If we're still on the same selection that was suppressed, hide the popover.
|
|
51
|
+
if (suppressedSelectionKeyRef.current !== null) {
|
|
52
|
+
if (selectionKey === suppressedSelectionKeyRef.current) {
|
|
53
|
+
const editorElem = editorRef.current;
|
|
54
|
+
if (editorElem) {
|
|
55
|
+
setFloatingElemPosition(null, editorElem);
|
|
56
|
+
}
|
|
57
|
+
setLastSelection(null);
|
|
58
|
+
setLinkData(emptyLinkData);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
// New selection — clear suppression.
|
|
62
|
+
suppressedSelectionKeyRef.current = null;
|
|
32
63
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
setIsLink(false);
|
|
64
|
+
setLinkData(getLinkDataFromSelection());
|
|
65
|
+
const editorElem = editorRef.current;
|
|
66
|
+
const nativeSelection = window.getSelection();
|
|
67
|
+
const activeElement = document.activeElement;
|
|
68
|
+
if (editorElem === null) {
|
|
69
|
+
return;
|
|
40
70
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
71
|
+
const rootElement = editor.getRootElement();
|
|
72
|
+
if (selection !== null && nativeSelection !== null && rootElement !== null && rootElement.contains(nativeSelection.anchorNode)) {
|
|
73
|
+
const range = nativeSelection.getRangeAt(0);
|
|
74
|
+
setFloatingElemPosition(range, editorElem);
|
|
75
|
+
setLastSelection(selection);
|
|
76
|
+
} else if (!activeElement || activeElement.className !== "link-input") {
|
|
77
|
+
if (rootElement !== null) {
|
|
78
|
+
setFloatingElemPosition(null, editorElem);
|
|
48
79
|
}
|
|
80
|
+
setLastSelection(null);
|
|
81
|
+
setLinkData(emptyLinkData);
|
|
49
82
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
83
|
+
return true;
|
|
84
|
+
}, [editor]);
|
|
85
|
+
const removeLink = useCallback(() => {
|
|
86
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
|
|
87
|
+
}, [editor]);
|
|
88
|
+
const applyChanges = useCallback(linkData => {
|
|
89
|
+
const confirmedLinkData = {
|
|
90
|
+
url: sanitizeUrl(linkData.url),
|
|
91
|
+
target: linkData.target,
|
|
92
|
+
alt: linkData.alt
|
|
93
|
+
};
|
|
94
|
+
if (lastSelection !== null) {
|
|
95
|
+
editor.read(() => {
|
|
96
|
+
const selection = $getSelection();
|
|
97
|
+
suppressedSelectionKeyRef.current = getSelectionKey(selection);
|
|
98
|
+
});
|
|
99
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, confirmedLinkData);
|
|
100
|
+
}
|
|
101
|
+
setLastSelection(null);
|
|
102
|
+
}, [editor, lastSelection]);
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
return mergeRegister(editor.registerUpdateListener(({
|
|
105
|
+
editorState
|
|
106
|
+
}) => {
|
|
107
|
+
editorState.read(() => {
|
|
108
|
+
updateLinkEditor();
|
|
109
|
+
});
|
|
110
|
+
}), editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
|
|
111
|
+
updateLinkEditor();
|
|
62
112
|
return false;
|
|
63
|
-
},
|
|
64
|
-
}, [editor,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
113
|
+
}, COMMAND_PRIORITY_LOW));
|
|
114
|
+
}, [editor, updateLinkEditor]);
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
editor.read(() => {
|
|
117
|
+
updateLinkEditor();
|
|
118
|
+
});
|
|
119
|
+
}, [editor, updateLinkEditor]);
|
|
120
|
+
return {
|
|
121
|
+
editorRef,
|
|
122
|
+
linkData,
|
|
123
|
+
applyChanges,
|
|
124
|
+
removeLink
|
|
125
|
+
};
|
|
70
126
|
}
|
|
71
127
|
|
|
72
128
|
//# sourceMappingURL=useFloatingLinkEditor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactDom","_hooks","_getSelectedNode","_lexicalNodes","_isChildOfLinkEditor","_debounce","_interopRequireDefault","_lexical","_utils","_FloatingLinkEditorPlugin","useFloatingLinkEditor","anchorElem","_useRichTextEditor","useRichTextEditor","editor","_useState","useState","_useState2","_slicedToArray2","default","isLink","setIsLink","debounceSetIsLink","useCallback","debounce","updateToolbar","selection","$getSelection","$isRangeSelection","node","getSelectedNode","linkParent","$findMatchingParent","$isLinkNode","autoLinkParent","$isAutoLinkNode","isLinkOrChildOfLink","Boolean","dirty","useEffect","mergeRegister","registerCommand","SELECTION_CHANGE_COMMAND","COMMAND_PRIORITY_CRITICAL","BLUR_COMMAND","payload","isChildOfLinkEditor","relatedTarget","COMMAND_PRIORITY_LOW","TOGGLE_LINK_COMMAND","createPortal","createElement","FloatingLinkEditor","isVisible"],"sources":["useFloatingLinkEditor.tsx"],"sourcesContent":["import React, { useCallback, useState, useEffect } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useRichTextEditor } from \"~/hooks\";\nimport { getSelectedNode } from \"~/utils/getSelectedNode\";\nimport { $isAutoLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from \"@webiny/lexical-nodes\";\nimport { isChildOfLinkEditor } from \"~/plugins/FloatingLinkEditorPlugin/isChildOfLinkEditor\";\nimport debounce from \"lodash/debounce\";\nimport {\n $getSelection,\n $isRangeSelection,\n BLUR_COMMAND,\n COMMAND_PRIORITY_CRITICAL,\n COMMAND_PRIORITY_LOW,\n SELECTION_CHANGE_COMMAND\n} from \"lexical\";\nimport { $findMatchingParent, mergeRegister } from \"@lexical/utils\";\nimport { FloatingLinkEditor } from \"./FloatingLinkEditorPlugin\";\n\nexport function useFloatingLinkEditor(anchorElem: HTMLElement): JSX.Element | null {\n const { editor } = useRichTextEditor();\n const [isLink, setIsLink] = useState(false);\n\n const debounceSetIsLink = useCallback(debounce(setIsLink, 50), []);\n\n const updateToolbar = useCallback(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return;\n }\n\n const node = getSelectedNode(selection);\n const linkParent = $findMatchingParent(node, $isLinkNode);\n const autoLinkParent = $findMatchingParent(node, $isAutoLinkNode);\n const isLinkOrChildOfLink = Boolean($isLinkNode(node) || linkParent);\n\n if (!isLinkOrChildOfLink) {\n // When hiding the toolbar, we want to hide immediately.\n setIsLink(false);\n }\n\n if (selection.dirty) {\n // We don't want this menu to open for auto links.\n if (linkParent != null && autoLinkParent == null) {\n // When showing the toolbar, we want to debounce it, because sometimes selection gets updated\n // multiple times, and the `selection.dirty` flag goes from true to false multiple times,\n // eventually settling on `false`, which we want to set once it has settled.\n debounceSetIsLink(true);\n }\n }\n }, []);\n\n useEffect(() => {\n return mergeRegister(\n editor.registerCommand(\n SELECTION_CHANGE_COMMAND,\n () => {\n updateToolbar();\n return false;\n },\n COMMAND_PRIORITY_CRITICAL\n ),\n editor.registerCommand(\n BLUR_COMMAND,\n payload => {\n if (!isChildOfLinkEditor(payload.relatedTarget as HTMLElement)) {\n setIsLink(false);\n }\n\n return false;\n },\n COMMAND_PRIORITY_LOW\n ),\n editor.registerCommand(\n TOGGLE_LINK_COMMAND,\n payload => {\n setIsLink(!!payload);\n return false;\n },\n COMMAND_PRIORITY_CRITICAL\n )\n );\n }, [editor, updateToolbar]);\n\n return createPortal(\n <FloatingLinkEditor isVisible={isLink} editor={editor} anchorElem={anchorElem} />,\n anchorElem\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useRef","useState","SELECTION_CHANGE_COMMAND","COMMAND_PRIORITY_LOW","$getSelection","$isRangeSelection","mergeRegister","$isLinkNode","TOGGLE_LINK_COMMAND","getSelectedNode","setFloatingElemPosition","sanitizeUrl","emptyLinkData","url","target","alt","getSelectionKey","selection","anchor","key","offset","focus","getLinkDataFromSelection","node","parent","getParent","getURL","getTarget","getAlt","useFloatingLinkEditor","editor","editorRef","linkData","setLinkData","lastSelection","setLastSelection","suppressedSelectionKeyRef","updateLinkEditor","selectionKey","current","editorElem","nativeSelection","window","getSelection","activeElement","document","rootElement","getRootElement","contains","anchorNode","range","getRangeAt","className","removeLink","dispatchCommand","applyChanges","confirmedLinkData","read","registerUpdateListener","editorState","registerCommand"],"sources":["useFloatingLinkEditor.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n SELECTION_CHANGE_COMMAND,\n type BaseSelection,\n type LexicalEditor,\n COMMAND_PRIORITY_LOW,\n $getSelection,\n $isRangeSelection,\n mergeRegister\n} from \"lexical\";\nimport { $isLinkNode, TOGGLE_LINK_COMMAND } from \"@webiny/lexical-nodes\";\nimport { getSelectedNode } from \"~/utils/getSelectedNode.js\";\nimport { setFloatingElemPosition } from \"~/utils/setFloatingElemPosition.js\";\nimport { sanitizeUrl } from \"~/utils/sanitizeUrl.js\";\nimport { LinkData } from \"./types.js\";\n\nconst emptyLinkData: LinkData = { url: \"\", target: null, alt: null };\n\nfunction getSelectionKey(selection: BaseSelection | null): string | null {\n if ($isRangeSelection(selection)) {\n return `${selection.anchor.key}:${selection.anchor.offset}-${selection.focus.key}:${selection.focus.offset}`;\n }\n return null;\n}\n\nfunction getLinkDataFromSelection(): LinkData {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n return emptyLinkData;\n }\n\n const node = getSelectedNode(selection);\n const parent = node.getParent();\n\n if ($isLinkNode(parent)) {\n return {\n url: parent.getURL(),\n target: parent.getTarget(),\n alt: parent.getAlt()\n };\n }\n\n if ($isLinkNode(node)) {\n return {\n url: node.getURL(),\n target: node.getTarget(),\n alt: node.getAlt()\n };\n }\n\n return emptyLinkData;\n}\n\nexport function useFloatingLinkEditor(editor: LexicalEditor) {\n const editorRef = useRef<HTMLDivElement | null>(null);\n const [linkData, setLinkData] = useState<LinkData>(emptyLinkData);\n const [lastSelection, setLastSelection] = useState<BaseSelection | null>(null);\n const suppressedSelectionKeyRef = useRef<string | null>(null);\n\n const updateLinkEditor = useCallback(() => {\n const selection = $getSelection();\n const selectionKey = getSelectionKey(selection);\n\n // If we're still on the same selection that was suppressed, hide the popover.\n if (suppressedSelectionKeyRef.current !== null) {\n if (selectionKey === suppressedSelectionKeyRef.current) {\n const editorElem = editorRef.current;\n if (editorElem) {\n setFloatingElemPosition(null, editorElem);\n }\n setLastSelection(null);\n setLinkData(emptyLinkData);\n return true;\n }\n // New selection — clear suppression.\n suppressedSelectionKeyRef.current = null;\n }\n\n setLinkData(getLinkDataFromSelection());\n\n const editorElem = editorRef.current;\n const nativeSelection = window.getSelection();\n const activeElement = document.activeElement;\n\n if (editorElem === null) {\n return;\n }\n\n const rootElement = editor.getRootElement();\n\n if (\n selection !== null &&\n nativeSelection !== null &&\n rootElement !== null &&\n rootElement.contains(nativeSelection.anchorNode)\n ) {\n const range = nativeSelection.getRangeAt(0);\n setFloatingElemPosition(range, editorElem);\n setLastSelection(selection);\n } else if (!activeElement || activeElement.className !== \"link-input\") {\n if (rootElement !== null) {\n setFloatingElemPosition(null, editorElem);\n }\n setLastSelection(null);\n setLinkData(emptyLinkData);\n }\n\n return true;\n }, [editor]);\n\n const removeLink = useCallback(() => {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);\n }, [editor]);\n\n const applyChanges = useCallback(\n (linkData: LinkData) => {\n const confirmedLinkData = {\n url: sanitizeUrl(linkData.url),\n target: linkData.target,\n alt: linkData.alt\n };\n\n if (lastSelection !== null) {\n editor.read(() => {\n const selection = $getSelection();\n suppressedSelectionKeyRef.current = getSelectionKey(selection);\n });\n\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, confirmedLinkData);\n }\n\n setLastSelection(null);\n },\n [editor, lastSelection]\n );\n\n useEffect(() => {\n return mergeRegister(\n editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n updateLinkEditor();\n });\n }),\n\n editor.registerCommand(\n SELECTION_CHANGE_COMMAND,\n () => {\n updateLinkEditor();\n return false;\n },\n COMMAND_PRIORITY_LOW\n )\n );\n }, [editor, updateLinkEditor]);\n\n useEffect(() => {\n editor.read(() => {\n updateLinkEditor();\n });\n }, [editor, updateLinkEditor]);\n\n return { editorRef, linkData, applyChanges, removeLink };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,34 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
themeColorName = payload.themeColorName;
|
|
20
|
-
var selection = (0, _lexical.$getSelection)();
|
|
21
|
-
if ((0, _lexical.$isRangeSelection)(selection)) {
|
|
22
|
-
var fontColorNode = (0, _lexicalNodes.$createFontColorNode)(selection.getTextContent(), color, themeColorName);
|
|
23
|
-
(0, _lexicalNodes.$applyStylesToNode)(fontColorNode, selection);
|
|
24
|
-
(0, _lexical.$insertNodes)([fontColorNode]);
|
|
25
|
-
if ((0, _lexical.$isRootOrShadowRoot)(fontColorNode.getParentOrThrow())) {
|
|
26
|
-
(0, _utils.$wrapNodeInElement)(fontColorNode, _lexicalNodes.$createParagraphNode).selectEnd();
|
|
27
|
-
}
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR } from "lexical";
|
|
3
|
+
import { ADD_FONT_COLOR_COMMAND } from "@webiny/lexical-nodes";
|
|
4
|
+
import { useRichTextEditor } from "../../hooks/index.js";
|
|
5
|
+
import { applyColorToSelection } from "./applyColorToSelection.js";
|
|
6
|
+
export const FontColorPlugin = () => {
|
|
7
|
+
const {
|
|
8
|
+
editor
|
|
9
|
+
} = useRichTextEditor();
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
return editor.registerCommand(ADD_FONT_COLOR_COMMAND, payload => {
|
|
12
|
+
editor.update(() => {
|
|
13
|
+
const {
|
|
14
|
+
color
|
|
15
|
+
} = payload;
|
|
16
|
+
const selection = $getSelection();
|
|
17
|
+
if ($isRangeSelection(selection)) {
|
|
18
|
+
applyColorToSelection(selection, color);
|
|
28
19
|
}
|
|
29
20
|
});
|
|
30
21
|
return true;
|
|
31
|
-
},
|
|
22
|
+
}, COMMAND_PRIORITY_EDITOR);
|
|
32
23
|
}, [editor]);
|
|
33
24
|
return null;
|
|
34
25
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["useEffect","$getSelection","$isRangeSelection","COMMAND_PRIORITY_EDITOR","ADD_FONT_COLOR_COMMAND","useRichTextEditor","applyColorToSelection","FontColorPlugin","editor","registerCommand","payload","update","color","selection"],"sources":["FontColorPlugin.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR } from \"lexical\";\nimport type { FontColorPayload } from \"@webiny/lexical-nodes\";\nimport { ADD_FONT_COLOR_COMMAND } from \"@webiny/lexical-nodes\";\nimport { useRichTextEditor } from \"~/hooks/index.js\";\nimport { applyColorToSelection } from \"./applyColorToSelection.js\";\n\nexport const FontColorPlugin = () => {\n const { editor } = useRichTextEditor();\n\n useEffect(() => {\n return editor.registerCommand<FontColorPayload>(\n ADD_FONT_COLOR_COMMAND,\n payload => {\n editor.update(() => {\n const { color } = payload;\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n applyColorToSelection(selection, color);\n }\n });\n return true;\n },\n COMMAND_PRIORITY_EDITOR\n );\n }, [editor]);\n\n return null;\n};\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,OAAO;AACjC,SAASC,aAAa,EAAEC,iBAAiB,EAAEC,uBAAuB,QAAQ,SAAS;AAEnF,SAASC,sBAAsB,QAAQ,uBAAuB;AAC9D,SAASC,iBAAiB;AAC1B,SAASC,qBAAqB;AAE9B,OAAO,MAAMC,eAAe,GAAGA,CAAA,KAAM;EACjC,MAAM;IAAEC;EAAO,CAAC,GAAGH,iBAAiB,CAAC,CAAC;EAEtCL,SAAS,CAAC,MAAM;IACZ,OAAOQ,MAAM,CAACC,eAAe,CACzBL,sBAAsB,EACtBM,OAAO,IAAI;MACPF,MAAM,CAACG,MAAM,CAAC,MAAM;QAChB,MAAM;UAAEC;QAAM,CAAC,GAAGF,OAAO;QACzB,MAAMG,SAAS,GAAGZ,aAAa,CAAC,CAAC;QAEjC,IAAIC,iBAAiB,CAACW,SAAS,CAAC,EAAE;UAC9BP,qBAAqB,CAACO,SAAS,EAAED,KAAK,CAAC;QAC3C;MACJ,CAAC,CAAC;MACF,OAAO,IAAI;IACf,CAAC,EACDT,uBACJ,CAAC;EACL,CAAC,EAAE,CAACK,MAAM,CAAC,CAAC;EAEZ,OAAO,IAAI;AACf,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { $applyStylesToNode, $createFontColorNode } from "@webiny/lexical-nodes";
|
|
2
|
+
export function applyColorToNode(textNode, color) {
|
|
3
|
+
const fontColorNode = $createFontColorNode(textNode.getTextContent(), color);
|
|
4
|
+
$applyStylesToNode(fontColorNode, textNode);
|
|
5
|
+
return textNode.replace(fontColorNode);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=applyColorToNode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["$applyStylesToNode","$createFontColorNode","applyColorToNode","textNode","color","fontColorNode","getTextContent","replace"],"sources":["applyColorToNode.ts"],"sourcesContent":["import type { TextNode } from \"lexical\";\nimport type { ThemeColorValue } from \"@webiny/lexical-nodes\";\nimport { $applyStylesToNode, $createFontColorNode } from \"@webiny/lexical-nodes\";\n\nexport function applyColorToNode(textNode: TextNode, color: ThemeColorValue) {\n const fontColorNode = $createFontColorNode(textNode.getTextContent(), color);\n $applyStylesToNode(fontColorNode, textNode);\n\n return textNode.replace(fontColorNode);\n}\n"],"mappings":"AAEA,SAASA,kBAAkB,EAAEC,oBAAoB,QAAQ,uBAAuB;AAEhF,OAAO,SAASC,gBAAgBA,CAACC,QAAkB,EAAEC,KAAsB,EAAE;EACzE,MAAMC,aAAa,GAAGJ,oBAAoB,CAACE,QAAQ,CAACG,cAAc,CAAC,CAAC,EAAEF,KAAK,CAAC;EAC5EJ,kBAAkB,CAACK,aAAa,EAAEF,QAAQ,CAAC;EAE3C,OAAOA,QAAQ,CAACI,OAAO,CAACF,aAAa,CAAC;AAC1C","ignoreList":[]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { TextNode } from "lexical";
|
|
2
|
+
import { applyColorToNode } from "./applyColorToNode.js";
|
|
3
|
+
export function applyColorToSelection(selection, color) {
|
|
4
|
+
// Basic variables
|
|
5
|
+
const textNodes = selection.getNodes().filter(node => node instanceof TextNode);
|
|
6
|
+
const selectedTextNodesLength = textNodes.length;
|
|
7
|
+
const startEndPoints = selection.getStartEndPoints();
|
|
8
|
+
if (startEndPoints === null) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const [anchor, focus] = startEndPoints;
|
|
12
|
+
const lastIndex = selectedTextNodesLength - 1;
|
|
13
|
+
const firstNode = textNodes[0];
|
|
14
|
+
const lastNode = textNodes[lastIndex];
|
|
15
|
+
const firstNodeText = firstNode.getTextContent();
|
|
16
|
+
const firstNodeTextLength = firstNodeText.length;
|
|
17
|
+
const focusOffset = focus.offset;
|
|
18
|
+
const anchorOffset = anchor.offset;
|
|
19
|
+
const isBefore = anchor.isBefore(focus);
|
|
20
|
+
const startOffset = isBefore ? anchorOffset : focusOffset;
|
|
21
|
+
const endOffset = isBefore ? focusOffset : anchorOffset;
|
|
22
|
+
|
|
23
|
+
// No actual text is selected, so do nothing.
|
|
24
|
+
if (startOffset === endOffset) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Only one node is selected.
|
|
29
|
+
if (selectedTextNodesLength === 1) {
|
|
30
|
+
// The entire node is selected.
|
|
31
|
+
if (startOffset === 0 && endOffset === firstNodeTextLength) {
|
|
32
|
+
const fontColorNode = applyColorToNode(firstNode, color);
|
|
33
|
+
fontColorNode.select(startOffset, endOffset);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The node is partially selected, so split it into two nodes and style the selected part.
|
|
38
|
+
const splitNodes = firstNode.splitText(startOffset, endOffset);
|
|
39
|
+
const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];
|
|
40
|
+
const fontColorNode = applyColorToNode(replacement, color);
|
|
41
|
+
fontColorNode.select(0, endOffset - startOffset);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Several nodes are selected.
|
|
46
|
+
textNodes.forEach(textNode => {
|
|
47
|
+
// First node is partially selected.
|
|
48
|
+
if (textNode === firstNode && startOffset > 0) {
|
|
49
|
+
const [, toColor] = textNode.splitText(startOffset);
|
|
50
|
+
applyColorToNode(toColor, color);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Last node is partially selected.
|
|
55
|
+
if (textNode === lastNode && lastNode.getTextContent().length !== endOffset) {
|
|
56
|
+
const [toColor] = textNode.splitText(endOffset);
|
|
57
|
+
applyColorToNode(toColor, color);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Colorize the whole node.
|
|
62
|
+
applyColorToNode(textNode, color);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=applyColorToSelection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TextNode","applyColorToNode","applyColorToSelection","selection","color","textNodes","getNodes","filter","node","selectedTextNodesLength","length","startEndPoints","getStartEndPoints","anchor","focus","lastIndex","firstNode","lastNode","firstNodeText","getTextContent","firstNodeTextLength","focusOffset","offset","anchorOffset","isBefore","startOffset","endOffset","fontColorNode","select","splitNodes","splitText","replacement","forEach","textNode","toColor"],"sources":["applyColorToSelection.ts"],"sourcesContent":["import type { RangeSelection } from \"lexical\";\nimport { TextNode } from \"lexical\";\nimport type { ThemeColorValue } from \"@webiny/lexical-nodes\";\nimport { applyColorToNode } from \"~/plugins/FontColorPlugin/applyColorToNode.js\";\n\nexport function applyColorToSelection(selection: RangeSelection, color: ThemeColorValue) {\n // Basic variables\n const textNodes = selection.getNodes().filter(node => node instanceof TextNode) as TextNode[];\n\n const selectedTextNodesLength = textNodes.length;\n const startEndPoints = selection.getStartEndPoints();\n\n if (startEndPoints === null) {\n return;\n }\n\n const [anchor, focus] = startEndPoints;\n\n const lastIndex = selectedTextNodesLength - 1;\n const firstNode = textNodes[0];\n const lastNode = textNodes[lastIndex];\n const firstNodeText = firstNode.getTextContent();\n const firstNodeTextLength = firstNodeText.length;\n const focusOffset = focus.offset;\n const anchorOffset = anchor.offset;\n const isBefore = anchor.isBefore(focus);\n const startOffset = isBefore ? anchorOffset : focusOffset;\n const endOffset = isBefore ? focusOffset : anchorOffset;\n\n // No actual text is selected, so do nothing.\n if (startOffset === endOffset) {\n return;\n }\n\n // Only one node is selected.\n if (selectedTextNodesLength === 1) {\n // The entire node is selected.\n if (startOffset === 0 && endOffset === firstNodeTextLength) {\n const fontColorNode = applyColorToNode(firstNode, color);\n fontColorNode.select(startOffset, endOffset);\n return;\n }\n\n // The node is partially selected, so split it into two nodes and style the selected part.\n const splitNodes = firstNode.splitText(startOffset, endOffset);\n const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];\n const fontColorNode = applyColorToNode(replacement, color);\n fontColorNode.select(0, endOffset - startOffset);\n\n return;\n }\n\n // Several nodes are selected.\n textNodes.forEach(textNode => {\n // First node is partially selected.\n if (textNode === firstNode && startOffset > 0) {\n const [, toColor] = textNode.splitText(startOffset);\n applyColorToNode(toColor, color);\n\n return;\n }\n\n // Last node is partially selected.\n if (textNode === lastNode && lastNode.getTextContent().length !== endOffset) {\n const [toColor] = textNode.splitText(endOffset);\n applyColorToNode(toColor, color);\n return;\n }\n\n // Colorize the whole node.\n applyColorToNode(textNode, color);\n });\n}\n"],"mappings":"AACA,SAASA,QAAQ,QAAQ,SAAS;AAElC,SAASC,gBAAgB;AAEzB,OAAO,SAASC,qBAAqBA,CAACC,SAAyB,EAAEC,KAAsB,EAAE;EACrF;EACA,MAAMC,SAAS,GAAGF,SAAS,CAACG,QAAQ,CAAC,CAAC,CAACC,MAAM,CAACC,IAAI,IAAIA,IAAI,YAAYR,QAAQ,CAAe;EAE7F,MAAMS,uBAAuB,GAAGJ,SAAS,CAACK,MAAM;EAChD,MAAMC,cAAc,GAAGR,SAAS,CAACS,iBAAiB,CAAC,CAAC;EAEpD,IAAID,cAAc,KAAK,IAAI,EAAE;IACzB;EACJ;EAEA,MAAM,CAACE,MAAM,EAAEC,KAAK,CAAC,GAAGH,cAAc;EAEtC,MAAMI,SAAS,GAAGN,uBAAuB,GAAG,CAAC;EAC7C,MAAMO,SAAS,GAAGX,SAAS,CAAC,CAAC,CAAC;EAC9B,MAAMY,QAAQ,GAAGZ,SAAS,CAACU,SAAS,CAAC;EACrC,MAAMG,aAAa,GAAGF,SAAS,CAACG,cAAc,CAAC,CAAC;EAChD,MAAMC,mBAAmB,GAAGF,aAAa,CAACR,MAAM;EAChD,MAAMW,WAAW,GAAGP,KAAK,CAACQ,MAAM;EAChC,MAAMC,YAAY,GAAGV,MAAM,CAACS,MAAM;EAClC,MAAME,QAAQ,GAAGX,MAAM,CAACW,QAAQ,CAACV,KAAK,CAAC;EACvC,MAAMW,WAAW,GAAGD,QAAQ,GAAGD,YAAY,GAAGF,WAAW;EACzD,MAAMK,SAAS,GAAGF,QAAQ,GAAGH,WAAW,GAAGE,YAAY;;EAEvD;EACA,IAAIE,WAAW,KAAKC,SAAS,EAAE;IAC3B;EACJ;;EAEA;EACA,IAAIjB,uBAAuB,KAAK,CAAC,EAAE;IAC/B;IACA,IAAIgB,WAAW,KAAK,CAAC,IAAIC,SAAS,KAAKN,mBAAmB,EAAE;MACxD,MAAMO,aAAa,GAAG1B,gBAAgB,CAACe,SAAS,EAAEZ,KAAK,CAAC;MACxDuB,aAAa,CAACC,MAAM,CAACH,WAAW,EAAEC,SAAS,CAAC;MAC5C;IACJ;;IAEA;IACA,MAAMG,UAAU,GAAGb,SAAS,CAACc,SAAS,CAACL,WAAW,EAAEC,SAAS,CAAC;IAC9D,MAAMK,WAAW,GAAGN,WAAW,KAAK,CAAC,GAAGI,UAAU,CAAC,CAAC,CAAC,GAAGA,UAAU,CAAC,CAAC,CAAC;IACrE,MAAMF,aAAa,GAAG1B,gBAAgB,CAAC8B,WAAW,EAAE3B,KAAK,CAAC;IAC1DuB,aAAa,CAACC,MAAM,CAAC,CAAC,EAAEF,SAAS,GAAGD,WAAW,CAAC;IAEhD;EACJ;;EAEA;EACApB,SAAS,CAAC2B,OAAO,CAACC,QAAQ,IAAI;IAC1B;IACA,IAAIA,QAAQ,KAAKjB,SAAS,IAAIS,WAAW,GAAG,CAAC,EAAE;MAC3C,MAAM,GAAGS,OAAO,CAAC,GAAGD,QAAQ,CAACH,SAAS,CAACL,WAAW,CAAC;MACnDxB,gBAAgB,CAACiC,OAAO,EAAE9B,KAAK,CAAC;MAEhC;IACJ;;IAEA;IACA,IAAI6B,QAAQ,KAAKhB,QAAQ,IAAIA,QAAQ,CAACE,cAAc,CAAC,CAAC,CAACT,MAAM,KAAKgB,SAAS,EAAE;MACzE,MAAM,CAACQ,OAAO,CAAC,GAAGD,QAAQ,CAACH,SAAS,CAACJ,SAAS,CAAC;MAC/CzB,gBAAgB,CAACiC,OAAO,EAAE9B,KAAK,CAAC;MAChC;IACJ;;IAEA;IACAH,gBAAgB,CAACgC,QAAQ,EAAE7B,KAAK,CAAC;EACrC,CAAC,CAAC;AACN","ignoreList":[]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export declare type InsertImagePayload = Readonly<ImagePayload>;
|
|
1
|
+
import type { ImagePayload } from "../../commands/index.js";
|
|
2
|
+
export type InsertImagePayload = Readonly<ImagePayload>;
|
|
4
3
|
export declare function ImagesPlugin({ captionsEnabled }: {
|
|
5
4
|
captionsEnabled?: boolean;
|
|
6
5
|
}): JSX.Element | null;
|
|
@@ -1,17 +1,5 @@
|
|
|
1
|
-
"use
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.ImagesPlugin = ImagesPlugin;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _utils = require("@lexical/utils");
|
|
9
|
-
var _lexical = require("lexical");
|
|
10
|
-
var _lexicalNodes = require("@webiny/lexical-nodes");
|
|
11
|
-
var _commands = require("../../commands");
|
|
12
|
-
var _canUseDOM = require("../../utils/canUseDOM");
|
|
13
|
-
var _insertImage = require("../../utils/insertImage");
|
|
14
|
-
var _hooks = require("../../hooks");
|
|
15
3
|
/**
|
|
16
4
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
17
5
|
*
|
|
@@ -19,53 +7,62 @@ var _hooks = require("../../hooks");
|
|
|
19
7
|
* LICENSE file in the root directory of this source tree.
|
|
20
8
|
*
|
|
21
9
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
10
|
+
import { useEffect } from "react";
|
|
11
|
+
import { $createRangeSelection, $getSelection, $isNodeSelection, $setSelection, mergeRegister, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND } from "lexical";
|
|
12
|
+
import { $isImageNode, ImageNode } from "@webiny/lexical-nodes";
|
|
13
|
+
import { INSERT_IMAGE_COMMAND } from "../../commands/index.js";
|
|
14
|
+
import { CAN_USE_DOM } from "../../utils/canUseDOM.js";
|
|
15
|
+
import { insertImage } from "../../utils/insertImage.js";
|
|
16
|
+
import { useRichTextEditor } from "../../hooks/index.js";
|
|
17
|
+
const getDOMSelection = targetWindow => CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
|
|
18
|
+
export function ImagesPlugin({
|
|
19
|
+
captionsEnabled
|
|
20
|
+
}) {
|
|
21
|
+
const {
|
|
22
|
+
editor
|
|
23
|
+
} = useRichTextEditor();
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!editor.hasNodes([ImageNode])) {
|
|
32
26
|
throw new Error("ImagesPlugin: ImageNode not registered in the editor!");
|
|
33
27
|
}
|
|
34
|
-
return
|
|
35
|
-
return (0, _insertImage.insertImage)(payload);
|
|
36
|
-
}, _lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(_lexical.DRAGSTART_COMMAND, function (event) {
|
|
28
|
+
return mergeRegister(editor.registerCommand(INSERT_IMAGE_COMMAND, payload => insertImage(payload), COMMAND_PRIORITY_EDITOR), editor.registerCommand(DRAGSTART_COMMAND, event => {
|
|
37
29
|
return onDragStart(event);
|
|
38
|
-
},
|
|
30
|
+
}, COMMAND_PRIORITY_HIGH), editor.registerCommand(DRAGOVER_COMMAND, event => {
|
|
39
31
|
return onDragover(event);
|
|
40
|
-
},
|
|
32
|
+
}, COMMAND_PRIORITY_LOW), editor.registerCommand(DROP_COMMAND, event => {
|
|
41
33
|
return onDrop(event, editor);
|
|
42
|
-
},
|
|
34
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
43
35
|
}, [captionsEnabled, editor]);
|
|
44
36
|
return null;
|
|
45
37
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
function getDragImage() {
|
|
39
|
+
if (!document) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const TRANSPARENT_IMAGE = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
43
|
+
const img = document.createElement("img");
|
|
44
|
+
img.src = TRANSPARENT_IMAGE;
|
|
45
|
+
return img;
|
|
46
|
+
}
|
|
49
47
|
function onDragStart(event) {
|
|
50
|
-
|
|
48
|
+
const node = getImageNodeInSelection();
|
|
51
49
|
if (!node) {
|
|
52
50
|
return false;
|
|
53
51
|
}
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
const dataTransfer = event.dataTransfer;
|
|
53
|
+
const dragImage = getDragImage();
|
|
54
|
+
if (!dataTransfer || !dragImage) {
|
|
56
55
|
return false;
|
|
57
56
|
}
|
|
58
57
|
dataTransfer.setData("text/plain", "_");
|
|
59
|
-
dataTransfer.setDragImage(
|
|
58
|
+
dataTransfer.setDragImage(dragImage, 0, 0);
|
|
60
59
|
dataTransfer.setData("application/x-lexical-drag", JSON.stringify({
|
|
61
60
|
data: {
|
|
62
61
|
id: node.__id,
|
|
63
62
|
altText: node.__altText,
|
|
64
|
-
caption: node.__caption,
|
|
65
63
|
height: node.__height,
|
|
66
64
|
key: node.getKey(),
|
|
67
65
|
maxWidth: node.__maxWidth,
|
|
68
|
-
showCaption: node.__showCaption,
|
|
69
66
|
src: node.__src,
|
|
70
67
|
width: node.__width
|
|
71
68
|
},
|
|
@@ -74,7 +71,7 @@ function onDragStart(event) {
|
|
|
74
71
|
return true;
|
|
75
72
|
}
|
|
76
73
|
function onDragover(event) {
|
|
77
|
-
|
|
74
|
+
const node = getImageNodeInSelection();
|
|
78
75
|
if (!node) {
|
|
79
76
|
return false;
|
|
80
77
|
}
|
|
@@ -84,65 +81,66 @@ function onDragover(event) {
|
|
|
84
81
|
return true;
|
|
85
82
|
}
|
|
86
83
|
function onDrop(event, editor) {
|
|
87
|
-
|
|
84
|
+
const node = getImageNodeInSelection();
|
|
88
85
|
if (!node) {
|
|
89
86
|
return false;
|
|
90
87
|
}
|
|
91
|
-
|
|
88
|
+
const data = getDragImageData(event);
|
|
92
89
|
if (!data) {
|
|
93
90
|
return false;
|
|
94
91
|
}
|
|
95
92
|
event.preventDefault();
|
|
96
93
|
if (canDropImage(event)) {
|
|
97
|
-
|
|
94
|
+
const range = getDragSelection(event);
|
|
98
95
|
node.remove();
|
|
99
|
-
|
|
96
|
+
const rangeSelection = $createRangeSelection();
|
|
100
97
|
if (range !== null && range !== undefined) {
|
|
101
98
|
rangeSelection.applyDOMRange(range);
|
|
102
99
|
}
|
|
103
|
-
|
|
104
|
-
editor.dispatchCommand(
|
|
100
|
+
$setSelection(rangeSelection);
|
|
101
|
+
editor.dispatchCommand(INSERT_IMAGE_COMMAND, data);
|
|
105
102
|
}
|
|
106
103
|
return true;
|
|
107
104
|
}
|
|
108
105
|
function getImageNodeInSelection() {
|
|
109
|
-
|
|
110
|
-
if (
|
|
106
|
+
const selection = $getSelection();
|
|
107
|
+
if (!$isNodeSelection(selection)) {
|
|
111
108
|
return null;
|
|
112
109
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return
|
|
110
|
+
const nodes = selection.getNodes();
|
|
111
|
+
const node = nodes[0];
|
|
112
|
+
return $isImageNode(node) ? node : null;
|
|
116
113
|
}
|
|
117
114
|
function getDragImageData(event) {
|
|
118
|
-
|
|
115
|
+
const dragData = event.dataTransfer?.getData("application/x-lexical-drag");
|
|
119
116
|
if (!dragData) {
|
|
120
117
|
return null;
|
|
121
118
|
}
|
|
122
|
-
|
|
123
|
-
type
|
|
124
|
-
data
|
|
119
|
+
const {
|
|
120
|
+
type,
|
|
121
|
+
data
|
|
122
|
+
} = JSON.parse(dragData);
|
|
125
123
|
if (type !== "image") {
|
|
126
124
|
return null;
|
|
127
125
|
}
|
|
128
126
|
return data;
|
|
129
127
|
}
|
|
130
128
|
function canDropImage(event) {
|
|
131
|
-
|
|
129
|
+
const target = event.target;
|
|
132
130
|
return !!(target && target instanceof HTMLElement && !target.closest("code, span.editor-image") && target.parentElement && target.parentElement.closest("div.ContentEditable__root"));
|
|
133
131
|
}
|
|
134
132
|
function getDragSelection(event) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
let range;
|
|
134
|
+
const target = event.target;
|
|
135
|
+
const targetWindow = target == null ? null : target.nodeType === 9 ? target.defaultView : target.ownerDocument.defaultView;
|
|
136
|
+
const domSelection = getDOMSelection(targetWindow);
|
|
139
137
|
if (document.caretRangeFromPoint) {
|
|
140
138
|
range = document.caretRangeFromPoint(event.clientX, event.clientY);
|
|
141
139
|
} else if (event.rangeParent && domSelection !== null) {
|
|
142
140
|
domSelection.collapse(event.rangeParent, event.rangeOffset || 0);
|
|
143
141
|
range = domSelection.getRangeAt(0);
|
|
144
142
|
} else {
|
|
145
|
-
throw Error(
|
|
143
|
+
throw Error(`Cannot get the selection when dragging`);
|
|
146
144
|
}
|
|
147
145
|
return range;
|
|
148
146
|
}
|