import { CacheManager, Disposable, DisposableCollection } from '@gedit/utils'; import type { EntityManager } from '../../common'; import { PlaygroundContext, PositionSchema } from '../../common'; import { PipelineEntities } from '../pipeline/pipeline-entities'; import { PipeEventName, PipelineDimension, PipeSupportEvent } from '../pipeline'; import { DOMCache, domUtils } from '@gedit/utils/lib/browser'; // import * as ReactDOM from 'react-dom'; import { createRoot } from 'react-dom/client'; import { PlaygroundCommandRegistry, PlaygroundKeybindingRegistry, PlaygroundMenuRegistry } from '../playground-registries'; import { SelectionService } from '@gedit/application-common'; import { PlaygroundDrag, PlaygroundDragEntitiesOpts } from '../utils'; import { PlaygroundConfigEntity } from './config'; import { Adsorber } from '../utils/adsorber'; import { FrontendApplicationStateService } from '@gedit/application-common/lib/browser'; /** * 基础layer */ export class Layer { id?: string; protected readonly toDispose = new DisposableCollection(); rootReact?: ReturnType; constructor() { this.toDispose.push(Disposable.create(() => { // ReactDOM.unmountComponentAtNode(this.node!); this.rootReact?.unmount(); this.rootReact = undefined; })); } /** * 命令注册器 */ commands: PlaygroundCommandRegistry; /** * 右键菜单注册器 */ menus: PlaygroundMenuRegistry; /** * 快捷键注册器 */ keybindings: PlaygroundKeybindingRegistry; /** * layer可能存在dom也可能没有, 如果有,则会加入到pipeline的dom节点上 */ node?: HTMLElement; /** * 父节点 */ pipelineNode: HTMLElement; /** * 注册的layer */ pipelineLayers: Layer[]; /** * 发送payload * @param payloadKey * @param payloadValue * @param cb - layer触发draw后的回调 */ dispatch

(payloadKey: string | Symbol, payloadValue: P, cb?: () => void): void { } /** * 当前layer的所有绑定的实体数据 */ entityBindedList: PipelineEntities; /** * 实体管理器 */ entityManager: EntityManager; /** * 绘制layer */ draw?(): void | React.JSX.Element /** * 全局选择 */ selectionService?: SelectionService; stateService?: FrontendApplicationStateService; /** * 由上层传入的上下文, 可被扩展使用 */ context: CONTEXT; /** * 监听playground上的事件 * 规则: * 1. 按priority排序,越高先执行 * 2. 没有提供,按layer的注册顺序,后注册先执行(符合冒泡排序) * 3. 执行返回true,则阻止后续的执行 */ listenPlaygroundEvent: (name: PipeEventName, handle: (event: PipeSupportEvent) => boolean | void, priority?: number) => Disposable; /** * 监听document上的事件 * 规则: * 1. 按priority排序,越高先执行 * 2. 没有提供,按layer的注册顺序,后注册先执行(符合冒泡排序) * 3. 执行返回true,则阻止后续的执行 */ listenGlobalEvent: (name: PipeEventName, handle: (event: PipeSupportEvent) => boolean | void, priority?: number) => Disposable; /** * 初始化时候触发 */ onReady?(): void /** * playground大小变化时候会触发 */ onResize?(size: PipelineDimension): void /** * playground focus时候触发 */ onFocus?(): void /** * playground blur时候触发 */ onBlur?(): void /** * 监听缩放 */ onZoom?(scale: number): void /** * 监听滚动 */ onScroll?(scroll: { scrollX: number, scrollY: number }): void /** * playground是否focused */ readonly isFocused: boolean; /** * 销毁 */ dispose(): void { this.toDispose.dispose(); } /** * 创建dom缓冲池 * @param className */ createDOMCache(className: string | (() => HTMLElement), children?: string): CacheManager { if (!this.node) throw new Error('DomCache need a parent dom node.'); return domUtils.createDOMCache(this.node, className, children); } /** * 加载layer注册的实体数据, 内部使用,不需要手动触发 * @return 数据是否变化 */ reloadEntities(): boolean { return false; } /** * 在画布上拖动实体 */ startDrag(clientX: number, clientY: number, opts: PlaygroundDragEntitiesOpts = {}): Disposable { const adsorbRefs = Adsorber.getRefsFromEntities(this.entityManager, opts.entities || [], this.config); return PlaygroundDrag.startDrag(clientX, clientY, { ...opts, adsorbRefs, config: this.config }); } /** * 全局画布配置 */ config: PlaygroundConfigEntity; /** * 获取鼠标在Playground的位置 */ getPosFromMouseEvent(event: { clientX: number, clientY: number }, addScale = true): PositionSchema { const pos = this.config.getPosFromMouseEvent(event, addScale); return { x: pos.x, y: pos.y, }; } } export interface LayerRegistry { new(): Layer, }