drag&drop logic 80%

This commit is contained in:
kangwei 2020-02-19 02:40:11 +08:00
parent f7c69af6c4
commit 59818ae3b6
10 changed files with 286 additions and 155 deletions

View File

@ -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<SimulatorProps> {
readonly isSimulator = true;
constructor(readonly document: DocumentModel) {}
readonly designer = this.document.designer;
@ -126,6 +129,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
get contentWindow() {
return this._contentWindow;
}
@obx.ref private _contentDocument?: Document;
get contentDocument() {
return this._contentDocument;
@ -192,8 +196,8 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
// 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<SimulatorProps> {
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<SimulatorProps> {
}
// 获得顶层 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<SimulatorProps> {
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<SimulatorProps> {
// cause edit
doc.addEventListener('dblclick', (e: MouseEvent) => {
// TODO:
});
}
@ -266,9 +271,9 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
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<SimulatorProps> {
};
}
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<SimulatorProps> {
}
}
}
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<SimulatorProps> {
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<SimulatorProps> {
}
}
// #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<SimulatorProps> {
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<SimulatorProps> {
}*/
return false;
}
//#endregion
// #endregion
}

View File

@ -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<Element | Text> | 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 }) {

View File

@ -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
}

View File

@ -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);
}

View File

@ -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,
};
}
/**

View File

@ -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
}

View File

@ -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}`);
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -59,6 +59,7 @@ export interface IViewport extends IScrollable {
*
*/
export interface ISimulator<P = object> extends ISensor {
readonly isSimulator: true;
/**
*
*/
@ -77,26 +78,23 @@ export interface ISimulator<P = object> 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<P = object> 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<P = object> 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<Element | Text> | 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<any> | object;
*/
export type ComponentInstance = Element | ReactComponent<any> | object;
export interface INodeInstance {
export interface INodeSelector {
node: Node;
instance?: ComponentInstance;
}