diff --git a/packages/designer/src/builtins/simulator/host/host.ts b/packages/designer/src/builtins/simulator/host/host.ts index 11e9688b5..56a571eab 100644 --- a/packages/designer/src/builtins/simulator/host/host.ts +++ b/packages/designer/src/builtins/simulator/host/host.ts @@ -1,5 +1,5 @@ import { obx, autorun, computed } from '@recore/obx'; -import { ISimulator, ComponentInstance, Component } from '../../../designer/simulator'; +import { ISimulator, ComponentInstance, Component, NodeInstance } from '../../../designer/simulator'; import Viewport from './viewport'; import { createSimulator } from './create-simulator'; import { SimulatorRenderer } from '../renderer/renderer'; @@ -12,6 +12,8 @@ import { LocationData } from '../../../designer/helper/location'; import { NodeData } from '../../../designer/schema'; import { ComponentDescriptionSpec } from '../../../designer/component-config'; import { ReactInstance } from 'react'; +import { setNativeSelection } from '../../../utils/navtive-selection'; +import cursor from '../../../designer/helper/cursor'; export interface SimulatorProps { // 从 documentModel 上获取 @@ -50,6 +52,7 @@ const defaultDepends = [ ]; export class SimulatorHost implements ISimulator { + readonly isSimulator = true; constructor(readonly document: DocumentModel) {} readonly designer = this.document.designer; @@ -126,6 +129,7 @@ export class SimulatorHost implements ISimulator { get contentWindow() { return this._contentWindow; } + @obx.ref private _contentDocument?: Document; get contentDocument() { return this._contentDocument; @@ -192,8 +196,8 @@ export class SimulatorHost implements ISimulator { // TODO: think of lock when edit a node // 事件路由 doc.addEventListener('mousedown', (downEvent: MouseEvent) => { - const target = documentModel.getNodeFromElement(downEvent.target as Element); - if (!target) { + const nodeInst = documentModel.getNodeInstanceFromElement(downEvent.target as Element); + if (!nodeInst?.node) { selection.clear(); return; } @@ -202,7 +206,7 @@ export class SimulatorHost implements ISimulator { const isLeftButton = downEvent.which === 1 || downEvent.button === 0; if (isLeftButton) { - let node: Node = target; + let node: Node = nodeInst.node; let nodes: Node[] = [node]; let ignoreUpSelected = false; if (isMulti) { @@ -214,7 +218,7 @@ export class SimulatorHost implements ISimulator { } // 获得顶层 nodes nodes = selection.getTopNodes(); - } else if (selection.containsNode(target)) { + } else if (selection.containsNode(node)) { nodes = selection.getTopNodes(); } else { // will clear current selection & select dragment in dragstart @@ -236,7 +240,7 @@ export class SimulatorHost implements ISimulator { doc.removeEventListener('mouseup', checkSelect, true); if (!isShaken(downEvent, e)) { // const node = hasConditionFlow(target) ? target.conditionFlow : target; - const node = target; + const node = nodeInst.node!; const id = node.id; designer.activeTracker.track(node); if (isMulti && selection.has(id)) { @@ -252,6 +256,7 @@ export class SimulatorHost implements ISimulator { // cause edit doc.addEventListener('dblclick', (e: MouseEvent) => { // TODO: + }); } @@ -266,9 +271,9 @@ export class SimulatorHost implements ISimulator { if (!hovering.enable) { return; } - const node = this.document.getNodeFromElement(e.target as Element); + const nodeInst = this.document.getNodeInstanceFromElement(e.target as Element); // TODO: enhance only hover one instance - hovering.hover(node); + hovering.hover(nodeInst?.node || null); e.stopPropagation(); }; const leave = () => hovering.leave(this.document); @@ -293,15 +298,6 @@ export class SimulatorHost implements ISimulator { }; } - setDraggingState(state: boolean): void { - throw new Error('Method not implemented.'); - } - isDraggingState(): boolean { - throw new Error('Method not implemented.'); - } - setCopyState(state: boolean): void { - throw new Error('Method not implemented.'); - } setSuspense(suspended: boolean) { if (suspended) { if (this.disableHovering) { @@ -315,15 +311,10 @@ export class SimulatorHost implements ISimulator { } } } + setDesignMode(mode: string): void { throw new Error('Method not implemented.'); } - isCopyState(): boolean { - throw new Error('Method not implemented.'); - } - clearState(): void { - throw new Error('Method not implemented.'); - } describeComponent(component: Component): ComponentDescriptionSpec { throw new Error('Method not implemented.'); @@ -345,8 +336,8 @@ export class SimulatorHost implements ISimulator { throw new Error('Method not implemented.'); } - getClosestNodeId(elem: Element): string | null { - return this.renderer?.getClosestNodeId(elem) || null; + getClosestNodeInstance(elem: Element): NodeInstance | null { + return this.renderer?.getClosestNodeInstance(elem) || null; } computeComponentInstanceRect(instance: ReactInstance): DOMRect | null { @@ -459,6 +450,20 @@ export class SimulatorHost implements ISimulator { } } + // #region ========= drag and drop helpers ============= + setNativeSelection(enableFlag: boolean) { + setNativeSelection(enableFlag); + } + setDraggingState(state: boolean) { + cursor.setDragging(state); + } + setCopyState(state: boolean) { + cursor.setCopy(state); + } + clearState() { + cursor.release(); + } + fixEvent(e: LocateEvent): LocateEvent { /* if (e.fixed) { @@ -483,7 +488,7 @@ export class SimulatorHost implements ISimulator { this.scroller.cancel(); } - //#region drag locate logic + // ========= drag location logic start ========== getDropTarget(e: LocateEvent): NodeParent | LocationData | null { /* const { target, dragTarget } = e; @@ -841,5 +846,5 @@ export class SimulatorHost implements ISimulator { }*/ return false; } - //#endregion + // #endregion } diff --git a/packages/designer/src/builtins/simulator/renderer/renderer.ts b/packages/designer/src/builtins/simulator/renderer/renderer.ts index ccf6f95aa..22380d8d2 100644 --- a/packages/designer/src/builtins/simulator/renderer/renderer.ts +++ b/packages/designer/src/builtins/simulator/renderer/renderer.ts @@ -9,6 +9,8 @@ import { Asset } from '../utils/asset'; import loader from '../utils/loader'; import { ComponentDescriptionSpec } from '../../../designer/component-config'; import { findDOMNodes } from '../utils/react'; +import { isESModule } from '../../../utils/is-es-module'; +import { NodeInstance } from '../../../designer/simulator'; let REACT_KEY = ''; function cacheReactKey(el: Element): Element { @@ -24,28 +26,36 @@ function cacheReactKey(el: Element): Element { const SYMBOL_VNID = Symbol('_LCNodeId'); -function getClosestNodeId(element: Element): string | null { +function getClosestNodeInstance(element: Element): NodeInstance | null { let el: any = element; if (el) { el = cacheReactKey(el); } while (el) { if (SYMBOL_VNID in el) { - return el[SYMBOL_VNID]; + return { + nodeId: el[SYMBOL_VNID], + instance: el, + }; } + // get fiberNode from element if (el[REACT_KEY]) { - return getNodeId(el[REACT_KEY]); + return getNodeInstance(el[REACT_KEY]); } el = el.parentElement; } return null; } -function getNodeId(instance: any): string { - if (instance.stateNode && SYMBOL_VNID in instance.stateNode) { - return instance.stateNode[SYMBOL_VNID]; +function getNodeInstance(fiberNode: any): NodeInstance | null { + const instance = fiberNode.stateNode; + if (instance && SYMBOL_VNID in instance) { + return { + nodeId: instance[SYMBOL_VNID], + instance, + }; } - return getNodeId(instance.return); + return getNodeInstance(fiberNode.return); } function checkInstanceMounted(instance: any): boolean { @@ -190,8 +200,8 @@ export class SimulatorRenderer { return this.instancesMap.get(id) || null; } - getClosestNodeId(element: Element): string | null { - return getClosestNodeId(element); + getClosestNodeInstance(element: Element): NodeInstance | null { + return getClosestNodeInstance(element); } findDOMNodes(instance: ReactInstance): Array | null { @@ -228,22 +238,31 @@ function accessLibrary(library: string | object) { return (window as any)[library]; } -function getSubComponent(component: any, paths: string[]) { +function getSubComponent(library: any, paths: string[]) { const l = paths.length; - if (l < 1) { - return component; + if (l < 1 || !library) { + return library; } let i = 0; + let component: any; while (i < l) { const key = paths[i]!; + let ex: any; try { - component = (component as any)[key]; + component = library[key]; } catch (e) { + ex = e; + component = null; + } + if (i === 0 && component == null && key === 'default') { + if (ex) { + return l === 1 ? library : null; + } + component = library; + } else if (component == null) { return null; } - if (!component) { - return null; - } + library = component; i++; } return component; @@ -253,13 +272,21 @@ function findComponent(componentName: string, npm?: NpmInfo) { if (!npm) { return accessLibrary(componentName); } + // libraryName the key access to global + // export { exportName } from xxx exportName === global.libraryName.exportName + // export exportName from xxx exportName === global.libraryName.default || global.libraryName + // export { exportName as componentName } from package + // if exportName == null exportName === componentName; + // const componentName = exportName.subName, if exportName empty subName donot use const libraryName = npm.exportName || npm.componentName || componentName; - const component = accessLibrary(libraryName); - const paths = npm.subName ? npm.subName.split('.') : []; + const library = accessLibrary(libraryName); + const paths = npm.exportName && npm.subName ? npm.subName.split('.') : []; if (npm.destructuring) { paths.unshift(libraryName); + } else if (isESModule(library)) { + paths.unshift('default'); } - return getSubComponent(component, paths); + return getSubComponent(library, paths); } function buildComponents(componentsMap: { [componentName: string]: ComponentDescriptionSpec }) { diff --git a/packages/designer/src/builtins/simulator/utils/cursor.less b/packages/designer/src/builtins/simulator/utils/cursor.less deleted file mode 100644 index 178e8b5c6..000000000 --- a/packages/designer/src/builtins/simulator/utils/cursor.less +++ /dev/null @@ -1,15 +0,0 @@ -html.my-cursor-dragging, html.my-cursor-dragging * { - cursor: move !important -} - -html.my-cursor-x-resizing, html.my-cursor-x-resizing * { - cursor: col-resize; -} - -html.my-cursor-y-resizing, html.my-cursor-y-resizing * { - cursor: row-resize; -} - -html.my-cursor-copy, html.my-cursor-copy * { - cursor: copy !important -} diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 0cbded379..31656d56d 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -12,7 +12,7 @@ import Node, { insertChildren } from './document/node/node'; import { isRootNode } from './document/node/root-node'; import { ComponentDescriptionSpec, ComponentConfig } from './component-config'; import Scroller, { IScrollable } from './helper/scroller'; -import { INodeInstance } from './simulator'; +import { INodeSelector } from './simulator'; import OffsetObserver, { createOffsetObserver } from './helper/offset-observer'; export interface DesignerProps { @@ -96,7 +96,7 @@ export default class Designer { private _dropLocation?: Location; /** - * 创建插入位置 + * 创建插入位置,考虑放到 dragon 中 */ createLocation(locationData: LocationData): Location { const loc = new Location(locationData); @@ -109,7 +109,7 @@ export default class Designer { /** * 清除插入位置 */ - private clearLocation() { + clearLocation() { if (this._dropLocation) { this._dropLocation.document.internalSetDropLocation(null); } @@ -120,7 +120,7 @@ export default class Designer { return new Scroller(scrollable); } - createOffsetObserver(nodeInstance: INodeInstance): OffsetObserver | null { + createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null { return createOffsetObserver(nodeInstance); } diff --git a/packages/designer/src/designer/document/document-model.ts b/packages/designer/src/designer/document/document-model.ts index 40d8ee2bd..7e2076d17 100644 --- a/packages/designer/src/designer/document/document-model.ts +++ b/packages/designer/src/designer/document/document-model.ts @@ -3,7 +3,7 @@ import { RootSchema, NodeData, isDOMText, isJSExpression, NodeSchema } from '../ import Node, { isNodeParent, insertChildren, insertChild, NodeParent } from './node/node'; import { Selection } from './selection'; import RootNode from './node/root-node'; -import { ISimulator, ComponentInstance, Component } from '../simulator'; +import { ISimulator, ComponentInstance, Component, NodeInstance } from '../simulator'; import { computed, obx } from '@recore/obx'; import Location from '../helper/location'; import { ComponentConfig } from '../component-config'; @@ -245,16 +245,20 @@ export default class DocumentModel { /** * 通过 DOM 节点获取节点,依赖 simulator 的接口 */ - getNodeFromElement(target: Element | null): Node | null { + getNodeInstanceFromElement(target: Element | null): NodeInstance | null { if (!this.simulator || !target) { return null; } - const id = this.simulator.getClosestNodeId(target); - if (!id) { + const nodeIntance = this.simulator.getClosestNodeInstance(target); + if (!nodeIntance) { return null; } - return this.getNode(id) as Node; + const node = this.getNode(nodeIntance.nodeId); + return { + ...nodeIntance, + node, + }; } /** diff --git a/packages/designer/src/designer/helper/cursor.less b/packages/designer/src/designer/helper/cursor.less new file mode 100644 index 000000000..a451db895 --- /dev/null +++ b/packages/designer/src/designer/helper/cursor.less @@ -0,0 +1,15 @@ +html.lc-cursor-dragging, html.lc-cursor-dragging * { + cursor: move !important +} + +html.lc-cursor-x-resizing, html.lc-cursor-x-resizing * { + cursor: col-resize; +} + +html.lc-cursor-y-resizing, html.lc-cursor-y-resizing * { + cursor: row-resize; +} + +html.lc-cursor-copy, html.lc-cursor-copy * { + cursor: copy !important +} diff --git a/packages/designer/src/builtins/simulator/utils/cursor.ts b/packages/designer/src/designer/helper/cursor.ts similarity index 89% rename from packages/designer/src/builtins/simulator/utils/cursor.ts rename to packages/designer/src/designer/helper/cursor.ts index a738d7b8e..698a398fd 100644 --- a/packages/designer/src/builtins/simulator/utils/cursor.ts +++ b/packages/designer/src/designer/helper/cursor.ts @@ -45,14 +45,14 @@ export class Cursor { private addState(state: string) { if (!this.states.has(state)) { this.states.add(state); - document.documentElement.classList.add(`my-cursor-${state}`); + document.documentElement.classList.add(`lc-cursor-${state}`); } } private removeState(state: string) { if (this.states.has(state)) { this.states.delete(state); - document.documentElement.classList.remove(`my-cursor-${state}`); + document.documentElement.classList.remove(`lc-cursor-${state}`); } } } diff --git a/packages/designer/src/designer/helper/dragon.ts b/packages/designer/src/designer/helper/dragon.ts index f47fc9a89..4fe4ba5a0 100644 --- a/packages/designer/src/designer/helper/dragon.ts +++ b/packages/designer/src/designer/helper/dragon.ts @@ -3,9 +3,11 @@ import { obx } from '@recore/obx'; import Location from './location'; import DocumentModel from '../document/document-model'; import { NodeData } from '../schema'; -import { ISimulator } from '../simulator'; +import { ISimulator, isSimulator } from '../simulator'; import Node from '../document/node/node'; import Designer from '../designer'; +import { setNativeSelection } from '../../utils/navtive-selection'; +import cursor from './cursor'; export interface LocateEvent { readonly type: 'LocateEvent'; @@ -22,10 +24,17 @@ export interface LocateEvent { * 拖拽对象 */ readonly dragObject: DragObject; + + /** + * 激活的感应器 + */ + sensor?: ISensor; + + // ======= 以下是 激活的 sensor 将填充的值 ======== /** * 浏览器事件响应目标 */ - target: Element | null; + target?: Element | null; /** * 当前激活文档画布坐标系 */ @@ -134,14 +143,18 @@ export default class Dragon { private sensors: ISensor[] = []; /** - * current actived sensor + * current actived sensor, 可用于感应区高亮 */ - private _activeSensor: ISensor | undefined; + @obx.ref private _activeSensor: ISensor | undefined; get activeSensor(): ISensor | undefined { return this._activeSensor; } - @obx.ref dragging = false; + @obx.ref private _dragging: boolean = false; + get dragging(): boolean { + return this._dragging; + } + private emitter = new EventEmitter(); constructor(readonly designer: Designer) {} @@ -168,66 +181,69 @@ export default class Dragon { } getMasterSensors(): ISimulator[] { - return this.designer.project.documents.map(doc => (doc.actived && doc.simulator) || null).filter(Boolean) as any; + return this.designer.project.documents.map(doc => { + if (doc.actived && doc.simulator?.sensorAvailable) { + return doc.simulator; + } + return null; + }).filter(Boolean) as any; } - /** - * dragTarget should be a INode | INode[] | NodeData | NodeData[] - */ boost(dragObject: DragObject, boostEvent: MouseEvent) { - /* const doc = document; - const fromTop = isFromTopDocument(boostEvent); - let lastLocation: any = null; - let lastSensor: ISensor | undefined; - this.dragging = false; + const isFromTop = isFromTopDocument(boostEvent); const masterSensors = this.getMasterSensors(); - masterSensors.forEach((sensor) => { - sensor.setNativeSelection(false); - }); - // + const designer = this.designer; + const newBie = dragObject.type !== DragObjectType.Node; + let lastSensor: ISensor | undefined; + + this._dragging = false; + // 禁用默认的文稿拖选 + this.setNativeSelection(false); const checkesc = (e: KeyboardEvent) => { if (e.keyCode === 27) { - lastLocation = null; - master.document.clearLocation(); + designer.clearLocation(); over(); } }; const checkcopy = (e: MouseEvent) => { if (newBie || e.altKey || e.ctrlKey) { - master.setCopy(true); + this.setCopyState(true); } else { - master.setCopy(false); + this.setCopyState(false); } }; + // period one fix: + // get evt source-sensor + // get globalX and globalY source-sensor + const drag = (e: MouseEvent) => { checkcopy(e); - const locateEvent = fixEvent(e); + const locateEvent = createLocateEvent(e); const sensor = chooseSensor(locateEvent); if (sensor) { sensor.fixEvent(locateEvent); - lastLocation = sensor.locate(locateEvent); + sensor.locate(locateEvent); } else { - master.document.clearLocation(); - lastLocation = null; + designer.clearLocation(); } - this.emitter.emit('drag', locateEvent, lastLocation); + this.emitter.emit('drag', locateEvent); }; const dragstart = () => { - const locateEvent = fixEvent(boostEvent); + const locateEvent = createLocateEvent(boostEvent); if (!newBie) { chooseSensor(locateEvent); } - master.setDragging(true); + this.setDraggingState(true); // ESC cancel drag doc.addEventListener('keydown', checkesc, false); - if (topDoc) { - topDoc.addEventListener('keydown', checkesc, false); + if (isFromTop) { + // topDoc.addEventListener('keydown', checkesc, false); } this.emitter.emit('dragstart', locateEvent); }; @@ -239,7 +255,7 @@ export default class Dragon { } if (isShaken(boostEvent, e)) { - this.dragging = true; + this._dragging = true; setShaken(boostEvent); dragstart(); @@ -249,23 +265,23 @@ export default class Dragon { const over = (e?: any) => { if (lastSensor) { - lastSensor.deactive(); + lastSensor.deactiveSensor(); } - master.setNativeSelection(true); + this.setNativeSelection(true); let exception; - if (this.dragging) { - this.dragging = false; + if (this._dragging) { + this._dragging = false; try { - this.emitter.emit('dragend', { dragTarget: dragObject, copy: master.isCopy() }, lastLocation); + this.emitter.emit('dragend', { dragTarget: dragObject, copy: this.isCopyState() }); } catch (ex) { exception = ex; } } - master.releaseCursor(); + this.clearState(); - if (fromTop) { + if (isFromTop) { doc.removeEventListener('mousemove', move, true); doc.removeEventListener('mouseup', over, true); doc.removeEventListener('mousedown', over, true); @@ -290,28 +306,44 @@ export default class Dragon { } }; - const fixEvent = (e: MouseEvent): LocateEvent => { + const createLocateEvent = (e: MouseEvent): LocateEvent => { if (isLocateEvent(e)) { return e; } + const evt: any = { type: 'LocateEvent', + dragObject, target: e.target, - dragTarget: dragObject, originalEvent: e, }; - if (e.view!.document === document) { - const l = viewport.toLocalPoint(e); - evt.clientX = l.clientX; - evt.clientY = l.clientY; + + const sourceDocument = e.view?.document; + + if (!sourceDocument || sourceDocument === document) { evt.globalX = e.clientX; evt.globalY = e.clientY; } else { - const g = viewport.toGlobalPoint(e); - evt.clientX = e.clientX; - evt.clientY = e.clientY; - evt.globalX = g.clientX; - evt.globalY = g.clientY; + let srcSim: ISimulator | undefined; + let lastSim = lastSensor && isSimulator(lastSensor) ? lastSensor : null; + if (lastSim && lastSim.contentDocument === sourceDocument) { + srcSim = lastSim; + } else { + srcSim = masterSensors.find(sim => sim.contentDocument === sourceDocument); + if (!srcSim && lastSim) { + srcSim = lastSim; + } + } + if (srcSim) { + const g = srcSim.viewport.toGlobalPoint(e); + evt.globalX = g.clientX; + evt.globalY = g.clientY; + evt.sensor = srcSim; + } else { + // this condition will not happen, just make sure ts ok + evt.globalX = e.clientX; + evt.globalY = e.clientY; + } } return evt; }; @@ -320,15 +352,13 @@ export default class Dragon { if (!isDragNodeObject(dragObject)) { return null; } - return (Array.isArray(dragObject.nodes) ? dragObject.nodes[0] : dragObject.nodes)?.document.simulator || null; + return dragObject.nodes[0]?.document.simulator || null; } - const simSensors = this.project.documents.map(doc => (doc.actived && doc.simulator) || null).filter(Boolean); const sourceSensor = getSourceSensor(dragObject); - // check simulator is empty - const sensors: ISensor[] = simSensors.concat(this.sensors); + const sensors: ISensor[] = (masterSensors as ISensor[]).concat(this.sensors); const chooseSensor = (e: LocateEvent) => { - let sensor = sensors.find(s => s.sensorAvailable && s.isEnter(e)); + let sensor = e.sensor || sensors.find(s => s.sensorAvailable && s.isEnter(e)); if (!sensor) { if (lastSensor) { sensor = lastSensor; @@ -343,6 +373,7 @@ export default class Dragon { lastSensor = sensor; } if (sensor) { + e.sensor = sensor; sensor.fixEvent(e); } this._activeSensor = sensor; @@ -352,26 +383,81 @@ export default class Dragon { doc.addEventListener('mousemove', move, true); doc.addEventListener('mouseup', over, true); doc.addEventListener('mousedown', over, true); - if (topDoc) { + if (isFromTop) {/* topDoc.addEventListener('mousemove', move, true); topDoc.addEventListener('mouseup', over, true); topDoc.addEventListener('mousedown', over, true); + */ } + if (!newBie) { doc.addEventListener('keydown', checkcopy as any, false); doc.addEventListener('keyup', checkcopy as any, false); - if (topDoc) { + if (isFromTop) {/* topDoc.addEventListener('keydown', checkcopy as any, false); topDoc.addEventListener('keyup', checkcopy as any, false); + */ } } - */ } + // #region ======== drag and drop helpers ============ + private setNativeSelection(enableFlag: boolean) { + setNativeSelection(enableFlag); + this.designer.project.documents.forEach(doc => { + doc.simulator?.setNativeSelection(enableFlag); + }); + } + + /** + * 设置拖拽态 + */ + private setDraggingState(state: boolean) { + cursor.setDragging(state); + this.designer.project.documents.forEach(doc => { + doc.simulator?.setDraggingState(state); + }); + } + + /** + * 设置拷贝态 + */ + private setCopyState(state: boolean) { + cursor.setCopy(state); + this.designer.project.documents.forEach(doc => { + doc.simulator?.setCopyState(state); + }); + } + + /** + * 是否拷贝态 + */ + private isCopyState(): boolean { + return cursor.isCopy(); + } + + /** + * 清除所有态:拖拽态、拷贝态 + */ + private clearState() { + cursor.release(); + this.designer.project.documents.forEach(doc => { + doc.simulator?.clearState(); + }); + } + // #endregion + + + /** + * 添加投放感应区 + */ addSensor(sensor: any) { this.sensors.push(sensor); } + /** + * 移除投放感应 + */ removeSensor(sensor: any) { const i = this.sensors.indexOf(sensor); if (i > -1) { @@ -386,14 +472,14 @@ export default class Dragon { }; } - onDrag(func: (e: LocateEvent, location: Location) => any) { + onDrag(func: (e: LocateEvent) => any) { this.emitter.on('drag', func); return () => { this.emitter.removeListener('drag', func); }; } - onDragend(func: (x: { dragObject: DragObject; copy: boolean }, location: Location) => any) { + onDragend(func: (x: { dragObject: DragObject; copy: boolean }) => any) { this.emitter.on('dragend', func); return () => { this.emitter.removeListener('dragend', func); diff --git a/packages/designer/src/designer/helper/offset-observer.ts b/packages/designer/src/designer/helper/offset-observer.ts index 981d0e28c..ebb1e241c 100644 --- a/packages/designer/src/designer/helper/offset-observer.ts +++ b/packages/designer/src/designer/helper/offset-observer.ts @@ -1,5 +1,5 @@ import { obx, computed } from '@recore/obx'; -import { INodeInstance, IViewport } from '../simulator'; +import { INodeSelector, IViewport } from '../simulator'; import Viewport from '../../builtins/simulator/host/viewport'; export default class OffsetObserver { @@ -24,7 +24,7 @@ export default class OffsetObserver { private pid: number | undefined; private viewport: IViewport; - constructor(readonly nodeInstance: INodeInstance) { + constructor(readonly nodeInstance: INodeSelector) { const { node, instance } = nodeInstance; const doc = node.document; const host = doc.simulator!; @@ -67,7 +67,7 @@ export default class OffsetObserver { } } -export function createOffsetObserver(nodeInstance: INodeInstance): OffsetObserver | null { +export function createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null { if (!nodeInstance.instance) { return null; } diff --git a/packages/designer/src/designer/simulator.ts b/packages/designer/src/designer/simulator.ts index 7f3b68ad4..f508920dd 100644 --- a/packages/designer/src/designer/simulator.ts +++ b/packages/designer/src/designer/simulator.ts @@ -59,6 +59,7 @@ export interface IViewport extends IScrollable { * 模拟器控制进程协议 */ export interface ISimulator

extends ISensor { + readonly isSimulator: true; /** * 获得边界维度等信息 */ @@ -77,26 +78,23 @@ export interface ISimulator

extends ISensor { // 获取区块代码, 通过 components 传递,可异步获取 setProps(props: P): void; + + setSuspense(suspensed: boolean): void; + + // #region ========= drag and drop helpers ============= + + /** + * 设置文字拖选 + */ + setNativeSelection(enableFlag: boolean): void; /** * 设置拖拽态 */ setDraggingState(state: boolean): void; - - /** - * 是否拖拽态 - */ - isDraggingState(): boolean; - /** * 设置拷贝态 */ setCopyState(state: boolean): void; - - /** - * 是否拷贝态 - */ - isCopyState(): boolean; - /** * 清除所有态:拖拽态、拷贝态 */ @@ -107,16 +105,18 @@ export interface ISimulator

extends ISensor { */ locate(e: LocateEvent): any; - /** - * 滚动视口到节点 - */ - scrollToNode(node: Node, detail?: any): void; - /** * 给 event 打补丁,添加 canvasX, globalX 等信息,用于拖拽 */ fixEvent(e: LocateEvent): LocateEvent; + // #endregion + + /** + * 滚动视口到节点 + */ + scrollToNode(node: Node, detail?: any): void; + /** * 描述组件 */ @@ -134,19 +134,28 @@ export interface ISimulator

extends ISensor { */ getComponentContext(node: Node): object | null; - getClosestNodeId(elem: Element): string | null; + getClosestNodeInstance(elem: Element): NodeInstance | null; computeComponentInstanceRect(instance: ComponentInstance): DOMRect | null; findDOMNodes(instance: ComponentInstance): Array | null; - setSuspense(suspensed: boolean): void; /** * 销毁 */ purge(): void; } +export function isSimulator(obj: any): obj is ISimulator { + return obj && obj.isSimulator; +} + +export interface NodeInstance { + nodeId: string; + instance: ComponentInstance; + node?: Node | null; +} + /** * 组件类定义 */ @@ -157,7 +166,7 @@ export type Component = ComponentType | object; */ export type ComponentInstance = Element | ReactComponent | object; -export interface INodeInstance { +export interface INodeSelector { node: Node; instance?: ComponentInstance; }