@lobehub/editor 4.15.2 → 4.16.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/es/editor-kernel/react/useDecorators.js +14 -8
- package/es/headless.d.ts +2 -0
- package/es/headless.js +710 -46
- package/es/index.d.ts +4 -3
- package/es/index.js +4 -3
- package/es/locale/index.d.ts +2 -0
- package/es/locale/index.js +5 -1
- package/es/plugins/auto-complete/plugin/index.js +3 -3
- package/es/plugins/block/index.d.ts +1 -1
- package/es/plugins/block/plugin/index.js +78 -2
- package/es/plugins/block/react/ReactBlockPlugin.js +172 -16
- package/es/plugins/block/react/drag/drag-utils.js +37 -10
- package/es/plugins/block/service/i-block-menu-service.d.ts +18 -1
- package/es/plugins/block/service/i-block-menu-service.js +24 -0
- package/es/plugins/block/service/index.d.ts +1 -1
- package/es/plugins/codeblock/plugin/index.js +25 -1
- package/es/plugins/common/plugin/register.js +2 -2
- package/es/plugins/litexml/plugin/index.js +8 -2
- package/es/plugins/slash/plugin/index.js +1 -1
- package/es/plugins/slash/react/ReactSlashPlugin.js +4 -4
- package/es/plugins/table/command/index.d.ts +13 -1
- package/es/plugins/table/command/index.js +220 -39
- package/es/plugins/table/index.d.ts +3 -2
- package/es/plugins/table/node/index.d.ts +2 -0
- package/es/plugins/table/node/index.js +130 -2
- package/es/plugins/table/plugin/index.d.ts +6 -0
- package/es/plugins/table/plugin/index.js +193 -4
- package/es/plugins/table/react/TableActionMenu/ActionMenu.js +82 -6
- package/es/plugins/table/react/TableActionMenu/index.js +9 -4
- package/es/plugins/table/react/TableColController.js +354 -0
- package/es/plugins/table/react/TableController/hooks.js +201 -0
- package/es/plugins/table/react/TableController/style.js +264 -0
- package/es/plugins/table/react/TableController/utils.js +25 -0
- package/es/plugins/table/react/TableControllerButton.js +81 -0
- package/es/plugins/table/react/TableControllerMenu.js +123 -0
- package/es/plugins/table/react/TableInsertButton.js +25 -0
- package/es/plugins/table/react/TableResize/index.js +153 -78
- package/es/plugins/table/react/TableRowController.js +349 -0
- package/es/plugins/table/react/hooks.js +77 -0
- package/es/plugins/table/react/index.js +139 -16
- package/es/plugins/table/react/style.js +89 -8
- package/es/plugins/table/react/type.d.ts +2 -0
- package/es/plugins/table/react/useAutoFitPastedTable.js +189 -0
- package/es/plugins/table/service/i-table-controller-menu-service.d.ts +44 -0
- package/es/plugins/table/service/i-table-controller-menu-service.js +31 -0
- package/es/plugins/table/service/index.d.ts +1 -0
- package/es/plugins/table/utils/autoFitColumnWidth.js +87 -0
- package/es/plugins/table/utils/distributeColumnWidth.js +37 -0
- package/es/plugins/table/utils/index.js +102 -2
- package/es/react/EditorProvider/index.d.ts +2 -2
- package/es/renderer/LexicalDiff.d.ts +2 -2
- package/package.json +1 -1
package/es/index.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { ReactAutoCompletePlugin } from "./plugins/auto-complete/react/ReactAuto
|
|
|
20
20
|
import { BlockMovePayload, MOVE_BLOCK_COMMAND, registerBlockMoveCommand } from "./plugins/block/command/index.js";
|
|
21
21
|
import { BlockPlugin, BlockPluginOptions } from "./plugins/block/plugin/index.js";
|
|
22
22
|
import { BlockDragTarget } from "./plugins/block/react/core/types.js";
|
|
23
|
-
import { BlockMenuService, IBlockActionButton, IBlockActionButtonIcon, IBlockMenuItem, IBlockMenuRenderContext, IBlockMenuService } from "./plugins/block/service/i-block-menu-service.js";
|
|
23
|
+
import { BlockMenuService, IBlockActionButton, IBlockActionButtonIcon, IBlockMenuItem, IBlockMenuRenderContext, IBlockMenuService, IBlockSelectHandler } from "./plugins/block/service/i-block-menu-service.js";
|
|
24
24
|
import { ReactBlockPlugin, ReactBlockPluginProps } from "./plugins/block/react/ReactBlockPlugin.js";
|
|
25
25
|
import { INSERT_CODEINLINE_COMMAND } from "./plugins/code/command/index.js";
|
|
26
26
|
import { CodePlugin } from "./plugins/code/plugin/index.js";
|
|
@@ -97,9 +97,10 @@ import { MenuRenderProps, ReactSlashOptionProps, ReactSlashPluginProps, SlashMen
|
|
|
97
97
|
import { SlashMenu } from "./plugins/slash/react/components/SlashMenu.js";
|
|
98
98
|
import { ReactSlashOption } from "./plugins/slash/react/ReactSlashOption.js";
|
|
99
99
|
import { ReactSlashPlugin } from "./plugins/slash/react/ReactSlashPlugin.js";
|
|
100
|
-
import { INSERT_TABLE_COMMAND, SELECT_TABLE_COMMAND } from "./plugins/table/command/index.js";
|
|
100
|
+
import { INSERT_TABLE_COLUMN_COMMAND, INSERT_TABLE_COMMAND, INSERT_TABLE_ROW_COMMAND, SELECT_TABLE_COMMAND } from "./plugins/table/command/index.js";
|
|
101
101
|
import { TablePlugin, TablePluginOptions } from "./plugins/table/plugin/index.js";
|
|
102
102
|
import { ReactTablePlugin } from "./plugins/table/react/index.js";
|
|
103
|
+
import { ITableControllerMenuActionItem, ITableControllerMenuItem, ITableControllerMenuRenderContext, ITableControllerMenuSeparatorItem, ITableControllerMenuService, TableControllerMenuAxis, TableControllerMenuService } from "./plugins/table/service/i-table-controller-menu-service.js";
|
|
103
104
|
import { HIDE_TOOLBAR_COMMAND, SHOW_TOOLBAR_COMMAND, ToolbarCommandOptions, registerToolbarCommand } from "./plugins/toolbar/command/index.js";
|
|
104
105
|
import { ReactToolbarPlugin } from "./plugins/toolbar/react/index.js";
|
|
105
106
|
import { UploadPlugin, UploadPluginOptions } from "./plugins/upload/plugin/index.js";
|
|
@@ -121,4 +122,4 @@ declare function enableHotReload(): void;
|
|
|
121
122
|
*/
|
|
122
123
|
declare function disableHotReload(): void;
|
|
123
124
|
//#endregion
|
|
124
|
-
export { $closest, $closestNodeType, $createCursorNode, $getNearestNodeFromDOMNode, $getNodeFromDOMNode, $isCardLikeElementNode, $isCursorNode, AutoCompletePlugin, BlockDragTarget, BlockMenuService, BlockMovePayload, BlockPlugin, BlockPluginOptions, CONTENT_BLOCKS_DATA_TYPE, CardLikeElementNode, CodePlugin, CodeblockPlugin, CodeblockPluginOptions, CodemirrorPlugin, CodemirrorPluginOptions, CommonPlugin, CommonPluginOptions, ContentBlock, ContentBlocksDataSource, ContentBlocksPlugin, ContentBlocksPluginOptions, DEFAULT_HEADLESS_EDITOR_PLUGINS, DOM_DOCUMENT_FRAGMENT_TYPE, DOM_DOCUMENT_TYPE, DOM_ELEMENT_TYPE, DOM_TEXT_TYPE, DataSource, DiffAction, EDITOR_THEME_KEY, ExtractContentBlocksOptions, FileContentBlock, FileListItem, FilePlugin, FilePluginOptions, GET_MARKDOWN_SELECTION_COMMAND, HIDE_TOOLBAR_COMMAND, HOVER_COMMAND, HRPlugin, HRPluginOptions, HeadlessDocumentType, HeadlessEditor, HeadlessEditorExport, HeadlessEditorExportOptions, HeadlessEditorHydrationInput, HeadlessEditorOptions, HeadlessLiteXMLBatchOperation, HeadlessLiteXMLInsertOperation, HeadlessLiteXMLOperation, HeadlessLiteXMLRemoveOperation, HeadlessLiteXMLReplaceOperation, HotkeyEnum, HotkeyId, HotkeyItem, HotkeyScopeEnum, HotkeyScopeId, IBlockActionButton, IBlockActionButtonIcon, IBlockMenuItem, IBlockMenuRenderContext, IBlockMenuService, type IEditor, ILinkService, ILitexmlService, IMarkdownShortCutService, INSERT_CHECK_LIST_COMMAND, INSERT_CODEINLINE_COMMAND, INSERT_CODEMIRROR_COMMAND, INSERT_FILE_COMMAND, INSERT_HEADING_COMMAND, INSERT_HORIZONTAL_RULE_COMMAND, INSERT_IMAGE_COMMAND, INSERT_LINK_COMMAND, INSERT_LINK_HIGHLIGHT_COMMAND, INSERT_MARKDOWN_COMMAND, INSERT_MATH_COMMAND, INSERT_MENTION_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_QUOTE_COMMAND, INSERT_TABLE_COMMAND, INSERT_UNORDERED_LIST_COMMAND, INodePlugin, INodePluginOptions, INodeService, ISlashMenuOption, ISlashOption, ISlashService, ITriggerContext, IUploadService, ImageContentBlock, ImageListItem, ImagePlugin, ImagePluginOptions, Kernel, KeyEnum, LITEXML_APPLY_COMMAND, LITEXML_DIFFNODE_ALL_COMMAND, LITEXML_DIFFNODE_COMMAND, LITEXML_INSERT_COMMAND, LITEXML_MODIFY_COMMAND, LITEXML_REMOVE_COMMAND, LexicalErrorBoundary, LexicalPortalContainer, LinkHighlightPlugin, LinkHighlightPluginOptions, LinkPlugin, LinkPluginOptions, ListPlugin, ListPluginOptions, LitexmlDataSource, LitexmlPlugin, LitexmlPluginOptions, LitexmlService, MARKDOWN_READER_LEVEL, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX, MOVE_BLOCK_COMMAND, MarkdownPlugin, MathPlugin, MediaLists, MentionPlugin, MentionPluginOptions, MenuRenderProps, ModifierCombination, REMOVE_LIST_COMMAND, ReactAutoCompletePlugin, ReactBlockPlugin, ReactBlockPluginProps, ReactCodePlugin, ReactCodeblockPlugin, ReactCodeblockPluginProps, ReactCodemirrorPlugin, ReactEditor, ReactEditorContent, ReactEditorContentProps, ReactFilePlugin, ReactFilePluginProps, ReactHRPlugin, ReactHRPluginProps, ReactImagePlugin, ReactImagePluginProps, ReactLinkHighlightPlugin, ReactLinkPlugin, ReactLinkPluginProps, ReactListPlugin, ReactListPluginProps, ReactLiteXmlPlugin, ReactMarkdownPlugin, ReactMathPlugin, ReactMentionPlugin, ReactMentionPluginProps, ReactNodePlugin, ReactPlainText, ReactPlainTextProps, ReactSlashOption, ReactSlashOptionProps, ReactSlashPlugin, ReactSlashPluginProps, ReactTablePlugin, ReactToolbarPlugin, ReactVirtualBlockPlugin, SELECT_AFTER_CODEMIRROR_COMMAND, SELECT_BEFORE_CODEMIRROR_COMMAND, SELECT_TABLE_COMMAND, SHOW_TOOLBAR_COMMAND, SerializedMentionNode, SlashMenu, SlashMenuProps, SlashOptions, SlashPlugin, SlashPluginOptions, TablePlugin, TablePluginOptions, TextContentBlock, ToolbarCommandOptions, UPDATE_CODEBLOCK_LANG, UPDATE_LIST_START_COMMAND, UPLOAD_PRIORITY_HIGH, UPLOAD_PRIORITY_LOW, UPLOAD_PRIORITY_MEDIUM, UploadPlugin, UploadPluginOptions, VirtualBlockPlugin, VirtualBlockPluginOptions, XMLReaderFunc, XMLReaderRecord, XMLWriterFunc, XMLWriterRecord, assert, browserDebug, bundledLanguagesInfo, compareNodeOrder, createDebugLogger, createEmptyEditorState, createHeadlessEditor, cursorNodeSerialized, debugLogger, debugLoggers, detectCodeLanguage, detectLanguage, devConsole, disableHotReload, enableHotReload, extractContentBlocks, extractMediaFromEditorState, extractMediaLists, genServiceId, generateEditorId, getHotkeyById, getKernelFromEditor, getKernelFromEditorConfig, getNodeKeyFromDOMNode, getParentElement, isDOMNode, isDocumentFragment, isPunctuationChar, isPureUrl, isValidUrl, moment, noop, prodSafeLogger, reconcileDecorator, registerBlockMoveCommand, registerEditorKernel, registerLinkHighlightCommand, registerToolbarCommand, resetRandomKey, scrollIntoView, unregisterEditorKernel, useHasDiffNode, useLexicalComposerContext, useLexicalEditor };
|
|
125
|
+
export { $closest, $closestNodeType, $createCursorNode, $getNearestNodeFromDOMNode, $getNodeFromDOMNode, $isCardLikeElementNode, $isCursorNode, AutoCompletePlugin, BlockDragTarget, BlockMenuService, BlockMovePayload, BlockPlugin, BlockPluginOptions, CONTENT_BLOCKS_DATA_TYPE, CardLikeElementNode, CodePlugin, CodeblockPlugin, CodeblockPluginOptions, CodemirrorPlugin, CodemirrorPluginOptions, CommonPlugin, CommonPluginOptions, ContentBlock, ContentBlocksDataSource, ContentBlocksPlugin, ContentBlocksPluginOptions, DEFAULT_HEADLESS_EDITOR_PLUGINS, DOM_DOCUMENT_FRAGMENT_TYPE, DOM_DOCUMENT_TYPE, DOM_ELEMENT_TYPE, DOM_TEXT_TYPE, DataSource, DiffAction, EDITOR_THEME_KEY, ExtractContentBlocksOptions, FileContentBlock, FileListItem, FilePlugin, FilePluginOptions, GET_MARKDOWN_SELECTION_COMMAND, HIDE_TOOLBAR_COMMAND, HOVER_COMMAND, HRPlugin, HRPluginOptions, HeadlessDocumentType, HeadlessEditor, HeadlessEditorExport, HeadlessEditorExportOptions, HeadlessEditorHydrationInput, HeadlessEditorOptions, HeadlessLiteXMLBatchOperation, HeadlessLiteXMLInsertOperation, HeadlessLiteXMLOperation, HeadlessLiteXMLRemoveOperation, HeadlessLiteXMLReplaceOperation, HotkeyEnum, HotkeyId, HotkeyItem, HotkeyScopeEnum, HotkeyScopeId, IBlockActionButton, IBlockActionButtonIcon, IBlockMenuItem, IBlockMenuRenderContext, IBlockMenuService, IBlockSelectHandler, type IEditor, ILinkService, ILitexmlService, IMarkdownShortCutService, INSERT_CHECK_LIST_COMMAND, INSERT_CODEINLINE_COMMAND, INSERT_CODEMIRROR_COMMAND, INSERT_FILE_COMMAND, INSERT_HEADING_COMMAND, INSERT_HORIZONTAL_RULE_COMMAND, INSERT_IMAGE_COMMAND, INSERT_LINK_COMMAND, INSERT_LINK_HIGHLIGHT_COMMAND, INSERT_MARKDOWN_COMMAND, INSERT_MATH_COMMAND, INSERT_MENTION_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_QUOTE_COMMAND, INSERT_TABLE_COLUMN_COMMAND, INSERT_TABLE_COMMAND, INSERT_TABLE_ROW_COMMAND, INSERT_UNORDERED_LIST_COMMAND, INodePlugin, INodePluginOptions, INodeService, ISlashMenuOption, ISlashOption, ISlashService, ITableControllerMenuActionItem, ITableControllerMenuItem, ITableControllerMenuRenderContext, ITableControllerMenuSeparatorItem, ITableControllerMenuService, ITriggerContext, IUploadService, ImageContentBlock, ImageListItem, ImagePlugin, ImagePluginOptions, Kernel, KeyEnum, LITEXML_APPLY_COMMAND, LITEXML_DIFFNODE_ALL_COMMAND, LITEXML_DIFFNODE_COMMAND, LITEXML_INSERT_COMMAND, LITEXML_MODIFY_COMMAND, LITEXML_REMOVE_COMMAND, LexicalErrorBoundary, LexicalPortalContainer, LinkHighlightPlugin, LinkHighlightPluginOptions, LinkPlugin, LinkPluginOptions, ListPlugin, ListPluginOptions, LitexmlDataSource, LitexmlPlugin, LitexmlPluginOptions, LitexmlService, MARKDOWN_READER_LEVEL, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX, MOVE_BLOCK_COMMAND, MarkdownPlugin, MathPlugin, MediaLists, MentionPlugin, MentionPluginOptions, MenuRenderProps, ModifierCombination, REMOVE_LIST_COMMAND, ReactAutoCompletePlugin, ReactBlockPlugin, ReactBlockPluginProps, ReactCodePlugin, ReactCodeblockPlugin, ReactCodeblockPluginProps, ReactCodemirrorPlugin, ReactEditor, ReactEditorContent, ReactEditorContentProps, ReactFilePlugin, ReactFilePluginProps, ReactHRPlugin, ReactHRPluginProps, ReactImagePlugin, ReactImagePluginProps, ReactLinkHighlightPlugin, ReactLinkPlugin, ReactLinkPluginProps, ReactListPlugin, ReactListPluginProps, ReactLiteXmlPlugin, ReactMarkdownPlugin, ReactMathPlugin, ReactMentionPlugin, ReactMentionPluginProps, ReactNodePlugin, ReactPlainText, ReactPlainTextProps, ReactSlashOption, ReactSlashOptionProps, ReactSlashPlugin, ReactSlashPluginProps, ReactTablePlugin, ReactToolbarPlugin, ReactVirtualBlockPlugin, SELECT_AFTER_CODEMIRROR_COMMAND, SELECT_BEFORE_CODEMIRROR_COMMAND, SELECT_TABLE_COMMAND, SHOW_TOOLBAR_COMMAND, SerializedMentionNode, SlashMenu, SlashMenuProps, SlashOptions, SlashPlugin, SlashPluginOptions, TableControllerMenuAxis, TableControllerMenuService, TablePlugin, TablePluginOptions, TextContentBlock, ToolbarCommandOptions, UPDATE_CODEBLOCK_LANG, UPDATE_LIST_START_COMMAND, UPLOAD_PRIORITY_HIGH, UPLOAD_PRIORITY_LOW, UPLOAD_PRIORITY_MEDIUM, UploadPlugin, UploadPluginOptions, VirtualBlockPlugin, VirtualBlockPluginOptions, XMLReaderFunc, XMLReaderRecord, XMLWriterFunc, XMLWriterRecord, assert, browserDebug, bundledLanguagesInfo, compareNodeOrder, createDebugLogger, createEmptyEditorState, createHeadlessEditor, cursorNodeSerialized, debugLogger, debugLoggers, detectCodeLanguage, detectLanguage, devConsole, disableHotReload, enableHotReload, extractContentBlocks, extractMediaFromEditorState, extractMediaLists, genServiceId, generateEditorId, getHotkeyById, getKernelFromEditor, getKernelFromEditorConfig, getNodeKeyFromDOMNode, getParentElement, isDOMNode, isDocumentFragment, isPunctuationChar, isPureUrl, isValidUrl, moment, noop, prodSafeLogger, reconcileDecorator, registerBlockMoveCommand, registerEditorKernel, registerLinkHighlightCommand, registerToolbarCommand, resetRandomKey, scrollIntoView, unregisterEditorKernel, useHasDiffNode, useLexicalComposerContext, useLexicalEditor };
|
package/es/index.js
CHANGED
|
@@ -43,14 +43,15 @@ import { ILinkService } from "./plugins/link/service/i-link-service.js";
|
|
|
43
43
|
import { LinkPlugin } from "./plugins/link/plugin/index.js";
|
|
44
44
|
import { INSERT_CHECK_LIST_COMMAND } from "./plugins/list/plugin/checkList.js";
|
|
45
45
|
import { ListPlugin } from "./plugins/list/plugin/index.js";
|
|
46
|
-
import {
|
|
46
|
+
import { BlockMenuService, IBlockMenuService } from "./plugins/block/service/i-block-menu-service.js";
|
|
47
|
+
import { INSERT_TABLE_COLUMN_COMMAND, INSERT_TABLE_COMMAND, INSERT_TABLE_ROW_COMMAND, SELECT_TABLE_COMMAND } from "./plugins/table/command/index.js";
|
|
48
|
+
import { ITableControllerMenuService, TableControllerMenuService } from "./plugins/table/service/i-table-controller-menu-service.js";
|
|
47
49
|
import { TablePlugin } from "./plugins/table/plugin/index.js";
|
|
48
50
|
import { extractMediaFromEditorState } from "./headless/extract-media-from-editor-state.js";
|
|
49
51
|
import { DEFAULT_HEADLESS_EDITOR_PLUGINS, HeadlessEditor, createHeadlessEditor } from "./headless/index.js";
|
|
50
52
|
import { AutoCompletePlugin } from "./plugins/auto-complete/plugin/index.js";
|
|
51
53
|
import ReactAutoCompletePlugin from "./plugins/auto-complete/react/ReactAutoCompletePlugin.js";
|
|
52
54
|
import { MOVE_BLOCK_COMMAND, registerBlockMoveCommand } from "./plugins/block/command/index.js";
|
|
53
|
-
import { BlockMenuService, IBlockMenuService } from "./plugins/block/service/i-block-menu-service.js";
|
|
54
55
|
import { BlockPlugin } from "./plugins/block/plugin/index.js";
|
|
55
56
|
import ReactBlockPlugin from "./plugins/block/react/ReactBlockPlugin.js";
|
|
56
57
|
import ReactCodePlugin from "./plugins/code/react/CodeReactPlugin.js";
|
|
@@ -126,4 +127,4 @@ function disableHotReload() {
|
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
//#endregion
|
|
129
|
-
export { $closest, $closestNodeType, $createCursorNode, $getNearestNodeFromDOMNode, $getNodeFromDOMNode, $isCardLikeElementNode, $isCursorNode, AutoCompletePlugin, BlockMenuService, BlockPlugin, CONTENT_BLOCKS_DATA_TYPE, CardLikeElementNode, CodePlugin, CodeblockPlugin, CodemirrorPlugin, CommonPlugin, ContentBlocksDataSource, ContentBlocksPlugin, DEFAULT_HEADLESS_EDITOR_PLUGINS, DOM_DOCUMENT_FRAGMENT_TYPE, DOM_DOCUMENT_TYPE, DOM_ELEMENT_TYPE, DOM_TEXT_TYPE, DataSource, DiffAction, EDITOR_THEME_KEY, FilePlugin, GET_MARKDOWN_SELECTION_COMMAND, HIDE_TOOLBAR_COMMAND, HOVER_COMMAND, HRPlugin, HeadlessEditor, HotkeyEnum, HotkeyScopeEnum, IBlockMenuService, ILinkService, ILitexmlService, IMarkdownShortCutService, INSERT_CHECK_LIST_COMMAND, INSERT_CODEINLINE_COMMAND, INSERT_CODEMIRROR_COMMAND, INSERT_FILE_COMMAND, INSERT_HEADING_COMMAND, INSERT_HORIZONTAL_RULE_COMMAND, INSERT_IMAGE_COMMAND, INSERT_LINK_COMMAND, INSERT_LINK_HIGHLIGHT_COMMAND, INSERT_MARKDOWN_COMMAND, INSERT_MATH_COMMAND, INSERT_MENTION_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_QUOTE_COMMAND, INSERT_TABLE_COMMAND, INSERT_UNORDERED_LIST_COMMAND, INodePlugin, INodeService, IUploadService, ImagePlugin, Kernel, KeyEnum, LITEXML_APPLY_COMMAND, LITEXML_DIFFNODE_ALL_COMMAND, LITEXML_DIFFNODE_COMMAND, LITEXML_INSERT_COMMAND, LITEXML_MODIFY_COMMAND, LITEXML_REMOVE_COMMAND, LexicalErrorBoundary, LexicalPortalContainer, LinkHighlightPlugin, LinkPlugin, ListPlugin, LitexmlDataSource, LitexmlPlugin, LitexmlService, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX, MOVE_BLOCK_COMMAND, MarkdownPlugin, MathPlugin, MentionPlugin, REMOVE_LIST_COMMAND, ReactAutoCompletePlugin, ReactBlockPlugin, ReactCodePlugin, ReactCodeblockPlugin, ReactCodemirrorPlugin, ReactEditor, ReactEditorContent, ReactFilePlugin, ReactHRPlugin, ReactImagePlugin, ReactLinkHighlightPlugin, ReactLinkPlugin, ReactListPlugin, ReactLiteXmlPlugin, ReactMarkdownPlugin, ReactMathPlugin, ReactMentionPlugin, ReactNodePlugin, ReactPlainText, ReactSlashOption, ReactSlashPlugin, ReactTablePlugin, ReactToolbarPlugin, ReactVirtualBlockPlugin, SELECT_AFTER_CODEMIRROR_COMMAND, SELECT_BEFORE_CODEMIRROR_COMMAND, SELECT_TABLE_COMMAND, SHOW_TOOLBAR_COMMAND, SlashMenu, SlashPlugin, TablePlugin, UPDATE_CODEBLOCK_LANG, UPDATE_LIST_START_COMMAND, UPLOAD_PRIORITY_HIGH, UPLOAD_PRIORITY_LOW, UPLOAD_PRIORITY_MEDIUM, UploadPlugin, VirtualBlockPlugin, assert, browserDebug, bundledLanguagesInfo, compareNodeOrder, createDebugLogger, createEmptyEditorState, createHeadlessEditor, cursorNodeSerialized, debugLogger, debugLoggers, detectCodeLanguage, detectLanguage, devConsole, disableHotReload, enableHotReload, extractContentBlocks, extractMediaFromEditorState, extractMediaLists, genServiceId, generateEditorId, getHotkeyById, getKernelFromEditor, getKernelFromEditorConfig, getNodeKeyFromDOMNode, getParentElement, isDOMNode, isDocumentFragment, isPunctuationChar, isPureUrl, isValidUrl, moment, noop, prodSafeLogger, reconcileDecorator, registerBlockMoveCommand, registerEditorKernel, registerLinkHighlightCommand, registerToolbarCommand, resetRandomKey, scrollIntoView, unregisterEditorKernel, useHasDiffNode, useLexicalComposerContext, useLexicalEditor };
|
|
130
|
+
export { $closest, $closestNodeType, $createCursorNode, $getNearestNodeFromDOMNode, $getNodeFromDOMNode, $isCardLikeElementNode, $isCursorNode, AutoCompletePlugin, BlockMenuService, BlockPlugin, CONTENT_BLOCKS_DATA_TYPE, CardLikeElementNode, CodePlugin, CodeblockPlugin, CodemirrorPlugin, CommonPlugin, ContentBlocksDataSource, ContentBlocksPlugin, DEFAULT_HEADLESS_EDITOR_PLUGINS, DOM_DOCUMENT_FRAGMENT_TYPE, DOM_DOCUMENT_TYPE, DOM_ELEMENT_TYPE, DOM_TEXT_TYPE, DataSource, DiffAction, EDITOR_THEME_KEY, FilePlugin, GET_MARKDOWN_SELECTION_COMMAND, HIDE_TOOLBAR_COMMAND, HOVER_COMMAND, HRPlugin, HeadlessEditor, HotkeyEnum, HotkeyScopeEnum, IBlockMenuService, ILinkService, ILitexmlService, IMarkdownShortCutService, INSERT_CHECK_LIST_COMMAND, INSERT_CODEINLINE_COMMAND, INSERT_CODEMIRROR_COMMAND, INSERT_FILE_COMMAND, INSERT_HEADING_COMMAND, INSERT_HORIZONTAL_RULE_COMMAND, INSERT_IMAGE_COMMAND, INSERT_LINK_COMMAND, INSERT_LINK_HIGHLIGHT_COMMAND, INSERT_MARKDOWN_COMMAND, INSERT_MATH_COMMAND, INSERT_MENTION_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_QUOTE_COMMAND, INSERT_TABLE_COLUMN_COMMAND, INSERT_TABLE_COMMAND, INSERT_TABLE_ROW_COMMAND, INSERT_UNORDERED_LIST_COMMAND, INodePlugin, INodeService, ITableControllerMenuService, IUploadService, ImagePlugin, Kernel, KeyEnum, LITEXML_APPLY_COMMAND, LITEXML_DIFFNODE_ALL_COMMAND, LITEXML_DIFFNODE_COMMAND, LITEXML_INSERT_COMMAND, LITEXML_MODIFY_COMMAND, LITEXML_REMOVE_COMMAND, LexicalErrorBoundary, LexicalPortalContainer, LinkHighlightPlugin, LinkPlugin, ListPlugin, LitexmlDataSource, LitexmlPlugin, LitexmlService, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX, MOVE_BLOCK_COMMAND, MarkdownPlugin, MathPlugin, MentionPlugin, REMOVE_LIST_COMMAND, ReactAutoCompletePlugin, ReactBlockPlugin, ReactCodePlugin, ReactCodeblockPlugin, ReactCodemirrorPlugin, ReactEditor, ReactEditorContent, ReactFilePlugin, ReactHRPlugin, ReactImagePlugin, ReactLinkHighlightPlugin, ReactLinkPlugin, ReactListPlugin, ReactLiteXmlPlugin, ReactMarkdownPlugin, ReactMathPlugin, ReactMentionPlugin, ReactNodePlugin, ReactPlainText, ReactSlashOption, ReactSlashPlugin, ReactTablePlugin, ReactToolbarPlugin, ReactVirtualBlockPlugin, SELECT_AFTER_CODEMIRROR_COMMAND, SELECT_BEFORE_CODEMIRROR_COMMAND, SELECT_TABLE_COMMAND, SHOW_TOOLBAR_COMMAND, SlashMenu, SlashPlugin, TableControllerMenuService, TablePlugin, UPDATE_CODEBLOCK_LANG, UPDATE_LIST_START_COMMAND, UPLOAD_PRIORITY_HIGH, UPLOAD_PRIORITY_LOW, UPLOAD_PRIORITY_MEDIUM, UploadPlugin, VirtualBlockPlugin, assert, browserDebug, bundledLanguagesInfo, compareNodeOrder, createDebugLogger, createEmptyEditorState, createHeadlessEditor, cursorNodeSerialized, debugLogger, debugLoggers, detectCodeLanguage, detectLanguage, devConsole, disableHotReload, enableHotReload, extractContentBlocks, extractMediaFromEditorState, extractMediaLists, genServiceId, generateEditorId, getHotkeyById, getKernelFromEditor, getKernelFromEditorConfig, getNodeKeyFromDOMNode, getParentElement, isDOMNode, isDocumentFragment, isPunctuationChar, isPureUrl, isValidUrl, moment, noop, prodSafeLogger, reconcileDecorator, registerBlockMoveCommand, registerEditorKernel, registerLinkHighlightCommand, registerToolbarCommand, resetRandomKey, scrollIntoView, unregisterEditorKernel, useHasDiffNode, useLexicalComposerContext, useLexicalEditor };
|
package/es/locale/index.d.ts
CHANGED
package/es/locale/index.js
CHANGED
|
@@ -3,7 +3,11 @@ import { __esmMin } from "../_virtual/_rolldown/runtime.js";
|
|
|
3
3
|
var locale_default;
|
|
4
4
|
var init_locale = __esmMin((() => {
|
|
5
5
|
locale_default = {
|
|
6
|
-
block: {
|
|
6
|
+
block: {
|
|
7
|
+
copy: "Copy",
|
|
8
|
+
delete: "Delete block",
|
|
9
|
+
select: "Select"
|
|
10
|
+
},
|
|
7
11
|
cancel: "Cancel",
|
|
8
12
|
codemirror: {
|
|
9
13
|
copySuccess: "Code copied to clipboard",
|
|
@@ -2,7 +2,7 @@ import { createDebugLogger, init_debug } from "../../../utils/debug.js";
|
|
|
2
2
|
import { KernelPlugin, init_plugin } from "../../../editor-kernel/plugin.js";
|
|
3
3
|
import { IMarkdownShortCutService } from "../../markdown/service/shortcut.js";
|
|
4
4
|
import { PlaceholderBlockNode, PlaceholderNode } from "../node/placeholderNode.js";
|
|
5
|
-
import { $getSelection, $isRangeSelection, $nodesOfType, $setSelection, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_HIGH, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND } from "lexical";
|
|
5
|
+
import { $getSelection, $isRangeSelection, $nodesOfType, $setSelection, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_HIGH, HISTORIC_TAG, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND } from "lexical";
|
|
6
6
|
//#region src/plugins/auto-complete/plugin/index.ts
|
|
7
7
|
init_plugin();
|
|
8
8
|
init_debug();
|
|
@@ -337,7 +337,7 @@ const AutoCompletePlugin = class extends KernelPlugin {
|
|
|
337
337
|
this.placeholderSelectionSnapshot = saveSel;
|
|
338
338
|
this.markdownService.insertIRootNode(editor, nodes, selection);
|
|
339
339
|
$setSelection(saveSel);
|
|
340
|
-
});
|
|
340
|
+
}, { tag: HISTORIC_TAG });
|
|
341
341
|
}
|
|
342
342
|
clearPlaceholderNodes(editor, options) {
|
|
343
343
|
const shouldRestoreSelection = options?.restoreSelection ?? true;
|
|
@@ -361,7 +361,7 @@ const AutoCompletePlugin = class extends KernelPlugin {
|
|
|
361
361
|
for (const node of $nodesOfType(PlaceholderNode)) node.remove();
|
|
362
362
|
for (const node of $nodesOfType(PlaceholderBlockNode)) node.remove();
|
|
363
363
|
if (shouldRestoreSelection && restoreSelection) $setSelection(restoreSelection);
|
|
364
|
-
});
|
|
364
|
+
}, { tag: HISTORIC_TAG });
|
|
365
365
|
}
|
|
366
366
|
applySuggestion(editor) {
|
|
367
367
|
if (!this.currentSuggestion) return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlockMovePayload, MOVE_BLOCK_COMMAND, registerBlockMoveCommand } from "./command/index.js";
|
|
2
2
|
import { BlockPlugin, BlockPluginOptions } from "./plugin/index.js";
|
|
3
3
|
import { BlockDragTarget } from "./react/core/types.js";
|
|
4
|
-
import { BlockMenuService, IBlockActionButton, IBlockActionButtonIcon, IBlockMenuItem, IBlockMenuRenderContext, IBlockMenuService } from "./service/i-block-menu-service.js";
|
|
4
|
+
import { BlockMenuService, IBlockActionButton, IBlockActionButtonIcon, IBlockMenuItem, IBlockMenuRenderContext, IBlockMenuService, IBlockSelectHandler } from "./service/i-block-menu-service.js";
|
|
5
5
|
import { ReactBlockPlugin, ReactBlockPluginProps } from "./react/ReactBlockPlugin.js";
|
|
@@ -1,10 +1,48 @@
|
|
|
1
1
|
import { KernelPlugin, init_plugin } from "../../../editor-kernel/plugin.js";
|
|
2
|
-
import { registerBlockMoveCommand } from "../command/index.js";
|
|
3
2
|
import { BlockMenuService, IBlockMenuService } from "../service/i-block-menu-service.js";
|
|
4
|
-
import {
|
|
3
|
+
import { registerBlockMoveCommand } from "../command/index.js";
|
|
4
|
+
import { $createNodeSelection, $createRangeSelection, $getNodeByKey, $isElementNode, $isTextNode, $setSelection, ParagraphNode } from "lexical";
|
|
5
|
+
import { $getClipboardDataFromSelection, copyToClipboard } from "@lexical/clipboard";
|
|
5
6
|
//#region src/plugins/block/plugin/index.ts
|
|
6
7
|
init_plugin();
|
|
7
8
|
const PATCHED_NODE_TYPES = /* @__PURE__ */ new Set();
|
|
9
|
+
const getBlockClipboardData = (node) => {
|
|
10
|
+
if ($isElementNode(node)) {
|
|
11
|
+
const selection = $createRangeSelection();
|
|
12
|
+
const parent = node.getParent();
|
|
13
|
+
if (parent) {
|
|
14
|
+
const index = node.getIndexWithinParent();
|
|
15
|
+
selection.anchor.set(parent.getKey(), index, "element");
|
|
16
|
+
selection.focus.set(parent.getKey(), index + 1, "element");
|
|
17
|
+
} else {
|
|
18
|
+
selection.anchor.set(node.getKey(), 0, "element");
|
|
19
|
+
selection.focus.set(node.getKey(), node.getChildrenSize(), "element");
|
|
20
|
+
}
|
|
21
|
+
return $getClipboardDataFromSelection(selection);
|
|
22
|
+
}
|
|
23
|
+
if ($isTextNode(node)) {
|
|
24
|
+
const selection = $createRangeSelection();
|
|
25
|
+
selection.setTextNodeRange(node, 0, node, node.getTextContentSize());
|
|
26
|
+
return $getClipboardDataFromSelection(selection);
|
|
27
|
+
}
|
|
28
|
+
const selection = $createNodeSelection();
|
|
29
|
+
selection.add(node.getKey());
|
|
30
|
+
return $getClipboardDataFromSelection(selection);
|
|
31
|
+
};
|
|
32
|
+
const selectBlockNode = (node) => {
|
|
33
|
+
if ($isElementNode(node)) {
|
|
34
|
+
node.select(0, node.getChildrenSize());
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if ($isTextNode(node)) {
|
|
38
|
+
node.select(0, node.getTextContentSize());
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
const selection = $createNodeSelection();
|
|
42
|
+
selection.add(node.getKey());
|
|
43
|
+
$setSelection(selection);
|
|
44
|
+
return true;
|
|
45
|
+
};
|
|
8
46
|
const resolveNodeClass = (node) => {
|
|
9
47
|
if (typeof node === "function") return node;
|
|
10
48
|
if (typeof node === "object" && node && typeof node.replace === "function") return node.replace;
|
|
@@ -63,6 +101,41 @@ const BlockPlugin = class extends KernelPlugin {
|
|
|
63
101
|
onInit(editor) {
|
|
64
102
|
const blockMenuService = this.kernel.requireService(IBlockMenuService);
|
|
65
103
|
if (blockMenuService) {
|
|
104
|
+
const unregisterDefaultSelectHandler = blockMenuService.registerSelectHandler({
|
|
105
|
+
key: "__block_default_select_handler",
|
|
106
|
+
onSelect: selectBlockNode,
|
|
107
|
+
order: 999
|
|
108
|
+
});
|
|
109
|
+
const unregisterCopyMenu = blockMenuService.registerMenu({
|
|
110
|
+
key: "__block_default_copy",
|
|
111
|
+
label: (context) => context.editor.t("block.copy"),
|
|
112
|
+
onClick: (context) => {
|
|
113
|
+
const lexicalEditor = context.editor.getLexicalEditor();
|
|
114
|
+
if (!lexicalEditor) return;
|
|
115
|
+
let clipboardData;
|
|
116
|
+
lexicalEditor.read(() => {
|
|
117
|
+
const target = $getNodeByKey(context.blockId);
|
|
118
|
+
if (!target) return;
|
|
119
|
+
clipboardData = getBlockClipboardData(target);
|
|
120
|
+
});
|
|
121
|
+
if (clipboardData) copyToClipboard(lexicalEditor, null, clipboardData);
|
|
122
|
+
},
|
|
123
|
+
order: 998
|
|
124
|
+
});
|
|
125
|
+
const unregisterSelectMenu = blockMenuService.registerMenu({
|
|
126
|
+
key: "__block_default_select",
|
|
127
|
+
label: (context) => context.editor.t("block.select"),
|
|
128
|
+
onClick: (context) => {
|
|
129
|
+
const lexicalEditor = context.editor.getLexicalEditor();
|
|
130
|
+
if (!lexicalEditor) return;
|
|
131
|
+
lexicalEditor.update(() => {
|
|
132
|
+
const target = $getNodeByKey(context.blockId);
|
|
133
|
+
if (!target) return;
|
|
134
|
+
blockMenuService.selectNode(target);
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
order: 997
|
|
138
|
+
});
|
|
66
139
|
const unregisterDeleteMenu = blockMenuService.registerMenu({
|
|
67
140
|
key: "__block_default_delete",
|
|
68
141
|
label: (context) => context.editor.t("block.delete"),
|
|
@@ -77,6 +150,9 @@ const BlockPlugin = class extends KernelPlugin {
|
|
|
77
150
|
},
|
|
78
151
|
order: 999
|
|
79
152
|
});
|
|
153
|
+
this.register(unregisterDefaultSelectHandler);
|
|
154
|
+
this.register(unregisterCopyMenu);
|
|
155
|
+
this.register(unregisterSelectMenu);
|
|
80
156
|
this.register(unregisterDeleteMenu);
|
|
81
157
|
}
|
|
82
158
|
this.register(registerBlockMoveCommand(editor));
|
|
@@ -5,7 +5,7 @@ import { useLexicalEditor } from "../../../editor-kernel/react/useLexicalEditor.
|
|
|
5
5
|
import { IBlockMenuService } from "../service/i-block-menu-service.js";
|
|
6
6
|
import { BlockPlugin } from "../plugin/index.js";
|
|
7
7
|
import { createRuntimeContext } from "./core/runtime-context.js";
|
|
8
|
-
import { collectDragBlocks } from "./drag/drag-utils.js";
|
|
8
|
+
import { collectDragBlocks, getBlockMeasureRect, getTableBlockRect, isTableBlockElement } from "./drag/drag-utils.js";
|
|
9
9
|
import { startBlockDragSession } from "./drag/drag-session.js";
|
|
10
10
|
import { styles } from "./style.js";
|
|
11
11
|
import { Icon } from "@lobehub/ui";
|
|
@@ -14,11 +14,22 @@ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
|
14
14
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
15
15
|
import { cx } from "antd-style";
|
|
16
16
|
import { Button as Button$1, Dropdown as Dropdown$1, theme } from "antd";
|
|
17
|
+
import { $findTableNode, $isTableSelection } from "@lexical/table";
|
|
18
|
+
import { $getNodeByKey, $getSelection, $isRangeSelection } from "lexical";
|
|
17
19
|
import { createPortal } from "react-dom";
|
|
18
20
|
//#region src/plugins/block/react/ReactBlockPlugin.tsx
|
|
19
21
|
init_debug();
|
|
20
22
|
const logger = createDebugLogger("plugin", "block-react");
|
|
21
23
|
const OPERATION_MENU_OVERLAY_CLASS = "lobe-block-operation-dropdown";
|
|
24
|
+
const TABLE_FOCUSED_MENU_OFFSET = 8;
|
|
25
|
+
const getTableMenuAnchorRect = (element) => {
|
|
26
|
+
const rect = getTableBlockRect(element);
|
|
27
|
+
if (!rect) return null;
|
|
28
|
+
return {
|
|
29
|
+
left: rect.left,
|
|
30
|
+
top: rect.top
|
|
31
|
+
};
|
|
32
|
+
};
|
|
22
33
|
const ReactBlockPlugin = (props) => {
|
|
23
34
|
const { token } = theme.useToken();
|
|
24
35
|
const [editor] = useLexicalComposerContext();
|
|
@@ -28,6 +39,7 @@ const ReactBlockPlugin = (props) => {
|
|
|
28
39
|
const dragLayerRef = useRef(null);
|
|
29
40
|
const contextRef = useRef(createRuntimeContext());
|
|
30
41
|
const [hoveredBlock, setHoveredBlock] = useState(null);
|
|
42
|
+
const [layoutVersion, setLayoutVersion] = useState(0);
|
|
31
43
|
const [menuVersion, setMenuVersion] = useState(0);
|
|
32
44
|
const [menuPosition, setMenuPosition] = useState({});
|
|
33
45
|
const [operationMenuOpen, setOperationMenuOpen] = useState(false);
|
|
@@ -35,7 +47,9 @@ const ReactBlockPlugin = (props) => {
|
|
|
35
47
|
const [dragIndicator, setDragIndicator] = useState(null);
|
|
36
48
|
const [dragLayerContainer, setDragLayerContainer] = useState(null);
|
|
37
49
|
const [isDragging, setIsDragging] = useState(false);
|
|
50
|
+
const [focusedTableBlockId, setFocusedTableBlockId] = useState(null);
|
|
38
51
|
const [blockMenuService, setBlockMenuService] = useState(null);
|
|
52
|
+
const blockMenuSuppressed = blockMenuService?.isMenuSuppressed() ?? false;
|
|
39
53
|
useLayoutEffect(() => {
|
|
40
54
|
if (locale) editor.registerLocale(locale);
|
|
41
55
|
editor.registerPlugin(BlockPlugin, {
|
|
@@ -68,6 +82,30 @@ const ReactBlockPlugin = (props) => {
|
|
|
68
82
|
setMenuVersion((v) => v + 1);
|
|
69
83
|
});
|
|
70
84
|
}, [blockMenuService]);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (!blockMenuSuppressed) return;
|
|
87
|
+
setHoveredBlock(null);
|
|
88
|
+
setOperationMenuOpen(false);
|
|
89
|
+
setOperationMenuContext(null);
|
|
90
|
+
contextRef.current.operationMenuAnchorBlockId = null;
|
|
91
|
+
}, [blockMenuSuppressed]);
|
|
92
|
+
useLexicalEditor((lexicalEditor) => {
|
|
93
|
+
return lexicalEditor.registerUpdateListener(({ editorState }) => {
|
|
94
|
+
editorState.read(() => {
|
|
95
|
+
const selection = $getSelection();
|
|
96
|
+
if ($isTableSelection(selection)) {
|
|
97
|
+
setFocusedTableBlockId(selection.tableKey);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if ($isRangeSelection(selection)) {
|
|
101
|
+
const anchorNode = $getNodeByKey(selection.anchor.key);
|
|
102
|
+
setFocusedTableBlockId((anchorNode ? $findTableNode(anchorNode) : null)?.getKey() ?? null);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
setFocusedTableBlockId(null);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}, [editor]);
|
|
71
109
|
useEffect(() => {
|
|
72
110
|
return () => {
|
|
73
111
|
contextRef.current.dragCleanup?.();
|
|
@@ -134,20 +172,31 @@ const ReactBlockPlugin = (props) => {
|
|
|
134
172
|
if (paddingLeft <= 0) return false;
|
|
135
173
|
return clientX <= rootRect.left + paddingLeft;
|
|
136
174
|
};
|
|
175
|
+
const resolveCurrentBlockElement = (root, blockId) => {
|
|
176
|
+
const currentBlock = Array.from(root.querySelectorAll("[data-block-id]")).find((element) => element.dataset.blockId === blockId);
|
|
177
|
+
return currentBlock && root.contains(currentBlock) ? currentBlock : null;
|
|
178
|
+
};
|
|
137
179
|
const getHoveredBlock = (target, clientX, clientY) => {
|
|
138
180
|
const root = editor.getRootElement();
|
|
139
181
|
if (!root || !(target instanceof Node)) return null;
|
|
140
182
|
const targetElement = target instanceof Element ? target : target.parentElement;
|
|
141
183
|
if (!targetElement) return null;
|
|
142
|
-
if (menuRef.current?.contains(targetElement)) return contextRef.current.hoveredBlock
|
|
143
|
-
|
|
184
|
+
if (menuRef.current?.contains(targetElement)) return contextRef.current.hoveredBlock ? {
|
|
185
|
+
...contextRef.current.hoveredBlock,
|
|
186
|
+
source: "existing"
|
|
187
|
+
} : null;
|
|
188
|
+
if (targetElement.closest(`.${OPERATION_MENU_OVERLAY_CLASS}`)) return contextRef.current.hoveredBlock ? {
|
|
189
|
+
...contextRef.current.hoveredBlock,
|
|
190
|
+
source: "existing"
|
|
191
|
+
} : null;
|
|
144
192
|
const blockElement = targetElement.closest("[data-block-id]");
|
|
145
193
|
if (blockElement instanceof HTMLElement && root.contains(blockElement)) {
|
|
146
194
|
const blockId = blockElement.dataset.blockId;
|
|
147
195
|
if (!blockId) return null;
|
|
148
196
|
return {
|
|
149
197
|
blockElement,
|
|
150
|
-
blockId
|
|
198
|
+
blockId,
|
|
199
|
+
source: "direct"
|
|
151
200
|
};
|
|
152
201
|
}
|
|
153
202
|
if (!root.contains(targetElement)) return null;
|
|
@@ -156,12 +205,19 @@ const ReactBlockPlugin = (props) => {
|
|
|
156
205
|
if (rects.length === 0) return null;
|
|
157
206
|
const entry = resolveBlockByY(rects, clientY);
|
|
158
207
|
if (!entry) return null;
|
|
208
|
+
const currentBlockElement = resolveCurrentBlockElement(root, entry.blockId);
|
|
209
|
+
if (!currentBlockElement) {
|
|
210
|
+
markBlockRectsDirty();
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
159
213
|
return {
|
|
160
|
-
blockElement:
|
|
161
|
-
blockId: entry.blockId
|
|
214
|
+
blockElement: currentBlockElement,
|
|
215
|
+
blockId: entry.blockId,
|
|
216
|
+
source: "padding"
|
|
162
217
|
};
|
|
163
218
|
};
|
|
164
219
|
const processHover = () => {
|
|
220
|
+
if (blockMenuSuppressed) return;
|
|
165
221
|
if (!latestPointer) return;
|
|
166
222
|
if (contextRef.current.draggingSource) return;
|
|
167
223
|
const { clientX, clientY, target } = latestPointer;
|
|
@@ -173,7 +229,10 @@ const ReactBlockPlugin = (props) => {
|
|
|
173
229
|
}
|
|
174
230
|
setHoveredBlock((current) => {
|
|
175
231
|
if (!current) return next;
|
|
176
|
-
if (next.blockId === current.blockId && next.blockElement === current.blockElement)
|
|
232
|
+
if (next.blockId === current.blockId && next.blockElement === current.blockElement) {
|
|
233
|
+
if (next.source === "padding") setLayoutVersion((version) => version + 1);
|
|
234
|
+
return current;
|
|
235
|
+
}
|
|
177
236
|
return next;
|
|
178
237
|
});
|
|
179
238
|
return;
|
|
@@ -192,6 +251,7 @@ const ReactBlockPlugin = (props) => {
|
|
|
192
251
|
});
|
|
193
252
|
};
|
|
194
253
|
const handleMouseMove = (event) => {
|
|
254
|
+
if (blockMenuSuppressed) return;
|
|
195
255
|
const root = editor.getRootElement();
|
|
196
256
|
const target = event.target;
|
|
197
257
|
if (!root || !(target instanceof Node)) {
|
|
@@ -216,25 +276,97 @@ const ReactBlockPlugin = (props) => {
|
|
|
216
276
|
};
|
|
217
277
|
const handleViewportChange = () => {
|
|
218
278
|
markBlockRectsDirty();
|
|
279
|
+
if (blockMenuSuppressed) return;
|
|
219
280
|
scheduleHoverProcess();
|
|
220
281
|
};
|
|
282
|
+
const clearMenuState = () => {
|
|
283
|
+
if (contextRef.current.hideTimer !== null) {
|
|
284
|
+
window.clearTimeout(contextRef.current.hideTimer);
|
|
285
|
+
contextRef.current.hideTimer = null;
|
|
286
|
+
}
|
|
287
|
+
latestPointer = null;
|
|
288
|
+
contextRef.current.operationMenuAnchorBlockId = null;
|
|
289
|
+
setHoveredBlock(null);
|
|
290
|
+
setOperationMenuOpen(false);
|
|
291
|
+
setOperationMenuContext(null);
|
|
292
|
+
};
|
|
293
|
+
const isInsideMenu = (target) => {
|
|
294
|
+
if (!(target instanceof Element)) return false;
|
|
295
|
+
return Boolean(menuRef.current?.contains(target)) || Boolean(target.closest(`.${OPERATION_MENU_OVERLAY_CLASS}`));
|
|
296
|
+
};
|
|
297
|
+
const handlePointerDown = (event) => {
|
|
298
|
+
const rootElement = editor.getRootElement();
|
|
299
|
+
const target = event.target;
|
|
300
|
+
if (!(target instanceof Node)) {
|
|
301
|
+
clearMenuState();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (rootElement?.contains(target) || isInsideMenu(target)) return;
|
|
305
|
+
clearMenuState();
|
|
306
|
+
};
|
|
307
|
+
const handleFocusOut = () => {
|
|
308
|
+
window.requestAnimationFrame(() => {
|
|
309
|
+
const rootElement = editor.getRootElement();
|
|
310
|
+
const activeElement = rootElement?.ownerDocument.activeElement;
|
|
311
|
+
if (!activeElement) {
|
|
312
|
+
clearMenuState();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (rootElement?.contains(activeElement) || isInsideMenu(activeElement)) return;
|
|
316
|
+
clearMenuState();
|
|
317
|
+
});
|
|
318
|
+
};
|
|
221
319
|
const rootResizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
222
320
|
markBlockRectsDirty();
|
|
321
|
+
setLayoutVersion((version) => version + 1);
|
|
322
|
+
if (blockMenuSuppressed) return;
|
|
323
|
+
scheduleHoverProcess();
|
|
223
324
|
}) : null;
|
|
224
325
|
const root = editor.getRootElement();
|
|
326
|
+
const rootMutationObserver = root && typeof MutationObserver !== "undefined" ? new MutationObserver(() => {
|
|
327
|
+
markBlockRectsDirty();
|
|
328
|
+
setLayoutVersion((version) => version + 1);
|
|
329
|
+
if (blockMenuSuppressed) return;
|
|
330
|
+
scheduleHoverProcess();
|
|
331
|
+
}) : null;
|
|
225
332
|
const unregisterUpdate = editor.getLexicalEditor()?.registerUpdateListener(() => {
|
|
226
333
|
markBlockRectsDirty();
|
|
334
|
+
if (blockMenuSuppressed) {
|
|
335
|
+
setHoveredBlock(null);
|
|
336
|
+
setLayoutVersion((version) => version + 1);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
setHoveredBlock((current) => {
|
|
340
|
+
if (!current) return current;
|
|
341
|
+
const currentRoot = editor.getRootElement();
|
|
342
|
+
const currentBlockId = current.blockElement.dataset.blockId;
|
|
343
|
+
if (!currentRoot || !current.blockElement.isConnected || !currentRoot.contains(current.blockElement) || currentBlockId !== current.blockId) return null;
|
|
344
|
+
return current;
|
|
345
|
+
});
|
|
346
|
+
setLayoutVersion((version) => version + 1);
|
|
227
347
|
scheduleHoverProcess();
|
|
228
348
|
}) || (() => {});
|
|
229
|
-
if (root)
|
|
349
|
+
if (root) {
|
|
350
|
+
rootResizeObserver?.observe(root);
|
|
351
|
+
rootMutationObserver?.observe(root, {
|
|
352
|
+
attributes: true,
|
|
353
|
+
childList: true,
|
|
354
|
+
subtree: true
|
|
355
|
+
});
|
|
356
|
+
}
|
|
230
357
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
358
|
+
document.addEventListener("pointerdown", handlePointerDown, true);
|
|
231
359
|
window.addEventListener("resize", handleViewportChange);
|
|
232
360
|
document.addEventListener("scroll", handleViewportChange, true);
|
|
361
|
+
root?.addEventListener("focusout", handleFocusOut);
|
|
233
362
|
return () => {
|
|
234
363
|
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
364
|
+
document.removeEventListener("pointerdown", handlePointerDown, true);
|
|
235
365
|
window.removeEventListener("resize", handleViewportChange);
|
|
236
366
|
document.removeEventListener("scroll", handleViewportChange, true);
|
|
367
|
+
root?.removeEventListener("focusout", handleFocusOut);
|
|
237
368
|
rootResizeObserver?.disconnect();
|
|
369
|
+
rootMutationObserver?.disconnect();
|
|
238
370
|
unregisterUpdate();
|
|
239
371
|
if (hoverRaf !== null) {
|
|
240
372
|
window.cancelAnimationFrame(hoverRaf);
|
|
@@ -245,21 +377,39 @@ const ReactBlockPlugin = (props) => {
|
|
|
245
377
|
contextRef.current.hideTimer = null;
|
|
246
378
|
}
|
|
247
379
|
};
|
|
248
|
-
}, [
|
|
249
|
-
|
|
380
|
+
}, [
|
|
381
|
+
blockMenuSuppressed,
|
|
382
|
+
editor,
|
|
383
|
+
isDragging
|
|
384
|
+
]);
|
|
385
|
+
useLayoutEffect(() => {
|
|
250
386
|
if (!hoveredBlock) {
|
|
251
387
|
if (operationMenuOpen) return;
|
|
252
388
|
setMenuPosition({});
|
|
253
389
|
return;
|
|
254
390
|
}
|
|
255
391
|
const updateMenuPosition = () => {
|
|
256
|
-
const
|
|
392
|
+
const blockRect = getBlockMeasureRect(hoveredBlock.blockElement);
|
|
393
|
+
if (!blockRect) {
|
|
394
|
+
setMenuPosition({});
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
257
397
|
const menuWidth = menuRef.current?.offsetWidth || 32;
|
|
258
398
|
const gap = 8;
|
|
259
399
|
const listItemOffset = hoveredBlock.blockElement.tagName === "LI" ? 16 : 0;
|
|
400
|
+
const isTableBlock = isTableBlockElement(hoveredBlock.blockElement);
|
|
401
|
+
const tableMenuOffset = focusedTableBlockId === hoveredBlock.blockId && isTableBlock ? TABLE_FOCUSED_MENU_OFFSET : 0;
|
|
402
|
+
const tableAnchorRect = isTableBlock ? getTableMenuAnchorRect(hoveredBlock.blockElement) : null;
|
|
403
|
+
const root = editor.getRootElement();
|
|
404
|
+
const rootRect = root?.getBoundingClientRect();
|
|
405
|
+
const rootPaddingLeft = root ? Number.parseFloat(window.getComputedStyle(root).paddingLeft || "0") : 0;
|
|
406
|
+
const minTableLeft = rootRect ? rootRect.left + rootPaddingLeft : gap;
|
|
407
|
+
const anchorLeft = isTableBlock && tableAnchorRect ? Math.max(tableAnchorRect.left, minTableLeft) : blockRect.left;
|
|
408
|
+
const rawAnchorTop = tableAnchorRect?.top ?? blockRect.top;
|
|
409
|
+
const anchorTop = rawAnchorTop >= blockRect.top - 1 && rawAnchorTop <= blockRect.bottom + 1 ? rawAnchorTop : blockRect.top;
|
|
260
410
|
setMenuPosition({
|
|
261
|
-
left: Math.max(gap,
|
|
262
|
-
top:
|
|
411
|
+
left: Math.max(gap, anchorLeft - menuWidth - gap - listItemOffset - tableMenuOffset),
|
|
412
|
+
top: anchorTop
|
|
263
413
|
});
|
|
264
414
|
};
|
|
265
415
|
updateMenuPosition();
|
|
@@ -269,7 +419,13 @@ const ReactBlockPlugin = (props) => {
|
|
|
269
419
|
window.removeEventListener("resize", updateMenuPosition);
|
|
270
420
|
document.removeEventListener("scroll", updateMenuPosition, true);
|
|
271
421
|
};
|
|
272
|
-
}, [
|
|
422
|
+
}, [
|
|
423
|
+
editor,
|
|
424
|
+
focusedTableBlockId,
|
|
425
|
+
hoveredBlock,
|
|
426
|
+
layoutVersion,
|
|
427
|
+
operationMenuOpen
|
|
428
|
+
]);
|
|
273
429
|
const menuContext = useMemo(() => {
|
|
274
430
|
if (!hoveredBlock) return null;
|
|
275
431
|
return {
|
|
@@ -385,8 +541,8 @@ const ReactBlockPlugin = (props) => {
|
|
|
385
541
|
setOperationMenuContext(null);
|
|
386
542
|
}
|
|
387
543
|
})), [operationMenus, operationMenuContext]);
|
|
388
|
-
const shouldRenderPortal = menuContext || dragIndicator;
|
|
389
|
-
const menuNode = menuContext && !isDragging ? /* @__PURE__ */ jsx("div", {
|
|
544
|
+
const shouldRenderPortal = !blockMenuSuppressed && menuContext || dragIndicator;
|
|
545
|
+
const menuNode = menuContext && !isDragging && !blockMenuSuppressed ? /* @__PURE__ */ jsx("div", {
|
|
390
546
|
className: styles.menu,
|
|
391
547
|
ref: menuRef,
|
|
392
548
|
style: menuPosition,
|
|
@@ -1,21 +1,48 @@
|
|
|
1
1
|
//#region src/plugins/block/react/drag/drag-utils.ts
|
|
2
|
+
const toRectSnapshot = (rect) => ({
|
|
3
|
+
bottom: rect.bottom,
|
|
4
|
+
height: rect.height,
|
|
5
|
+
left: rect.left,
|
|
6
|
+
top: rect.top,
|
|
7
|
+
width: rect.width
|
|
8
|
+
});
|
|
9
|
+
const isTableBlockElement = (element) => {
|
|
10
|
+
return element instanceof HTMLTableElement || Boolean(element.querySelector("table.editor_table, table"));
|
|
11
|
+
};
|
|
12
|
+
const getTableBlockRect = (element) => {
|
|
13
|
+
const table = element instanceof HTMLTableElement ? element : element.querySelector("table.editor_table, table");
|
|
14
|
+
if (!(table instanceof HTMLElement)) return null;
|
|
15
|
+
const tableRect = table.getBoundingClientRect();
|
|
16
|
+
const firstCell = table.querySelector("th, td");
|
|
17
|
+
if (firstCell instanceof HTMLElement) {
|
|
18
|
+
const cellRect = firstCell.getBoundingClientRect();
|
|
19
|
+
if (cellRect.width > 0 && cellRect.height > 0) return {
|
|
20
|
+
bottom: tableRect.height > 0 ? tableRect.bottom : cellRect.bottom,
|
|
21
|
+
height: tableRect.height > 0 ? tableRect.height : cellRect.height,
|
|
22
|
+
left: cellRect.left,
|
|
23
|
+
top: tableRect.height > 0 ? tableRect.top : cellRect.top,
|
|
24
|
+
width: tableRect.width > 0 ? tableRect.width : cellRect.width
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (tableRect.height <= 0) return null;
|
|
28
|
+
return toRectSnapshot(tableRect);
|
|
29
|
+
};
|
|
30
|
+
const getBlockMeasureRect = (block) => {
|
|
31
|
+
const rect = isTableBlockElement(block) ? getTableBlockRect(block) : toRectSnapshot(block.getBoundingClientRect());
|
|
32
|
+
if (!rect || rect.height <= 0) return null;
|
|
33
|
+
return rect;
|
|
34
|
+
};
|
|
2
35
|
const collectDragBlocks = (root) => {
|
|
3
36
|
if (!root) return [];
|
|
4
37
|
return Array.from(root.querySelectorAll("[data-block-id]")).reduce((acc, block) => {
|
|
5
38
|
const blockId = block.dataset.blockId;
|
|
6
39
|
if (!blockId) return acc;
|
|
7
|
-
const rect = block
|
|
8
|
-
if (rect
|
|
40
|
+
const rect = getBlockMeasureRect(block);
|
|
41
|
+
if (!rect) return acc;
|
|
9
42
|
acc.push({
|
|
10
43
|
block,
|
|
11
44
|
blockId,
|
|
12
|
-
rect
|
|
13
|
-
bottom: rect.bottom,
|
|
14
|
-
height: rect.height,
|
|
15
|
-
left: rect.left,
|
|
16
|
-
top: rect.top,
|
|
17
|
-
width: rect.width
|
|
18
|
-
}
|
|
45
|
+
rect
|
|
19
46
|
});
|
|
20
47
|
return acc;
|
|
21
48
|
}, []).sort((a, b) => a.rect.top - b.rect.top);
|
|
@@ -92,4 +119,4 @@ const resolveNearestInsertionSlot = (sourceBlockId, blocks, y) => {
|
|
|
92
119
|
return bestSlot;
|
|
93
120
|
};
|
|
94
121
|
//#endregion
|
|
95
|
-
export { collectDragBlocks, getAutoScrollDelta, resolveNearestInsertionSlot, resolveScrollContainers };
|
|
122
|
+
export { collectDragBlocks, getAutoScrollDelta, getBlockMeasureRect, getTableBlockRect, isTableBlockElement, resolveNearestInsertionSlot, resolveScrollContainers };
|