fix(editor): remove rootRect and modify layout

This commit is contained in:
austaras 2022-07-26 17:28:19 +08:00
parent 8b5e47ed73
commit b9f46028a8
21 changed files with 138 additions and 200 deletions

View File

@ -20,6 +20,7 @@ export function LigoVirgoRootContainer() {
const StyledMainContainer = styled('div')({ const StyledMainContainer = styled('div')({
flex: 'auto', flex: 'auto',
display: 'flex', display: 'flex',
overflowY: 'hidden',
}); });
const StyledRootContainer = styled('div')({ const StyledRootContainer = styled('div')({

View File

@ -55,7 +55,7 @@ export function Page(props: PageProps) {
); );
await services.api.editorBlock.clearUndoRedo(props.workspace); await services.api.editorBlock.clearUndoRedo(props.workspace);
}; };
update_recent_pages(); updateRecentPages();
}, [user, props.workspace, page_id]); }, [user, props.workspace, page_id]);
return ( return (
@ -89,7 +89,7 @@ export function Page(props: PageProps) {
title="Activities" title="Activities"
initialOpen={false} initialOpen={false}
> >
<Activities></Activities> <Activities />
</CollapsibleTitle> </CollapsibleTitle>
</div> </div>
<div> <div>
@ -102,25 +102,23 @@ export function Page(props: PageProps) {
</WorkspaceSidebar> </WorkspaceSidebar>
</LigoLeftContainer> </LigoLeftContainer>
<LigoRightContainer> <LigoRightContainer>
<LigoEditorOuterContainer> {page_id ? (
{page_id ? ( <AffineEditor
<AffineEditor workspace={props.workspace}
workspace={props.workspace} rootBlockId={page_id}
rootBlockId={page_id} />
/> ) : (
) : ( <Box
<Box sx={{
sx={{ display: 'flex',
display: 'flex', justifyContent: 'center',
justifyContent: 'center', alignItems: 'center',
alignItems: 'center', width: '100%',
width: '100%', }}
}} >
> <CircularProgress />
<CircularProgress /> </Box>
</Box> )}
)}
</LigoEditorOuterContainer>
</LigoRightContainer> </LigoRightContainer>
</LigoApp> </LigoApp>
); );
@ -128,7 +126,6 @@ export function Page(props: PageProps) {
const LigoApp = styled('div')({ const LigoApp = styled('div')({
width: '100vw', width: '100vw',
position: 'relative',
display: 'flex', display: 'flex',
flex: '1 1 0%', flex: '1 1 0%',
backgroundColor: 'white', backgroundColor: 'white',
@ -136,19 +133,11 @@ const LigoApp = styled('div')({
}); });
const LigoRightContainer = styled('div')({ const LigoRightContainer = styled('div')({
position: 'relative',
width: '100%', width: '100%',
overflowY: 'auto',
flex: 'auto', flex: 'auto',
}); });
const LigoEditorOuterContainer = styled('div')({
position: 'absolute',
height: '100%',
width: '100%',
overflowX: 'hidden',
overflowY: 'hidden',
});
const LigoLeftContainer = styled('div')({ const LigoLeftContainer = styled('div')({
flex: '0 0 auto', flex: '0 0 auto',
}); });

View File

@ -31,10 +31,8 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
editorElement, editorElement,
children, children,
}) => { }) => {
const contentRef = useRef<HTMLDivElement>(null);
const selectionRef = useRef<SelectionRef>(null); const selectionRef = useRef<SelectionRef>(null);
const triggeredBySelect = useRef(false); const triggeredBySelect = useRef(false);
const [container, setContainer] = useState<HTMLDivElement>();
const [pageWidth, setPageWidth] = useState<number>(MIN_PAGE_WIDTH); const [pageWidth, setPageWidth] = useState<number>(MIN_PAGE_WIDTH);
const isOnDrag = useIsOnDrag(editor); const isOnDrag = useIsOnDrag(editor);
@ -55,13 +53,6 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
} }
}, [editor.workspace, rootId]); }, [editor.workspace, rootId]);
useEffect(() => {
if (container) {
editor.container = container;
editor.getHooks().render();
}
}, [editor, container]);
useEffect(() => { useEffect(() => {
fetchPageBlockWidth(); fetchPageBlockWidth();
@ -85,11 +76,7 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
event: React.MouseEvent<HTMLDivElement, MouseEvent> event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => { ) => {
selectionRef.current?.onMouseMove(event); selectionRef.current?.onMouseMove(event);
if (!contentRef.current) { editor.getHooks().onRootNodeMouseMove(event);
return;
}
const rootRect: DOMRect = contentRef.current.getBoundingClientRect();
editor.getHooks().onRootNodeMouseMove(event, rootRect);
const slidingBlock = await editor.getBlockByPoint( const slidingBlock = await editor.getBlockByPoint(
new Point(event.clientX, event.clientY) new Point(event.clientX, event.clientY)
@ -100,7 +87,6 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
blockId: slidingBlock.id, blockId: slidingBlock.id,
dom: slidingBlock.dom, dom: slidingBlock.dom,
rect: slidingBlock.dom.getBoundingClientRect(), rect: slidingBlock.dom.getBoundingClientRect(),
rootRect: rootRect,
type: slidingBlock.type, type: slidingBlock.type,
properties: slidingBlock.getProperties(), properties: slidingBlock.getProperties(),
}); });
@ -149,33 +135,21 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
}; };
const onDragOver = (event: React.DragEvent<Element>) => { const onDragOver = (event: React.DragEvent<Element>) => {
event.dataTransfer.dropEffect = 'move';
event.preventDefault();
if (!contentRef.current) {
return;
}
const rootRect: DOMRect = contentRef.current.getBoundingClientRect();
editor.dragDropManager.handlerEditorDragOver(event); editor.dragDropManager.handlerEditorDragOver(event);
if (editor.dragDropManager.isEnabled()) { if (editor.dragDropManager.isEnabled()) {
editor.getHooks().onRootNodeDragOver(event, rootRect); editor.getHooks().onRootNodeDragOver(event);
} }
}; };
const onDragOverCapture = (event: React.DragEvent<Element>) => { const onDragOverCapture = (event: React.DragEvent<Element>) => {
event.preventDefault();
if (!contentRef.current) {
return;
}
const rootRect: DOMRect = contentRef.current.getBoundingClientRect();
if (editor.dragDropManager.isEnabled()) { if (editor.dragDropManager.isEnabled()) {
editor.getHooks().onRootNodeDragOver(event, rootRect); editor.getHooks().onRootNodeDragOver(event);
} }
}; };
const onDragEnd = (event: React.DragEvent<Element>) => { const onDragEnd = (event: React.DragEvent<Element>) => {
const rootRect: DOMRect = contentRef.current.getBoundingClientRect();
editor.dragDropManager.handlerEditorDragEnd(event); editor.dragDropManager.handlerEditorDragEnd(event);
editor.getHooks().onRootNodeDragEnd(event, rootRect); editor.getHooks().onRootNodeDragEnd(event);
}; };
const onDrop = (event: React.DragEvent<Element>) => { const onDrop = (event: React.DragEvent<Element>) => {
@ -192,7 +166,10 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
<Container <Container
isWhiteboard={editor.isWhiteboard} isWhiteboard={editor.isWhiteboard}
ref={ref => { ref={ref => {
ref && setContainer(ref); if (ref != null && ref !== editor.container) {
editor.container = ref;
editor.getHooks().render();
}
}} }}
onMouseMove={onMouseMove} onMouseMove={onMouseMove}
onMouseDown={onMouseDown} onMouseDown={onMouseDown}
@ -208,18 +185,13 @@ export const RenderRoot: FC<PropsWithChildren<RenderRootProps>> = ({
onDrop={onDrop} onDrop={onDrop}
isOnDrag={isOnDrag} isOnDrag={isOnDrag}
> >
<Content <Content style={{ maxWidth: pageWidth + 'px' }}>
ref={contentRef}
style={{ maxWidth: pageWidth + 'px' }}
>
{children} {children}
{patchedNodes}
</Content> </Content>
{/** TODO: remove selectionManager insert */} {/** TODO: remove selectionManager insert */}
{container && editor && ( {editor && <SelectionRect ref={selectionRef} editor={editor} />}
<SelectionRect ref={selectionRef} editor={editor} />
)}
{editor.isWhiteboard ? null : <ScrollBlank editor={editor} />} {editor.isWhiteboard ? null : <ScrollBlank editor={editor} />}
{patchedNodes}
</Container> </Container>
</RootContext.Provider> </RootContext.Provider>
); );
@ -281,6 +253,8 @@ function ScrollBlank({ editor }: { editor: BlockEditor }) {
); );
} }
const PADDING_X = 150;
const Container = styled('div')( const Container = styled('div')(
({ ({
isWhiteboard, isWhiteboard,
@ -290,9 +264,7 @@ const Container = styled('div')(
isOnDrag: boolean; isOnDrag: boolean;
}) => ({ }) => ({
width: '100%', width: '100%',
height: '100%', padding: isWhiteboard ? 0 : `96px ${PADDING_X}px 0 ${PADDING_X}px`,
overflowY: isWhiteboard ? 'unset' : 'auto',
padding: isWhiteboard ? 0 : '96px 150px 0 150px',
minWidth: isWhiteboard ? 'unset' : '940px', minWidth: isWhiteboard ? 'unset' : '940px',
position: 'relative', position: 'relative',
...(isOnDrag && { ...(isOnDrag && {
@ -309,7 +281,9 @@ const Content = styled('div')({
margin: '0 auto', margin: '0 auto',
transitionDuration: '.2s', transitionDuration: '.2s',
transitionTimingFunction: 'ease-in', transitionTimingFunction: 'ease-in',
position: 'relative',
}); });
const ScrollBlankContainter = styled('div')({ paddingBottom: '30vh' }); const ScrollBlankContainter = styled('div')({
paddingBottom: '30vh',
margin: `0 -${PADDING_X}px`,
});

View File

@ -1,8 +1,6 @@
import { AsyncBlock, BlockEditor } from '../editor'; import { AsyncBlock, BlockEditor } from '../editor';
import { ReactElement } from 'react'; import { ReactElement } from 'react';
export const dragDropWrapperClass = 'drag-drop-wrapper';
interface DragDropWrapperProps { interface DragDropWrapperProps {
editor: BlockEditor; editor: BlockEditor;
block: AsyncBlock; block: AsyncBlock;
@ -14,25 +12,16 @@ export function DragDropWrapper({
editor, editor,
block, block,
}: DragDropWrapperProps) { }: DragDropWrapperProps) {
const handler_drag_over: React.DragEventHandler< const handlerDragOver: React.DragEventHandler<HTMLDivElement> = event => {
HTMLDivElement if (block.dom) {
> = async event => {
event.preventDefault();
const rootDom = await editor.getBlockDomById(editor.getRootBlockId());
if (block.dom && rootDom) {
editor.getHooks().afterOnNodeDragOver(event, { editor.getHooks().afterOnNodeDragOver(event, {
blockId: block.id, blockId: block.id,
dom: block.dom, dom: block.dom,
rect: block.dom?.getBoundingClientRect(), rect: block.dom?.getBoundingClientRect(),
rootRect: rootDom.getBoundingClientRect(),
type: block.type, type: block.type,
properties: block.getProperties(), properties: block.getProperties(),
}); });
} }
}; };
return ( return <div onDragOver={handlerDragOver}>{children}</div>;
<div onDragOver={handler_drag_over} className={dragDropWrapperClass}>
{children}
</div>
);
} }

View File

@ -15,37 +15,37 @@ interface PluginHookInfo {
} }
export class Hooks implements HooksRunner, PluginHooks { export class Hooks implements HooksRunner, PluginHooks {
private hooks_map: Map<string, PluginHookInfo[]> = new Map(); private _hooksMap: Map<string, PluginHookInfo[]> = new Map();
dispose() { dispose() {
this.hooks_map.clear(); this._hooksMap.clear();
} }
private run_hook(key: HookType, ...params: unknown[]): void { private _runHook(key: HookType, ...params: unknown[]): void {
const hook_infos: PluginHookInfo[] = this.hooks_map.get(key) || []; const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
hook_infos.forEach(hook_info => { hookInfos.forEach(hookInfo => {
if (hook_info.once) { if (hookInfo.once) {
this.removeHook(key, hook_info.callback); this.removeHook(key, hookInfo.callback);
} }
let is_stopped_propagation = false; let isStoppedPropagation = false;
const hookOption: HookBaseArgs = { const hookOption: HookBaseArgs = {
stopImmediatePropagation: () => { stopImmediatePropagation: () => {
is_stopped_propagation = true; isStoppedPropagation = true;
}, },
}; };
hook_info.callback.call( hookInfo.callback.call(
hook_info.thisObj || this, hookInfo.thisObj || this,
...params, ...params,
hookOption hookOption
); );
return is_stopped_propagation; return isStoppedPropagation;
}); });
} }
private has_hook(key: HookType, callback: AnyFunction): boolean { private _hasHook(key: HookType, callback: AnyFunction): boolean {
const hook_infos: PluginHookInfo[] = this.hooks_map.get(key) || []; const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
for (let i = hook_infos.length - 1; i >= 0; i--) { for (let i = hookInfos.length - 1; i >= 0; i--) {
if (hook_infos[i].callback === callback) { if (hookInfos[i].callback === callback) {
return true; return true;
} }
} }
@ -59,14 +59,14 @@ export class Hooks implements HooksRunner, PluginHooks {
thisObj?: AnyThisType, thisObj?: AnyThisType,
once?: boolean once?: boolean
): void { ): void {
if (this.has_hook(key, callback)) { if (this._hasHook(key, callback)) {
throw new Error('Duplicate registration of the same class'); throw new Error('Duplicate registration of the same class');
} }
if (!this.hooks_map.has(key)) { if (!this._hooksMap.has(key)) {
this.hooks_map.set(key, []); this._hooksMap.set(key, []);
} }
const hook_infos: PluginHookInfo[] = this.hooks_map.get(key); const hookInfos: PluginHookInfo[] = this._hooksMap.get(key);
hook_infos.push({ callback, thisObj, once }); hookInfos.push({ callback, thisObj, once });
} }
// 执行一次 // 执行一次
@ -80,122 +80,112 @@ export class Hooks implements HooksRunner, PluginHooks {
// 移除 // 移除
public removeHook(key: HookType, callback: AnyFunction): void { public removeHook(key: HookType, callback: AnyFunction): void {
const hook_infos: PluginHookInfo[] = this.hooks_map.get(key) || []; const hookInfos: PluginHookInfo[] = this._hooksMap.get(key) || [];
for (let i = hook_infos.length - 1; i >= 0; i--) { for (let i = hookInfos.length - 1; i >= 0; i--) {
if (hook_infos[i].callback === callback) { if (hookInfos[i].callback === callback) {
hook_infos.splice(i, 1); hookInfos.splice(i, 1);
} }
} }
} }
public init(): void { public init(): void {
this.run_hook(HookType.INIT); this._runHook(HookType.INIT);
} }
public render(): void { public render(): void {
this.run_hook(HookType.RENDER); this._runHook(HookType.RENDER);
} }
public onRootNodeKeyDown(e: React.KeyboardEvent<HTMLDivElement>): void { public onRootNodeKeyDown(e: React.KeyboardEvent<HTMLDivElement>): void {
this.run_hook(HookType.ON_ROOT_NODE_KEYDOWN, e); this._runHook(HookType.ON_ROOT_NODE_KEYDOWN, e);
} }
public onRootNodeKeyDownCapture( public onRootNodeKeyDownCapture(
e: React.KeyboardEvent<HTMLDivElement> e: React.KeyboardEvent<HTMLDivElement>
): void { ): void {
this.run_hook(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE, e); this._runHook(HookType.ON_ROOT_NODE_KEYDOWN_CAPTURE, e);
} }
public onRootNodeKeyUp(e: React.KeyboardEvent<HTMLDivElement>): void { public onRootNodeKeyUp(e: React.KeyboardEvent<HTMLDivElement>): void {
this.run_hook(HookType.ON_ROOT_NODE_KEYUP, e); this._runHook(HookType.ON_ROOT_NODE_KEYUP, e);
} }
public onRootNodeMouseDown( public onRootNodeMouseDown(
e: React.MouseEvent<HTMLDivElement, MouseEvent> e: React.MouseEvent<HTMLDivElement, MouseEvent>
): void { ): void {
this.run_hook(HookType.ON_ROOTNODE_MOUSE_DOWN, e); this._runHook(HookType.ON_ROOTNODE_MOUSE_DOWN, e);
} }
public onRootNodeMouseMove( public onRootNodeMouseMove(
e: React.MouseEvent<HTMLDivElement, MouseEvent>, e: React.MouseEvent<HTMLDivElement, MouseEvent>
root_rect: DOMRect
): void { ): void {
this.run_hook(HookType.ON_ROOTNODE_MOUSE_MOVE, e, root_rect); this._runHook(HookType.ON_ROOTNODE_MOUSE_MOVE, e);
} }
public onRootNodeMouseUp( public onRootNodeMouseUp(
e: React.MouseEvent<HTMLDivElement, MouseEvent> e: React.MouseEvent<HTMLDivElement, MouseEvent>
): void { ): void {
this.run_hook(HookType.ON_ROOTNODE_MOUSE_UP, e); this._runHook(HookType.ON_ROOTNODE_MOUSE_UP, e);
} }
public onRootNodeMouseOut( public onRootNodeMouseOut(
e: React.MouseEvent<HTMLDivElement, MouseEvent> e: React.MouseEvent<HTMLDivElement, MouseEvent>
): void { ): void {
this.run_hook(HookType.ON_ROOTNODE_MOUSE_OUT, e); this._runHook(HookType.ON_ROOTNODE_MOUSE_OUT, e);
} }
public onRootNodeMouseLeave( public onRootNodeMouseLeave(
e: React.MouseEvent<HTMLDivElement, MouseEvent> e: React.MouseEvent<HTMLDivElement, MouseEvent>
): void { ): void {
this.run_hook(HookType.ON_ROOTNODE_MOUSE_LEAVE, e); this._runHook(HookType.ON_ROOTNODE_MOUSE_LEAVE, e);
} }
public afterOnNodeMouseMove( public afterOnNodeMouseMove(
e: React.MouseEvent<HTMLDivElement, MouseEvent>, e: React.MouseEvent<HTMLDivElement, MouseEvent>,
node: BlockDomInfo node: BlockDomInfo
): void { ): void {
this.run_hook(HookType.AFTER_ON_NODE_MOUSE_MOVE, e, node); this._runHook(HookType.AFTER_ON_NODE_MOUSE_MOVE, e, node);
} }
public afterOnResize( public afterOnResize(
e: React.MouseEvent<HTMLDivElement, MouseEvent> e: React.MouseEvent<HTMLDivElement, MouseEvent>
): void { ): void {
this.run_hook(HookType.AFTER_ON_RESIZE, e); this._runHook(HookType.AFTER_ON_RESIZE, e);
} }
public onRootNodeDragOver( public onRootNodeDragOver(e: React.DragEvent<Element>): void {
e: React.DragEvent<Element>, this._runHook(HookType.ON_ROOTNODE_DRAG_OVER, e);
root_rect: DOMRect
): void {
this.run_hook(HookType.ON_ROOTNODE_DRAG_OVER, e, root_rect);
} }
public onRootNodeDragEnd( public onRootNodeDragEnd(e: React.DragEvent<Element>): void {
e: React.DragEvent<Element>, this._runHook(HookType.ON_ROOTNODE_DRAG_END, e);
root_rect: DOMRect
): void {
this.run_hook(HookType.ON_ROOTNODE_DRAG_END, e, root_rect);
} }
public onRootNodeDrop(e: React.DragEvent<Element>): void { public onRootNodeDrop(e: React.DragEvent<Element>): void {
this.run_hook(HookType.ON_ROOTNODE_DROP, e); this._runHook(HookType.ON_ROOTNODE_DROP, e);
} }
public onRootNodeDragOverCapture( public onRootNodeDragOverCapture(e: React.DragEvent<Element>): void {
e: React.DragEvent<Element>, this._runHook(HookType.ON_ROOTNODE_DRAG_OVER_CAPTURE, e);
root_rect: DOMRect
): void {
this.run_hook(HookType.ON_ROOTNODE_DRAG_OVER_CAPTURE, e, root_rect);
} }
public afterOnNodeDragOver( public afterOnNodeDragOver(
e: React.DragEvent<Element>, e: React.DragEvent<Element>,
node: BlockDomInfo node: BlockDomInfo
): void { ): void {
this.run_hook(HookType.AFTER_ON_NODE_DRAG_OVER, e, node); this._runHook(HookType.AFTER_ON_NODE_DRAG_OVER, e, node);
} }
public onSearch(): void { public onSearch(): void {
this.run_hook(HookType.ON_SEARCH); this._runHook(HookType.ON_SEARCH);
} }
public beforeCopy(e: ClipboardEvent): void { public beforeCopy(e: ClipboardEvent): void {
this.run_hook(HookType.BEFORE_COPY, e); this._runHook(HookType.BEFORE_COPY, e);
} }
public beforeCut(e: ClipboardEvent): void { public beforeCut(e: ClipboardEvent): void {
this.run_hook(HookType.BEFORE_CUT, e); this._runHook(HookType.BEFORE_CUT, e);
} }
public onRootNodeScroll(e: React.UIEvent): void { public onRootNodeScroll(e: React.UIEvent): void {

View File

@ -186,7 +186,6 @@ export interface BlockDomInfo {
dom: HTMLElement; dom: HTMLElement;
type: BlockFlavorKeys; type: BlockFlavorKeys;
rect: DOMRect; rect: DOMRect;
rootRect: DOMRect;
properties: Record<string, unknown>; properties: Record<string, unknown>;
} }
@ -201,8 +200,7 @@ export interface HooksRunner {
e: React.MouseEvent<HTMLDivElement, MouseEvent> e: React.MouseEvent<HTMLDivElement, MouseEvent>
) => void; ) => void;
onRootNodeMouseMove: ( onRootNodeMouseMove: (
e: React.MouseEvent<HTMLDivElement, MouseEvent>, e: React.MouseEvent<HTMLDivElement, MouseEvent>
root_rect: DOMRect
) => void; ) => void;
onRootNodeMouseUp: ( onRootNodeMouseUp: (
e: React.MouseEvent<HTMLDivElement, MouseEvent> e: React.MouseEvent<HTMLDivElement, MouseEvent>
@ -219,14 +217,8 @@ export interface HooksRunner {
node: BlockDomInfo node: BlockDomInfo
) => void; ) => void;
afterOnResize: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void; afterOnResize: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
onRootNodeDragOver: ( onRootNodeDragOver: (e: React.DragEvent<Element>) => void;
e: React.DragEvent<Element>, onRootNodeDragEnd: (e: React.DragEvent<Element>) => void;
root_rect: DOMRect
) => void;
onRootNodeDragEnd: (
e: React.DragEvent<Element>,
root_rect: DOMRect
) => void;
onRootNodeDrop: (e: React.DragEvent<Element>) => void; onRootNodeDrop: (e: React.DragEvent<Element>) => void;
afterOnNodeDragOver: ( afterOnNodeDragOver: (
e: React.DragEvent<Element>, e: React.DragEvent<Element>,

View File

@ -41,8 +41,8 @@ export abstract class BasePlugin implements Plugin {
return hooks.removeHook(...args); return hooks.removeHook(...args);
}, },
}; };
this.on_render = this.on_render.bind(this); this._onRender = this._onRender.bind(this);
hooks.addHook(HookType.RENDER, this.on_render, this); hooks.addHook(HookType.RENDER, this._onRender, this);
} }
/** /**
@ -55,7 +55,7 @@ export abstract class BasePlugin implements Plugin {
/** /**
* will trigger multiple times * will trigger multiple times
*/ */
protected on_render(): void { protected _onRender(): void {
// implement in subclass // implement in subclass
} }

View File

@ -60,7 +60,7 @@ export class BlockPropertyPlugin extends BasePlugin {
); );
}; };
protected override on_render(): void { protected override _onRender(): void {
this.hooks.addHook( this.hooks.addHook(
HookType.AFTER_ON_NODE_MOUSE_MOVE, HookType.AFTER_ON_NODE_MOUSE_MOVE,
this.on_mouse_move, this.on_mouse_move,

View File

@ -12,7 +12,7 @@ export class AddCommentPlugin extends BasePlugin {
private root: PluginRenderRoot; private root: PluginRenderRoot;
protected override on_render(): void { protected override _onRender(): void {
this.root = new PluginRenderRoot({ this.root = new PluginRenderRoot({
name: AddCommentPlugin.pluginName, name: AddCommentPlugin.pluginName,
render: this.editor.reactRenderRoot?.render, render: this.editor.reactRenderRoot?.render,

View File

@ -14,8 +14,7 @@ export class CommandMenuPlugin extends BasePlugin {
return PLUGIN_NAME; return PLUGIN_NAME;
} }
protected override on_render(): void { protected override _onRender(): void {
if (this.editor.isWhiteboard) return;
const container = document.createElement('div'); const container = document.createElement('div');
// TODO remove // TODO remove
container.classList.add(`id-${PLUGIN_NAME}`); container.classList.add(`id-${PLUGIN_NAME}`);

View File

@ -4,7 +4,7 @@ import {
PluginHooks, PluginHooks,
Virgo, Virgo,
} from '@toeverything/components/editor-core'; } from '@toeverything/components/editor-core';
import { domToRect, Point } from '@toeverything/utils'; import { Point } from '@toeverything/utils';
import { GroupDirection } from '@toeverything/framework/virgo'; import { GroupDirection } from '@toeverything/framework/virgo';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import { DragItem } from './DragItem'; import { DragItem } from './DragItem';
@ -46,7 +46,7 @@ export const GroupMenu = function ({ editor, hooks }: GroupMenuProps) {
setShowMenu(false); setShowMenu(false);
} }
}, },
[setShowMenu] []
); );
const handleRootDragOver = useCallback( const handleRootDragOver = useCallback(
@ -128,8 +128,8 @@ export const GroupMenu = function ({ editor, hooks }: GroupMenuProps) {
if (editor.container) { if (editor.container) {
setPosition( setPosition(
new Point( new Point(
groupBlock.dom.offsetLeft - editor.container.offsetLeft, groupBlock.dom.offsetLeft,
groupBlock.dom.offsetTop - editor.container.offsetTop groupBlock.dom.offsetTop
) )
); );
} }

View File

@ -22,9 +22,9 @@ export const Line = function ({ direction, editor, groupBlock }: LineProps) {
if (groupBlock && groupBlock.dom && editor.container) { if (groupBlock && groupBlock.dom && editor.container) {
setRect( setRect(
Rect.fromLWTH( Rect.fromLWTH(
groupBlock.dom.offsetLeft - editor.container.offsetLeft, groupBlock.dom.offsetLeft,
groupBlock.dom.offsetWidth, groupBlock.dom.offsetWidth,
groupBlock.dom.offsetTop - editor.container.offsetTop, groupBlock.dom.offsetTop,
groupBlock.dom.offsetHeight groupBlock.dom.offsetHeight
) )
); );

View File

@ -13,7 +13,7 @@ export class GroupMenuPlugin extends BasePlugin {
return PLUGIN_NAME; return PLUGIN_NAME;
} }
protected override on_render(): void { protected override _onRender(): void {
if (this.editor.isWhiteboard) return; if (this.editor.isWhiteboard) return;
this.root = new PluginRenderRoot({ this.root = new PluginRenderRoot({
name: PLUGIN_NAME, name: PLUGIN_NAME,

View File

@ -12,7 +12,7 @@ export class InlineMenuPlugin extends BasePlugin {
private root: PluginRenderRoot; private root: PluginRenderRoot;
protected override on_render(): void { protected override _onRender(): void {
this.root = new PluginRenderRoot({ this.root = new PluginRenderRoot({
name: InlineMenuPlugin.pluginName, name: InlineMenuPlugin.pluginName,
render: this.editor.reactRenderRoot?.render, render: this.editor.reactRenderRoot?.render,

View File

@ -39,8 +39,8 @@ type LineInfo = {
blockInfo: BlockDomInfo; blockInfo: BlockDomInfo;
}; };
function Line(props: { lineInfo: LineInfo }) { function Line(props: { lineInfo: LineInfo; rootRect: DOMRect }) {
const { lineInfo } = props; const { lineInfo, rootRect } = props;
if (!lineInfo || lineInfo.direction === BlockDropPlacement.none) { if (!lineInfo || lineInfo.direction === BlockDropPlacement.none) {
return null; return null;
} }
@ -58,7 +58,7 @@ function Line(props: { lineInfo: LineInfo }) {
...lineStyle, ...lineStyle,
width: intersectionRect.width, width: intersectionRect.width,
height: 2, height: 2,
left: intersectionRect.x - blockInfo.rootRect.x, left: intersectionRect.x - rootRect.x,
}; };
const topLineStyle = { const topLineStyle = {
...horizontalLineStyle, ...horizontalLineStyle,
@ -66,22 +66,22 @@ function Line(props: { lineInfo: LineInfo }) {
}; };
const bottomLineStyle = { const bottomLineStyle = {
...horizontalLineStyle, ...horizontalLineStyle,
top: intersectionRect.bottom + 1 - blockInfo.rootRect.y, top: intersectionRect.bottom + 1 - rootRect.y,
}; };
const verticalLineStyle = { const verticalLineStyle = {
...lineStyle, ...lineStyle,
width: 2, width: 2,
height: intersectionRect.height, height: intersectionRect.height,
top: intersectionRect.y - blockInfo.rootRect.y, top: intersectionRect.y - rootRect.y,
}; };
const leftLineStyle = { const leftLineStyle = {
...verticalLineStyle, ...verticalLineStyle,
left: intersectionRect.x - 10 - blockInfo.rootRect.x, left: intersectionRect.x - 10 - rootRect.x,
}; };
const rightLineStyle = { const rightLineStyle = {
...verticalLineStyle, ...verticalLineStyle,
left: intersectionRect.right + 10 - blockInfo.rootRect.x, left: intersectionRect.right + 10 - rootRect.x,
}; };
const styleMap = { const styleMap = {
left: leftLineStyle, left: leftLineStyle,
@ -120,6 +120,7 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
const [visible, setVisible] = useState(defaultVisible); const [visible, setVisible] = useState(defaultVisible);
const [anchorEl, setAnchorEl] = useState<Element>(); const [anchorEl, setAnchorEl] = useState<Element>();
const [rootRect, setRootRect] = useState(() => new DOMRect());
const [block, setBlock] = useState<BlockDomInfo | undefined>(); const [block, setBlock] = useState<BlockDomInfo | undefined>();
const [line, setLine] = useState<LineInfo | undefined>(undefined); const [line, setLine] = useState<LineInfo | undefined>(undefined);
@ -135,6 +136,7 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
const onDragStart = async (event: React.DragEvent<Element>) => { const onDragStart = async (event: React.DragEvent<Element>) => {
editor.dragDropManager.isOnDrag = true; editor.dragDropManager.isOnDrag = true;
if (block == null) return; if (block == null) return;
setRootRect(editor.container.getBoundingClientRect());
const dragImage = await editor.blockHelper.getBlockDragImg( const dragImage = await editor.blockHelper.getBlockDragImg(
block.blockId block.blockId
); );
@ -182,6 +184,7 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
const sub = blockInfo.subscribe(block => { const sub = blockInfo.subscribe(block => {
setBlock(block); setBlock(block);
if (block != null) { if (block != null) {
setRootRect(editor.container.getBoundingClientRect());
setVisible(true); setVisible(true);
} }
}); });
@ -194,6 +197,7 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
setLine(undefined); setLine(undefined);
} else { } else {
const { direction, blockInfo } = data; const { direction, blockInfo } = data;
setRootRect(editor.container.getBoundingClientRect());
setLine(prev => { setLine(prev => {
if ( if (
prev?.blockInfo.blockId !== blockInfo.blockId || prev?.blockInfo.blockId !== blockInfo.blockId ||
@ -210,7 +214,7 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
} }
}); });
return () => sub.unsubscribe(); return () => sub.unsubscribe();
}, [editor.dragDropManager, lineInfo]); }, [editor, lineInfo]);
return ( return (
<> <>
@ -223,8 +227,8 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
block.rect.left - block.rect.left -
MENU_WIDTH - MENU_WIDTH -
MENU_BUTTON_OFFSET MENU_BUTTON_OFFSET
) - block.rootRect.left, ) - rootRect.left,
top: block.rect.top - block.rootRect.top, top: block.rect.top - rootRect.top,
opacity: visible ? 1 : 0, opacity: visible ? 1 : 0,
zIndex: 1, zIndex: 1,
}} }}
@ -246,7 +250,7 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
} }
</DragComponent> </DragComponent>
)} )}
<Line lineInfo={line} /> <Line lineInfo={line} rootRect={rootRect} />
</> </>
); );
}; };

View File

@ -147,7 +147,7 @@ export class LeftMenuPlugin extends BasePlugin {
this._blockInfo.next(blockInfo); this._blockInfo.next(blockInfo);
}; };
protected override on_render(): void { protected override _onRender(): void {
this.root = new PluginRenderRoot({ this.root = new PluginRenderRoot({
name: LeftMenuPlugin.pluginName, name: LeftMenuPlugin.pluginName,
render: (...args) => { render: (...args) => {

View File

@ -13,7 +13,7 @@ export class ReferenceMenuPlugin extends BasePlugin {
return PLUGIN_NAME; return PLUGIN_NAME;
} }
protected override on_render(): void { protected override _onRender(): void {
const container = document.createElement('div'); const container = document.createElement('div');
// TODO: remove // TODO: remove
container.classList.add(`id-${PLUGIN_NAME}`); container.classList.add(`id-${PLUGIN_NAME}`);

View File

@ -12,7 +12,7 @@ export class SelectionGroupPlugin extends BasePlugin {
private root: PluginRenderRoot | undefined; private root: PluginRenderRoot | undefined;
protected override on_render() { protected override _onRender() {
this.root = new PluginRenderRoot({ this.root = new PluginRenderRoot({
name: SelectionGroupPlugin.pluginName, name: SelectionGroupPlugin.pluginName,
render: this.editor.reactRenderRoot?.render, render: this.editor.reactRenderRoot?.render,

View File

@ -12,7 +12,7 @@ export class PlaceholderPlugin extends BasePlugin {
return PLUGIN_NAME; return PLUGIN_NAME;
} }
protected override on_render(): void { protected override _onRender(): void {
const container = document.createElement('div'); const container = document.createElement('div');
// TODO remove // TODO remove
container.classList.add(`id-${PLUGIN_NAME}`); container.classList.add(`id-${PLUGIN_NAME}`);

View File

@ -6,12 +6,12 @@ export type UnPatchNode = () => void;
export type PatchNode = (key: string, node: ReactNode) => UnPatchNode; export type PatchNode = (key: string, node: ReactNode) => UnPatchNode;
export const usePatchNodes = () => { export const usePatchNodes = () => {
const [nodes, set_nodes] = useState<Record<string, ReactNode>>({}); const [nodes, setNodes] = useState<Record<string, ReactNode>>({});
const patch_node: PatchNode = (key: string, node: ReactNode) => { const patchNode: PatchNode = (key: string, node: ReactNode) => {
set_nodes(oldNodes => ({ ...oldNodes, [key]: node })); setNodes(oldNodes => ({ ...oldNodes, [key]: node }));
return () => { return () => {
set_nodes(oldNodes => { setNodes(oldNodes => {
const nodes = { ...oldNodes }; const nodes = { ...oldNodes };
delete nodes[key]; delete nodes[key];
return nodes; return nodes;
@ -19,11 +19,11 @@ export const usePatchNodes = () => {
}; };
}; };
const has_node = (key: string) => { const hasNode = (key: string) => {
return has(nodes, key); return has(nodes, key);
}; };
const patched_nodes = ( const patchedNodes = (
<> <>
{Object.entries(nodes).map(([key, node]) => { {Object.entries(nodes).map(([key, node]) => {
return <Fragment key={key}>{node}</Fragment>; return <Fragment key={key}>{node}</Fragment>;
@ -32,8 +32,8 @@ export const usePatchNodes = () => {
); );
return { return {
patch: patch_node, patch: patchNode,
has: has_node, has: hasNode,
patchedNodes: patched_nodes, patchedNodes: patchedNodes,
}; };
}; };

View File

@ -27,8 +27,8 @@ export { message } from './message';
export { Input } from './input'; export { Input } from './input';
export type { InputProps } from './input'; export type { InputProps } from './input';
export { Tooltip } from './tooltip'; export { Tooltip } from './tooltip';
export { usePatchNodes } from './patch-elements'; export { usePatchNodes } from './PatchElements';
export type { PatchNode, UnPatchNode } from './patch-elements'; export type { PatchNode, UnPatchNode } from './PatchElements';
export { Tag } from './tag'; export { Tag } from './tag';
export type { TagProps } from './tag'; export type { TagProps } from './tag';
export { Divider } from './divider'; export { Divider } from './divider';