@lexical/react 0.45.1-nightly.20260618.0 → 0.45.1-nightly.20260622.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/dist/LexicalAutoEmbedPlugin.d.ts +25 -0
- package/dist/LexicalAutoEmbedPlugin.dev.js +19 -4
- package/dist/LexicalAutoEmbedPlugin.dev.mjs +19 -4
- package/dist/LexicalAutoEmbedPlugin.prod.js +1 -1
- package/dist/LexicalAutoEmbedPlugin.prod.mjs +1 -1
- package/dist/LexicalAutoFocusPlugin.d.ts +10 -0
- package/dist/LexicalAutoFocusPlugin.dev.js +14 -1
- package/dist/LexicalAutoFocusPlugin.dev.mjs +14 -1
- package/dist/LexicalAutoFocusPlugin.prod.js +1 -1
- package/dist/LexicalAutoFocusPlugin.prod.mjs +1 -1
- package/dist/LexicalAutoLinkPlugin.d.ts +13 -0
- package/dist/LexicalAutoLinkPlugin.dev.js +14 -0
- package/dist/LexicalAutoLinkPlugin.dev.mjs +14 -0
- package/dist/LexicalBlockWithAlignableContents.d.ts +9 -0
- package/dist/LexicalBlockWithAlignableContents.dev.js +11 -2
- package/dist/LexicalBlockWithAlignableContents.dev.mjs +12 -3
- package/dist/LexicalBlockWithAlignableContents.prod.js +1 -1
- package/dist/LexicalBlockWithAlignableContents.prod.mjs +1 -1
- package/dist/LexicalCharacterLimitPlugin.d.ts +10 -0
- package/dist/LexicalCharacterLimitPlugin.dev.js +14 -5
- package/dist/LexicalCharacterLimitPlugin.dev.mjs +14 -5
- package/dist/LexicalCharacterLimitPlugin.prod.js +2 -2
- package/dist/LexicalCharacterLimitPlugin.prod.mjs +2 -2
- package/dist/LexicalCheckListPlugin.d.ts +11 -0
- package/dist/LexicalCheckListPlugin.dev.js +12 -0
- package/dist/LexicalCheckListPlugin.dev.mjs +12 -0
- package/dist/LexicalClearEditorPlugin.d.ts +10 -0
- package/dist/LexicalClearEditorPlugin.dev.js +10 -0
- package/dist/LexicalClearEditorPlugin.dev.mjs +10 -0
- package/dist/LexicalClickableLinkPlugin.d.ts +10 -0
- package/dist/LexicalClickableLinkPlugin.dev.js +11 -0
- package/dist/LexicalClickableLinkPlugin.dev.mjs +11 -0
- package/dist/LexicalCollaborationContext.d.ts +25 -0
- package/dist/LexicalCollaborationContext.dev.js +23 -0
- package/dist/LexicalCollaborationContext.dev.mjs +23 -0
- package/dist/LexicalCollaborationPlugin.d.ts +18 -0
- package/dist/LexicalCollaborationPlugin.dev.js +26 -5
- package/dist/LexicalCollaborationPlugin.dev.mjs +24 -3
- package/dist/LexicalCollaborationPlugin.prod.js +1 -1
- package/dist/LexicalCollaborationPlugin.prod.mjs +1 -1
- package/dist/LexicalComposer.d.ts +22 -0
- package/dist/LexicalComposer.dev.js +28 -2
- package/dist/LexicalComposer.dev.mjs +29 -3
- package/dist/LexicalComposer.prod.js +1 -1
- package/dist/LexicalComposer.prod.mjs +1 -1
- package/dist/LexicalComposerContext.d.ts +35 -0
- package/dist/LexicalComposerContext.dev.js +39 -0
- package/dist/LexicalComposerContext.dev.mjs +39 -0
- package/dist/LexicalContentEditable.d.ts +13 -0
- package/dist/LexicalContentEditable.dev.js +26 -3
- package/dist/LexicalContentEditable.dev.mjs +26 -3
- package/dist/LexicalContentEditable.prod.js +2 -2
- package/dist/LexicalContentEditable.prod.mjs +2 -2
- package/dist/LexicalDecoratorBlockNode.d.ts +14 -0
- package/dist/LexicalDecoratorBlockNode.dev.js +17 -0
- package/dist/LexicalDecoratorBlockNode.dev.mjs +17 -0
- package/dist/LexicalDraggableBlockPlugin.d.ts +10 -0
- package/dist/LexicalDraggableBlockPlugin.dev.js +38 -20
- package/dist/LexicalDraggableBlockPlugin.dev.mjs +33 -15
- package/dist/LexicalDraggableBlockPlugin.prod.js +1 -1
- package/dist/LexicalDraggableBlockPlugin.prod.mjs +1 -1
- package/dist/LexicalErrorBoundary.d.ts +16 -2
- package/dist/LexicalErrorBoundary.dev.js +38 -10
- package/dist/LexicalErrorBoundary.dev.mjs +38 -10
- package/dist/LexicalErrorBoundary.js.flow +1 -0
- package/dist/LexicalErrorBoundary.prod.js +2 -2
- package/dist/LexicalErrorBoundary.prod.mjs +2 -2
- package/dist/LexicalExtensionComposer.d.ts +3 -0
- package/dist/LexicalExtensionEditorComposer.d.ts +3 -0
- package/dist/LexicalHashtagPlugin.d.ts +10 -0
- package/dist/LexicalHashtagPlugin.dev.js +11 -0
- package/dist/LexicalHashtagPlugin.dev.mjs +11 -0
- package/dist/LexicalHistoryPlugin.d.ts +11 -0
- package/dist/LexicalHistoryPlugin.dev.js +11 -0
- package/dist/LexicalHistoryPlugin.dev.mjs +11 -0
- package/dist/LexicalHorizontalRuleNode.dev.js +4 -5
- package/dist/LexicalHorizontalRuleNode.dev.mjs +2 -3
- package/dist/LexicalHorizontalRuleNode.prod.js +2 -2
- package/dist/LexicalHorizontalRuleNode.prod.mjs +2 -2
- package/dist/LexicalHorizontalRulePlugin.d.ts +5 -1
- package/dist/LexicalHorizontalRulePlugin.dev.js +5 -1
- package/dist/LexicalHorizontalRulePlugin.dev.mjs +5 -1
- package/dist/LexicalLinkPlugin.d.ts +12 -0
- package/dist/LexicalLinkPlugin.dev.js +12 -0
- package/dist/LexicalLinkPlugin.dev.mjs +12 -0
- package/dist/LexicalListPlugin.d.ts +13 -0
- package/dist/LexicalListPlugin.dev.js +15 -0
- package/dist/LexicalListPlugin.dev.mjs +15 -0
- package/dist/LexicalMarkdownShortcutPlugin.d.ts +13 -0
- package/dist/LexicalMarkdownShortcutPlugin.dev.js +14 -0
- package/dist/LexicalMarkdownShortcutPlugin.dev.mjs +14 -0
- package/dist/LexicalNestedComposer.d.ts +17 -0
- package/dist/LexicalNestedComposer.dev.js +15 -0
- package/dist/LexicalNestedComposer.dev.mjs +15 -0
- package/dist/LexicalNodeContextMenuPlugin.d.ts +21 -0
- package/dist/LexicalNodeContextMenuPlugin.dev.js +23 -0
- package/dist/LexicalNodeContextMenuPlugin.dev.mjs +23 -0
- package/dist/LexicalNodeEventPlugin.d.ts +8 -0
- package/dist/LexicalNodeEventPlugin.dev.js +10 -2
- package/dist/LexicalNodeEventPlugin.dev.mjs +10 -2
- package/dist/LexicalNodeEventPlugin.prod.js +1 -1
- package/dist/LexicalNodeEventPlugin.prod.mjs +1 -1
- package/dist/LexicalNodeMenuPlugin.d.ts +12 -0
- package/dist/LexicalNodeMenuPlugin.dev.js +123 -30
- package/dist/LexicalNodeMenuPlugin.dev.mjs +122 -29
- package/dist/LexicalNodeMenuPlugin.prod.js +1 -1
- package/dist/LexicalNodeMenuPlugin.prod.mjs +1 -1
- package/dist/LexicalOnChangePlugin.d.ts +8 -0
- package/dist/LexicalOnChangePlugin.dev.js +9 -0
- package/dist/LexicalOnChangePlugin.dev.mjs +9 -0
- package/dist/LexicalPlainTextPlugin.d.ts +12 -0
- package/dist/LexicalPlainTextPlugin.dev.js +3 -4
- package/dist/LexicalPlainTextPlugin.dev.mjs +2 -3
- package/dist/LexicalPlainTextPlugin.prod.js +1 -1
- package/dist/LexicalPlainTextPlugin.prod.mjs +1 -1
- package/dist/LexicalReactPluginHostExtension.dev.js +45 -2
- package/dist/LexicalReactPluginHostExtension.dev.mjs +45 -2
- package/dist/LexicalReactPluginHostExtension.prod.js +1 -1
- package/dist/LexicalReactPluginHostExtension.prod.mjs +1 -1
- package/dist/LexicalRichTextPlugin.d.ts +12 -0
- package/dist/LexicalRichTextPlugin.dev.js +3 -4
- package/dist/LexicalRichTextPlugin.dev.mjs +2 -3
- package/dist/LexicalRichTextPlugin.prod.js +1 -1
- package/dist/LexicalRichTextPlugin.prod.mjs +1 -1
- package/dist/LexicalSelectionAlwaysOnDisplay.d.ts +11 -0
- package/dist/LexicalSelectionAlwaysOnDisplay.dev.js +11 -0
- package/dist/LexicalSelectionAlwaysOnDisplay.dev.mjs +11 -0
- package/dist/LexicalTabIndentationPlugin.d.ts +3 -0
- package/dist/LexicalTabIndentationPlugin.dev.js +3 -0
- package/dist/LexicalTabIndentationPlugin.dev.mjs +3 -0
- package/dist/LexicalTableOfContentsPlugin.d.ts +13 -0
- package/dist/LexicalTableOfContentsPlugin.dev.js +18 -3
- package/dist/LexicalTableOfContentsPlugin.dev.mjs +18 -3
- package/dist/LexicalTableOfContentsPlugin.prod.js +1 -1
- package/dist/LexicalTableOfContentsPlugin.prod.mjs +1 -1
- package/dist/LexicalTablePlugin.d.ts +6 -0
- package/dist/LexicalTablePlugin.dev.js +8 -0
- package/dist/LexicalTablePlugin.dev.mjs +8 -0
- package/dist/LexicalTreeView.d.ts +4 -0
- package/dist/LexicalTreeView.dev.js +2 -2
- package/dist/LexicalTreeView.dev.mjs +1 -1
- package/dist/LexicalTreeView.prod.js +1 -1
- package/dist/LexicalTreeView.prod.mjs +1 -1
- package/dist/LexicalTreeViewExtension.dev.js +7 -0
- package/dist/LexicalTreeViewExtension.dev.mjs +7 -0
- package/dist/LexicalTypeaheadMenuPlugin.d.ts +32 -1
- package/dist/LexicalTypeaheadMenuPlugin.dev.js +152 -57
- package/dist/LexicalTypeaheadMenuPlugin.dev.mjs +151 -56
- package/dist/LexicalTypeaheadMenuPlugin.prod.js +1 -1
- package/dist/LexicalTypeaheadMenuPlugin.prod.mjs +1 -1
- package/dist/ReactPluginHostExtension.d.ts +50 -0
- package/dist/TreeViewExtension.d.ts +12 -0
- package/dist/shared/LexicalContentEditableElement.d.ts +16 -0
- package/dist/shared/LexicalMenu.d.ts +37 -2
- package/dist/shared/getScrollParent.d.ts +19 -0
- package/dist/shared/types.d.ts +21 -0
- package/dist/useExtensionComponent.d.ts +22 -0
- package/dist/useLexicalEditable.dev.js +7 -0
- package/dist/useLexicalEditable.dev.mjs +7 -0
- package/dist/useLexicalExtensionComponent.dev.js +24 -0
- package/dist/useLexicalExtensionComponent.dev.mjs +24 -0
- package/dist/useLexicalIsTextContentEmpty.d.ts +7 -0
- package/dist/useLexicalIsTextContentEmpty.dev.js +9 -1
- package/dist/useLexicalIsTextContentEmpty.dev.mjs +9 -1
- package/dist/useLexicalIsTextContentEmpty.prod.js +1 -1
- package/dist/useLexicalIsTextContentEmpty.prod.mjs +1 -1
- package/dist/useLexicalNodeSelection.dev.js +1 -1
- package/dist/useLexicalNodeSelection.dev.mjs +1 -1
- package/dist/useLexicalNodeSelection.prod.js +1 -1
- package/dist/useLexicalNodeSelection.prod.mjs +1 -1
- package/dist/useLexicalSubscription.d.ts +5 -0
- package/dist/useLexicalSubscription.dev.js +7 -0
- package/dist/useLexicalSubscription.dev.mjs +7 -0
- package/dist/useLexicalTextEntity.d.ts +7 -0
- package/dist/useLexicalTextEntity.dev.js +10 -2
- package/dist/useLexicalTextEntity.dev.mjs +9 -1
- package/dist/useLexicalTextEntity.prod.js +1 -1
- package/dist/useLexicalTextEntity.prod.mjs +1 -1
- package/package.json +19 -20
- package/src/LexicalAutoEmbedPlugin.tsx +28 -3
- package/src/LexicalAutoFocusPlugin.ts +15 -1
- package/src/LexicalAutoLinkPlugin.ts +13 -0
- package/src/LexicalBlockWithAlignableContents.tsx +13 -5
- package/src/LexicalCharacterLimitPlugin.tsx +10 -0
- package/src/LexicalCheckListPlugin.tsx +11 -0
- package/src/LexicalClearEditorPlugin.ts +10 -0
- package/src/LexicalClickableLinkPlugin.tsx +10 -0
- package/src/LexicalCollaborationContext.tsx +25 -0
- package/src/LexicalCollaborationPlugin.tsx +18 -0
- package/src/LexicalComposer.tsx +31 -2
- package/src/LexicalComposerContext.ts +35 -0
- package/src/LexicalContentEditable.tsx +13 -0
- package/src/LexicalDecoratorBlockNode.ts +14 -0
- package/src/LexicalDraggableBlockPlugin.tsx +44 -14
- package/src/LexicalErrorBoundary.tsx +59 -20
- package/src/LexicalExtensionComposer.tsx +3 -0
- package/src/LexicalExtensionEditorComposer.tsx +3 -0
- package/src/LexicalHashtagPlugin.ts +10 -0
- package/src/LexicalHistoryPlugin.ts +11 -0
- package/src/LexicalHorizontalRuleNode.tsx +5 -6
- package/src/LexicalHorizontalRulePlugin.ts +5 -1
- package/src/LexicalLinkPlugin.ts +12 -0
- package/src/LexicalListPlugin.ts +13 -0
- package/src/LexicalMarkdownShortcutPlugin.tsx +13 -0
- package/src/LexicalNestedComposer.tsx +17 -0
- package/src/LexicalNodeContextMenuPlugin.tsx +21 -0
- package/src/LexicalNodeEventPlugin.ts +9 -2
- package/src/LexicalNodeMenuPlugin.tsx +12 -0
- package/src/LexicalOnChangePlugin.ts +8 -0
- package/src/LexicalPlainTextPlugin.tsx +12 -0
- package/src/LexicalRichTextPlugin.tsx +12 -0
- package/src/LexicalSelectionAlwaysOnDisplay.tsx +11 -0
- package/src/LexicalTabIndentationPlugin.tsx +3 -0
- package/src/LexicalTableOfContentsPlugin.tsx +16 -3
- package/src/LexicalTablePlugin.ts +6 -0
- package/src/LexicalTreeView.tsx +5 -1
- package/src/LexicalTypeaheadMenuPlugin.tsx +41 -35
- package/src/ReactPluginHostExtension.tsx +51 -1
- package/src/TreeViewExtension.tsx +12 -0
- package/src/shared/LexicalContentEditableElement.tsx +16 -0
- package/src/shared/LexicalMenu.tsx +86 -38
- package/src/shared/getScrollParent.ts +54 -0
- package/src/shared/types.ts +21 -0
- package/src/shared/useCanShowPlaceholder.ts +5 -4
- package/src/shared/useCharacterLimit.ts +3 -6
- package/src/shared/usePlainTextSetup.ts +1 -1
- package/src/shared/useRichTextSetup.ts +1 -1
- package/src/shared/useYjsCollaboration.tsx +6 -2
- package/src/useExtensionComponent.tsx +22 -0
- package/src/useLexicalIsTextContentEmpty.ts +11 -3
- package/src/useLexicalNodeSelection.ts +1 -1
- package/src/useLexicalSubscription.tsx +5 -0
- package/src/useLexicalTextEntity.ts +8 -1
|
@@ -9,18 +9,43 @@ import type { CommandListenerPriority, LexicalNode } from 'lexical';
|
|
|
9
9
|
import type { JSX } from 'react';
|
|
10
10
|
import { MenuOption, type MenuRenderFn } from '@lexical/react/LexicalNodeMenuPlugin';
|
|
11
11
|
import { LexicalCommand, LexicalEditor } from 'lexical';
|
|
12
|
+
/**
|
|
13
|
+
* The result of matching a URL for an embed: the matched `url`, an `id`
|
|
14
|
+
* identifying the embedded resource, and optional provider-specific `data`.
|
|
15
|
+
*/
|
|
12
16
|
export type EmbedMatchResult<TEmbedMatchResult = unknown> = {
|
|
13
17
|
url: string;
|
|
14
18
|
id: string;
|
|
15
19
|
data?: TEmbedMatchResult;
|
|
16
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* Describes a kind of embed (for example YouTube, a tweet, or Google Maps) that
|
|
23
|
+
* {@link LexicalAutoEmbedPlugin} can detect and insert. Each config has a `type`
|
|
24
|
+
* identifier, a `parseUrl` function that decides whether a URL matches and
|
|
25
|
+
* extracts its data, and an `insertNode` function that inserts the corresponding
|
|
26
|
+
* Lexical node.
|
|
27
|
+
*/
|
|
17
28
|
export interface EmbedConfig<TEmbedMatchResultData = unknown, TEmbedMatchResult = EmbedMatchResult<TEmbedMatchResultData>> {
|
|
18
29
|
type: string;
|
|
19
30
|
parseUrl: (text: string) => Promise<TEmbedMatchResult | null> | TEmbedMatchResult | null;
|
|
20
31
|
insertNode: (editor: LexicalEditor, result: TEmbedMatchResult) => void;
|
|
21
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* A general-purpose regular expression for detecting URLs, provided as a
|
|
35
|
+
* convenience for implementing an {@link EmbedConfig}'s `parseUrl`.
|
|
36
|
+
*/
|
|
22
37
|
export declare const URL_MATCHER: RegExp;
|
|
38
|
+
/**
|
|
39
|
+
* Command dispatched to start inserting an embed. Its payload is the `type` of
|
|
40
|
+
* the {@link EmbedConfig} to use; {@link LexicalAutoEmbedPlugin} listens for it
|
|
41
|
+
* and runs that config's URL detection flow.
|
|
42
|
+
*/
|
|
23
43
|
export declare const INSERT_EMBED_COMMAND: LexicalCommand<EmbedConfig['type']>;
|
|
44
|
+
/**
|
|
45
|
+
* A {@link MenuOption} for the auto-embed menu, pairing a display `title` with
|
|
46
|
+
* an `onSelect` callback invoked when the user chooses to embed the detected
|
|
47
|
+
* URL.
|
|
48
|
+
*/
|
|
24
49
|
export declare class AutoEmbedOption extends MenuOption {
|
|
25
50
|
title: string;
|
|
26
51
|
onSelect: (targetNode: LexicalNode | null) => void;
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
var link = require('@lexical/link');
|
|
12
12
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
13
13
|
var LexicalNodeMenuPlugin = require('@lexical/react/LexicalNodeMenuPlugin');
|
|
14
|
-
var utils = require('@lexical/utils');
|
|
15
14
|
var lexical = require('lexical');
|
|
16
15
|
var react = require('react');
|
|
17
16
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -24,8 +23,24 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
24
23
|
*
|
|
25
24
|
*/
|
|
26
25
|
|
|
26
|
+
/**
|
|
27
|
+
* A general-purpose regular expression for detecting URLs, provided as a
|
|
28
|
+
* convenience for implementing an {@link EmbedConfig}'s `parseUrl`.
|
|
29
|
+
*/
|
|
27
30
|
const URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Command dispatched to start inserting an embed. Its payload is the `type` of
|
|
34
|
+
* the {@link EmbedConfig} to use; {@link LexicalAutoEmbedPlugin} listens for it
|
|
35
|
+
* and runs that config's URL detection flow.
|
|
36
|
+
*/
|
|
28
37
|
const INSERT_EMBED_COMMAND = /* @__PURE__ */lexical.createCommand('INSERT_EMBED_COMMAND');
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A {@link MenuOption} for the auto-embed menu, pairing a display `title` with
|
|
41
|
+
* an `onSelect` callback invoked when the user chooses to embed the detected
|
|
42
|
+
* URL.
|
|
43
|
+
*/
|
|
29
44
|
class AutoEmbedOption extends LexicalNodeMenuPlugin.MenuOption {
|
|
30
45
|
title;
|
|
31
46
|
onSelect;
|
|
@@ -78,7 +93,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
78
93
|
setActiveEmbedConfig(null);
|
|
79
94
|
}, []);
|
|
80
95
|
const checkIfLinkNodeIsEmbeddable = react.useCallback(async key => {
|
|
81
|
-
const url = editor.
|
|
96
|
+
const url = editor.read('latest', function () {
|
|
82
97
|
const linkNode = lexical.$getNodeByKey(key);
|
|
83
98
|
if (link.$isLinkNode(linkNode)) {
|
|
84
99
|
return linkNode.getURL();
|
|
@@ -108,7 +123,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
108
123
|
}
|
|
109
124
|
}
|
|
110
125
|
};
|
|
111
|
-
return
|
|
126
|
+
return lexical.mergeRegister(...[link.LinkNode, link.AutoLinkNode].map(Klass => editor.registerMutationListener(Klass, (...args) => listener(...args), {
|
|
112
127
|
skipInitialization: true
|
|
113
128
|
})));
|
|
114
129
|
}, [checkIfLinkNodeIsEmbeddable, editor, nodeKey, reset]);
|
|
@@ -127,7 +142,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
127
142
|
}, [editor, embedConfigs, onOpenEmbedModalForConfig]);
|
|
128
143
|
const embedLinkViaActiveEmbedConfig = react.useCallback(async function () {
|
|
129
144
|
if (activeEmbedConfig != null && nodeKey != null) {
|
|
130
|
-
const linkNode = editor.
|
|
145
|
+
const linkNode = editor.read('latest', () => {
|
|
131
146
|
const node = lexical.$getNodeByKey(nodeKey);
|
|
132
147
|
if (link.$isLinkNode(node)) {
|
|
133
148
|
return node;
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
import { $isLinkNode, LinkNode, AutoLinkNode } from '@lexical/link';
|
|
10
10
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
11
11
|
import { MenuOption, LexicalNodeMenuPlugin } from '@lexical/react/LexicalNodeMenuPlugin';
|
|
12
|
-
import { mergeRegister } from '
|
|
13
|
-
import { createCommand, $getNodeByKey, COMMAND_PRIORITY_EDITOR, $getSelection, COMMAND_PRIORITY_LOW, PASTE_TAG } from 'lexical';
|
|
12
|
+
import { createCommand, $getNodeByKey, mergeRegister, COMMAND_PRIORITY_EDITOR, $getSelection, COMMAND_PRIORITY_LOW, PASTE_TAG } from 'lexical';
|
|
14
13
|
import { useState, useCallback, useEffect, useMemo } from 'react';
|
|
15
14
|
import { jsx } from 'react/jsx-runtime';
|
|
16
15
|
|
|
@@ -22,8 +21,24 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
22
21
|
*
|
|
23
22
|
*/
|
|
24
23
|
|
|
24
|
+
/**
|
|
25
|
+
* A general-purpose regular expression for detecting URLs, provided as a
|
|
26
|
+
* convenience for implementing an {@link EmbedConfig}'s `parseUrl`.
|
|
27
|
+
*/
|
|
25
28
|
const URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Command dispatched to start inserting an embed. Its payload is the `type` of
|
|
32
|
+
* the {@link EmbedConfig} to use; {@link LexicalAutoEmbedPlugin} listens for it
|
|
33
|
+
* and runs that config's URL detection flow.
|
|
34
|
+
*/
|
|
26
35
|
const INSERT_EMBED_COMMAND = /* @__PURE__ */createCommand('INSERT_EMBED_COMMAND');
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A {@link MenuOption} for the auto-embed menu, pairing a display `title` with
|
|
39
|
+
* an `onSelect` callback invoked when the user chooses to embed the detected
|
|
40
|
+
* URL.
|
|
41
|
+
*/
|
|
27
42
|
class AutoEmbedOption extends MenuOption {
|
|
28
43
|
title;
|
|
29
44
|
onSelect;
|
|
@@ -76,7 +91,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
76
91
|
setActiveEmbedConfig(null);
|
|
77
92
|
}, []);
|
|
78
93
|
const checkIfLinkNodeIsEmbeddable = useCallback(async key => {
|
|
79
|
-
const url = editor.
|
|
94
|
+
const url = editor.read('latest', function () {
|
|
80
95
|
const linkNode = $getNodeByKey(key);
|
|
81
96
|
if ($isLinkNode(linkNode)) {
|
|
82
97
|
return linkNode.getURL();
|
|
@@ -125,7 +140,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
125
140
|
}, [editor, embedConfigs, onOpenEmbedModalForConfig]);
|
|
126
141
|
const embedLinkViaActiveEmbedConfig = useCallback(async function () {
|
|
127
142
|
if (activeEmbedConfig != null && nodeKey != null) {
|
|
128
|
-
const linkNode = editor.
|
|
143
|
+
const linkNode = editor.read('latest', () => {
|
|
129
144
|
const node = $getNodeByKey(nodeKey);
|
|
130
145
|
if ($isLinkNode(node)) {
|
|
131
146
|
return node;
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("@lexical/link"),t=require("@lexical/react/LexicalComposerContext"),n=require("@lexical/react/LexicalNodeMenuPlugin"),
|
|
9
|
+
"use strict";var e=require("@lexical/link"),t=require("@lexical/react/LexicalComposerContext"),n=require("@lexical/react/LexicalNodeMenuPlugin"),o=require("lexical"),i=require("react"),l=require("react/jsx-runtime");const r=/* @__PURE__ */o.createCommand("INSERT_EMBED_COMMAND");class s extends n.MenuOption{title;onSelect;constructor(e,t){super(e),this.title=e,this.onSelect=t.onSelect.bind(this)}}exports.AutoEmbedOption=s,exports.INSERT_EMBED_COMMAND=r,exports.LexicalAutoEmbedPlugin=function({embedConfigs:s,onOpenEmbedModalForConfig:u,getMenuOptions:a,menuRenderFn:c,menuCommandPriority:d=o.COMMAND_PRIORITY_LOW}){const[m]=t.useLexicalComposerContext(),[p,f]=i.useState(null),[C,x]=i.useState(null),M=i.useCallback(()=>{f(null),x(null)},[]),N=i.useCallback(async t=>{const n=m.read("latest",function(){const n=o.$getNodeByKey(t);if(e.$isLinkNode(n))return n.getURL()});if(void 0!==n)for(const e of s){null!=await Promise.resolve(e.parseUrl(n))&&(x(e),f(t))}},[m,s]);i.useEffect(()=>o.mergeRegister(...[e.LinkNode,e.AutoLinkNode].map(e=>m.registerMutationListener(e,(...e)=>((e,{updateTags:t,dirtyLeaves:n})=>{for(const[i,l]of e)"created"===l&&t.has(o.PASTE_TAG)&&n.size<=3?N(i):i===p&&M()})(...e),{skipInitialization:!0}))),[N,m,p,M]),i.useEffect(()=>{if(u)return m.registerCommand(r,e=>{const t=s.find(({type:t})=>t===e);return!!t&&(u(t),!0)},o.COMMAND_PRIORITY_EDITOR)},[m,s,u]);const g=i.useCallback(async function(){if(null!=C&&null!=p){const t=m.read("latest",()=>{const t=o.$getNodeByKey(p);return e.$isLinkNode(t)?t:null});if(e.$isLinkNode(t)){const e=await Promise.resolve(C.parseUrl(t.__url));null!=e&&m.update(()=>{o.$getSelection()||t.selectEnd(),C.insertNode(m,e),t.isAttached()&&t.remove()})}}},[C,m,p]),E=i.useMemo(()=>null!=C&&null!=p?a(C,g,M):[],[C,g,a,p,M]),L=i.useCallback((e,t,n)=>{m.update(()=>{e.onSelect(t),n()})},[m]);return null!=p?/*#__PURE__*/l.jsx(n.LexicalNodeMenuPlugin,{nodeKey:p,onClose:M,onSelectOption:L,options:E,menuRenderFn:c,commandPriority:d}):null},exports.URL_MATCHER=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{$isLinkNode as e,LinkNode as t,AutoLinkNode as n}from"@lexical/link";import{useLexicalComposerContext as o}from"@lexical/react/LexicalComposerContext";import{MenuOption as r,LexicalNodeMenuPlugin as i}from"@lexical/react/LexicalNodeMenuPlugin";import{
|
|
9
|
+
import{$isLinkNode as e,LinkNode as t,AutoLinkNode as n}from"@lexical/link";import{useLexicalComposerContext as o}from"@lexical/react/LexicalComposerContext";import{MenuOption as r,LexicalNodeMenuPlugin as i}from"@lexical/react/LexicalNodeMenuPlugin";import{createCommand as l,$getNodeByKey as s,mergeRegister as a,COMMAND_PRIORITY_EDITOR as c,$getSelection as u,COMMAND_PRIORITY_LOW as m,PASTE_TAG as d}from"lexical";import{useState as p,useCallback as f,useEffect as x,useMemo as g}from"react";import{jsx as w}from"react/jsx-runtime";const C=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/,y=/* @__PURE__ */l("INSERT_EMBED_COMMAND");class M extends r{title;onSelect;constructor(e,t){super(e),this.title=e,this.onSelect=t.onSelect.bind(this)}}function h({embedConfigs:r,onOpenEmbedModalForConfig:l,getMenuOptions:C,menuRenderFn:M,menuCommandPriority:h=m}){const[S]=o(),[_,v]=p(null),[z,A]=p(null),E=f(()=>{v(null),A(null)},[]),L=f(async t=>{const n=S.read("latest",function(){const n=s(t);if(e(n))return n.getURL()});if(void 0!==n)for(const e of r){null!=await Promise.resolve(e.parseUrl(n))&&(A(e),v(t))}},[S,r]);x(()=>a(...[t,n].map(e=>S.registerMutationListener(e,(...e)=>((e,{updateTags:t,dirtyLeaves:n})=>{for(const[o,r]of e)"created"===r&&t.has(d)&&n.size<=3?L(o):o===_&&E()})(...e),{skipInitialization:!0}))),[L,S,_,E]),x(()=>{if(l)return S.registerCommand(y,e=>{const t=r.find(({type:t})=>t===e);return!!t&&(l(t),!0)},c)},[S,r,l]);const P=f(async function(){if(null!=z&&null!=_){const t=S.read("latest",()=>{const t=s(_);return e(t)?t:null});if(e(t)){const e=await Promise.resolve(z.parseUrl(t.__url));null!=e&&S.update(()=>{u()||t.selectEnd(),z.insertNode(S,e),t.isAttached()&&t.remove()})}}},[z,S,_]),b=g(()=>null!=z&&null!=_?C(z,P,E):[],[z,P,C,_,E]),N=f((e,t,n)=>{S.update(()=>{e.onSelect(t),n()})},[S]);return null!=_?/*#__PURE__*/w(i,{nodeKey:_,onClose:E,onSelectOption:N,options:b,menuRenderFn:M,commandPriority:h}):null}export{M as AutoEmbedOption,y as INSERT_EMBED_COMMAND,h as LexicalAutoEmbedPlugin,C as URL_MATCHER};
|
|
@@ -8,5 +8,15 @@
|
|
|
8
8
|
type Props = {
|
|
9
9
|
defaultSelection?: 'rootStart' | 'rootEnd';
|
|
10
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* Focuses the editor when the component is mounted. Pass `defaultSelection`
|
|
13
|
+
* to control whether the selection is placed at the start (`'rootStart'`) or
|
|
14
|
+
* end (`'rootEnd'`) of the root when there is no existing selection to restore.
|
|
15
|
+
*
|
|
16
|
+
* This is a legacy plugin. When building an editor with the extension API,
|
|
17
|
+
* configure {@link AutoFocusExtension} instead.
|
|
18
|
+
*
|
|
19
|
+
* @returns `null`, this plugin renders no DOM of its own.
|
|
20
|
+
*/
|
|
11
21
|
export declare function AutoFocusPlugin({ defaultSelection }: Props): null;
|
|
12
22
|
export {};
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
11
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
12
|
+
var lexical = require('lexical');
|
|
12
13
|
var react = require('react');
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -19,6 +20,16 @@ var react = require('react');
|
|
|
19
20
|
*
|
|
20
21
|
*/
|
|
21
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Focuses the editor when the component is mounted. Pass `defaultSelection`
|
|
25
|
+
* to control whether the selection is placed at the start (`'rootStart'`) or
|
|
26
|
+
* end (`'rootEnd'`) of the root when there is no existing selection to restore.
|
|
27
|
+
*
|
|
28
|
+
* This is a legacy plugin. When building an editor with the extension API,
|
|
29
|
+
* configure {@link AutoFocusExtension} instead.
|
|
30
|
+
*
|
|
31
|
+
* @returns `null`, this plugin renders no DOM of its own.
|
|
32
|
+
*/
|
|
22
33
|
function AutoFocusPlugin({
|
|
23
34
|
defaultSelection
|
|
24
35
|
}) {
|
|
@@ -29,8 +40,10 @@ function AutoFocusPlugin({
|
|
|
29
40
|
// trigger a re-focus on the element. So in the case this occurs, we'll need to correct it.
|
|
30
41
|
// Normally this is fine, Selection API !== Focus API, but fore the intents of the naming
|
|
31
42
|
// of this plugin, which should preserve focus too.
|
|
32
|
-
const activeElement = document.activeElement;
|
|
33
43
|
const rootElement = editor.getRootElement();
|
|
44
|
+
// getActiveElement rather than document.activeElement, which reports
|
|
45
|
+
// the shadow host when the editor is in a shadow root.
|
|
46
|
+
const activeElement = rootElement !== null ? lexical.getActiveElement(rootElement) : null;
|
|
34
47
|
if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
|
|
35
48
|
// Note: preventScroll won't work in Webkit.
|
|
36
49
|
rootElement.focus({
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
10
|
+
import { getActiveElement } from 'lexical';
|
|
10
11
|
import { useEffect } from 'react';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -17,6 +18,16 @@ import { useEffect } from 'react';
|
|
|
17
18
|
*
|
|
18
19
|
*/
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Focuses the editor when the component is mounted. Pass `defaultSelection`
|
|
23
|
+
* to control whether the selection is placed at the start (`'rootStart'`) or
|
|
24
|
+
* end (`'rootEnd'`) of the root when there is no existing selection to restore.
|
|
25
|
+
*
|
|
26
|
+
* This is a legacy plugin. When building an editor with the extension API,
|
|
27
|
+
* configure {@link AutoFocusExtension} instead.
|
|
28
|
+
*
|
|
29
|
+
* @returns `null`, this plugin renders no DOM of its own.
|
|
30
|
+
*/
|
|
20
31
|
function AutoFocusPlugin({
|
|
21
32
|
defaultSelection
|
|
22
33
|
}) {
|
|
@@ -27,8 +38,10 @@ function AutoFocusPlugin({
|
|
|
27
38
|
// trigger a re-focus on the element. So in the case this occurs, we'll need to correct it.
|
|
28
39
|
// Normally this is fine, Selection API !== Focus API, but fore the intents of the naming
|
|
29
40
|
// of this plugin, which should preserve focus too.
|
|
30
|
-
const activeElement = document.activeElement;
|
|
31
41
|
const rootElement = editor.getRootElement();
|
|
42
|
+
// getActiveElement rather than document.activeElement, which reports
|
|
43
|
+
// the shadow host when the editor is in a shadow root.
|
|
44
|
+
const activeElement = rootElement !== null ? getActiveElement(rootElement) : null;
|
|
32
45
|
if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
|
|
33
46
|
// Note: preventScroll won't work in Webkit.
|
|
34
47
|
rootElement.focus({
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("react");exports.AutoFocusPlugin=function({defaultSelection:
|
|
9
|
+
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("lexical"),l=require("react");exports.AutoFocusPlugin=function({defaultSelection:n}){const[o]=e.useLexicalComposerContext();return l.useEffect(()=>{o.focus(()=>{const e=o.getRootElement(),l=null!==e?t.getActiveElement(e):null;null===e||null!==l&&e.contains(l)||e.focus({preventScroll:!0})},{defaultSelection:n})},[n,o]),null};
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{useLexicalComposerContext as
|
|
9
|
+
import{useLexicalComposerContext as l}from"@lexical/react/LexicalComposerContext";import{getActiveElement as o}from"lexical";import{useEffect as t}from"react";function e({defaultSelection:e}){const[n]=l();return t(()=>{n.focus(()=>{const l=n.getRootElement(),t=null!==l?o(l):null;null===l||null!==t&&l.contains(t)||l.focus({preventScroll:!0})},{defaultSelection:e})},[e,n]),null}export{e as AutoFocusPlugin};
|
|
@@ -9,6 +9,19 @@ import type { ChangeHandler, LinkMatcher } from '@lexical/link';
|
|
|
9
9
|
import type { ElementNode } from 'lexical';
|
|
10
10
|
import type { JSX } from 'react';
|
|
11
11
|
export { type ChangeHandler, createLinkMatcherWithRegExp, type LinkMatcher, } from '@lexical/link';
|
|
12
|
+
/**
|
|
13
|
+
* Automatically converts text that matches one of the provided `matchers` into
|
|
14
|
+
* {@link AutoLinkNode}s as the user types, and reverts them back to plain text
|
|
15
|
+
* when they no longer match. Provide `onChange` to react to links being
|
|
16
|
+
* created, updated, or removed, and `excludeParents` to skip matching inside
|
|
17
|
+
* particular ancestor nodes. The editor must have the {@link AutoLinkNode}
|
|
18
|
+
* registered.
|
|
19
|
+
*
|
|
20
|
+
* This is a legacy plugin. When building an editor with the extension API,
|
|
21
|
+
* configure {@link AutoLinkExtension} instead.
|
|
22
|
+
*
|
|
23
|
+
* @returns `null`, this plugin renders no DOM of its own.
|
|
24
|
+
*/
|
|
12
25
|
export declare function AutoLinkPlugin({ matchers, onChange, excludeParents, }: {
|
|
13
26
|
matchers: LinkMatcher[];
|
|
14
27
|
onChange?: ChangeHandler;
|
|
@@ -42,6 +42,20 @@ function useAutoLink(editor, matchers, onChange, excludeParents) {
|
|
|
42
42
|
});
|
|
43
43
|
}, [editor, matchers, onChange, excludeParents]);
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Automatically converts text that matches one of the provided `matchers` into
|
|
48
|
+
* {@link AutoLinkNode}s as the user types, and reverts them back to plain text
|
|
49
|
+
* when they no longer match. Provide `onChange` to react to links being
|
|
50
|
+
* created, updated, or removed, and `excludeParents` to skip matching inside
|
|
51
|
+
* particular ancestor nodes. The editor must have the {@link AutoLinkNode}
|
|
52
|
+
* registered.
|
|
53
|
+
*
|
|
54
|
+
* This is a legacy plugin. When building an editor with the extension API,
|
|
55
|
+
* configure {@link AutoLinkExtension} instead.
|
|
56
|
+
*
|
|
57
|
+
* @returns `null`, this plugin renders no DOM of its own.
|
|
58
|
+
*/
|
|
45
59
|
function AutoLinkPlugin({
|
|
46
60
|
matchers,
|
|
47
61
|
onChange,
|
|
@@ -41,6 +41,20 @@ function useAutoLink(editor, matchers, onChange, excludeParents) {
|
|
|
41
41
|
});
|
|
42
42
|
}, [editor, matchers, onChange, excludeParents]);
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Automatically converts text that matches one of the provided `matchers` into
|
|
47
|
+
* {@link AutoLinkNode}s as the user types, and reverts them back to plain text
|
|
48
|
+
* when they no longer match. Provide `onChange` to react to links being
|
|
49
|
+
* created, updated, or removed, and `excludeParents` to skip matching inside
|
|
50
|
+
* particular ancestor nodes. The editor must have the {@link AutoLinkNode}
|
|
51
|
+
* registered.
|
|
52
|
+
*
|
|
53
|
+
* This is a legacy plugin. When building an editor with the extension API,
|
|
54
|
+
* configure {@link AutoLinkExtension} instead.
|
|
55
|
+
*
|
|
56
|
+
* @returns `null`, this plugin renders no DOM of its own.
|
|
57
|
+
*/
|
|
44
58
|
function AutoLinkPlugin({
|
|
45
59
|
matchers,
|
|
46
60
|
onChange,
|
|
@@ -17,5 +17,14 @@ type Props = Readonly<{
|
|
|
17
17
|
focus: string;
|
|
18
18
|
}>;
|
|
19
19
|
}>;
|
|
20
|
+
/**
|
|
21
|
+
* A wrapper component for the contents of a {@link DecoratorBlockNode} that
|
|
22
|
+
* keeps the block in sync with node selection and element alignment. It renders
|
|
23
|
+
* its `children` inside a container that reflects the node's `format`
|
|
24
|
+
* alignment, responds to `FORMAT_ELEMENT_COMMAND` to update that alignment, and
|
|
25
|
+
* toggles the node's selection when the container is clicked.
|
|
26
|
+
*
|
|
27
|
+
* @returns The element to render for the decorator block.
|
|
28
|
+
*/
|
|
20
29
|
export declare function BlockWithAlignableContents({ children, format, nodeKey, className, }: Props): JSX.Element;
|
|
21
30
|
export {};
|
|
@@ -24,6 +24,15 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
24
24
|
*
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* A wrapper component for the contents of a {@link DecoratorBlockNode} that
|
|
29
|
+
* keeps the block in sync with node selection and element alignment. It renders
|
|
30
|
+
* its `children` inside a container that reflects the node's `format`
|
|
31
|
+
* alignment, responds to `FORMAT_ELEMENT_COMMAND` to update that alignment, and
|
|
32
|
+
* toggles the node's selection when the container is clicked.
|
|
33
|
+
*
|
|
34
|
+
* @returns The element to render for the decorator block.
|
|
35
|
+
*/
|
|
27
36
|
function BlockWithAlignableContents({
|
|
28
37
|
children,
|
|
29
38
|
format,
|
|
@@ -34,7 +43,7 @@ function BlockWithAlignableContents({
|
|
|
34
43
|
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection.useLexicalNodeSelection(nodeKey);
|
|
35
44
|
const ref = react.useRef(null);
|
|
36
45
|
react.useEffect(() => {
|
|
37
|
-
return
|
|
46
|
+
return lexical.mergeRegister(editor.registerCommand(lexical.FORMAT_ELEMENT_COMMAND, formatType => {
|
|
38
47
|
if (isSelected) {
|
|
39
48
|
const selection = lexical.$getSelection();
|
|
40
49
|
if (lexical.$isNodeSelection(selection)) {
|
|
@@ -57,7 +66,7 @@ function BlockWithAlignableContents({
|
|
|
57
66
|
}
|
|
58
67
|
return false;
|
|
59
68
|
}, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.CLICK_COMMAND, event => {
|
|
60
|
-
if (event
|
|
69
|
+
if (lexical.getComposedEventTarget(event) === ref.current) {
|
|
61
70
|
event.preventDefault();
|
|
62
71
|
if (!event.shiftKey) {
|
|
63
72
|
clearSelection();
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
10
10
|
import { $isDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode';
|
|
11
11
|
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
|
|
12
|
-
import {
|
|
13
|
-
import { FORMAT_ELEMENT_COMMAND, $getSelection, $isNodeSelection, $getNodeByKey, $isRangeSelection, COMMAND_PRIORITY_LOW, CLICK_COMMAND } from 'lexical';
|
|
12
|
+
import { $getNearestBlockElementAncestorOrThrow } from '@lexical/utils';
|
|
13
|
+
import { mergeRegister, FORMAT_ELEMENT_COMMAND, $getSelection, $isNodeSelection, $getNodeByKey, $isRangeSelection, COMMAND_PRIORITY_LOW, CLICK_COMMAND, getComposedEventTarget } from 'lexical';
|
|
14
14
|
import { useRef, useEffect } from 'react';
|
|
15
15
|
import { jsx } from 'react/jsx-runtime';
|
|
16
16
|
|
|
@@ -22,6 +22,15 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
22
22
|
*
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* A wrapper component for the contents of a {@link DecoratorBlockNode} that
|
|
27
|
+
* keeps the block in sync with node selection and element alignment. It renders
|
|
28
|
+
* its `children` inside a container that reflects the node's `format`
|
|
29
|
+
* alignment, responds to `FORMAT_ELEMENT_COMMAND` to update that alignment, and
|
|
30
|
+
* toggles the node's selection when the container is clicked.
|
|
31
|
+
*
|
|
32
|
+
* @returns The element to render for the decorator block.
|
|
33
|
+
*/
|
|
25
34
|
function BlockWithAlignableContents({
|
|
26
35
|
children,
|
|
27
36
|
format,
|
|
@@ -55,7 +64,7 @@ function BlockWithAlignableContents({
|
|
|
55
64
|
}
|
|
56
65
|
return false;
|
|
57
66
|
}, COMMAND_PRIORITY_LOW), editor.registerCommand(CLICK_COMMAND, event => {
|
|
58
|
-
if (event
|
|
67
|
+
if (getComposedEventTarget(event) === ref.current) {
|
|
59
68
|
event.preventDefault();
|
|
60
69
|
if (!event.shiftKey) {
|
|
61
70
|
clearSelection();
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("@lexical/react/LexicalDecoratorBlockNode"),r=require("@lexical/react/useLexicalNodeSelection"),o=require("@lexical/utils"),i=require("lexical"),l=require("react"),c=require("react/jsx-runtime");exports.BlockWithAlignableContents=function({children:s,format:
|
|
9
|
+
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("@lexical/react/LexicalDecoratorBlockNode"),r=require("@lexical/react/useLexicalNodeSelection"),o=require("@lexical/utils"),i=require("lexical"),l=require("react"),c=require("react/jsx-runtime");exports.BlockWithAlignableContents=function({children:s,format:n,nodeKey:a,className:u}){const[d]=e.useLexicalComposerContext(),[f,m,x]=r.useLexicalNodeSelection(a),N=l.useRef(null);return l.useEffect(()=>i.mergeRegister(d.registerCommand(i.FORMAT_ELEMENT_COMMAND,e=>{if(f){const r=i.$getSelection();if(i.$isNodeSelection(r)){const r=i.$getNodeByKey(a);t.$isDecoratorBlockNode(r)&&r.setFormat(e)}else if(i.$isRangeSelection(r)){const i=r.getNodes();for(const r of i)if(t.$isDecoratorBlockNode(r))r.setFormat(e);else{o.$getNearestBlockElementAncestorOrThrow(r).setFormat(e)}}return!0}return!1},i.COMMAND_PRIORITY_LOW),d.registerCommand(i.CLICK_COMMAND,e=>i.getComposedEventTarget(e)===N.current&&(e.preventDefault(),e.shiftKey||x(),m(!f),!0),i.COMMAND_PRIORITY_LOW)),[x,d,f,a,m]),/*#__PURE__*/c.jsx("div",{className:[u.base,f?u.focus:null].filter(Boolean).join(" "),ref:N,style:{textAlign:n||void 0},children:s})};
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{useLexicalComposerContext as e}from"@lexical/react/LexicalComposerContext";import{$isDecoratorBlockNode as
|
|
9
|
+
import{useLexicalComposerContext as e}from"@lexical/react/LexicalComposerContext";import{$isDecoratorBlockNode as r}from"@lexical/react/LexicalDecoratorBlockNode";import{useLexicalNodeSelection as t}from"@lexical/react/useLexicalNodeSelection";import{$getNearestBlockElementAncestorOrThrow as o}from"@lexical/utils";import{mergeRegister as i,FORMAT_ELEMENT_COMMAND as l,$getSelection as c,$isNodeSelection as a,$getNodeByKey as m,$isRangeSelection as n,COMMAND_PRIORITY_LOW as s,CLICK_COMMAND as f,getComposedEventTarget as u}from"lexical";import{useRef as x,useEffect as d}from"react";import{jsx as p}from"react/jsx-runtime";function N({children:N,format:g,nodeKey:C,className:h}){const[v]=e(),[y,F,L]=t(C),j=x(null);return d(()=>i(v.registerCommand(l,e=>{if(y){const t=c();if(a(t)){const t=m(C);r(t)&&t.setFormat(e)}else if(n(t)){const i=t.getNodes();for(const t of i)if(r(t))t.setFormat(e);else{o(t).setFormat(e)}}return!0}return!1},s),v.registerCommand(f,e=>u(e)===j.current&&(e.preventDefault(),e.shiftKey||L(),F(!y),!0),s)),[L,v,y,C,F]),/*#__PURE__*/p("div",{className:[h.base,y?h.focus:null].filter(Boolean).join(" "),ref:j,style:{textAlign:g||void 0},children:N})}export{N as BlockWithAlignableContents};
|
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
import type { JSX } from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* Tracks the length of the editor's text content against `maxLength` and
|
|
11
|
+
* renders the number of remaining characters, marking any overflowing text so
|
|
12
|
+
* it can be styled. Length is measured in either `'UTF-8'` or `'UTF-16'`
|
|
13
|
+
* (default) code units via the `charset` prop, and the display can be
|
|
14
|
+
* customized with the `renderer` prop.
|
|
15
|
+
*
|
|
16
|
+
* @returns The element produced by `renderer` (by default a `<span>` showing
|
|
17
|
+
* the number of remaining characters).
|
|
18
|
+
*/
|
|
9
19
|
export declare function CharacterLimitPlugin({ charset, maxLength, renderer, }: {
|
|
10
20
|
charset: 'UTF-8' | 'UTF-16';
|
|
11
21
|
maxLength: number;
|
|
@@ -46,11 +46,9 @@ function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({}))
|
|
|
46
46
|
}
|
|
47
47
|
}, [editor]);
|
|
48
48
|
react.useEffect(() => {
|
|
49
|
-
let text$1 = editor.
|
|
50
|
-
editor
|
|
51
|
-
});
|
|
49
|
+
let text$1 = editor.read('latest', text.$rootTextContent);
|
|
52
50
|
let lastComputedTextLength = 0;
|
|
53
|
-
return
|
|
51
|
+
return lexical.mergeRegister(editor.registerTextContentListener(currentText => {
|
|
54
52
|
text$1 = currentText;
|
|
55
53
|
}), editor.registerUpdateListener(({
|
|
56
54
|
dirtyLeaves,
|
|
@@ -145,7 +143,7 @@ function $wrapOverflowedNodes(offset) {
|
|
|
145
143
|
// below. Element slot values need no special case: their interior is
|
|
146
144
|
// counted leaf-by-leaf like any other subtree.
|
|
147
145
|
const isSlotValueLeaf = lexical.$isLeafNode(node) && lexical.$getSlotHost(node) !== null;
|
|
148
|
-
const needsOverflowParent = lexical.$isLeafNode(node) && !isSlotValueLeaf && !
|
|
146
|
+
const needsOverflowParent = lexical.$isLeafNode(node) && !isSlotValueLeaf && !lexical.$findMatchingParent(node, overflow.$isOverflowNode);
|
|
149
147
|
if (overflow.$isOverflowNode(node)) {
|
|
150
148
|
const previousLength = accumulatedLength;
|
|
151
149
|
const nextLength = accumulatedLength + node.getTextContentSize();
|
|
@@ -282,6 +280,17 @@ function DefaultRenderer({
|
|
|
282
280
|
children: remainingCharacters
|
|
283
281
|
});
|
|
284
282
|
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Tracks the length of the editor's text content against `maxLength` and
|
|
286
|
+
* renders the number of remaining characters, marking any overflowing text so
|
|
287
|
+
* it can be styled. Length is measured in either `'UTF-8'` or `'UTF-16'`
|
|
288
|
+
* (default) code units via the `charset` prop, and the display can be
|
|
289
|
+
* customized with the `renderer` prop.
|
|
290
|
+
*
|
|
291
|
+
* @returns The element produced by `renderer` (by default a `<span>` showing
|
|
292
|
+
* the number of remaining characters).
|
|
293
|
+
*/
|
|
285
294
|
function CharacterLimitPlugin({
|
|
286
295
|
charset = 'UTF-16',
|
|
287
296
|
maxLength = CHARACTER_LIMIT,
|
|
@@ -10,8 +10,8 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
|
|
|
10
10
|
import { useEffect, useState, useMemo } from 'react';
|
|
11
11
|
import { OverflowNode, $isOverflowNode, $createOverflowNode } from '@lexical/overflow';
|
|
12
12
|
import { $rootTextContent } from '@lexical/text';
|
|
13
|
-
import {
|
|
14
|
-
import { HISTORY_MERGE_TAG, DELETE_CHARACTER_COMMAND, $getSelection, $isRangeSelection, $isElementNode, COMMAND_PRIORITY_LOW, $isLeafNode, $getSlotHost, $isTextNode, $setSelection } from 'lexical';
|
|
13
|
+
import { $dfsWithSlots, $unwrapNode } from '@lexical/utils';
|
|
14
|
+
import { mergeRegister, HISTORY_MERGE_TAG, DELETE_CHARACTER_COMMAND, $getSelection, $isRangeSelection, $isElementNode, COMMAND_PRIORITY_LOW, $isLeafNode, $getSlotHost, $findMatchingParent, $isTextNode, $setSelection } from 'lexical';
|
|
15
15
|
import { jsx } from 'react/jsx-runtime';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -44,9 +44,7 @@ function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({}))
|
|
|
44
44
|
}
|
|
45
45
|
}, [editor]);
|
|
46
46
|
useEffect(() => {
|
|
47
|
-
let text = editor.
|
|
48
|
-
editor
|
|
49
|
-
});
|
|
47
|
+
let text = editor.read('latest', $rootTextContent);
|
|
50
48
|
let lastComputedTextLength = 0;
|
|
51
49
|
return mergeRegister(editor.registerTextContentListener(currentText => {
|
|
52
50
|
text = currentText;
|
|
@@ -280,6 +278,17 @@ function DefaultRenderer({
|
|
|
280
278
|
children: remainingCharacters
|
|
281
279
|
});
|
|
282
280
|
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Tracks the length of the editor's text content against `maxLength` and
|
|
284
|
+
* renders the number of remaining characters, marking any overflowing text so
|
|
285
|
+
* it can be styled. Length is measured in either `'UTF-8'` or `'UTF-16'`
|
|
286
|
+
* (default) code units via the `charset` prop, and the display can be
|
|
287
|
+
* customized with the `renderer` prop.
|
|
288
|
+
*
|
|
289
|
+
* @returns The element produced by `renderer` (by default a `<span>` showing
|
|
290
|
+
* the number of remaining characters).
|
|
291
|
+
*/
|
|
283
292
|
function CharacterLimitPlugin({
|
|
284
293
|
charset = 'UTF-16',
|
|
285
294
|
maxLength = CHARACTER_LIMIT,
|
|
@@ -6,5 +6,5 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("react"),n=require("@lexical/overflow"),r=require("@lexical/text"),i=require("@lexical/utils"),o=require("lexical"),s=require("react/jsx-runtime");function l(e,s,l=Object.freeze({})){const{strlen:f=e=>e.length,remainingCharacters:g=()=>{}}=l;t.useEffect(()=>{e.hasNodes([n.OverflowNode])||function(e,...t){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",e);for(const e of t)r.append("v",e);throw n.search=r.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}(57)},[e]),t.useEffect(()=>{let t=e.
|
|
10
|
-
return s.jsx("span",{className:"characters-limit "+(e<0?"characters-limit-exceeded":""),children:e})}exports.CharacterLimitPlugin=function({charset:n="UTF-16",maxLength:r=5,renderer:i=
|
|
9
|
+
"use strict";var e=require("@lexical/react/LexicalComposerContext"),t=require("react"),n=require("@lexical/overflow"),r=require("@lexical/text"),i=require("@lexical/utils"),o=require("lexical"),s=require("react/jsx-runtime");function l(e,s,l=Object.freeze({})){const{strlen:f=e=>e.length,remainingCharacters:g=()=>{}}=l;t.useEffect(()=>{e.hasNodes([n.OverflowNode])||function(e,...t){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",e);for(const e of t)r.append("v",e);throw n.search=r.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}(57)},[e]),t.useEffect(()=>{let t=e.read("latest",r.$rootTextContent),l=0;return o.mergeRegister(e.registerTextContentListener(e=>{t=e}),e.registerUpdateListener(({dirtyLeaves:r,dirtyElements:u})=>{const d=e.isComposing(),h=r.size>0||u.size>0;if(d||!h)return;const m=f(t),x=m>s||null!==l&&l>s;if(g(s-m),null===l||x){const r=function(e,t,n){let r=0,i=0;if("function"==typeof Intl.Segmenter){const o=(new Intl.Segmenter).segment(e);for(const{segment:e}of o){const o=i+n(e);if(o>t)break;i=o,r+=e.length}}else{const o=Array.from(e),s=o.length;for(let e=0;e<s;e++){const s=o[e],l=i+n(s);if(l>t)break;i=l,r+=s.length}}return r}(t,s,f);e.update(()=>{!function(e){const t=i.$dfsWithSlots(),r=t.length;let s=0;for(let l=0;l<r;l+=1){const{node:r}=t[l],f=o.$isLeafNode(r)&&null!==o.$getSlotHost(r),g=o.$isLeafNode(r)&&!f&&!o.$findMatchingParent(r,n.$isOverflowNode);if(n.$isOverflowNode(r)){const t=s;if(s+r.getTextContentSize()<=e){const e=r.getParent(),t=r.getPreviousSibling(),n=r.getNextSibling();i.$unwrapNode(r);const s=o.$getSelection();!o.$isRangeSelection(s)||s.anchor.getNode().isAttached()&&s.focus.getNode().isAttached()||(o.$isTextNode(t)?t.select():o.$isTextNode(n)?n.select():null!==e&&e.select())}else if(t<e){const n=r.getFirstDescendant(),s=t+(null!==n?n.getTextContentSize():0);(o.$isTextNode(n)&&n.isSimpleText()||s<=e)&&i.$unwrapNode(r)}}else if(f)s+=r.getTextContentSize();else if(g){const t=s;if(s+=r.getTextContentSize(),s>e&&!n.$isOverflowNode(r.getParent())){const n=o.$getSelection();let i;if(t<e&&o.$isTextNode(r)&&r.isSimpleText()){const[,n]=r.splitText(e-t);i=c(n)}else i=c(r);null!==n&&o.$setSelection(n),a(i)}}}}(r)},{tag:o.HISTORY_MERGE_TAG})}l=m}),e.registerCommand(o.DELETE_CHARACTER_COMMAND,e=>{const t=o.$getSelection();if(!o.$isRangeSelection(t))return!1;const n=t.anchor.getNode().getParent(),r=n?n.getParent():null,i=r?r.getNextSibling():null;return t.deleteCharacter(e),r&&r.isEmpty()?r.remove():o.$isElementNode(i)&&i.isEmpty()&&i.remove(),!0},o.COMMAND_PRIORITY_LOW))},[e,s,g,f])}function c(e){const t=n.$createOverflowNode();return e.replace(t),t.append(e),t}function a(e){const t=e.getPreviousSibling();if(!n.$isOverflowNode(t))return;const r=e.getFirstChild(),i=t.getChildren(),s=i.length;if(null===r)e.append(...i);else for(let e=0;e<s;e++)r.insertBefore(i[e]);const l=o.$getSelection();if(o.$isRangeSelection(l)){const n=l.anchor,r=n.getNode(),i=l.focus,o=n.getNode();r.is(t)?n.set(e.getKey(),n.offset,"element"):r.is(e)&&n.set(e.getKey(),s+n.offset,"element"),o.is(t)?i.set(e.getKey(),i.offset,"element"):o.is(e)&&i.set(e.getKey(),s+i.offset,"element")}t.remove()}let f=null;function g(e){const t=void 0===window.TextEncoder?null:(null===f&&(f=new window.TextEncoder),f);if(null===t){const t=encodeURIComponent(e).match(/%[89ABab]/g);return e.length+(t?t.length:0)}return t.encode(e).length}function u({remainingCharacters:e}){/*#__PURE__*/
|
|
10
|
+
return s.jsx("span",{className:"characters-limit "+(e<0?"characters-limit-exceeded":""),children:e})}exports.CharacterLimitPlugin=function({charset:n="UTF-16",maxLength:r=5,renderer:i=u}){const[o]=e.useLexicalComposerContext(),[s,c]=t.useState(r),a=t.useMemo(()=>({remainingCharacters:c,strlen:e=>{if("UTF-8"===n)return g(e);if("UTF-16"===n)return e.length;throw new Error("Unrecognized charset")}}),[n]);return l(o,r,a),i({remainingCharacters:s})};
|