mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
feat(plugin): migrate plugin runner to rxjs
This commit is contained in:
@@ -9,30 +9,35 @@ import {
|
||||
import { Clip } from './clip';
|
||||
import assert from 'assert';
|
||||
import ClipboardParse from './clipboard-parse';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
class ClipboardPopulator {
|
||||
private editor: Editor;
|
||||
private hooks: PluginHooks;
|
||||
private selection_manager: SelectionManager;
|
||||
private clipboard: any;
|
||||
private clipboard_parse: ClipboardParse;
|
||||
private _editor: Editor;
|
||||
private _hooks: PluginHooks;
|
||||
private _selectionManager: SelectionManager;
|
||||
private _clipboardParse: ClipboardParse;
|
||||
private _sub = new Subscription();
|
||||
|
||||
constructor(
|
||||
editor: Editor,
|
||||
hooks: PluginHooks,
|
||||
selectionManager: SelectionManager,
|
||||
clipboard: any
|
||||
selectionManager: SelectionManager
|
||||
) {
|
||||
this.editor = editor;
|
||||
this.hooks = hooks;
|
||||
this.selection_manager = selectionManager;
|
||||
this.clipboard = clipboard;
|
||||
this.clipboard_parse = new ClipboardParse(editor);
|
||||
hooks.addHook(HookType.BEFORE_COPY, this.populate_app_clipboard, this);
|
||||
hooks.addHook(HookType.BEFORE_CUT, this.populate_app_clipboard, this);
|
||||
this._editor = editor;
|
||||
this._hooks = hooks;
|
||||
this._selectionManager = selectionManager;
|
||||
this._clipboardParse = new ClipboardParse(editor);
|
||||
this._sub.add(
|
||||
hooks
|
||||
.get(HookType.BEFORE_COPY)
|
||||
.subscribe(this._populateAppClipboard)
|
||||
);
|
||||
this._sub.add(
|
||||
hooks.get(HookType.BEFORE_CUT).subscribe(this._populateAppClipboard)
|
||||
);
|
||||
}
|
||||
|
||||
private async populate_app_clipboard(e: ClipboardEvent) {
|
||||
private _populateAppClipboard = async (e: ClipboardEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const clips = await this.getClips();
|
||||
@@ -58,7 +63,8 @@ class ClipboardPopulator {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private copy_to_cliboard_from_pc(clips: any[]) {
|
||||
let success = false;
|
||||
const tempElem = document.createElement('textarea');
|
||||
@@ -91,8 +97,8 @@ class ClipboardPopulator {
|
||||
}
|
||||
|
||||
private async get_clip_block_info(selBlock: SelectBlock) {
|
||||
const block = await this.editor.getBlockById(selBlock.blockId);
|
||||
const block_view = this.editor.getView(block.type);
|
||||
const block = await this._editor.getBlockById(selBlock.blockId);
|
||||
const block_view = this._editor.getView(block.type);
|
||||
assert(block_view);
|
||||
const block_info: ClipBlockInfo = {
|
||||
type: block.type,
|
||||
@@ -112,7 +118,8 @@ class ClipboardPopulator {
|
||||
|
||||
private async get_inner_clip(): Promise<InnerClipInfo> {
|
||||
const clips: ClipBlockInfo[] = [];
|
||||
const select_info: SelectInfo = await this.selection_manager.getSelectInfo();
|
||||
const select_info: SelectInfo =
|
||||
await this._selectionManager.getSelectInfo();
|
||||
for (let i = 0; i < select_info.blocks.length; i++) {
|
||||
const sel_block = select_info.blocks[i];
|
||||
const clip_block_info = await this.get_clip_block_info(sel_block);
|
||||
@@ -136,7 +143,7 @@ class ClipboardPopulator {
|
||||
)
|
||||
);
|
||||
|
||||
const html_clip = await this.clipboard_parse.generateHtml();
|
||||
const html_clip = await this._clipboardParse.generateHtml();
|
||||
html_clip &&
|
||||
clips.push(new Clip(OFFICE_CLIPBOARD_MIMETYPE.HTML, html_clip));
|
||||
|
||||
@@ -144,12 +151,8 @@ class ClipboardPopulator {
|
||||
}
|
||||
|
||||
disposeInternal() {
|
||||
this.hooks.removeHook(
|
||||
HookType.BEFORE_COPY,
|
||||
this.populate_app_clipboard
|
||||
);
|
||||
this.hooks.removeHook(HookType.BEFORE_CUT, this.populate_app_clipboard);
|
||||
this.hooks = null;
|
||||
this._sub.unsubscribe();
|
||||
this._hooks = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,8 +186,7 @@ export class Editor implements Virgo {
|
||||
this.clipboard_populator = new ClipboardPopulator(
|
||||
this,
|
||||
this.hooks,
|
||||
this.selectionManager,
|
||||
this.clipboard
|
||||
this.selectionManager
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +1,37 @@
|
||||
import {
|
||||
HooksRunner,
|
||||
PluginHooks,
|
||||
HookType,
|
||||
HookBaseArgs,
|
||||
BlockDomInfo,
|
||||
AnyFunction,
|
||||
AnyThisType,
|
||||
} from '../types';
|
||||
|
||||
interface PluginHookInfo {
|
||||
thisObj?: AnyThisType;
|
||||
callback: AnyFunction;
|
||||
once: boolean;
|
||||
}
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { HooksRunner, HookType, BlockDomInfo, PluginHooks } from '../types';
|
||||
|
||||
export class Hooks implements HooksRunner, PluginHooks {
|
||||
private _hooksMap: Map<string, PluginHookInfo[]> = new Map();
|
||||
private _subject: Record<string, Subject<unknown>> = {};
|
||||
private _observable: Record<string, Observable<unknown>> = {};
|
||||
|
||||
dispose() {
|
||||
this._hooksMap.clear();
|
||||
this._subject = {};
|
||||
}
|
||||
|
||||
private _runHook(key: HookType, ...params: unknown[]): void {
|
||||
const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
|
||||
hookInfos.forEach(hookInfo => {
|
||||
if (hookInfo.once) {
|
||||
this.removeHook(key, hookInfo.callback);
|
||||
}
|
||||
let isStoppedPropagation = false;
|
||||
const hookOption: HookBaseArgs = {
|
||||
stopImmediatePropagation: () => {
|
||||
isStoppedPropagation = true;
|
||||
},
|
||||
};
|
||||
hookInfo.callback.call(
|
||||
hookInfo.thisObj || this,
|
||||
...params,
|
||||
hookOption
|
||||
);
|
||||
return isStoppedPropagation;
|
||||
});
|
||||
if (this._subject[key] == null) {
|
||||
this._subject[key] = new Subject();
|
||||
this._observable[key] = this._subject[key].asObservable();
|
||||
}
|
||||
let payload: unknown = params;
|
||||
|
||||
if (params.length === 0) {
|
||||
payload = undefined;
|
||||
}
|
||||
if (params.length === 1) {
|
||||
payload = params[0];
|
||||
}
|
||||
this._subject[key].next(payload);
|
||||
}
|
||||
|
||||
private _hasHook(key: HookType, callback: AnyFunction): boolean {
|
||||
const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
|
||||
for (let i = hookInfos.length - 1; i >= 0; i--) {
|
||||
if (hookInfos[i].callback === callback) {
|
||||
return true;
|
||||
}
|
||||
public get<K extends keyof HooksRunner>(key: K) {
|
||||
if (this._subject[key] == null) {
|
||||
this._subject[key] = new Subject();
|
||||
this._observable[key] = this._subject[key].asObservable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 执行多次
|
||||
public addHook(
|
||||
key: HookType,
|
||||
callback: AnyFunction,
|
||||
thisObj?: AnyThisType,
|
||||
once?: boolean
|
||||
): void {
|
||||
if (this._hasHook(key, callback)) {
|
||||
throw new Error('Duplicate registration of the same class');
|
||||
}
|
||||
if (!this._hooksMap.has(key)) {
|
||||
this._hooksMap.set(key, []);
|
||||
}
|
||||
const hookInfos: PluginHookInfo[] = this._hooksMap.get(key);
|
||||
hookInfos.push({ callback, thisObj, once });
|
||||
}
|
||||
|
||||
// 执行一次
|
||||
public addOnceHook(
|
||||
key: HookType,
|
||||
callback: AnyFunction,
|
||||
thisObj?: AnyThisType
|
||||
): void {
|
||||
this.addHook(key, callback, thisObj, true);
|
||||
}
|
||||
|
||||
// 移除
|
||||
public removeHook(key: HookType, callback: AnyFunction): void {
|
||||
const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
|
||||
for (let i = hookInfos.length - 1; i >= 0; i--) {
|
||||
if (hookInfos[i].callback === callback) {
|
||||
hookInfos.splice(i, 1);
|
||||
}
|
||||
}
|
||||
return this._observable[key] as any;
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import EventEmitter from 'eventemitter3';
|
||||
|
||||
import { domToRect, Rect } from '@toeverything/utils';
|
||||
import type { Editor as Block_editor } from '../editor';
|
||||
import type { Editor as BlockEditor } from '../editor';
|
||||
|
||||
import { AsyncBlock } from '../block';
|
||||
|
||||
@@ -9,7 +9,7 @@ type VerticalTypes = 'up' | 'down' | null;
|
||||
type HorizontalTypes = 'left' | 'right' | null;
|
||||
|
||||
export class ScrollManager {
|
||||
private _editor: Block_editor;
|
||||
private _editor: BlockEditor;
|
||||
private _animationFrame: null | number = null;
|
||||
private _eventName = 'scrolling';
|
||||
private _currentMoveDirection: [HorizontalTypes, VerticalTypes] = [
|
||||
@@ -20,9 +20,8 @@ export class ScrollManager {
|
||||
private _scrollMoveOffset = 8;
|
||||
private _scrollingEvent = new EventEmitter();
|
||||
|
||||
constructor(editor: Block_editor) {
|
||||
constructor(editor: BlockEditor) {
|
||||
this._editor = editor;
|
||||
console.log('scrollmanager constructor', this._editor.ui_container);
|
||||
}
|
||||
|
||||
private _updateScrollInfo(left: number, top: number) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import type { BlockHelper } from './block/block-helper';
|
||||
import type { BlockCommands } from './commands/block-commands';
|
||||
import type { DragDropManager } from './drag-drop';
|
||||
import { MouseManager } from './mouse';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
// import { BrowserClipboard } from './clipboard/browser-clipboard';
|
||||
|
||||
@@ -176,10 +177,6 @@ export enum HookType {
|
||||
BEFORE_CUT = 'beforeCut',
|
||||
}
|
||||
|
||||
export interface HookBaseArgs {
|
||||
stopImmediatePropagation: () => void;
|
||||
}
|
||||
|
||||
export interface BlockDomInfo {
|
||||
blockId: string;
|
||||
dom: HTMLElement;
|
||||
@@ -227,25 +224,16 @@ export interface HooksRunner {
|
||||
beforeCut: (e: ClipboardEvent) => void;
|
||||
}
|
||||
|
||||
export type AnyFunction = (...args: any[]) => any;
|
||||
export type AnyThisType = ThisParameterType<any>;
|
||||
export type PayloadType<T extends Array<any>> = T extends []
|
||||
? void
|
||||
: T extends [infer U]
|
||||
? U
|
||||
: T;
|
||||
|
||||
// hook管理,在editor、plugin中使用
|
||||
export interface PluginHooks {
|
||||
// 执行多次
|
||||
addHook: (
|
||||
key: HookType,
|
||||
callback: AnyFunction,
|
||||
thisObj?: AnyThisType,
|
||||
once?: boolean
|
||||
) => void;
|
||||
// 执行一次
|
||||
addOnceHook: (
|
||||
key: HookType,
|
||||
callback: AnyFunction,
|
||||
thisObj?: AnyThisType
|
||||
) => void;
|
||||
// 移除
|
||||
removeHook: (key: HookType, callback: AnyFunction) => void;
|
||||
get<K extends keyof HooksRunner>(
|
||||
key: K
|
||||
): Observable<PayloadType<Parameters<HooksRunner[K]>>>;
|
||||
}
|
||||
|
||||
export * from './drag-drop/types';
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import {
|
||||
HookType,
|
||||
Virgo,
|
||||
Plugin,
|
||||
PluginHooks,
|
||||
HookType,
|
||||
} from '@toeverything/framework/virgo';
|
||||
import { genErrorObj } from '@toeverything/utils';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
export abstract class BasePlugin implements Plugin {
|
||||
protected editor: Virgo;
|
||||
protected hooks: PluginHooks;
|
||||
private hook_queue: [type: HookType, fn: (...args: unknown[]) => void][] =
|
||||
[];
|
||||
private is_disposed = false;
|
||||
protected sub: Subscription;
|
||||
private _disposed = false;
|
||||
|
||||
// Unique identifier to distinguish between different Plugins
|
||||
public static get pluginName(): string {
|
||||
@@ -27,22 +27,8 @@ export abstract class BasePlugin implements Plugin {
|
||||
|
||||
constructor(editor: Virgo, hooks: PluginHooks) {
|
||||
this.editor = editor;
|
||||
// TODO perfect it
|
||||
this.hooks = {
|
||||
addHook: (...args) => {
|
||||
this.hook_queue.push([args[0], args[1]]);
|
||||
return hooks.addHook(...args);
|
||||
},
|
||||
addOnceHook(...args) {
|
||||
return hooks.addHook(...args);
|
||||
},
|
||||
// TODO fix remove
|
||||
removeHook(...args) {
|
||||
return hooks.removeHook(...args);
|
||||
},
|
||||
};
|
||||
this._onRender = this._onRender.bind(this);
|
||||
hooks.addHook(HookType.RENDER, this._onRender, this);
|
||||
this.hooks = hooks;
|
||||
this.sub = hooks.get(HookType.RENDER).subscribe(() => this._onRender());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,18 +48,12 @@ export abstract class BasePlugin implements Plugin {
|
||||
public dispose(): void {
|
||||
// See https://stackoverflow.com/questions/33387318/access-to-static-properties-via-this-constructor-in-typescript
|
||||
const pluginName = (this.constructor as typeof BasePlugin).pluginName;
|
||||
if (this.is_disposed) {
|
||||
if (this._disposed) {
|
||||
console.warn(`Plugin '${pluginName}' already disposed`);
|
||||
return;
|
||||
}
|
||||
this.is_disposed = true;
|
||||
// FIX will remove hook multiple times
|
||||
// if the hook has been removed manually
|
||||
// or set once flag when add hook
|
||||
this.hook_queue.forEach(([type, fn]) => {
|
||||
this.hooks.removeHook(type, fn);
|
||||
});
|
||||
this.hook_queue = [];
|
||||
this.sub.unsubscribe();
|
||||
this._disposed = true;
|
||||
|
||||
const errorMsg = `You are trying to access an invalid editor or hooks.
|
||||
The plugin '${pluginName}' has been disposed.
|
||||
|
||||
82
libs/components/editor-plugins/src/block-property/Plugin.tsx
Normal file
82
libs/components/editor-plugins/src/block-property/Plugin.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
import { createRoot, type Root } from 'react-dom/client';
|
||||
import { BasePlugin } from '../base-plugin';
|
||||
import { BlockDomInfo, HookType } from '@toeverything/framework/virgo';
|
||||
|
||||
import View from './View';
|
||||
import { Subscription } from 'rxjs';
|
||||
const PLUGIN_NAME = 'block-property';
|
||||
|
||||
export class BlockPropertyPlugin extends BasePlugin {
|
||||
public static override get pluginName(): string {
|
||||
return PLUGIN_NAME;
|
||||
}
|
||||
|
||||
private _root: Root | undefined;
|
||||
private _rootDom: HTMLElement;
|
||||
// record mouse moving block id
|
||||
private _currentSlidingBlockInfo: BlockDomInfo;
|
||||
private _hover = false;
|
||||
|
||||
private _setHover = (isHover: boolean) => {
|
||||
this._hover = isHover;
|
||||
};
|
||||
private _insertRootToBlock = async () => {
|
||||
this._rootDom = document.createElement('div');
|
||||
this._rootDom.style.position = 'relative';
|
||||
this._rootDom.style.zIndex = '1000';
|
||||
this._rootDom.classList.add(`id-${PLUGIN_NAME}`);
|
||||
this._currentSlidingBlockInfo.dom.appendChild(this._rootDom);
|
||||
this._root = createRoot(this._rootDom);
|
||||
};
|
||||
|
||||
private _onSlidingBlockChange = async (blockDomInfo: BlockDomInfo) => {
|
||||
this._currentSlidingBlockInfo = blockDomInfo;
|
||||
await this._insertRootToBlock();
|
||||
this._renderView();
|
||||
};
|
||||
|
||||
private _onMouseMove = async ([event, blockDomInfo]: [
|
||||
React.MouseEvent,
|
||||
BlockDomInfo
|
||||
]) => {
|
||||
if (
|
||||
blockDomInfo.blockId !== this._currentSlidingBlockInfo?.blockId &&
|
||||
!this._hover
|
||||
) {
|
||||
await this.dispose();
|
||||
|
||||
await this._onSlidingBlockChange(blockDomInfo);
|
||||
}
|
||||
};
|
||||
|
||||
private _renderView = () => {
|
||||
this._root.render(
|
||||
<View
|
||||
blockDomInfo={this._currentSlidingBlockInfo}
|
||||
setIsHover={this._setHover}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
protected override _onRender(): void {
|
||||
const sub = this.hooks
|
||||
.get(HookType.AFTER_ON_NODE_MOUSE_MOVE)
|
||||
.subscribe(this._onMouseMove);
|
||||
|
||||
this.sub.add(sub);
|
||||
}
|
||||
|
||||
override async dispose() {
|
||||
if (this._currentSlidingBlockInfo) {
|
||||
this._currentSlidingBlockInfo.dom.removeChild(this._rootDom);
|
||||
this._currentSlidingBlockInfo = undefined;
|
||||
}
|
||||
|
||||
this._rootDom = undefined;
|
||||
if (this._root) {
|
||||
this._root.unmount();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import React from 'react';
|
||||
import { createRoot, type Root } from 'react-dom/client';
|
||||
import { BasePlugin } from '../base-plugin';
|
||||
import { BlockDomInfo, HookType } from '@toeverything/framework/virgo';
|
||||
|
||||
import View from './view';
|
||||
const PLUGIN_NAME = 'block-property';
|
||||
|
||||
export class BlockPropertyPlugin extends BasePlugin {
|
||||
public static override get pluginName(): string {
|
||||
return PLUGIN_NAME;
|
||||
}
|
||||
|
||||
private root: Root | undefined;
|
||||
private root_dom: HTMLElement;
|
||||
// record mouse moving block id
|
||||
private current_sliding_block_info: BlockDomInfo;
|
||||
private is_render = false;
|
||||
private is_hover = false;
|
||||
|
||||
private set_is_hover = (isHover: boolean) => {
|
||||
this.is_hover = isHover;
|
||||
};
|
||||
private insert_root_to_block = async () => {
|
||||
this.root_dom = document.createElement('div');
|
||||
this.root_dom.style.position = 'relative';
|
||||
this.root_dom.style.zIndex = '1000';
|
||||
this.root_dom.classList.add(`id-${PLUGIN_NAME}`);
|
||||
this.current_sliding_block_info.dom.appendChild(this.root_dom);
|
||||
this.root = createRoot(this.root_dom);
|
||||
};
|
||||
|
||||
private on_sliding_block_change = async (blockDomInfo: BlockDomInfo) => {
|
||||
this.current_sliding_block_info = blockDomInfo;
|
||||
await this.insert_root_to_block();
|
||||
this.render_view();
|
||||
this.is_render = true;
|
||||
};
|
||||
|
||||
private on_mouse_move = async (
|
||||
event: React.MouseEvent,
|
||||
blockDomInfo: BlockDomInfo
|
||||
) => {
|
||||
if (
|
||||
blockDomInfo.blockId !== this.current_sliding_block_info?.blockId &&
|
||||
!this.is_hover
|
||||
) {
|
||||
await this.dispose();
|
||||
|
||||
await this.on_sliding_block_change(blockDomInfo);
|
||||
}
|
||||
};
|
||||
|
||||
private render_view = () => {
|
||||
this.root.render(
|
||||
<View
|
||||
blockDomInfo={this.current_sliding_block_info}
|
||||
setIsHover={this.set_is_hover}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
protected override _onRender(): void {
|
||||
this.hooks.addHook(
|
||||
HookType.AFTER_ON_NODE_MOUSE_MOVE,
|
||||
this.on_mouse_move,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
override async dispose() {
|
||||
if (this.current_sliding_block_info) {
|
||||
this.current_sliding_block_info.dom.removeChild(this.root_dom);
|
||||
this.current_sliding_block_info = undefined;
|
||||
}
|
||||
|
||||
this.root_dom = undefined;
|
||||
this.is_render = false;
|
||||
if (this.root) {
|
||||
this.root.unmount();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,13 +190,12 @@ export const CommandMenuContainer = ({
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
hooks.addHook(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE, handleKeyDown);
|
||||
const sub = hooks
|
||||
.get(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE)
|
||||
.subscribe(handle_key_down);
|
||||
|
||||
return () => {
|
||||
hooks.removeHook(
|
||||
HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE,
|
||||
handleKeyDown
|
||||
);
|
||||
sub.unsubscribe();
|
||||
};
|
||||
}, [hooks, handleKeyDown]);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
commonCommandMenuHandler,
|
||||
menuItemsMap,
|
||||
} from './config';
|
||||
import { QueryBlocks, QueryResult } from '../../search';
|
||||
import { QueryResult } from '../../search';
|
||||
|
||||
export type CommandMenuProps = {
|
||||
editor: Virgo;
|
||||
@@ -31,9 +31,11 @@ type CommandMenuPosition = {
|
||||
bottom: number | 'initial';
|
||||
};
|
||||
|
||||
const COMMAND_MENU_HEIGHT = 509;
|
||||
|
||||
export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => {
|
||||
const [is_show, set_is_show] = useState(false);
|
||||
const [block_id, set_block_id] = useState<string>();
|
||||
const [show, setShow] = useState(false);
|
||||
const [blockId, setBlockId] = useState<string>();
|
||||
const [commandMenuPosition, setCommandMenuPosition] =
|
||||
useState<CommandMenuPosition>({
|
||||
left: 0,
|
||||
@@ -85,8 +87,8 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => {
|
||||
anchorNode.id
|
||||
);
|
||||
if (text.endsWith('/')) {
|
||||
set_block_id(anchorNode.id);
|
||||
editor.blockHelper.removeSearchSlash(block_id);
|
||||
setBlockId(anchorNode.id);
|
||||
editor.blockHelper.removeSearchSlash(blockId);
|
||||
setTimeout(() => {
|
||||
const textSelection =
|
||||
editor.blockHelper.selectionToSlateRange(
|
||||
@@ -103,18 +105,16 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => {
|
||||
}
|
||||
});
|
||||
set_search_text('');
|
||||
set_is_show(true);
|
||||
setShow(true);
|
||||
const rect =
|
||||
editor.selection.currentSelectInfo?.browserSelection
|
||||
?.getRangeAt(0)
|
||||
?.getBoundingClientRect();
|
||||
if (rect) {
|
||||
let top = rect.top;
|
||||
let clientHeight =
|
||||
const clientHeight =
|
||||
document.documentElement.clientHeight;
|
||||
|
||||
const COMMAND_MENU_HEIGHT =
|
||||
window.innerHeight * 0.4;
|
||||
if (clientHeight - top <= COMMAND_MENU_HEIGHT) {
|
||||
top = clientHeight - top + 10;
|
||||
setCommandMenuPosition({
|
||||
@@ -135,33 +135,33 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => {
|
||||
}
|
||||
}
|
||||
},
|
||||
[editor, block_id]
|
||||
[editor, blockId]
|
||||
);
|
||||
|
||||
const handle_click_others = useCallback(
|
||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (is_show) {
|
||||
if (show) {
|
||||
const { anchorNode } = editor.selection.currentSelectInfo;
|
||||
if (anchorNode.id !== block_id) {
|
||||
set_is_show(false);
|
||||
if (anchorNode.id !== blockId) {
|
||||
setShow(false);
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
const searchText =
|
||||
editor.blockHelper.getSearchSlashText(block_id);
|
||||
editor.blockHelper.getSearchSlashText(blockId);
|
||||
// check if has search text
|
||||
if (searchText && searchText.startsWith('/')) {
|
||||
set_search_text(searchText.slice(1));
|
||||
} else {
|
||||
set_is_show(false);
|
||||
setShow(false);
|
||||
}
|
||||
if (searchText.length > 6 && !types.length) {
|
||||
set_is_show(false);
|
||||
setShow(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
[editor, is_show, block_id, types]
|
||||
[editor, show, blockId, types]
|
||||
);
|
||||
|
||||
const handle_keyup = useCallback(
|
||||
@@ -175,59 +175,61 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => {
|
||||
const handle_key_down = useCallback(
|
||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (event.code === 'Escape') {
|
||||
set_is_show(false);
|
||||
setShow(false);
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
hooks.addHook(HookType.ON_ROOT_NODE_KEYUP, handle_keyup);
|
||||
hooks.addHook(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE, handle_key_down);
|
||||
const sub = hooks
|
||||
.get(HookType.ON_ROOT_NODE_KEYUP)
|
||||
.subscribe(handle_keyup);
|
||||
sub.add(
|
||||
hooks
|
||||
.get(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE)
|
||||
.subscribe(handle_key_down)
|
||||
);
|
||||
|
||||
return () => {
|
||||
hooks.removeHook(HookType.ON_ROOT_NODE_KEYUP, handle_keyup);
|
||||
hooks.removeHook(
|
||||
HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE,
|
||||
handle_key_down
|
||||
);
|
||||
sub.unsubscribe();
|
||||
};
|
||||
}, [handle_keyup, handle_key_down, hooks]);
|
||||
|
||||
const handle_click_away = () => {
|
||||
set_is_show(false);
|
||||
setShow(false);
|
||||
};
|
||||
|
||||
const handle_selected = async (type: BlockFlavorKeys | string) => {
|
||||
const text = await editor.commands.textCommands.getBlockText(block_id);
|
||||
editor.blockHelper.removeSearchSlash(block_id, true);
|
||||
const text = await editor.commands.textCommands.getBlockText(blockId);
|
||||
editor.blockHelper.removeSearchSlash(blockId, true);
|
||||
if (type.startsWith('Virgo')) {
|
||||
const handler =
|
||||
commandMenuHandlerMap[Protocol.Block.Type.reference];
|
||||
handler(block_id, type, editor);
|
||||
handler(blockId, type, editor);
|
||||
} else if (text.length > 1) {
|
||||
const handler = commandMenuHandlerMap[type];
|
||||
if (handler) {
|
||||
await handler(block_id, type, editor);
|
||||
await handler(blockId, type, editor);
|
||||
} else {
|
||||
await commonCommandMenuHandler(block_id, type, editor);
|
||||
await commonCommandMenuHandler(blockId, type, editor);
|
||||
}
|
||||
const block = await editor.getBlockById(block_id);
|
||||
const block = await editor.getBlockById(blockId);
|
||||
block.remove();
|
||||
} else {
|
||||
if (Protocol.Block.Type[type as BlockFlavorKeys]) {
|
||||
const block = await editor.commands.blockCommands.convertBlock(
|
||||
block_id,
|
||||
blockId,
|
||||
type as BlockFlavorKeys
|
||||
);
|
||||
block.firstCreateFlag = true;
|
||||
}
|
||||
}
|
||||
set_is_show(false);
|
||||
setShow(false);
|
||||
};
|
||||
|
||||
const handle_close = () => {
|
||||
editor.blockHelper.removeSearchSlash(block_id);
|
||||
editor.blockHelper.removeSearchSlash(blockId);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -237,24 +239,21 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => {
|
||||
ref={commandMenuContentRef}
|
||||
>
|
||||
<MuiClickAwayListener onClickAway={handle_click_away}>
|
||||
{/* MuiClickAwayListener 渲染子节点问题*/}
|
||||
<div>
|
||||
<CommandMenuContainer
|
||||
editor={editor}
|
||||
hooks={hooks}
|
||||
style={{
|
||||
...commandMenuPosition,
|
||||
...style,
|
||||
}}
|
||||
isShow={is_show}
|
||||
blockId={block_id}
|
||||
onSelected={handle_selected}
|
||||
onclose={handle_close}
|
||||
searchBlocks={search_blocks}
|
||||
types={types}
|
||||
categories={categories}
|
||||
/>
|
||||
</div>
|
||||
<CommandMenuContainer
|
||||
editor={editor}
|
||||
hooks={hooks}
|
||||
style={{
|
||||
...commandMenuPosition,
|
||||
...style,
|
||||
}}
|
||||
isShow={show}
|
||||
blockId={blockId}
|
||||
onSelected={handle_selected}
|
||||
onclose={handle_close}
|
||||
searchBlocks={search_blocks}
|
||||
types={types}
|
||||
categories={categories}
|
||||
/>
|
||||
</MuiClickAwayListener>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -91,29 +91,31 @@ export const GroupMenu = function ({ editor, hooks }: GroupMenuProps) {
|
||||
[editor, groupBlock]
|
||||
);
|
||||
|
||||
const handleRootDragEnd = (e: DragEvent) => {
|
||||
const handleRootDragEnd = () => {
|
||||
setDragOverGroup(null);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
hooks.addHook(HookType.ON_ROOTNODE_MOUSE_MOVE, handleRootMouseMove);
|
||||
hooks.addHook(HookType.ON_ROOTNODE_MOUSE_DOWN, handleRootMouseDown);
|
||||
hooks.addHook(HookType.ON_ROOTNODE_DRAG_OVER, handleRootDragOver);
|
||||
hooks.addHook(HookType.ON_ROOTNODE_DRAG_END, handleRootDragEnd);
|
||||
const sub = hooks
|
||||
.get(HookType.ON_ROOTNODE_MOUSE_MOVE)
|
||||
.subscribe(handleRootMouseMove);
|
||||
sub.add(
|
||||
hooks
|
||||
.get(HookType.ON_ROOTNODE_MOUSE_DOWN)
|
||||
.subscribe(handleRootMouseDown)
|
||||
);
|
||||
sub.add(
|
||||
hooks
|
||||
.get(HookType.ON_ROOTNODE_DRAG_OVER)
|
||||
.subscribe(handleRootDragOver)
|
||||
);
|
||||
sub.add(
|
||||
hooks
|
||||
.get(HookType.ON_ROOTNODE_DRAG_END)
|
||||
.subscribe(handleRootDragEnd)
|
||||
);
|
||||
return () => {
|
||||
hooks.removeHook(
|
||||
HookType.ON_ROOTNODE_MOUSE_MOVE,
|
||||
handleRootMouseMove
|
||||
);
|
||||
hooks.removeHook(
|
||||
HookType.ON_ROOTNODE_MOUSE_DOWN,
|
||||
handleRootMouseDown
|
||||
);
|
||||
hooks.removeHook(
|
||||
HookType.ON_ROOTNODE_DRAG_OVER,
|
||||
handleRootDragOver
|
||||
);
|
||||
hooks.removeHook(HookType.ON_ROOTNODE_DRAG_END, handleRootDragEnd);
|
||||
sub.unsubscribe();
|
||||
};
|
||||
}, [
|
||||
hooks,
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useState, useEffect, FC } from 'react';
|
||||
import {
|
||||
Virgo,
|
||||
BlockDomInfo,
|
||||
HookType,
|
||||
PluginHooks,
|
||||
BlockDropPlacement,
|
||||
} from '@toeverything/framework/virgo';
|
||||
@@ -116,7 +115,7 @@ function DragComponent(props: {
|
||||
}
|
||||
|
||||
export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
|
||||
const { editor, blockInfo, defaultVisible, hooks, lineInfo } = props;
|
||||
const { editor, blockInfo, defaultVisible, lineInfo } = props;
|
||||
const [visible, setVisible] = useState(defaultVisible);
|
||||
const [anchorEl, setAnchorEl] = useState<Element>();
|
||||
|
||||
@@ -128,10 +127,6 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
|
||||
window.addEventListener('dragover', handleDragOverCapture, {
|
||||
capture: true,
|
||||
});
|
||||
hooks.addHook(
|
||||
HookType.ON_ROOTNODE_DRAG_OVER_CAPTURE,
|
||||
handleDragOverCapture
|
||||
);
|
||||
|
||||
const onDragStart = async (event: React.DragEvent<Element>) => {
|
||||
editor.dragDropManager.isOnDrag = true;
|
||||
|
||||
@@ -8,10 +8,10 @@ import { Subject } from 'rxjs';
|
||||
import { domToRect, last, Point } from '@toeverything/utils';
|
||||
|
||||
export class LeftMenuPlugin extends BasePlugin {
|
||||
private mousedown?: boolean;
|
||||
private root?: PluginRenderRoot;
|
||||
private preBlockId: string;
|
||||
private hideTimer: number;
|
||||
private _mousedown?: boolean;
|
||||
private _root?: PluginRenderRoot;
|
||||
private _preBlockId: string;
|
||||
private _hideTimer: number;
|
||||
|
||||
private _blockInfo: Subject<BlockDomInfo | undefined> = new Subject();
|
||||
private _lineInfo: LineInfoSubject = new Subject();
|
||||
@@ -21,39 +21,49 @@ export class LeftMenuPlugin extends BasePlugin {
|
||||
}
|
||||
|
||||
public override init(): void {
|
||||
this.hooks.addHook(
|
||||
HookType.AFTER_ON_NODE_MOUSE_MOVE,
|
||||
this._handleMouseMove
|
||||
this.sub.add(
|
||||
this.hooks
|
||||
.get(HookType.AFTER_ON_NODE_MOUSE_MOVE)
|
||||
.subscribe(this._handleMouseMove)
|
||||
);
|
||||
this.hooks.addHook(
|
||||
HookType.ON_ROOTNODE_MOUSE_DOWN,
|
||||
this._handleMouseDown
|
||||
this.sub.add(
|
||||
this.hooks
|
||||
.get(HookType.ON_ROOTNODE_MOUSE_DOWN)
|
||||
.subscribe(this._handleMouseDown)
|
||||
);
|
||||
this.hooks.addHook(
|
||||
HookType.ON_ROOTNODE_MOUSE_LEAVE,
|
||||
this._handleRootMouseLeave,
|
||||
this
|
||||
this.sub.add(
|
||||
this.hooks
|
||||
.get(HookType.ON_ROOTNODE_MOUSE_LEAVE)
|
||||
.subscribe(this._hideLeftMenu)
|
||||
);
|
||||
this.hooks.addHook(HookType.ON_ROOTNODE_MOUSE_UP, this._handleMouseUp);
|
||||
this.hooks.addHook(
|
||||
HookType.AFTER_ON_NODE_DRAG_OVER,
|
||||
this._handleDragOverBlockNode
|
||||
this.sub.add(
|
||||
this.hooks
|
||||
.get(HookType.ON_ROOTNODE_MOUSE_UP)
|
||||
.subscribe(this._handleMouseUp)
|
||||
);
|
||||
this.sub.add(
|
||||
this.hooks
|
||||
.get(HookType.AFTER_ON_NODE_DRAG_OVER)
|
||||
.subscribe(this._handleDragOverBlockNode)
|
||||
);
|
||||
this.sub.add(
|
||||
this.hooks
|
||||
.get(HookType.ON_ROOT_NODE_KEYDOWN)
|
||||
.subscribe(this._handleKeyDown)
|
||||
);
|
||||
this.sub.add(
|
||||
this.hooks.get(HookType.ON_ROOTNODE_DROP).subscribe(this._onDrop)
|
||||
);
|
||||
this.hooks.addHook(HookType.ON_ROOT_NODE_KEYDOWN, this._handleKeyDown);
|
||||
this.hooks.addHook(HookType.ON_ROOTNODE_DROP, this._onDrop);
|
||||
}
|
||||
|
||||
private _handleRootMouseLeave() {
|
||||
this._hideLeftMenu();
|
||||
}
|
||||
private _onDrop = () => {
|
||||
this.preBlockId = '';
|
||||
this._preBlockId = '';
|
||||
this._lineInfo.next(undefined);
|
||||
};
|
||||
private _handleDragOverBlockNode = async (
|
||||
event: React.DragEvent<Element>,
|
||||
blockInfo: BlockDomInfo
|
||||
) => {
|
||||
private _handleDragOverBlockNode = async ([event, blockInfo]: [
|
||||
React.DragEvent<Element>,
|
||||
BlockDomInfo
|
||||
]) => {
|
||||
const { type, dom, blockId } = blockInfo;
|
||||
event.preventDefault();
|
||||
if (this.editor.dragDropManager.isDragBlock(event)) {
|
||||
@@ -70,24 +80,24 @@ export class LeftMenuPlugin extends BasePlugin {
|
||||
}
|
||||
};
|
||||
|
||||
private _handleMouseMove = async (
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
node: BlockDomInfo
|
||||
) => {
|
||||
if (!this.hideTimer) {
|
||||
this.hideTimer = window.setTimeout(() => {
|
||||
if (this.mousedown) {
|
||||
private _handleMouseMove = async ([e, node]: [
|
||||
React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
BlockDomInfo
|
||||
]) => {
|
||||
if (!this._hideTimer) {
|
||||
this._hideTimer = window.setTimeout(() => {
|
||||
if (this._mousedown) {
|
||||
this._hideLeftMenu();
|
||||
return;
|
||||
}
|
||||
this.hideTimer = 0;
|
||||
this._hideTimer = 0;
|
||||
}, 300);
|
||||
}
|
||||
if (this.editor.readonly) {
|
||||
this._hideLeftMenu();
|
||||
return;
|
||||
}
|
||||
if (node.blockId !== this.preBlockId) {
|
||||
if (node.blockId !== this._preBlockId) {
|
||||
if (node.dom) {
|
||||
const mousePoint = new Point(e.clientX, e.clientY);
|
||||
const children = await (
|
||||
@@ -109,27 +119,21 @@ export class LeftMenuPlugin extends BasePlugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.preBlockId = node.blockId;
|
||||
this._preBlockId = node.blockId;
|
||||
this._showLeftMenu(node);
|
||||
}
|
||||
};
|
||||
|
||||
private _handleMouseUp(
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
node: BlockDomInfo
|
||||
) {
|
||||
if (this.hideTimer) {
|
||||
window.clearTimeout(this.hideTimer);
|
||||
this.hideTimer = 0;
|
||||
private _handleMouseUp() {
|
||||
if (this._hideTimer) {
|
||||
window.clearTimeout(this._hideTimer);
|
||||
this._hideTimer = 0;
|
||||
}
|
||||
this.mousedown = false;
|
||||
this._mousedown = false;
|
||||
}
|
||||
|
||||
private _handleMouseDown = (
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
node: BlockDomInfo
|
||||
) => {
|
||||
this.mousedown = true;
|
||||
private _handleMouseDown = () => {
|
||||
this._mousedown = true;
|
||||
};
|
||||
|
||||
private _hideLeftMenu = (): void => {
|
||||
@@ -148,14 +152,14 @@ export class LeftMenuPlugin extends BasePlugin {
|
||||
};
|
||||
|
||||
protected override _onRender(): void {
|
||||
this.root = new PluginRenderRoot({
|
||||
this._root = new PluginRenderRoot({
|
||||
name: LeftMenuPlugin.pluginName,
|
||||
render: (...args) => {
|
||||
return this.editor.reactRenderRoot?.render(...args);
|
||||
},
|
||||
});
|
||||
this.root.mount();
|
||||
this.root.render(
|
||||
this._root.mount();
|
||||
this._root.render(
|
||||
<StrictMode>
|
||||
<LeftMenuDraggable
|
||||
key={Math.random() + ''}
|
||||
@@ -170,8 +174,7 @@ export class LeftMenuPlugin extends BasePlugin {
|
||||
}
|
||||
|
||||
public override dispose(): void {
|
||||
// TODO: rxjs
|
||||
this.root?.unmount();
|
||||
this._root?.unmount();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,13 +142,12 @@ export const ReferenceMenuContainer = ({
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
hooks.addHook(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE, handle_key_down);
|
||||
const sub = hooks
|
||||
.get(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE)
|
||||
.subscribe(handle_key_down);
|
||||
|
||||
return () => {
|
||||
hooks.removeHook(
|
||||
HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE,
|
||||
handle_key_down
|
||||
);
|
||||
sub.unsubscribe();
|
||||
};
|
||||
}, [hooks, handle_key_down]);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { MuiClickAwayListener } from '@toeverything/components/ui';
|
||||
import { Virgo, HookType, PluginHooks } from '@toeverything/framework/virgo';
|
||||
import { Point } from '@toeverything/utils';
|
||||
|
||||
import { ReferenceMenuContainer } from './container';
|
||||
import { ReferenceMenuContainer } from './Container';
|
||||
import { QueryBlocks, QueryResult } from '../../search';
|
||||
|
||||
export type ReferenceMenuProps = {
|
||||
@@ -87,15 +87,17 @@ export const ReferenceMenu = ({ editor, hooks, style }: ReferenceMenuProps) => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
hooks.addHook(HookType.ON_ROOT_NODE_KEYUP, handle_keyup);
|
||||
hooks.addHook(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE, handle_key_down);
|
||||
const sub = hooks
|
||||
.get(HookType.ON_ROOT_NODE_KEYUP)
|
||||
.subscribe(handle_keyup);
|
||||
sub.add(
|
||||
hooks
|
||||
.get(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE)
|
||||
.subscribe(handle_key_down)
|
||||
);
|
||||
|
||||
return () => {
|
||||
hooks.removeHook(HookType.ON_ROOT_NODE_KEYUP, handle_keyup);
|
||||
hooks.removeHook(
|
||||
HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE,
|
||||
handle_key_down
|
||||
);
|
||||
sub.unsubscribe();
|
||||
};
|
||||
}, [handle_keyup, handle_key_down, hooks]);
|
||||
|
||||
|
||||
@@ -3,30 +3,10 @@ import {
|
||||
styled,
|
||||
} from '@toeverything/components/ui';
|
||||
import { Protocol } from '@toeverything/datasource/db-service';
|
||||
import type {
|
||||
AsyncBlock,
|
||||
PluginHooks,
|
||||
Virgo,
|
||||
} from '@toeverything/framework/virgo';
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
type CSSProperties,
|
||||
} from 'react';
|
||||
import type { AsyncBlock, Virgo } from '@toeverything/framework/virgo';
|
||||
import { useEffect, useState, type CSSProperties } from 'react';
|
||||
|
||||
export type Store =
|
||||
| {
|
||||
editor: Virgo;
|
||||
hooks: PluginHooks;
|
||||
}
|
||||
| Record<string, never>;
|
||||
|
||||
export const StoreContext = createContext<Store>({});
|
||||
|
||||
export const MenuApp = () => {
|
||||
const { editor } = useContext(StoreContext);
|
||||
export const MenuApp = ({ editor }: { editor: Virgo }) => {
|
||||
const [show, setShow] = useState<boolean>(false);
|
||||
const [style, setStyle] = useState<CSSProperties>();
|
||||
const [selectedNodes, setSelectedNodes] = useState<AsyncBlock[]>([]);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { StrictMode } from 'react';
|
||||
import { BasePlugin } from '../../base-plugin';
|
||||
import { PluginRenderRoot } from '../../utils';
|
||||
import { MenuApp, StoreContext } from './MenuApp';
|
||||
import { MenuApp } from './MenuApp';
|
||||
|
||||
const PLUGIN_NAME = 'selection-group';
|
||||
|
||||
@@ -10,27 +10,23 @@ export class SelectionGroupPlugin extends BasePlugin {
|
||||
return PLUGIN_NAME;
|
||||
}
|
||||
|
||||
private root: PluginRenderRoot | undefined;
|
||||
private _root: PluginRenderRoot | undefined;
|
||||
|
||||
protected override _onRender() {
|
||||
this.root = new PluginRenderRoot({
|
||||
this._root = new PluginRenderRoot({
|
||||
name: SelectionGroupPlugin.pluginName,
|
||||
render: this.editor.reactRenderRoot?.render,
|
||||
});
|
||||
this.root.mount();
|
||||
this.root.render(
|
||||
this._root.mount();
|
||||
this._root.render(
|
||||
<StrictMode>
|
||||
<StoreContext.Provider
|
||||
value={{ editor: this.editor, hooks: this.hooks }}
|
||||
>
|
||||
<MenuApp />
|
||||
</StoreContext.Provider>
|
||||
<MenuApp editor={this.editor} />
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
public override dispose() {
|
||||
this.root?.unmount();
|
||||
this._root?.unmount();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ export class FullTextSearchPlugin extends BasePlugin {
|
||||
}
|
||||
|
||||
public override init(): void {
|
||||
this.hooks.addHook(HookType.ON_SEARCH, this.handle_search, this);
|
||||
this.sub.add(
|
||||
this.hooks.get(HookType.ON_SEARCH).subscribe(this._handleSearch)
|
||||
);
|
||||
}
|
||||
|
||||
protected override _onRender(): void {
|
||||
@@ -31,12 +33,13 @@ export class FullTextSearchPlugin extends BasePlugin {
|
||||
this.#root.unmount();
|
||||
// this.#root = undefined;
|
||||
}
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
private handle_search() {
|
||||
private _handleSearch = () => {
|
||||
this.editor.setHotKeysScope('search');
|
||||
this.render_search();
|
||||
}
|
||||
};
|
||||
private render_search() {
|
||||
if (this.#root) {
|
||||
this.#root.mount();
|
||||
|
||||
Reference in New Issue
Block a user