diff --git a/packages/designer/auxilary-bak/README.md b/packages/designer/auxilary-bak/README.md
deleted file mode 100644
index bd959599f..000000000
--- a/packages/designer/auxilary-bak/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-辅助类
- 对齐线
- 插入指示 insertion 竖线 横线 插入块 禁止插入块
- 幽灵替身 ghost
- 聚焦编辑指示
-
-
-插入指示 insertion 竖线 横线 插入块 禁止插入块
-
-竖线:红色,绿色
-横线:红色,绿色
-插入块:透明绿色,透明红色
-
-投放指示线
-
-cover
-
-轮廓服务
- 悬停指示线 xray mode?
- 选中指示线
- 投放指示线
- 透视线 x-ray
diff --git a/packages/designer/auxilary-bak/embed-editor-toolbar.tsx b/packages/designer/auxilary-bak/embed-editor-toolbar.tsx
deleted file mode 100644
index e8d6d8fac..000000000
--- a/packages/designer/auxilary-bak/embed-editor-toolbar.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { Component } from 'react';
-import embedEditor from '../../globals/embed-editor';
-
-export default class EmbedEditorToolbar extends Component {
- shouldComponentUpdate() {
- return false;
- }
-
- render() {
- return
embedEditor.mount(shell)} />;
- }
-}
diff --git a/packages/designer/src/builtins/simulator/host/auxilary/auxiliary.tsx b/packages/designer/src/builtins/simulator/host/auxilary/auxiliary.tsx
index ea5dbfcfd..57e6e7d35 100644
--- a/packages/designer/src/builtins/simulator/host/auxilary/auxiliary.tsx
+++ b/packages/designer/src/builtins/simulator/host/auxilary/auxiliary.tsx
@@ -3,9 +3,10 @@ import { Component } from 'react';
import { OutlineHovering } from './outline-hovering';
import { SimulatorContext } from '../context';
import { SimulatorHost } from '../host';
+import { OutlineSelecting } from './outline-selecting';
+import { InsertionView } from './insertion';
import './auxiliary.less';
import './outlines.less';
-import { OutlineSelecting } from './outline-selecting';
@observer
export class AuxiliaryView extends Component {
@@ -22,6 +23,7 @@ export class AuxiliaryView extends Component {
+
);
}
diff --git a/packages/designer/auxilary-bak/insertion.less b/packages/designer/src/builtins/simulator/host/auxilary/insertion.less
similarity index 95%
rename from packages/designer/auxilary-bak/insertion.less
rename to packages/designer/src/builtins/simulator/host/auxilary/insertion.less
index 871210b7b..b5cb19f50 100644
--- a/packages/designer/auxilary-bak/insertion.less
+++ b/packages/designer/src/builtins/simulator/host/auxilary/insertion.less
@@ -1,4 +1,4 @@
-.my-insertion {
+.lc-insertion {
position: absolute;
top: -1.5px;
left: 0;
diff --git a/packages/designer/auxilary-bak/insertion.tsx b/packages/designer/src/builtins/simulator/host/auxilary/insertion.tsx
similarity index 57%
rename from packages/designer/auxilary-bak/insertion.tsx
rename to packages/designer/src/builtins/simulator/host/auxilary/insertion.tsx
index cc09d6ec4..99790f044 100644
--- a/packages/designer/auxilary-bak/insertion.tsx
+++ b/packages/designer/src/builtins/simulator/host/auxilary/insertion.tsx
@@ -1,34 +1,35 @@
import { Component } from 'react';
-import { observer } from '@ali/recore';
-import { getCurrentDocument } from '../../globals';
+import { computed } from '@recore/obx';
+import { observer } from '@recore/core-obx';
+import { SimulatorContext } from '../context';
+import { SimulatorHost } from '../host';
+import Location, { Rect, isLocationChildrenDetail, LocationChildrenDetail, isVertical } from '../../../../designer/helper/location';
+import { ISimulator } from '../../../../designer/simulator';
+import { NodeParent } from '../../../../designer/document/node/node';
import './insertion.less';
-import Location, { isLocationChildrenDetail, isVertical, LocationChildrenDetail, Rect } from '../../document/location';
-import { isConditionFlow } from '../../document/node/condition-flow';
-import { getChildAt, INodeParent } from '../../document/node';
-import DocumentContext from '../../document/document-context';
-
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-function processPropDetail() {
- // return { insertType: 'cover', coverEdge: ? };
-}
interface InsertionData {
- edge?: Rect;
+ edge?: DOMRect;
insertType?: string;
vertical?: boolean;
nearRect?: Rect;
- coverRect?: Rect;
+ coverRect?: DOMRect;
}
/**
* 处理拖拽子节点(INode)情况
*/
function processChildrenDetail(
- doc: DocumentContext,
- target: INodeParent,
+ sim: ISimulator,
+ target: NodeParent,
detail: LocationChildrenDetail,
): InsertionData {
- const edge = doc.computeRect(target);
+ let edge = detail.edge || null;
+
+ if (edge) {
+ edge = sim.computeRect(target);
+ }
+
if (!edge) {
return {};
}
@@ -38,15 +39,9 @@ function processChildrenDetail(
insertType: 'before',
};
- if (isConditionFlow(target)) {
- ret.insertType = 'cover';
- ret.coverRect = edge;
- return ret;
- }
-
if (detail.near) {
const { node, pos, rect, align } = detail.near;
- ret.nearRect = rect || doc.computeRect(node);
+ ret.nearRect = rect || sim.computeRect(node);
ret.vertical = align ? align === 'V' : isVertical(ret.nearRect);
ret.insertType = pos;
return ret;
@@ -55,10 +50,10 @@ function processChildrenDetail(
// from outline-tree: has index, but no near
// TODO: think of shadowNode & ConditionFlow
const { index } = detail;
- let nearNode = getChildAt(target, index);
+ let nearNode = target.children.get(index);
if (!nearNode) {
// index = 0, eg. nochild,
- nearNode = getChildAt(target, index > 0 ? index - 1 : 0);
+ nearNode = target.children.get(index > 0 ? index - 1 : 0);
if (!nearNode) {
ret.insertType = 'cover';
ret.coverRect = edge;
@@ -67,7 +62,7 @@ function processChildrenDetail(
ret.insertType = 'after';
}
if (nearNode) {
- ret.nearRect = doc.computeRect(nearNode);
+ ret.nearRect = sim.computeRect(nearNode);
ret.vertical = isVertical(ret.nearRect);
}
return ret;
@@ -77,44 +72,56 @@ function processChildrenDetail(
* 将 detail 信息转换为页面"坐标"信息
*/
function processDetail({ target, detail, document }: Location): InsertionData {
+ const sim = document.simulator;
+ if (!sim) {
+ return {};
+ }
if (isLocationChildrenDetail(detail)) {
- return processChildrenDetail(document, target, detail);
+ return processChildrenDetail(sim, target, detail);
} else {
// TODO: others...
- const edge = document.computeRect(target);
+ const instances = sim.getComponentInstances(target);
+ if (!instances) {
+ return {};
+ }
+ const edge = sim.computeComponentInstanceRect(instances[0]);
return edge ? { edge, insertType: 'cover', coverRect: edge } : {};
}
}
@observer
export class InsertionView extends Component {
+ static contextType = SimulatorContext;
+
+ @computed get host(): SimulatorHost {
+ return this.context;
+ }
+
shouldComponentUpdate() {
return false;
}
render() {
- const doc = getCurrentDocument();
- if (!doc || !doc.dropLocation) {
+ const loc = this.host.document.dropLocation;
+ if (!loc) {
return null;
}
- const { scale, scrollTarget } = doc.viewport;
- const sx = scrollTarget!.left;
- const sy = scrollTarget!.top;
+ const { scale, scrollX, scrollY } = this.host.viewport;
+ const { edge, insertType, coverRect, nearRect, vertical } = processDetail(loc);
- const { edge, insertType, coverRect, nearRect, vertical } = processDetail(doc.dropLocation);
if (!edge) {
return null;
}
- let className = 'my-insertion';
+ let className = 'lc-insertion';
const style: any = {};
let x: number;
let y: number;
if (insertType === 'cover') {
className += ' cover';
- x = (coverRect!.left + sx) * scale;
- y = (coverRect!.top + sy) * scale;
+ x = (coverRect!.left + scrollX) * scale;
+ y = (coverRect!.top + scrollY) * scale;
style.width = coverRect!.width * scale;
style.height = coverRect!.height * scale;
} else {
@@ -123,12 +130,12 @@ export class InsertionView extends Component {
}
if (vertical) {
className += ' vertical';
- x = ((insertType === 'before' ? nearRect.left : nearRect.right) + sx) * scale;
- y = (nearRect.top + sy) * scale;
+ x = ((insertType === 'before' ? nearRect.left : nearRect.right) + scrollX) * scale;
+ y = (nearRect.top + scrollY) * scale;
style.height = nearRect!.height * scale;
} else {
- x = (nearRect.left + sx) * scale;
- y = ((insertType === 'before' ? nearRect.top : nearRect.bottom) + sy) * scale;
+ x = (nearRect.left + scrollX) * scale;
+ y = ((insertType === 'before' ? nearRect.top : nearRect.bottom) + scrollY) * scale;
style.width = nearRect.width * scale;
}
}
diff --git a/packages/designer/src/builtins/simulator/host/auxilary/outline-hovering.tsx b/packages/designer/src/builtins/simulator/host/auxilary/outline-hovering.tsx
index a56109e1f..2e33073ec 100644
--- a/packages/designer/src/builtins/simulator/host/auxilary/outline-hovering.tsx
+++ b/packages/designer/src/builtins/simulator/host/auxilary/outline-hovering.tsx
@@ -75,7 +75,7 @@ export class OutlineHovering extends Component {
if (!current) {
return
;
}
- const instances = host.getComponentInstance(current);
+ const instances = host.getComponentInstances(current);
if (!instances || instances.length < 1) {
return
;
}
@@ -83,7 +83,7 @@ export class OutlineHovering extends Component {
if (instances.length === 1) {
return (
{instances.map((inst, i) => (
{selecting.map(node => {
- const instances = this.host.getComponentInstance(node);
+ const instances = this.host.getComponentInstances(node);
if (!instances || instances.length < 1) {
return null;
}
diff --git a/packages/designer/src/builtins/simulator/host/host.ts b/packages/designer/src/builtins/simulator/host/host.ts
index b66dc85ff..ba816c96d 100644
--- a/packages/designer/src/builtins/simulator/host/host.ts
+++ b/packages/designer/src/builtins/simulator/host/host.ts
@@ -1,19 +1,38 @@
import { obx, autorun, computed } from '@recore/obx';
-import { ISimulator, ComponentInstance, Component, NodeInstance } from '../../../designer/simulator';
+import { ISimulator, Component, NodeInstance } from '../../../designer/simulator';
import Viewport from './viewport';
import { createSimulator } from './create-simulator';
import { SimulatorRenderer } from '../renderer/renderer';
-import Node, { NodeParent } from '../../../designer/document/node/node';
+import Node, { NodeParent, isNodeParent, isNode, contains } from '../../../designer/document/node/node';
import DocumentModel from '../../../designer/document/document-model';
import ResourceConsumer from './resource-consumer';
import { AssetLevel, Asset, assetBundle, assetItem, AssetType } from '../utils/asset';
-import { DragObjectType, isShaken, LocateEvent, DragNodeObject, DragNodeDataObject } from '../../../designer/helper/dragon';
-import { LocationData } from '../../../designer/helper/location';
-import { NodeData } from '../../../designer/schema';
+import {
+ DragObjectType,
+ isShaken,
+ LocateEvent,
+ DragNodeObject,
+ DragNodeDataObject,
+ isDragAnyObject,
+ isDragNodeObject,
+} from '../../../designer/helper/dragon';
+import {
+ LocationData,
+ isLocationData,
+ LocationChildrenDetail,
+ LocationDetailType,
+ isChildInline,
+ isRowContainer,
+ getRectTarget,
+ Rect,
+ CanvasPoint,
+} from '../../../designer/helper/location';
+import { isNodeSchema, NodeSchema } from '../../../designer/schema';
import { ComponentDescriptionSpec } from '../../../designer/component-config';
import { ReactInstance } from 'react';
import { setNativeSelection } from '../../../designer/helper/navtive-selection';
import cursor from '../../../designer/helper/cursor';
+import { isRootNode } from '../../../designer/document/node/root-node';
export interface SimulatorProps {
// 从 documentModel 上获取
@@ -53,15 +72,11 @@ const defaultDepends = [
export class SimulatorHost implements ISimulator {
readonly isSimulator = true;
+
constructor(readonly document: DocumentModel) {}
readonly designer = this.document.designer;
- private _sensorAvailable: boolean = true;
- get sensorAvailable(): boolean {
- return this._sensorAvailable;
- }
-
@computed get device(): string | undefined {
// 根据 device 不同来做画布外框样式变化 渲染时可选择不同组件
// renderer 依赖
@@ -92,6 +107,9 @@ export class SimulatorHost implements ISimulator {
}
@obx.ref _props: SimulatorProps = {};
+ /**
+ * @see ISimulator
+ */
setProps(props: SimulatorProps) {
this._props = props;
}
@@ -196,7 +214,7 @@ export class SimulatorHost implements ISimulator {
// TODO: think of lock when edit a node
// 事件路由
doc.addEventListener('mousedown', (downEvent: MouseEvent) => {
- const nodeInst = documentModel.getNodeInstanceFromElement(downEvent.target as Element);
+ const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
if (!nodeInst?.node) {
selection.clear();
return;
@@ -256,7 +274,6 @@ export class SimulatorHost implements ISimulator {
// cause edit
doc.addEventListener('dblclick', (e: MouseEvent) => {
// TODO:
-
});
}
@@ -271,8 +288,9 @@ export class SimulatorHost implements ISimulator {
if (!hovering.enable) {
return;
}
- const nodeInst = this.document.getNodeInstanceFromElement(e.target as Element);
+ const nodeInst = this.getNodeInstanceFromElement(e.target as Element);
// TODO: enhance only hover one instance
+ console.info(nodeInst);
hovering.hover(nodeInst?.node || null);
e.stopPropagation();
};
@@ -298,6 +316,9 @@ export class SimulatorHost implements ISimulator {
};
}
+ /**
+ * @see ISimulator
+ */
setSuspense(suspended: boolean) {
if (suspended) {
if (this.disableHovering) {
@@ -312,35 +333,61 @@ export class SimulatorHost implements ISimulator {
}
}
- setDesignMode(mode: string): void {
- throw new Error('Method not implemented.');
- }
-
+ /**
+ * @see ISimulator
+ */
describeComponent(component: Component): ComponentDescriptionSpec {
throw new Error('Method not implemented.');
}
- getComponent(componentName: string): Component {
- throw new Error('Method not implemented.');
+ /**
+ * @see ISimulator
+ */
+ getComponent(componentName: string): Component | null {
+ return null;
}
- getComponentInstance(node: Node): ReactInstance[] | null {
- return this._renderer?.getComponentInstance(node.id) || null;
+ /**
+ * @see ISimulator
+ */
+ getComponentInstances(node: Node): ReactInstance[] | null {
+ return this._renderer?.getComponentInstances(node.id) || null;
}
- getComponentInstanceId(instance: ReactInstance) {
-
- }
+ /**
+ * @see ISimulator
+ */
+ getComponentInstanceId(instance: ReactInstance) {}
+ /**
+ * @see ISimulator
+ */
getComponentContext(node: Node): object {
throw new Error('Method not implemented.');
}
- getClosestNodeInstance(elem: Element): NodeInstance | null {
- return this.renderer?.getClosestNodeInstance(elem) || null;
+ /**
+ * @see ISimulator
+ */
+ getClosestNodeInstance(from: ReactInstance, specId?: string): NodeInstance | null {
+ return this.renderer?.getClosestNodeInstance(from, specId) || null;
}
- computeComponentInstanceRect(instance: ReactInstance): DOMRect | null {
+ /**
+ * @see ISimulator
+ */
+ computeRect(node: Node): Rect | null {
+ const instances = this.getComponentInstances(node);
+ if (!instances) {
+ return null;
+ }
+ return this.computeComponentInstanceRect(instances[0]);
+ }
+
+ /**
+ * @see ISimulator
+ */
+ computeComponentInstanceRect(instance: ReactInstance): Rect | null {
const renderer = this.renderer!;
const elements = renderer.findDOMNodes(instance);
if (!elements) {
@@ -348,10 +395,12 @@ export class SimulatorHost implements ISimulator {
}
let rects: DOMRect[] | undefined;
- let last: { x: number; y: number; r: number; b: number; } | undefined;
+ let last: { x: number; y: number; r: number; b: number } | undefined;
+ let computed = false;
+ const elems = elements.slice();
while (true) {
if (!rects || rects.length < 1) {
- const elem = elements.pop();
+ const elem = elems.pop();
if (!elem) {
break;
}
@@ -372,30 +421,62 @@ export class SimulatorHost implements ISimulator {
}
if (rect.left < last.x) {
last.x = rect.left;
+ computed = true;
}
if (rect.top < last.y) {
last.y = rect.top;
+ computed = true;
}
if (rect.right > last.r) {
last.r = rect.right;
+ computed = true;
}
if (rect.bottom > last.b) {
last.b = rect.bottom;
+ computed = true;
}
}
if (last) {
- return new DOMRect(last.x, last.y, last.r - last.x, last.b - last.y);
+ const r: any = new DOMRect(last.x, last.y, last.r - last.x, last.b - last.y);
+ r.elements = elements;
+ r.computed = computed;
+ return r;
}
return null;
}
+ /**
+ * @see ISimulator
+ */
findDOMNodes(instance: ReactInstance): Array | null {
return this._renderer?.findDOMNodes(instance) || null;
}
+ /**
+ * 通过 DOM 节点获取节点,依赖 simulator 的接口
+ */
+ getNodeInstanceFromElement(target: Element | null): NodeInstance | null {
+ if (!target) {
+ return null;
+ }
+
+ const nodeIntance = this.getClosestNodeInstance(target);
+ if (!nodeIntance) {
+ return null;
+ }
+ const node = this.document.getNode(nodeIntance.nodeId);
+ return {
+ ...nodeIntance,
+ node,
+ };
+ }
+
private tryScrollAgain: number | null = null;
+ /**
+ * @see ISimulator
+ */
scrollToNode(node: Node, detail?: any, tryTimes = 0) {
this.tryScrollAgain = null;
if (this.sensing) {
@@ -451,80 +532,251 @@ export class SimulatorHost implements ISimulator {
}
// #region ========= drag and drop helpers =============
+ /**
+ * @see ISimulator
+ */
setNativeSelection(enableFlag: boolean) {
- setNativeSelection(enableFlag);
+ this.renderer?.setNativeSelection(enableFlag);
}
+ /**
+ * @see ISimulator
+ */
setDraggingState(state: boolean) {
- cursor.setDragging(state);
+ this.renderer?.setDraggingState(state);
}
+ /**
+ * @see ISimulator
+ */
setCopyState(state: boolean) {
- cursor.setCopy(state);
+ this.renderer?.setCopyState(state);
}
+ /**
+ * @see ISimulator
+ */
clearState() {
- cursor.release();
+ this.renderer?.clearState();
}
+ private _sensorAvailable: boolean = true;
+ /**
+ * @see ISensor
+ */
+ get sensorAvailable(): boolean {
+ return this._sensorAvailable;
+ }
+
+ /**
+ * @see ISensor
+ */
fixEvent(e: LocateEvent): LocateEvent {
- /*
if (e.fixed) {
return e;
}
- if (!e.target || e.originalEvent.view!.document !== this.contentDocument) {
- e.target = this.contentDocument!.elementFromPoint(e.canvasX, e.canvasY);
- }*/
+
+ const notMyEvent = e.originalEvent.view?.document !== this.contentDocument;
+ // fix canvasX canvasY : 当前激活文档画布坐标系
+ if (notMyEvent || !('canvasX' in e) || !('canvasY' in e)) {
+ const l = this.viewport.toLocalPoint({
+ clientX: e.globalX,
+ clientY: e.globalY,
+ });
+ e.canvasX = l.clientX;
+ e.canvasY = l.clientY;
+ }
+
+ // fix target : 浏览器事件响应目标
+ if (!e.target || notMyEvent) {
+ e.target = this.contentDocument!.elementFromPoint(e.canvasX!, e.canvasY!);
+ }
+
+ // documentModel : 目标文档
+ e.documentModel = this.document;
+
+ // 事件已订正
+ e.fixed = true;
return e;
}
+ /**
+ * @see ISensor
+ */
isEnter(e: LocateEvent): boolean {
- return false; /*
- const rect = this.bounds;
+ const rect = this.viewport.bounds;
return e.globalY >= rect.top && e.globalY <= rect.bottom && e.globalX >= rect.left && e.globalX <= rect.right;
- */
}
private sensing: boolean = false;
+ /**
+ * @see ISensor
+ */
deactiveSensor() {
this.sensing = false;
this.scroller.cancel();
}
- // ========= drag location logic start ==========
+ // ========= drag location logic: hepler for locate ==========
+
+ /**
+ * @see ISensor
+ */
+ locate(e: LocateEvent): any {
+ this.sensing = true;
+ this.scroller.scrolling(e);
+ const dropTarget = this.getDropTarget(e);
+ console.info('aa', dropTarget);
+ if (!dropTarget) {
+ return null;
+ }
+
+ if (isLocationData(dropTarget)) {
+ return this.designer.createLocation(dropTarget);
+ }
+
+ const target = dropTarget;
+ const targetInstance = e.targetInstance as ReactInstance;
+
+ const parentInstance = this.getClosestNodeInstance(targetInstance, target.id);
+ const edge = this.computeComponentInstanceRect(parentInstance?.instance as any);
+
+ if (!edge) {
+ return null;
+ }
+
+ const children = target.children;
+
+ const detail: LocationChildrenDetail = {
+ type: LocationDetailType.Children,
+ index: 0,
+ edge,
+ };
+
+ const locationData = {
+ target,
+ detail,
+ };
+
+ if (!children || children.size < 1 || !edge) {
+ return this.designer.createLocation(locationData);
+ }
+
+ let nearRect = null;
+ let nearIndex = 0;
+ let nearNode = null;
+ let nearDistance = null;
+ let minTop = null;
+ let maxBottom = null;
+
+ for (let i = 0, l = children.size; i < l; i++) {
+ let node = children.get(i)!;
+ let index = i;
+ const instances = this.getComponentInstances(node);
+ const inst = instances
+ ? instances.length > 1
+ ? instances.find(inst => {
+ return this.getClosestNodeInstance(inst, target.id)?.instance === targetInstance;
+ })
+ : instances[0]
+ : null;
+ const rect = inst ? this.computeComponentInstanceRect(inst) : null;
+
+ if (!rect) {
+ continue;
+ }
+
+ const distance = isPointInRect(e as any, rect) ? 0 : distanceToRect(e as any, rect);
+
+ if (distance === 0) {
+ nearDistance = distance;
+ nearNode = node;
+ nearIndex = index;
+ nearRect = rect;
+ break;
+ }
+
+ // 标记子节点最顶
+ if (minTop === null || rect.top < minTop) {
+ minTop = rect.top;
+ }
+ // 标记子节点最底
+ if (maxBottom === null || rect.bottom > maxBottom) {
+ maxBottom = rect.bottom;
+ }
+
+ if (nearDistance === null || distance < nearDistance) {
+ nearDistance = distance;
+ nearNode = node;
+ nearIndex = index;
+ nearRect = rect;
+ }
+ }
+
+ detail.index = nearIndex;
+
+ if (nearNode && nearRect) {
+ const el = getRectTarget(nearRect);
+ const inline = el ? isChildInline(el) : false;
+ const row = el ? isRowContainer(el.parentElement!) : false;
+ const vertical = inline || row;
+ // TODO: fix type
+ const near: any = {
+ node: nearNode,
+ pos: 'before',
+ align: vertical ? 'V' : 'H',
+ };
+ detail.near = near;
+ if (isNearAfter(e as any, nearRect, vertical)) {
+ near.pos = 'after';
+ detail.index = nearIndex + 1;
+ }
+ if (!row && nearDistance !== 0) {
+ const edgeDistance = distanceToEdge(e as any, edge);
+ if (edgeDistance.distance < nearDistance!) {
+ const nearAfter = edgeDistance.nearAfter;
+ if (minTop == null) {
+ minTop = edge.top;
+ }
+ if (maxBottom == null) {
+ maxBottom = edge.bottom;
+ }
+ near.rect = new DOMRect(edge.left, minTop, edge.width, maxBottom - minTop);
+ near.align = 'H';
+ near.pos = nearAfter ? 'after' : 'before';
+ detail.index = nearAfter ? children.size : 0;
+ }
+ }
+ }
+
+ return this.designer.createLocation(locationData);
+ }
+
getDropTarget(e: LocateEvent): NodeParent | LocationData | null {
- /*
- const { target, dragTarget } = e;
- const isAny = isAnyDragTarget(dragTarget);
+ const { target, dragObject } = e;
+ const isAny = isDragAnyObject(dragObject);
let container: any;
+
if (target) {
- const ref = this.document.getNodeFromElement(target as Element);
- if (ref) {
- container = ref;
+ const ref = this.getNodeInstanceFromElement(target);
+ if (ref?.node) {
+ e.targetInstance = ref.instance;
+ e.targetNode = ref.node;
+ container = ref.node;
} else if (isAny) {
return null;
} else {
- container = this.document.view;
+ container = this.document.rootNode;
}
} else if (isAny) {
return null;
} else {
- container = this.document.view;
+ container = this.document.rootNode;
}
- if (!isElementNode(container) && !isRootNode(container)) {
+ if (!isNodeParent(container) && !isRootNode(container)) {
container = container.parent;
}
- // use spec container to accept specialData
if (isAny) {
- while (container) {
- if (isRootNode(container)) {
- return null;
- }
- const locationData = this.acceptAnyData(container, e);
- if (locationData) {
- return locationData;
- }
- container = container.parent;
- }
+ // TODO: use spec container to accept specialData
return null;
}
@@ -546,7 +798,8 @@ export class SimulatorHost implements ISimulator {
} else {
container = container.parent;
}
- } else if (res === AT_CHILD) {
+ }
+ /* else if (res === AT_CHILD) {
if (!upward) {
upward = container.parent;
}
@@ -555,31 +808,30 @@ export class SimulatorHost implements ISimulator {
container = upward;
upward = null;
}
- } else if (isNode(res)) {
+ }*/
+ else if (isNode(res)) {
+ console.info('res', res);
container = res;
upward = null;
}
- }*/
+ }
return null;
}
- acceptNodes(container: Node, e: LocateEvent) {
- /*
- const { dragTarget } = e;
+ acceptNodes(container: NodeParent, e: LocateEvent) {
+ const { dragObject } = e;
if (isRootNode(container)) {
- return this.checkDropTarget(container, dragTarget as any);
+ return this.checkDropTarget(container, dragObject as any);
}
- const proto = container.prototype;
+ const config = container.componentConfig;
- const acceptable: boolean = this.isAcceptable(container);
- if (!proto.isContainer && !acceptable) {
+ if (!config.isContainer) {
return false;
}
-
// check is contains, get common parent
- if (isNodesDragTarget(dragTarget)) {
- const nodes = dragTarget.nodes;
+ if (isDragNodeObject(dragObject)) {
+ const nodes = dragObject.nodes;
let i = nodes.length;
let p: any = container;
while (i-- > 0) {
@@ -588,41 +840,16 @@ export class SimulatorHost implements ISimulator {
}
}
if (p !== container) {
- return p || this.document.view;
+ return p || this.document.rootNode;
}
}
- // first use accept
- if (acceptable) {
- const view: any = this.document.getView(container);
- if (view && '$accept' in view) {
- if (view.$accept === false) {
- return false;
- }
- if (view.$accept === AT_CHILD || view.$accept === '@CHILD') {
- return AT_CHILD;
- }
- if (typeof view.$accept === 'function') {
- const ret = view.$accept(container, e);
- if (ret || ret === false) {
- return ret;
- }
- }
- }
- if (proto.acceptable) {
- const ret = proto.accept(container, e);
- if (ret || ret === false) {
- return ret;
- }
- }
- }
-
- return this.checkNesting(container, dragTarget as any);
- */
+ return this.checkNesting(container, dragObject as any);
}
+ /*
getNearByContainer(container: NodeParent, e: LocateEvent) {
- /*
+
const children = container.children;
if (!children || children.length < 1) {
return null;
@@ -656,195 +883,76 @@ export class SimulatorHost implements ISimulator {
}
}
- return nearBy;*/
+ return nearBy;
}
+ */
- locate(e: LocateEvent): any {
- /*
- this.sensing = true;
- this.scroller.scrolling(e);
- const dropTarget = this.getDropTarget(e);
- if (!dropTarget) {
- return null;
- }
-
- if (isLocationData(dropTarget)) {
- return this.document.createLocation(dropTarget);
- }
-
- const target = dropTarget;
-
- const edge = this.document.computeRect(target);
-
- const children = target.children;
-
- const detail: LocationChildrenDetail = {
- type: LocationDetailType.Children,
- index: 0,
- };
-
- const locationData = {
- target,
- detail,
- };
-
- if (!children || children.length < 1 || !edge) {
- return this.document.createLocation(locationData);
- }
-
- let nearRect = null;
- let nearIndex = 0;
- let nearNode = null;
- let nearDistance = null;
- let top = null;
- let bottom = null;
-
- for (let i = 0, l = children.length; i < l; i++) {
- let node = children[i];
- let index = i;
- if (hasConditionFlow(node)) {
- node = node.conditionFlow;
- index = node.index;
- // skip flow items
- i = index + (node as any).length - 1;
- }
- const rect = this.document.computeRect(node);
-
- if (!rect) {
- continue;
- }
-
- const distance = isPointInRect(e, rect) ? 0 : distanceToRect(e, rect);
-
- if (distance === 0) {
- nearDistance = distance;
- nearNode = node;
- nearIndex = index;
- nearRect = rect;
- break;
- }
-
- // TODO: 忘记为什么这么处理了,记得添加注释
- if (top === null || rect.top < top) {
- top = rect.top;
- }
- if (bottom === null || rect.bottom > bottom) {
- bottom = rect.bottom;
- }
-
- if (nearDistance === null || distance < nearDistance) {
- nearDistance = distance;
- nearNode = node;
- nearIndex = index;
- nearRect = rect;
- }
- }
-
- detail.index = nearIndex;
-
- if (nearNode && nearRect) {
- const el = getRectTarget(nearRect);
- const inline = el ? isChildInline(el) : false;
- const row = el ? isRowContainer(el.parentElement!) : false;
- const vertical = inline || row;
- // TODO: fix type
- const near: any = {
- node: nearNode,
- pos: 'before',
- align: vertical ? 'V' : 'H',
- };
- detail.near = near;
- if (isNearAfter(e, nearRect, vertical)) {
- near.pos = 'after';
- detail.index = nearIndex + (isConditionFlow(nearNode) ? nearNode.length : 1);
- }
- if (!row && nearDistance !== 0) {
- const edgeDistance = distanceToEdge(e, edge);
- if (edgeDistance.distance < nearDistance!) {
- const nearAfter = edgeDistance.nearAfter;
- if (top == null) {
- top = edge.top;
- }
- if (bottom == null) {
- bottom = edge.bottom;
- }
- near.rect = new DOMRect(edge.left, top, edge.width, bottom - top);
- near.align = 'H';
- near.pos = nearAfter ? 'after' : 'before';
- detail.index = nearAfter ? children.length : 0;
- }
- }
- }
-
- return this.document.createLocation(locationData);
- */
- }
-
- isAcceptable(container: NodeParent): boolean {
- return false;
- /*
- const proto = container.prototype;
- const view: any = this.getComponentInstance(container);
- if (view && '$accept' in view) {
- return true;
- }
- return proto.acceptable;*/
- }
-
- acceptAnyData(container: Node, e: LocateEvent | MouseEvent | KeyboardEvent) {
- /*
- const proto = container.prototype;
- const view: any = this.document.getView(container);
- // use view instance method: $accept
- if (view && typeof view.$accept === 'function') {
- // should return LocationData
- return view.$accept(container, e);
- }
- // use prototype method: accept
- return proto.accept(container, e);*/
- }
-
- checkNesting(dropTarget: Node, dragTarget: DragNodeObject | DragNodeDataObject): boolean {
- return false;
- /*
- const items: Array = dragTarget.nodes || (dragTarget as NodeDatasDragTarget).data;
+ checkNesting(dropTarget: NodeParent, dragObject: DragNodeObject | DragNodeDataObject): boolean {
+ const items: Array = dragObject.nodes || (dragObject as DragNodeDataObject).data;
return items.every(item => this.checkNestingDown(dropTarget, item));
- */
}
- checkDropTarget(dropTarget: Node, dragTarget: DragNodeObject | DragNodeDataObject): boolean {
- return false;
- /*
- const items: Array = dragTarget.nodes || (dragTarget as NodeDatasDragTarget).data;
+ checkDropTarget(dropTarget: NodeParent, dragObject: DragNodeObject | DragNodeDataObject): boolean {
+ const items: Array = dragObject.nodes || (dragObject as DragNodeDataObject).data;
return items.every(item => this.checkNestingUp(dropTarget, item));
- */
}
- checkNestingUp(parent: NodeParent, target: NodeData | Node): boolean {
- /*
- if (isElementNode(target) || isElementData(target)) {
- const proto = isElementNode(target)
- ? target.prototype
- : this.document.getPrototypeByTagNameOrURI(target.tagName, target.uri);
- if (proto) {
- return proto.checkNestingUp(target, parent);
+ checkNestingUp(parent: NodeParent, target: NodeSchema | Node): boolean {
+ if (isNode(target) || isNodeSchema(target)) {
+ const config = isNode(target) ? target.componentConfig : this.designer.getComponentConfig(target.componentName);
+ if (config) {
+ return config.checkNestingUp(target, parent);
}
- }*/
+ }
return true;
}
- checkNestingDown(parent: NodeParent, target: NodeData | Node): boolean {
- /*
- const proto = parent.prototype;
- if (isConditionFlow(parent)) {
- return parent.children.every(
- child => proto.checkNestingDown(parent, child) && this.checkNestingUp(parent, child),
- );
- } else {
- return proto.checkNestingDown(parent, target) && this.checkNestingUp(parent, target);
- }*/
- return false;
+ checkNestingDown(parent: NodeParent, target: NodeSchema | Node): boolean {
+ const config = parent.componentConfig;
+ return config.checkNestingDown(parent, target) && this.checkNestingUp(parent, target);
}
// #endregion
}
+
+
+function isPointInRect(point: CanvasPoint, rect: Rect) {
+ return (
+ point.canvasY >= rect.top &&
+ point.canvasY <= rect.bottom &&
+ (point.canvasX >= rect.left && point.canvasX <= rect.right)
+ );
+}
+
+function distanceToRect(point: CanvasPoint, rect: Rect) {
+ let minX = Math.min(Math.abs(point.canvasX - rect.left), Math.abs(point.canvasX - rect.right));
+ let minY = Math.min(Math.abs(point.canvasY - rect.top), Math.abs(point.canvasY - rect.bottom));
+ if (point.canvasX >= rect.left && point.canvasX <= rect.right) {
+ minX = 0;
+ }
+ if (point.canvasY >= rect.top && point.canvasY <= rect.bottom) {
+ minY = 0;
+ }
+
+ return Math.sqrt(minX ** 2 + minY ** 2);
+}
+
+function distanceToEdge(point: CanvasPoint, rect: Rect) {
+ const distanceTop = Math.abs(point.canvasY - rect.top);
+ const distanceBottom = Math.abs(point.canvasY - rect.bottom);
+
+ return {
+ distance: Math.min(distanceTop, distanceBottom),
+ nearAfter: distanceBottom < distanceTop,
+ };
+}
+
+function isNearAfter(point: CanvasPoint, rect: Rect, inline: boolean) {
+ if (inline) {
+ return (
+ Math.abs(point.canvasX - rect.left) + Math.abs(point.canvasY - rect.top) >
+ Math.abs(point.canvasX - rect.right) + Math.abs(point.canvasY - rect.bottom)
+ );
+ }
+ return Math.abs(point.canvasY - rect.top) > Math.abs(point.canvasY - rect.bottom);
+}
diff --git a/packages/designer/src/builtins/simulator/renderer/renderer.ts b/packages/designer/src/builtins/simulator/renderer/renderer.ts
index a9328551e..15974c6e7 100644
--- a/packages/designer/src/builtins/simulator/renderer/renderer.ts
+++ b/packages/designer/src/builtins/simulator/renderer/renderer.ts
@@ -8,10 +8,12 @@ import { getClientRects } from '../../../utils/get-client-rects';
import { Asset } from '../utils/asset';
import loader from '../utils/loader';
import { ComponentDescriptionSpec } from '../../../designer/component-config';
-import { reactFindDOMNodes } from '../utils/react-find-dom-nodes';
+import { reactFindDOMNodes, FIBER_KEY } from '../utils/react-find-dom-nodes';
import { isESModule } from '../../../utils/is-es-module';
import { NodeInstance } from '../../../designer/simulator';
import { isElement } from '../../../utils/is-element';
+import cursor from '../../../designer/helper/cursor';
+import { setNativeSelection } from '../../../designer/helper/navtive-selection';
export class SimulatorRenderer {
readonly isSimulatorRenderer = true;
@@ -133,7 +135,9 @@ export class SimulatorRenderer {
let instances = this.instancesMap.get(id);
if (instances) {
instances = instances.filter(checkInstanceMounted);
- instances.push(instance);
+ if (!instances.includes(instance)) {
+ instances.push(instance);
+ }
instancesMap.set(id, instances);
} else {
instancesMap.set(id, [instance]);
@@ -144,12 +148,12 @@ export class SimulatorRenderer {
this.ctxMap.set(id, ctx);
}
- getComponentInstance(id: string): ReactInstance[] | null {
+ getComponentInstances(id: string): ReactInstance[] | null {
return this.instancesMap.get(id) || null;
}
- getClosestNodeInstance(element: Element): NodeInstance | null {
- return getClosestNodeInstance(element);
+ getClosestNodeInstance(from: ReactInstance, nodeId?: string): NodeInstance | null {
+ return getClosestNodeInstance(from, nodeId);
}
findDOMNodes(instance: ReactInstance): Array | null {
@@ -160,6 +164,28 @@ export class SimulatorRenderer {
return getClientRects(element);
}
+ setNativeSelection(enableFlag: boolean) {
+ setNativeSelection(enableFlag);
+ }
+ /**
+ * @see ISimulator
+ */
+ setDraggingState(state: boolean) {
+ cursor.setDragging(state);
+ }
+ /**
+ * @see ISimulator
+ */
+ setCopyState(state: boolean) {
+ cursor.setCopy(state);
+ }
+ /**
+ * @see ISimulator
+ */
+ clearState() {
+ cursor.release();
+ }
+
private _running: boolean = false;
run() {
if (this._running) {
@@ -260,34 +286,44 @@ function cacheReactKey(el: Element): Element {
const SYMBOL_VNID = Symbol('_LCNodeId');
-function getClosestNodeInstance(element: Element): NodeInstance | null {
- let el: any = element;
+function getClosestNodeInstance(from: ReactInstance, specId?: string): NodeInstance | null {
+ let el: any = from;
if (el) {
- el = cacheReactKey(el);
+ if (isElement(el)) {
+ el = cacheReactKey(el);
+ } else {
+ return getNodeInstance(el[FIBER_KEY], specId);
+ }
}
while (el) {
if (SYMBOL_VNID in el) {
- return {
- nodeId: el[SYMBOL_VNID],
- instance: el,
- };
+ const nodeId = el[SYMBOL_VNID];
+ if (!specId || specId === nodeId) {
+ return {
+ nodeId: nodeId,
+ instance: el,
+ };
+ }
}
// get fiberNode from element
if (el[REACT_KEY]) {
- return getNodeInstance(el[REACT_KEY]);
+ return getNodeInstance(el[REACT_KEY], specId);
}
el = el.parentElement;
}
return null;
}
-function getNodeInstance(fiberNode: any): NodeInstance | null {
+function getNodeInstance(fiberNode: any, specId?: string): NodeInstance | null {
const instance = fiberNode.stateNode;
if (instance && SYMBOL_VNID in instance) {
- return {
- nodeId: instance[SYMBOL_VNID],
- instance,
- };
+ const nodeId = instance[SYMBOL_VNID];
+ if (!specId || specId === nodeId) {
+ return {
+ nodeId: nodeId,
+ instance: instance,
+ };
+ }
}
return getNodeInstance(fiberNode.return);
}
diff --git a/packages/designer/src/builtins/simulator/utils/react-find-dom-nodes.ts b/packages/designer/src/builtins/simulator/utils/react-find-dom-nodes.ts
index f2bcf9664..9783804de 100644
--- a/packages/designer/src/builtins/simulator/utils/react-find-dom-nodes.ts
+++ b/packages/designer/src/builtins/simulator/utils/react-find-dom-nodes.ts
@@ -2,7 +2,7 @@ import { ReactInstance } from 'react';
import { isElement } from '../../../utils/is-element';
import { isDOMNode } from '../../../utils/is-dom-node';
-const FIBER_KEY = '_reactInternalFiber';
+export const FIBER_KEY = '_reactInternalFiber';
function elementsFromFiber(fiber: any, elements: Array) {
if (fiber) {
diff --git a/packages/designer/src/designer/component-config.ts b/packages/designer/src/designer/component-config.ts
index fde51b636..64bb76fe0 100644
--- a/packages/designer/src/designer/component-config.ts
+++ b/packages/designer/src/designer/component-config.ts
@@ -280,7 +280,7 @@ export class ComponentConfig {
}
private _isContainer?: boolean;
get isContainer(): boolean {
- return this._isContainer!;
+ return this._isContainer! || this.isRootComponent();
}
private _isModal?: boolean;
get isModal(): boolean {
@@ -354,6 +354,10 @@ export class ComponentConfig {
}
}
+ isRootComponent() {
+ return this.componentName === 'Page' || this.componentName === 'Block' || this.componentName === 'Component';
+ }
+
set spec(spec: ComponentDescriptionSpec) {
this._spec = spec;
this.parseSpec(spec);
diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts
index 9fcc34bf6..2ed1ecfc3 100644
--- a/packages/designer/src/designer/designer.ts
+++ b/packages/designer/src/designer/designer.ts
@@ -56,7 +56,7 @@ export default class Designer {
});
this.dragon.onDrag(e => {
- console.info(e);
+ console.info('dropLocation', this._dropLocation);
if (this.props?.onDrag) {
this.props.onDrag(e);
}
@@ -247,12 +247,9 @@ export default class Designer {
return this._componentConfigsMap.get(componentName)!;
}
- const config = new ComponentConfig({
+ return new ComponentConfig({
componentName,
});
-
- this._componentConfigsMap.set(componentName, config);
- return config;
}
get componentsMap(): { [key: string]: ComponentDescriptionSpec } {
diff --git a/packages/designer/src/designer/document/document-model.ts b/packages/designer/src/designer/document/document-model.ts
index 72319414a..cb80d77a3 100644
--- a/packages/designer/src/designer/document/document-model.ts
+++ b/packages/designer/src/designer/document/document-model.ts
@@ -223,59 +223,16 @@ export default class DocumentModel {
// TODO: emit simulator mounted
}
- /**
- * 根据节点取得视图实例,在循环等场景会有多个,依赖 simulator 的接口
- */
- getComponentInstance(node: Node): ComponentInstance[] | null {
- if (this.simulator) {
- this.simulator.getComponentInstance(node);
- }
- return null;
- }
-
getComponent(componentName: string): any {
return this.simulator!.getComponent(componentName);
}
- getComponentConfig(component: Component, componentName: string): ComponentConfig {
+ getComponentConfig(componentName: string, component?: Component | null): ComponentConfig {
// TODO: guess componentConfig from component by simulator
return this.designer.getComponentConfig(componentName);
}
- /**
- * 通过 DOM 节点获取节点,依赖 simulator 的接口
- */
- getNodeInstanceFromElement(target: Element | null): NodeInstance | null {
- if (!this.simulator || !target) {
- return null;
- }
- const nodeIntance = this.simulator.getClosestNodeInstance(target);
- if (!nodeIntance) {
- return null;
- }
- const node = this.getNode(nodeIntance.nodeId);
- return {
- ...nodeIntance,
- node,
- };
- }
-
- /**
- * 获得到的结果是一个数组
- * 表示一个实例对应多个外层 DOM 节点,依赖 simulator 的接口
- */
- getDOMNodes(instance: ComponentInstance): Array | null {
- if (!this.simulator) {
- return null;
- }
-
- if (isElement(instance)) {
- return [instance];
- }
-
- return this.simulator.findDOMNodes(instance);
- }
private _opened: boolean = true;
private _suspensed: boolean = false;
diff --git a/packages/designer/src/designer/document/node/node-children.ts b/packages/designer/src/designer/document/node/node-children.ts
index 58bff9747..b29fa4b22 100644
--- a/packages/designer/src/designer/document/node/node-children.ts
+++ b/packages/designer/src/designer/document/node/node-children.ts
@@ -1,8 +1,9 @@
import Node, { NodeParent } from './node';
import { NodeData } from '../../schema';
+import { obx, computed } from '@recore/obx';
export default class NodeChildren {
- private children: Node[];
+ @obx.val private children: Node[];
constructor(readonly owner: NodeParent, childrenData: NodeData | NodeData[]) {
this.children = (Array.isArray(childrenData) ? childrenData : [childrenData]).map(child => {
const node = this.owner.document.createNode(child);
@@ -22,14 +23,14 @@ export default class NodeChildren {
/**
* 元素个数
*/
- get size(): number {
+ @computed get size(): number {
return this.children.length;
}
/**
* 是否空
*/
- isEmpty() {
+ @computed isEmpty() {
return this.size < 1;
}
diff --git a/packages/designer/src/designer/document/node/node-content.ts b/packages/designer/src/designer/document/node/node-content.ts
index af146a15b..436681830 100644
--- a/packages/designer/src/designer/document/node/node-content.ts
+++ b/packages/designer/src/designer/document/node/node-content.ts
@@ -1,10 +1,10 @@
-import { obx } from '@recore/obx';
+import { obx, computed } from '@recore/obx';
import { JSExpression, isJSExpression } from '../../schema';
export default class NodeContent {
@obx.ref private _value: string | JSExpression = '';
- get value(): string | JSExpression {
+ @computed get value(): string | JSExpression {
return this._value;
}
@@ -15,7 +15,7 @@ export default class NodeContent {
/**
* 获得表达式值
*/
- get code() {
+ @computed get code() {
if (isJSExpression(this._value)) {
return this._value.value;
}
@@ -70,14 +70,14 @@ export default class NodeContent {
/**
* 是否表达式
*/
- isJSExpression(): boolean {
+ @computed isJSExpression(): boolean {
return isJSExpression(this._value);
}
/**
* 是否空值
*/
- isEmpty() {
+ @computed isEmpty() {
if (isJSExpression(this._value)) {
return this._value.value === '';
}
diff --git a/packages/designer/src/designer/document/node/node.ts b/packages/designer/src/designer/document/node/node.ts
index abb6c16d1..5101ab34b 100644
--- a/packages/designer/src/designer/document/node/node.ts
+++ b/packages/designer/src/designer/document/node/node.ts
@@ -54,8 +54,8 @@ export default class Node {
protected _directives?: Props;
protected _extras?: Props;
protected _children: NodeChildren | NodeContent;
- private _parent: NodeParent | null = null;
- private _zLevel = 0;
+ @obx.ref private _parent: NodeParent | null = null;
+ @obx.ref private _zLevel = 0;
get props(): Props | undefined {
return this._props;
}
@@ -165,15 +165,18 @@ export default class Node {
/**
* 节点组件类
*/
- @obx.ref get component(): Component {
- return this.document.getComponent(this.componentName);
+ @obx.ref get component(): Component | null {
+ if (this.isNodeParent) {
+ return this.document.getComponent(this.componentName);
+ }
+ return null;
}
/**
* 节点组件描述
*/
@obx.ref get componentConfig(): ComponentConfig {
- return this.document.getComponentConfig(this.component, this.componentName);
+ return this.document.getComponentConfig(this.componentName, this.component);
}
@obx.ref get propsData(): PropsMap | PropsList | null {
@@ -258,7 +261,7 @@ export default class Node {
/**
* 获取节点在父容器中的索引
*/
- get index(): number {
+ @computed get index(): number {
if (!this.parent) {
return -1;
}
diff --git a/packages/designer/src/designer/document/node/props/prop.ts b/packages/designer/src/designer/document/node/props/prop.ts
index 274c56d90..281d941d1 100644
--- a/packages/designer/src/designer/document/node/props/prop.ts
+++ b/packages/designer/src/designer/document/node/props/prop.ts
@@ -125,7 +125,7 @@ export default class Prop implements IPropParent {
* 值是否包含表达式
* 包含 JSExpresion | JSSlot 等值
*/
- isContainJSExpression(): boolean {
+ @computed isContainJSExpression(): boolean {
const type = this._type;
if (type === 'expression') {
return true;
@@ -142,12 +142,12 @@ export default class Prop implements IPropParent {
/**
* 是否简单 JSON 数据
*/
- isJSON() {
+ @computed isJSON() {
return !this.isContainJSExpression();
}
- private _items: Prop[] | null = null;
- private _maps: Map | null = null;
+ @obx.val private _items: Prop[] | null = null;
+ @obx.val private _maps: Map | null = null;
@computed private get items(): Prop[] | null {
let _items: any;
untracked(() => {
diff --git a/packages/designer/src/designer/document/node/props/props.ts b/packages/designer/src/designer/document/node/props/props.ts
index 62e30d433..091b094a0 100644
--- a/packages/designer/src/designer/document/node/props/props.ts
+++ b/packages/designer/src/designer/document/node/props/props.ts
@@ -11,7 +11,7 @@ export type UNSET = typeof UNSET;
export default class Props implements IPropParent {
readonly id = uniqueId('props');
@obx.val private items: Prop[] = [];
- @obx.ref private get maps(): Map {
+ @computed private get maps(): Map {
const maps = new Map();
if (this.items.length > 0) {
this.items.forEach(prop => {
@@ -36,7 +36,7 @@ export default class Props implements IPropParent {
/**
* 元素个数
*/
- get size() {
+ @computed get size() {
return this.items.length;
}
diff --git a/packages/designer/src/designer/document/node/props/stash-space.ts b/packages/designer/src/designer/document/node/props/stash-space.ts
index 14cb36e18..e38d14015 100644
--- a/packages/designer/src/designer/document/node/props/stash-space.ts
+++ b/packages/designer/src/designer/document/node/props/stash-space.ts
@@ -1,10 +1,10 @@
-import { obx, autorun, untracked } from '@recore/obx';
+import { obx, autorun, untracked, computed } from '@recore/obx';
import Prop, { IPropParent } from './prop';
export type PendingItem = Prop[];
export default class StashSpace implements IPropParent {
@obx.val private space: Set = new Set();
- @obx.ref private get maps(): Map {
+ @computed private get maps(): Map {
const maps = new Map();
if (this.space.size > 0) {
this.space.forEach(prop => {
diff --git a/packages/designer/src/designer/helper/dragon.ts b/packages/designer/src/designer/helper/dragon.ts
index bb8b17419..b19e5ceb9 100644
--- a/packages/designer/src/designer/helper/dragon.ts
+++ b/packages/designer/src/designer/helper/dragon.ts
@@ -2,8 +2,8 @@ import { EventEmitter } from 'events';
import { obx } from '@recore/obx';
import Location from './location';
import DocumentModel from '../document/document-model';
-import { NodeData } from '../schema';
-import { ISimulator, isSimulator } from '../simulator';
+import { NodeData, NodeSchema } from '../schema';
+import { ISimulator, isSimulator, ComponentInstance } from '../simulator';
import Node from '../document/node/node';
import Designer from '../designer';
import { setNativeSelection } from './navtive-selection';
@@ -43,11 +43,14 @@ export interface LocateEvent {
/**
* 激活或目标文档
*/
- document?: DocumentModel;
+ documentModel?: DocumentModel;
/**
* 事件订正标识,初始构造时,从发起端构造,缺少 canvasX,canvasY, 需要经过订正才有
*/
fixed?: true;
+
+ targetNode?: Node;
+ targetInstance?: ComponentInstance;
}
/**
@@ -89,8 +92,8 @@ export interface DragNodeObject {
}
export interface DragNodeDataObject {
type: DragObjectType.NodeData;
- data: NodeData | NodeData[];
- maps?: { [tagName: string]: string };
+ data: NodeSchema | NodeSchema[];
+ maps?: { [componentName: string]: string };
thumbnail?: string;
description?: string;
[extra: string]: any;
@@ -279,7 +282,7 @@ export default class Dragon {
if (this._dragging) {
this._dragging = false;
try {
- this.emitter.emit('dragend', { dragTarget: dragObject, copy: this.isCopyState() });
+ this.emitter.emit('dragend', { dragObject, copy: this.isCopyState() });
} catch (ex) {
exception = ex;
}
@@ -339,6 +342,8 @@ export default class Dragon {
const g = srcSim.viewport.toGlobalPoint(e);
evt.globalX = g.clientX;
evt.globalY = g.clientY;
+ evt.canvasX = e.clientX;
+ evt.canvasY = e.clientY;
evt.sensor = srcSim;
} else {
// this condition will not happen, just make sure ts ok
@@ -352,10 +357,12 @@ export default class Dragon {
const sourceSensor = getSourceSensor(dragObject);
const sensors: ISensor[] = (masterSensors as ISensor[]).concat(this.sensors);
const chooseSensor = (e: LocateEvent) => {
- let sensor = e.sensor || sensors.find(s => s.sensorAvailable && s.isEnter(e));
+ let sensor = e.sensor && e.sensor.isEnter(e) ? e.sensor : sensors.find(s => s.sensorAvailable && s.isEnter(e));
if (!sensor) {
if (lastSensor) {
sensor = lastSensor;
+ } else if (e.sensor) {
+ sensor = e.sensor;
} else if (sourceSensor) {
sensor = sourceSensor;
}
diff --git a/packages/designer/src/designer/helper/hovering.ts b/packages/designer/src/designer/helper/hovering.ts
index 7af2493c3..215435c76 100644
--- a/packages/designer/src/designer/helper/hovering.ts
+++ b/packages/designer/src/designer/helper/hovering.ts
@@ -21,7 +21,6 @@ export default class Hovering {
}
hover(node: Node | null) {
- console.info(node);
this._current = node;
}
diff --git a/packages/designer/src/designer/helper/location.ts b/packages/designer/src/designer/helper/location.ts
index 22eac5dc3..c8e06de92 100644
--- a/packages/designer/src/designer/helper/location.ts
+++ b/packages/designer/src/designer/helper/location.ts
@@ -14,6 +14,7 @@ export enum LocationDetailType {
export interface LocationChildrenDetail {
type: LocationDetailType.Children;
index: number;
+ edge?: DOMRect;
near?: {
node: ComponentNode;
pos: 'before' | 'after';
@@ -36,11 +37,16 @@ export interface Point {
clientY: number;
}
-export type Rects = Array & {
+export interface CanvasPoint {
+ canvasX: number;
+ canvasY: number;
+}
+
+export type Rects = DOMRect[] & {
elements: Array;
};
-export type Rect = (ClientRect | DOMRect) & {
+export type Rect = DOMRect & {
elements: Array;
computed?: boolean;
};
diff --git a/packages/designer/src/designer/simulator.ts b/packages/designer/src/designer/simulator.ts
index f508920dd..5a5ee0502 100644
--- a/packages/designer/src/designer/simulator.ts
+++ b/packages/designer/src/designer/simulator.ts
@@ -100,16 +100,6 @@ export interface ISimulator extends ISensor {
*/
clearState(): void;
- /**
- * 在模拟器拖拽定位
- */
- locate(e: LocateEvent): any;
-
- /**
- * 给 event 打补丁,添加 canvasX, globalX 等信息,用于拖拽
- */
- fixEvent(e: LocateEvent): LocateEvent;
-
// #endregion
/**
@@ -128,13 +118,15 @@ export interface ISimulator
extends ISensor {
/**
* 根据节点获取节点的组件实例
*/
- getComponentInstance(node: Node): ComponentInstance[] | null;
+ getComponentInstances(node: Node): ComponentInstance[] | null;
/**
* 根据节点获取节点的组件运行上下文
*/
getComponentContext(node: Node): object | null;
- getClosestNodeInstance(elem: Element): NodeInstance | null;
+ getClosestNodeInstance(from: ComponentInstance, specId?: string): NodeInstance | null;
+
+ computeRect(node: Node): DOMRect | null;
computeComponentInstanceRect(instance: ComponentInstance): DOMRect | null;
@@ -150,9 +142,9 @@ export function isSimulator(obj: any): obj is ISimulator {
return obj && obj.isSimulator;
}
-export interface NodeInstance {
+export interface NodeInstance {
nodeId: string;
- instance: ComponentInstance;
+ instance: T;
node?: Node | null;
}