diff --git a/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx b/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx index 8e83c601a0..8d470671ef 100644 --- a/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx +++ b/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx @@ -1,7 +1,5 @@ -import { Route, Routes, useParams } from 'react-router'; - import { useUserAndSpaces } from '@toeverything/datasource/state'; - +import { Route, Routes, useParams } from 'react-router'; import { WorkspaceRootContainer } from './Container'; import { Page } from './docs'; import { Edgeless } from './Edgeless'; @@ -10,7 +8,7 @@ import Labels from './labels'; import Pages from './pages'; export function WorkspaceContainer() { - const { workspace_id } = useParams(); + const { workspace_id, page_id } = useParams(); const { user, currentSpaceId } = useUserAndSpaces(); if ( diff --git a/libs/components/common/src/lib/text/slate-utils.ts b/libs/components/common/src/lib/text/slate-utils.ts index fd1de5f674..29639c3e05 100644 --- a/libs/components/common/src/lib/text/slate-utils.ts +++ b/libs/components/common/src/lib/text/slate-utils.ts @@ -713,7 +713,10 @@ class SlateUtils { if (!this.editor) { return undefined; } - const { selectionEnd } = this.getSelectionStartAndEnd(); + const selectionEnd = this.getSelectionStartAndEnd()?.selectionEnd; + if (!selectionEnd) { + return undefined; + } return this.getStringBetween(this.getStart(), selectionEnd); } diff --git a/libs/components/editor-core/src/editor/types.ts b/libs/components/editor-core/src/editor/types.ts index 1b97cf0f86..25c37b5172 100644 --- a/libs/components/editor-core/src/editor/types.ts +++ b/libs/components/editor-core/src/editor/types.ts @@ -10,8 +10,6 @@ */ import type { PatchNode } from '@toeverything/components/ui'; import type { BlockFlavors } from '@toeverything/datasource/db-service'; -import type { IdList, SelectionInfo, SelectionManager } from './selection'; - import { Point } from '@toeverything/utils'; import { Observable } from 'rxjs'; import type { AsyncBlock } from './block'; @@ -20,6 +18,7 @@ import type { BlockCommands } from './commands/block-commands'; import type { DragDropManager } from './drag-drop'; import { MouseManager } from './mouse'; import { ScrollManager } from './scroll'; +import type { IdList, SelectionInfo, SelectionManager } from './selection'; // import { BrowserClipboard } from './clipboard/browser-clipboard'; @@ -109,6 +108,7 @@ export interface Virgo { getGroupBlockByPoint: (point: Point) => Promise; isEdgeless: boolean; mouseManager: MouseManager; + getHooks: () => HooksRunner & PluginHooks; } export interface Plugin { diff --git a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx index 3540ba0ba1..4650a07c70 100644 --- a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx +++ b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx @@ -192,9 +192,10 @@ export const DoubleLinkMenu = ({ anchorNode.id !== curBlockId && editor.blockHelper.isSelectionCollapsed(anchorNode.id)) ) { - const text = editor.blockHelper.getBlockTextBeforeSelection( - anchorNode.id - ); + const text = + editor.blockHelper.getBlockTextBeforeSelection( + anchorNode.id + ) || ''; if (text.endsWith('[[')) { resetState(curBlockId, anchorNode.id); } diff --git a/libs/components/editor-plugins/src/search/Search.tsx b/libs/components/editor-plugins/src/search/Search.tsx index b689345f64..23a3f46c2c 100644 --- a/libs/components/editor-plugins/src/search/Search.tsx +++ b/libs/components/editor-plugins/src/search/Search.tsx @@ -5,7 +5,12 @@ import { styled, TransitionsModal, } from '@toeverything/components/ui'; -import { BlockEditor, Virgo } from '@toeverything/framework/virgo'; +import { + BlockEditor, + HookType, + PluginHooks, + Virgo, +} from '@toeverything/framework/virgo'; import { throttle } from '@toeverything/utils'; import { useCallback, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router'; @@ -31,7 +36,7 @@ const styles = style9.create({ export type QueryResult = Awaited>; -const query_blocks = ( +const queryBlocksExec = ( editor: Virgo, search: string, callback: (result: QueryResult) => void @@ -39,45 +44,58 @@ const query_blocks = ( (editor as BlockEditor).search(search).then(pages => callback(pages)); }; -export const QueryBlocks = throttle(query_blocks, 500); +export const QueryBlocks = throttle(queryBlocksExec, 500); type SearchProps = { - onClose: () => void; editor: Virgo; + hooks: PluginHooks; }; export const Search = (props: SearchProps) => { - const { workspace_id } = useParams(); + const { workspace_id: workspaceId } = useParams(); const navigate = useNavigate(); - const [open, set_open] = useState(true); - const [search, set_search] = useState(''); - const [result, set_result] = useState([]); + const [open, setOpen] = useState(false); + const [search, setSearch] = useState(); + const [result, setResult] = useState([]); useEffect(() => { - QueryBlocks(props.editor, search, result => { - set_result(result); - }); + search !== undefined && + QueryBlocks(props.editor, search, result => { + setResult(result); + }); }, [props.editor, search]); - const handle_navigate = useCallback( - (id: string) => navigate(`/${workspace_id}/${id}`), - [navigate, workspace_id] + const handleNavigate = useCallback( + (id: string) => navigate(`/${workspaceId}/${id}`), + [navigate, workspaceId] ); + const handleSearch = useCallback(() => { + setOpen(true); + setSearch(''); + }, []); + + useEffect(() => { + const sub = props.hooks.get(HookType.ON_SEARCH).subscribe(handleSearch); + + return () => { + sub.unsubscribe(); + }; + }, [props, handleSearch]); + return ( { - set_open(false); - props.onClose(); + setOpen(false); }} > set_search(e.target.value)} + onChange={e => setSearch(e.target.value)} /> { { - handle_navigate(block.id); - props.onClose(); + handleNavigate(block.id); }} /> ))} diff --git a/libs/components/editor-plugins/src/search/index.tsx b/libs/components/editor-plugins/src/search/index.tsx index 41a13695c4..b74e3572a8 100644 --- a/libs/components/editor-plugins/src/search/index.tsx +++ b/libs/components/editor-plugins/src/search/index.tsx @@ -1,59 +1,40 @@ import { StrictMode } from 'react'; - -import { HookType } from '@toeverything/framework/virgo'; - import { BasePlugin } from '../base-plugin'; import { PluginRenderRoot } from '../utils'; import { Search } from './Search'; export class FullTextSearchPlugin extends BasePlugin { - #root?: PluginRenderRoot; + private root?: PluginRenderRoot; public static override get pluginName(): string { return 'search'; } - public override init(): void { - this.sub.add( - this.hooks.get(HookType.ON_SEARCH).subscribe(this._handleSearch) - ); - } - protected override _onRender(): void { - this.#root = new PluginRenderRoot({ + this.root = new PluginRenderRoot({ name: FullTextSearchPlugin.pluginName, render: this.editor.reactRenderRoot.render, }); + this._renderSearch(); } - private unmount() { - if (this.#root) { - this.editor.setHotKeysScope(); - this.#root.unmount(); - // this.#root = undefined; - } - this.sub.unsubscribe(); - } - - private _handleSearch = () => { - this.editor.setHotKeysScope('search'); - this.render_search(); - }; - private render_search() { - if (this.#root) { - this.#root.mount(); - this.#root.render( + private _renderSearch() { + if (this.root) { + this.root.mount(); + this.root.render( - this.unmount()} - editor={this.editor} - /> + ); } } public renderSearch() { - this.render_search(); + this._renderSearch(); + } + + public override dispose() { + this.root?.unmount(); + super.dispose(); } } diff --git a/libs/components/layout/src/header/LayoutHeader.tsx b/libs/components/layout/src/header/LayoutHeader.tsx index 2d6913ac60..efef6116b1 100644 --- a/libs/components/layout/src/header/LayoutHeader.tsx +++ b/libs/components/layout/src/header/LayoutHeader.tsx @@ -1,5 +1,3 @@ -import { useMemo } from 'react'; - import { LogoIcon, SearchIcon, @@ -8,10 +6,11 @@ import { } from '@toeverything/components/icons'; import { IconButton, styled } from '@toeverything/components/ui'; import { + useCurrentEditors, useLocalTrigger, useShowSettingsSidebar, } from '@toeverything/datasource/state'; - +import { useCallback, useMemo } from 'react'; import { EditorBoardSwitcher } from './EditorBoardSwitcher'; import { FileSystem, fsApiSupported } from './FileSystem'; import { CurrentPageTitle } from './Title'; @@ -31,6 +30,14 @@ export const LayoutHeader = () => { } }, [isLocalWorkspace]); + const { currentEditors } = useCurrentEditors(); + + const handleSearch = useCallback(() => { + for (const key in currentEditors || {}) { + currentEditors[key].getHooks().onSearch(); + } + }, [currentEditors]); + return ( @@ -48,8 +55,7 @@ export const LayoutHeader = () => {