diff --git a/libs/components/editor-core/src/editor/types.ts b/libs/components/editor-core/src/editor/types.ts index f412417014..797d68f46c 100644 --- a/libs/components/editor-core/src/editor/types.ts +++ b/libs/components/editor-core/src/editor/types.ts @@ -23,6 +23,7 @@ import type { DragDropManager } from './drag-drop'; import { MouseManager } from './mouse'; import { Observable } from 'rxjs'; import { Point } from '@toeverything/utils'; +import { ScrollManager } from './scroll'; // import { BrowserClipboard } from './clipboard/browser-clipboard'; @@ -63,6 +64,7 @@ export interface VirgoSelection { // Editor's external API export interface Virgo { selectionManager: SelectionManager; + scrollManager: ScrollManager; createBlock: ( type: keyof BlockFlavors, parentId?: string diff --git a/libs/components/editor-plugins/src/menu/command-menu/Menu.tsx b/libs/components/editor-plugins/src/menu/command-menu/Menu.tsx index 3ab140f3bc..11e8d665da 100644 --- a/libs/components/editor-plugins/src/menu/command-menu/Menu.tsx +++ b/libs/components/editor-plugins/src/menu/command-menu/Menu.tsx @@ -40,26 +40,30 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => { bottom: 0, }); - const [search_text, set_search_text] = useState(''); - const [search_blocks, set_search_blocks] = useState([]); + const [searchText, setSearchText] = useState(''); + const [searchBlocks, setSearchBlocks] = useState([]); const commandMenuContentRef = useRef(); // TODO: Two-way link to be developed // useEffect(() => { - // QueryBlocks(editor, search_text, result => set_search_blocks(result)); - // }, [editor, search_text]); + // QueryBlocks(editor, searchText, result => set_searchBlocks(result)); + // }, [editor, searchText]); + const hideMenu = () => { + setShow(false); + editor.scrollManager.unLock(); + }; const [types, categories] = useMemo(() => { const types: Array = []; const categories: Array = []; - if (search_blocks.length) { - Object.values(search_blocks).forEach(({ id }) => types.push(id)); + if (searchBlocks.length) { + Object.values(searchBlocks).forEach(({ id }) => types.push(id)); categories.push(CommandMenuCategories.pages); } Object.entries(menuItemsMap).forEach(([category, itemInfoList]) => { itemInfoList.forEach(info => { if ( - !search_text || - info.text.toLowerCase().includes(search_text.toLowerCase()) + !searchText || + info.text.toLowerCase().includes(searchText.toLowerCase()) ) { types.push(info.type); } @@ -73,9 +77,9 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => { }); }); return [types, categories]; - }, [search_blocks, search_text]); + }, [searchBlocks, searchText]); - const check_if_show_command_menu = useCallback( + const checkIfShowCommandMenu = useCallback( async (event: React.KeyboardEvent) => { const { type, anchorNode } = editor.selection.currentSelectInfo; if (event.key === '/' && type === 'Range') { @@ -101,8 +105,9 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => { ); } }); - set_search_text(''); + setSearchText(''); setShow(true); + editor.scrollManager.lock(); const rect = editor.selection.currentSelectInfo?.browserSelection ?.getRangeAt(0) @@ -137,12 +142,12 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => { [editor, blockId] ); - const handle_click_others = useCallback( + const handleClickOthers = useCallback( (event: React.KeyboardEvent) => { if (show) { const { anchorNode } = editor.selection.currentSelectInfo; if (anchorNode.id !== blockId) { - setShow(false); + hideMenu(); return; } setTimeout(() => { @@ -150,12 +155,12 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => { editor.blockHelper.getSearchSlashText(blockId); // check if has search text if (searchText && searchText.startsWith('/')) { - set_search_text(searchText.slice(1)); + setSearchText(searchText.slice(1)); } else { - setShow(false); + hideMenu(); } if (searchText.length > 6 && !types.length) { - setShow(false); + hideMenu(); } }); } @@ -163,18 +168,18 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => { [editor, show, blockId, types] ); - const handle_keyup = useCallback( + const handleKeyup = useCallback( (event: React.KeyboardEvent) => { - check_if_show_command_menu(event); - handle_click_others(event); + checkIfShowCommandMenu(event); + handleClickOthers(event); }, - [check_if_show_command_menu, handle_click_others] + [checkIfShowCommandMenu, handleClickOthers] ); - const handle_key_down = useCallback( + const handleKeyDown = useCallback( (event: React.KeyboardEvent) => { if (event.code === 'Escape') { - setShow(false); + hideMenu(); } }, [] @@ -183,23 +188,23 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => { useEffect(() => { const sub = hooks .get(HookType.ON_ROOT_NODE_KEYUP) - .subscribe(handle_keyup); + .subscribe(handleKeyup); sub.add( hooks .get(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE) - .subscribe(handle_key_down) + .subscribe(handleKeyDown) ); return () => { sub.unsubscribe(); }; - }, [handle_keyup, handle_key_down, hooks]); + }, [handleKeyup, handleKeyDown, hooks]); - const handle_click_away = () => { - setShow(false); + const handleClickAway = () => { + hideMenu(); }; - const handle_selected = async (type: BlockFlavorKeys | string) => { + const handleSelected = async (type: BlockFlavorKeys | string) => { const text = await editor.commands.textCommands.getBlockText(blockId); editor.blockHelper.removeSearchSlash(blockId, true); if (type.startsWith('Virgo')) { @@ -224,20 +229,20 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => { block.firstCreateFlag = true; } } - setShow(false); + hideMenu(); }; - const handle_close = () => { + const handleClose = () => { editor.blockHelper.removeSearchSlash(blockId); }; return (
- +
{ }} isShow={show} blockId={blockId} - onSelected={handle_selected} - onclose={handle_close} - searchBlocks={search_blocks} + onSelected={handleSelected} + onclose={handleClose} + searchBlocks={searchBlocks} types={types} categories={categories} />