complete router

This commit is contained in:
kangwei 2020-08-12 18:05:07 +08:00
parent 45ffc98277
commit dc8542a8fa
18 changed files with 336 additions and 244 deletions

View File

@ -57,7 +57,10 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {
@computed get current() { @computed get current() {
const host = this.props.host; const host = this.props.host;
const doc = host.document; const doc = host.currentDocument;
if (!doc) {
return null;
}
const selection = doc.selection; const selection = doc.selection;
const current = host.designer.detecting.current; const current = host.designer.detecting.current;
if (!current || current.document !== doc || selection.has(current.id)) { if (!current || current.document !== doc || selection.has(current.id)) {

View File

@ -5,6 +5,7 @@ import classNames from 'classnames';
import { SimulatorContext } from '../context'; import { SimulatorContext } from '../context';
import { BuiltinSimulatorHost } from '../host'; import { BuiltinSimulatorHost } from '../host';
import { OffsetObserver, Designer } from '../../designer'; import { OffsetObserver, Designer } from '../../designer';
import { Node } from '../../document';
@observer @observer
export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost }> { export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost }> {
@ -19,8 +20,8 @@ export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost
} }
@computed get selecting() { @computed get selecting() {
const doc = this.host.document; const doc = this.host.currentDocument;
if (doc.suspensed) { if (!doc || doc.suspensed) {
return null; return null;
} }
const selection = doc.selection; const selection = doc.selection;
@ -146,9 +147,9 @@ export class BoxResizingInstance extends Component<{
metaData.experimental.callbacks && metaData.experimental.callbacks &&
typeof metaData.experimental.callbacks.onResize === 'function' typeof metaData.experimental.callbacks.onResize === 'function'
) { ) {
e.trigger = direction; (e as any).trigger = direction;
e.deltaX = moveX; (e as any).deltaX = moveX;
e.deltaY = moveY; (e as any).deltaY = moveY;
metaData.experimental.callbacks.onResize(e, node); metaData.experimental.callbacks.onResize(e, node);
} }
}; };
@ -161,7 +162,7 @@ export class BoxResizingInstance extends Component<{
metaData.experimental.callbacks && metaData.experimental.callbacks &&
typeof metaData.experimental.callbacks.onResizeStart === 'function' typeof metaData.experimental.callbacks.onResizeStart === 'function'
) { ) {
e.trigger = direction; (e as any).trigger = direction;
metaData.experimental.callbacks.onResizeStart(e, node); metaData.experimental.callbacks.onResizeStart(e, node);
} }
}; };
@ -174,7 +175,7 @@ export class BoxResizingInstance extends Component<{
metaData.experimental.callbacks && metaData.experimental.callbacks &&
typeof metaData.experimental.callbacks.onResizeEnd === 'function' typeof metaData.experimental.callbacks.onResizeEnd === 'function'
) { ) {
e.trigger = direction; (e as any).trigger = direction;
metaData.experimental.callbacks.onResizeStart(e, node); metaData.experimental.callbacks.onResizeStart(e, node);
} }

View File

@ -198,8 +198,8 @@ export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> {
} }
@computed get selecting() { @computed get selecting() {
const doc = this.host.document; const doc = this.host.currentDocument;
if (doc.suspensed || this.host.liveEditing.editing) { if (!doc || doc.suspensed || this.host.liveEditing.editing) {
return null; return null;
} }
const selection = doc.selection; const selection = doc.selection;

View File

@ -119,7 +119,7 @@ export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> {
render() { render() {
const { host } = this.props; const { host } = this.props;
const loc = host.document.dropLocation; const loc = host.currentDocument?.dropLocation;
if (!loc) { if (!loc) {
return null; return null;
} }

View File

@ -2,7 +2,7 @@ import { obx, autorun, computed, getPublicPath, hotkey, focusTracker } from '@al
import { ISimulatorHost, Component, NodeInstance, ComponentInstance } from '../simulator'; import { ISimulatorHost, Component, NodeInstance, ComponentInstance } from '../simulator';
import Viewport from './viewport'; import Viewport from './viewport';
import { createSimulator } from './create-simulator'; import { createSimulator } from './create-simulator';
import { Node, ParentalNode, DocumentModel, isNode, contains, isRootNode } from '../document'; import { Node, ParentalNode, isNode, contains, isRootNode } from '../document';
import ResourceConsumer from './resource-consumer'; import ResourceConsumer from './resource-consumer';
import { import {
AssetLevel, AssetLevel,
@ -89,6 +89,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
readonly designer = this.project.designer; readonly designer = this.project.designer;
get currentDocument() {
return this.project.currentDocument;
}
@computed get device(): string { @computed get device(): string {
return this.get('device') || 'default'; return this.get('device') || 'default';
} }
@ -141,6 +145,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return autorun(fn as any, true); return autorun(fn as any, true);
} }
autorun(fn: (context: { dispose: () => void; firstRun: boolean }) => void) {
return autorun(fn as any, true);
}
purge(): void { purge(): void {
// todo // todo
} }
@ -245,9 +253,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
} }
setupDragAndClick() { setupDragAndClick() {
const documentModel = this.document; const designer = this.designer;
const selection = documentModel.selection;
const designer = documentModel.designer;
const doc = this.contentDocument!; const doc = this.contentDocument!;
// TODO: think of lock when edit a node // TODO: think of lock when edit a node
@ -257,9 +263,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
(downEvent: MouseEvent) => { (downEvent: MouseEvent) => {
// fix for popups close logic // fix for popups close logic
document.dispatchEvent(new Event('mousedown')); document.dispatchEvent(new Event('mousedown'));
if (this.liveEditing.editing) { const documentModel = this.project.currentDocument;
if (this.liveEditing.editing || !documentModel) {
return; return;
} }
const selection = documentModel.selection;
// stop response document focus event // stop response document focus event
downEvent.stopPropagation(); downEvent.stopPropagation();
downEvent.preventDefault(); downEvent.preventDefault();
@ -267,8 +275,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
// FIXME: dirty fix remove label-for fro liveEditing // FIXME: dirty fix remove label-for fro liveEditing
(downEvent.target as HTMLElement).removeAttribute('for'); (downEvent.target as HTMLElement).removeAttribute('for');
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element); const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
const node = nodeInst?.node || this.document.rootNode; const node = nodeInst?.node || documentModel.rootNode;
const isMulti = downEvent.metaKey || downEvent.ctrlKey; const isMulti = downEvent.metaKey || downEvent.ctrlKey;
const isLeftButton = downEvent.which === 1 || downEvent.button === 0; const isLeftButton = downEvent.which === 1 || downEvent.button === 0;
const checkSelect = (e: MouseEvent) => { const checkSelect = (e: MouseEvent) => {
@ -280,6 +289,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
selection.remove(id); selection.remove(id);
} else { } else {
selection.select(id); selection.select(id);
// dirty code should refector
const editor = this.designer?.editor; const editor = this.designer?.editor;
const npm = node?.componentMeta?.npm; const npm = node?.componentMeta?.npm;
const selected = const selected =
@ -303,7 +314,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
selection.add(node.id); selection.add(node.id);
ignoreUpSelected = true; ignoreUpSelected = true;
} }
selection.remove(this.document.rootNode.id); selection.remove(documentModel.rootNode.id);
// 获得顶层 nodes // 获得顶层 nodes
nodes = selection.getTopNodes(); nodes = selection.getTopNodes();
} else if (selection.containsNode(node, true)) { } else if (selection.containsNode(node, true)) {
@ -359,7 +370,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
*/ */
setupDetecting() { setupDetecting() {
const doc = this.contentDocument!; const doc = this.contentDocument!;
const detecting = this.document.designer.detecting; const detecting = this.designer.detecting;
const hover = (e: MouseEvent) => { const hover = (e: MouseEvent) => {
if (!detecting.enable) { if (!detecting.enable) {
return; return;
@ -368,7 +379,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
detecting.capture(nodeInst?.node || null); detecting.capture(nodeInst?.node || null);
e.stopPropagation(); e.stopPropagation();
}; };
const leave = () => detecting.leave(this.document); const leave = () => detecting.leave(this.project.currentDocument);
doc.addEventListener('mouseover', hover, true); doc.addEventListener('mouseover', hover, true);
doc.addEventListener('mouseleave', leave, false); doc.addEventListener('mouseleave', leave, false);
@ -383,7 +394,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
); );
this.disableHovering = () => { this.disableHovering = () => {
detecting.leave(this.document); detecting.leave(this.project.currentDocument);
doc.removeEventListener('mouseover', hover, true); doc.removeEventListener('mouseover', hover, true);
doc.removeEventListener('mouseleave', leave, false); doc.removeEventListener('mouseleave', leave, false);
this.disableHovering = undefined; this.disableHovering = undefined;
@ -406,7 +417,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
if (!nodeInst) { if (!nodeInst) {
return; return;
} }
const node = nodeInst.node || this.document.rootNode; const node = nodeInst.node || this.project.currentDocument?.rootNode;
if (!node) {
return;
}
const rootElement = this.findDOMNodes(nodeInst.instance, node.componentMeta.rootSelector)?.find((item) => const rootElement = this.findDOMNodes(nodeInst.instance, node.componentMeta.rootSelector)?.find((item) =>
item.contains(targetElement), item.contains(targetElement),
@ -450,10 +464,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
if (!nodeInst) { if (!nodeInst) {
return; return;
} }
const node = nodeInst.node || this.document.rootNode; const node = nodeInst.node || this.project.currentDocument?.rootNode;
if (!node) { if (!node) {
return; return;
} }
// dirty code should refector
const editor = this.designer?.editor; const editor = this.designer?.editor;
const npm = node?.componentMeta?.npm; const npm = node?.componentMeta?.npm;
const selected = const selected =
@ -504,14 +520,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
} }
createComponent(schema: ComponentSchema): Component | null { createComponent(schema: ComponentSchema): Component | null {
return this.renderer?.createComponent(schema) || null; return null;
// return this.renderer?.createComponent(schema) || null;
} }
@obx private instancesMap: { @obx private instancesMap: {
[docId: string]: Map<string, ComponentInstance[]>; [docId: string]: Map<string, ComponentInstance[]>;
} = {}; } = {};
setInstance(docId: string, id: string, instances: ComponentInstance[] | null) { setInstance(docId: string, id: string, instances: ComponentInstance[] | null) {
if (hasOwnProperty(this.instancesMap, docId)) { if (!hasOwnProperty(this.instancesMap, docId)) {
this.instancesMap[docId] = new Map(); this.instancesMap[docId] = new Map();
} }
if (instances == null) { if (instances == null) {
@ -524,17 +541,18 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
/** /**
* @see ISimulator * @see ISimulator
*/ */
getComponentInstances(node: Node): ComponentInstance[] | null { getComponentInstances(node: Node, context?: NodeInstance): ComponentInstance[] | null {
const docId = node.document.id; const docId = node.document.id;
return this.instancesMap[docId]?.get(node.id) || null; let instances = this.instancesMap[docId]?.get(node.id) || null;
} if (!instances || !context) {
return instances;
}
/** // filter with context
* @see ISimulator return instances.filter((instance) => {
*/ return this.getClosestNodeInstance(instance, context.nodeId)?.instance === context.instance
getComponentInstanceId(instance: ComponentInstance) { });
throw new Error('Method not implemented.');
} }
/** /**
@ -659,7 +677,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
if (!nodeIntance) { if (!nodeIntance) {
return null; return null;
} }
const node = this.document.getNode(nodeIntance.nodeId); const { docId } = nodeIntance;
const doc = this.project.getDocument(docId)!;
const node = doc.getNode(nodeIntance.nodeId);
return { return {
...nodeIntance, ...nodeIntance,
node, node,
@ -782,9 +802,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
e.target = this.contentDocument!.elementFromPoint(e.canvasX!, e.canvasY!); e.target = this.contentDocument!.elementFromPoint(e.canvasX!, e.canvasY!);
} }
// documentModel : 目标文档
e.documentModel = this.document;
// 事件已订正 // 事件已订正
e.fixed = true; e.fixed = true;
return e; return e;
@ -815,6 +832,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
locate(e: LocateEvent): any { locate(e: LocateEvent): any {
this.sensing = true; this.sensing = true;
this.scroller.scrolling(e); this.scroller.scrolling(e);
const document = this.project.currentDocument;
if (!document) {
return null;
}
const dropContainer = this.getDropContainer(e); const dropContainer = this.getDropContainer(e);
if (!dropContainer) { if (!dropContainer) {
return null; return null;
@ -841,9 +862,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
}; };
const locationData = { const locationData = {
target: container, target: container as ParentalNode,
detail, detail,
source: 'simulator' + this.document.id, source: 'simulator' + document.id,
event: e, event: e,
}; };
@ -854,9 +875,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
e.dragObject.nodes[0].getPrototype()?.isModal() e.dragObject.nodes[0].getPrototype()?.isModal()
) { ) {
return this.designer.createLocation({ return this.designer.createLocation({
target: this.document.rootNode, target: document.rootNode,
detail, detail,
source: 'simulator' + this.document.id, source: 'simulator' + document.id,
event: e, event: e,
}); });
} }
@ -960,7 +981,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
getDropContainer(e: LocateEvent): DropContainer | LocationData | null { getDropContainer(e: LocateEvent): DropContainer | LocationData | null {
const { target, dragObject } = e; const { target, dragObject } = e;
const isAny = isDragAnyObject(dragObject); const isAny = isDragAnyObject(dragObject);
const { modalNode, currentRoot } = this.document; const document = this.project.currentDocument!;
const { currentRoot } = document;
let container: Node; let container: Node;
let nodeInstance: NodeInstance<ComponentInstance> | undefined; let nodeInstance: NodeInstance<ComponentInstance> | undefined;
@ -984,11 +1006,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
container = container.parent || currentRoot; container = container.parent || currentRoot;
} }
// check container if in modalNode layer, if not, use modalNode
if (modalNode && !modalNode.contains(container)) {
container = modalNode;
}
// TODO: use spec container to accept specialData // TODO: use spec container to accept specialData
if (isAny) { if (isAny) {
// will return locationData // will return locationData
@ -996,7 +1013,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
} }
// get common parent, avoid drop container contains by dragObject // get common parent, avoid drop container contains by dragObject
// TODO: renderengine support pointerEvents: none for acceleration
const drillDownExcludes = new Set<Node>(); const drillDownExcludes = new Set<Node>();
if (isDragNodeObject(dragObject)) { if (isDragNodeObject(dragObject)) {
const nodes = dragObject.nodes; const nodes = dragObject.nodes;
@ -1008,63 +1024,70 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
} }
} }
if (p !== container) { if (p !== container) {
container = p || this.document.rootNode; container = p || document.rootNode;
drillDownExcludes.add(container); drillDownExcludes.add(container);
} }
} }
const ret: any = { let instance: any;
container,
};
if (nodeInstance) { if (nodeInstance) {
if (nodeInstance.node === container) { if (nodeInstance.node === container) {
ret.instance = nodeInstance.instance; instance = nodeInstance.instance;
} else { } else {
ret.instance = this.getClosestNodeInstance(nodeInstance.instance as any, container.id)?.instance; instance = this.getClosestNodeInstance(nodeInstance.instance as any, container.id)?.instance;
} }
} else { } else {
ret.instance = this.getComponentInstances(container)?.[0]; instance = this.getComponentInstances(container)?.[0];
} }
let dropContainer: DropContainer = {
container: container as any,
instance
};
let res: any; let res: any;
let upward: any; let upward: DropContainer | null = null;
// TODO: complete drill down logic
while (container) { while (container) {
if (ret.container !== container) { res = this.handleAccept(dropContainer, e);
ret.container = container;
ret.instance = this.getClosestNodeInstance(ret.instance, container.id)?.instance;
}
res = this.handleAccept(ret, e);
if (isLocationData(res)) { if (isLocationData(res)) {
return res; return res;
} }
if (res === true) { if (res === true) {
return ret; return dropContainer;
} }
if (!res) { if (!res) {
drillDownExcludes.add(container); drillDownExcludes.add(container);
if (upward) { if (upward) {
container = upward; dropContainer = upward;
container = dropContainer.container;
upward = null; upward = null;
} else if (container.parent) { } else if (container.parent) {
container = container.parent; container = container.parent;
instance = this.getClosestNodeInstance(dropContainer.instance, container.id)?.instance;
dropContainer = {
container: container as ParentalNode,
instance
};
} else { } else {
return null; return null;
} }
} else if (isNode(res)) { }/* else if (res === DRILL_DOWN) {
/* else if (res === DRILL_DOWN) {
if (!upward) { if (!upward) {
upward = container.parent; container = container.parent;
instance = this.getClosestNodeInstance(dropContainer.instance, container.id)?.instance;
upward = {
container,
instance
};
} }
container = this.getNearByContainer(container, drillExcludes, e); dropContainer = this.getNearByContainer(dropContainer, drillDownExcludes, e);
if (!container) { if (!dropContainer) {
container = upward; dropContainer = upward;
upward = null; upward = null;
} }
} else if (isNode(res)) {
// TODO:
}*/ }*/
container = res;
upward = null;
}
} }
return null; return null;
} }
@ -1086,8 +1109,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
*/ */
handleAccept({ container, instance }: DropContainer, e: LocateEvent) { handleAccept({ container, instance }: DropContainer, e: LocateEvent) {
const { dragObject } = e; const { dragObject } = e;
const document = this.currentDocument!;
if (isRootNode(container)) { if (isRootNode(container)) {
return this.document.checkDropTarget(container, dragObject as any); return document.checkDropTarget(container, dragObject as any);
} }
const meta = (container as Node).componentMeta; const meta = (container as Node).componentMeta;
@ -1126,36 +1150,44 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
} }
// check nesting // check nesting
return this.document.checkNesting(container, dragObject as any); return document.checkNesting(container, dragObject as any);
} }
/** /**
* *
*/ */
getNearByContainer(container: ParentalNode, e: LocateEvent) { getNearByContainer({ container, instance }: DropContainer, drillDownExcludes: Set<Node>, e: LocateEvent) {
/*
const children = container.children; const children = container.children;
if (!children || children.length < 1) { const document = this.project.currentDocument!;
if (!children || children.isEmpty()) {
return null; return null;
} }
let nearDistance: any = null; let nearDistance: any = null;
let nearBy: any = null; let nearBy: any = null;
for (let i = 0, l = children.length; i < l; i++) { for (let i = 0, l = children.size; i < l; i++) {
let child: any = children[i]; let child = children.get(i);
if (!isElementNode(child)) {
if (!child) {
continue; continue;
} }
if (hasConditionFlow(child)) { if (child.conditionGroup) {
const bn = child.conditionFlow; const bn = child.conditionGroup;
i = bn.index + bn.length - 1; i = bn.index + bn.length - 1;
child = bn.visibleNode; child = bn.visibleNode;
} }
const rect = this.document.computeRect(child); if (!child.isParental() || drillDownExcludes.has(child)) {
continue;
}
// TODO:
this.findDOMNodes(instance);
this.getComponentInstances(child)
const rect = this.computeRect(child);
if (!rect) { if (!rect) {
continue; continue;
} }
/*
if (isPointInRect(e, rect)) { if (isPointInRect(e, rect)) {
return child; return child;
} }
@ -1164,11 +1196,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
if (nearDistance === null || distance < nearDistance) { if (nearDistance === null || distance < nearDistance) {
nearDistance = distance; nearDistance = distance;
nearBy = child; nearBy = child;
} }*/
} }
return nearBy; return nearBy;
*/
} }
// #endregion // #endregion
} }

View File

@ -29,7 +29,7 @@ export class Detecting {
} }
} }
leave(document: DocumentModel) { leave(document: DocumentModel | undefined) {
if (this.current && this.current.document === document) { if (this.current && this.current.document === document) {
this._current = null; this._current = null;
} }

View File

@ -202,8 +202,7 @@ export class Dragon {
private emitter = new EventEmitter(); private emitter = new EventEmitter();
constructor(readonly designer: Designer) { constructor(readonly designer: Designer) {}
}
/** /**
* Quick listen a shell(container element) drag behavior * Quick listen a shell(container element) drag behavior
@ -416,7 +415,8 @@ export class Dragon {
if (!sourceDocument || sourceDocument === document) { if (!sourceDocument || sourceDocument === document) {
evt.globalX = e.clientX; evt.globalX = e.clientX;
evt.globalY = e.clientY; evt.globalY = e.clientY;
} else { // event from simulator sandbox } else {
// event from simulator sandbox
let srcSim: ISimulatorHost | undefined; let srcSim: ISimulatorHost | undefined;
const lastSim = lastSensor && isSimulatorHost(lastSensor) ? lastSensor : null; const lastSim = lastSensor && isSimulatorHost(lastSensor) ? lastSensor : null;
// check source simulator // check source simulator
@ -517,22 +517,30 @@ export class Dragon {
} }
private getMasterSensors(): ISimulatorHost[] { private getMasterSensors(): ISimulatorHost[] {
return this.designer.project.documents return Array.from(
.map((doc) => { new Set(
// TODO: not use actived, this.designer.project.documents
if (doc.actived && doc.simulator?.sensorAvailable) { .map((doc) => {
return doc.simulator; // TODO: not use actived,
} if (doc.actived && doc.simulator?.sensorAvailable) {
return null; return doc.simulator;
}) }
.filter(Boolean) as any; return null;
})
.filter(Boolean) as any,
),
);
}
private getSimulators() {
return new Set(this.designer.project.documents.map(doc => doc.simulator));
} }
// #region ======== drag and drop helpers ============ // #region ======== drag and drop helpers ============
private setNativeSelection(enableFlag: boolean) { private setNativeSelection(enableFlag: boolean) {
setNativeSelection(enableFlag); setNativeSelection(enableFlag);
this.designer.project.documents.forEach((doc) => { this.getSimulators().forEach((sim) => {
doc.simulator?.setNativeSelection(enableFlag); sim?.setNativeSelection(enableFlag);
}); });
} }
@ -541,8 +549,8 @@ export class Dragon {
*/ */
private setDraggingState(state: boolean) { private setDraggingState(state: boolean) {
cursor.setDragging(state); cursor.setDragging(state);
this.designer.project.documents.forEach((doc) => { this.getSimulators().forEach((sim) => {
doc.simulator?.setDraggingState(state); sim?.setDraggingState(state);
}); });
} }
@ -551,8 +559,8 @@ export class Dragon {
*/ */
private setCopyState(state: boolean) { private setCopyState(state: boolean) {
cursor.setCopy(state); cursor.setCopy(state);
this.designer.project.documents.forEach((doc) => { this.getSimulators().forEach((sim) => {
doc.simulator?.setCopyState(state); sim?.setCopyState(state);
}); });
} }
@ -561,8 +569,8 @@ export class Dragon {
*/ */
private clearState() { private clearState() {
cursor.release(); cursor.release();
this.designer.project.documents.forEach((doc) => { this.getSimulators().forEach((sim) => {
doc.simulator?.clearState(); sim?.clearState();
}); });
} }
// #endregion // #endregion

View File

@ -1,4 +1,3 @@
export * from './document-view';
export * from './document-model'; export * from './document-model';
export * from './node'; export * from './node';
export * from './selection'; export * from './selection';

View File

@ -28,6 +28,10 @@ export class ExclusiveGroup {
return this.children[0]!; return this.children[0]!;
} }
get index() {
return this.firstNode.index;
}
add(node: Node) { add(node: Node) {
if (node.nextSibling && node.nextSibling.conditionGroup === this) { if (node.nextSibling && node.nextSibling.conditionGroup === this) {
const i = this.children.indexOf(node.nextSibling); const i = this.children.indexOf(node.nextSibling);

View File

@ -12,17 +12,9 @@
background: transparent url(//img.alicdn.com/tfs/TB1xLKQAbj1gK0jSZFuXXcrHpXa-90-90.png) center 30% no-repeat; background: transparent url(//img.alicdn.com/tfs/TB1xLKQAbj1gK0jSZFuXXcrHpXa-90-90.png) center 30% no-repeat;
padding-top: 50%; padding-top: 50%;
} }
.lc-document {
.lc-simulator-shell {
width: 100%; width: 100%;
height: 100%; height: 100%;
&-hidden {
// todo:
display: none;
}
.lc-simulator-shell {
width: 100%;
height: 100%;
}
} }
} }

View File

@ -11,8 +11,6 @@ export class Project {
private data: ProjectSchema = { version: '1.0.0', componentsMap: [], componentsTree: [] }; private data: ProjectSchema = { version: '1.0.0', componentsMap: [], componentsTree: [] };
@obx.ref canvasDisplayMode: 'exclusive' | 'overview' = 'exclusive';
private _simulator?: ISimulatorHost; private _simulator?: ISimulatorHost;
/** /**
@ -112,14 +110,26 @@ export class Project {
| string, | string,
): any {} ): any {}
private documentsMap = new Map<string, DocumentModel>();
getDocument(id: string): DocumentModel | null {
return this.documentsMap.get(id) || null;
}
createDocument(data?: RootSchema): DocumentModel {
const doc = new DocumentModel(this, data);
this.documents.push(doc);
this.documentsMap.set(doc.id, doc);
return doc;
}
open(doc?: string | DocumentModel | RootSchema): DocumentModel | null { open(doc?: string | DocumentModel | RootSchema): DocumentModel | null {
if (!doc) { if (!doc) {
const got = this.documents.find((item) => item.isBlank()); const got = this.documents.find((item) => item.isBlank());
if (got) { if (got) {
return got.open(); return got.open();
} }
doc = new DocumentModel(this); doc = this.createDocument();
this.documents.push(doc);
return doc.open(); return doc.open();
} }
if (typeof doc === 'string') { if (typeof doc === 'string') {
@ -130,8 +140,7 @@ export class Project {
const data = this.data.componentsTree.find((data) => data.fileName === doc); const data = this.data.componentsTree.find((data) => data.fileName === doc);
if (data) { if (data) {
doc = new DocumentModel(this, data); doc = this.createDocument(data);
this.documents.push(doc);
return doc.open(); return doc.open();
} }
@ -142,8 +151,7 @@ export class Project {
return doc.open(); return doc.open();
} }
doc = new DocumentModel(this, doc); doc = this.createDocument(doc);
this.documents.push(doc);
return doc.open(); return doc.open();
} }

View File

@ -86,7 +86,6 @@ export class Trunk {
} }
registerSetter(type: string, setter: CustomView | RegisteredSetter) { registerSetter(type: string, setter: CustomView | RegisteredSetter) {
// console.warn('Trunk.registerSetter is deprecated');
registerSetter(type, setter); registerSetter(type, setter);
} }

View File

@ -25,7 +25,7 @@ class Contents extends Component<{ area: Area }> {
const top: any[] = []; const top: any[] = [];
const bottom: any[] = []; const bottom: any[] = [];
area.container.items.forEach((item) => { area.container.items.forEach((item) => {
const content = <div id={`left-area-${item.name}`}>{item.content}</div>; const content = <div key={`left-area-${item.name}`}>{item.content}</div>;
if (item.align === 'bottom') { if (item.align === 'bottom') {
bottom.push(content); bottom.push(content);
} else { } else {

View File

@ -30,7 +30,7 @@ class Contents extends Component<{ area: Area, itemClassName?: string }> {
return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);
}).forEach(item => { }).forEach(item => {
const content = ( const content = (
<div className={itemClassName || ''} id={`top-area-${item.name}`}> <div className={itemClassName || ''} key={`top-area-${item.name}`}>
{item.content} {item.content}
</div> </div>
); );

View File

@ -82,9 +82,6 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
e.target = document.elementFromPoint(e.canvasX!, e.canvasY!); e.target = document.elementFromPoint(e.canvasX!, e.canvasY!);
} }
// documentModel : 目标文档
e.documentModel = this._designer?.currentDocument;
// 事件已订正 // 事件已订正
e.fixed = true; e.fixed = true;
return e; return e;

View File

@ -2,6 +2,7 @@ import LowCodeRenderer from '@ali/lowcode-react-renderer';
import { ReactInstance, Fragment, Component, createElement } from 'react'; import { ReactInstance, Fragment, Component, createElement } from 'react';
import { observer } from '@recore/obx-react'; import { observer } from '@recore/obx-react';
import { SimulatorRendererContainer, DocumentInstance } from './renderer'; import { SimulatorRendererContainer, DocumentInstance } from './renderer';
import { Router, Route, Switch } from 'react-router';
import './renderer.less'; import './renderer.less';
// patch cloneElement avoid lost keyProps // patch cloneElement avoid lost keyProps
@ -38,17 +39,19 @@ export default class SimulatorRendererView extends Component<{ rendererContainer
render() { render() {
const { rendererContainer } = this.props; const { rendererContainer } = this.props;
return ( return (
<Layout rendererContainer={rendererContainer}> <Router history={rendererContainer.history}>
<Router onChange={(currentPath: string) => { <Layout rendererContainer={rendererContainer}>
rendererContainer.redirect(currentPath); <Switch>
}}> {rendererContainer.documentInstances.map((instance) => (
{rendererContainer.getDocumentInstances().map((instance) => { <Route
return <Route path={instance.document.get('fileName')}> path={instance.path}
<Renderer documentInstance={instance} /> key={instance.id}
</Route> render={(routeProps) => <Renderer documentInstance={instance} {...routeProps} />}
})} />
</Router> ))}
</Layout> </Switch>
</Layout>
</Router>
); );
} }
} }
@ -106,7 +109,6 @@ class Renderer extends Component<{ documentInstance: DocumentInstance }> {
schema={documentInstance.schema} schema={documentInstance.schema}
components={container.components} components={container.components}
appHelper={container.context} appHelper={container.context}
// context={renderer.context}
designMode={designMode} designMode={designMode}
suspended={documentInstance.suspended} suspended={documentInstance.suspended}
self={documentInstance.scope} self={documentInstance.scope}
@ -116,27 +118,44 @@ class Renderer extends Component<{ documentInstance: DocumentInstance }> {
const leaf = documentInstance.getNode(__id); const leaf = documentInstance.getNode(__id);
viewProps._leaf = leaf; viewProps._leaf = leaf;
viewProps._componentName = leaf?.componentName; viewProps._componentName = leaf?.componentName;
let _children = leaf?.isContainer() ? (children == null ? [] : Array.isArray(children) ? children : [children]) : children; let _children = leaf?.isContainer()
? children == null
? []
: Array.isArray(children)
? children
: [children]
: children;
if (props.children && props.children.length) { if (props.children && props.children.length) {
if (Array.isArray(props.children)) { if (Array.isArray(props.children)) {
_children = Array.isArray(_children) ? _children.concat(props.children) : props.children.unshift(_children); _children = Array.isArray(_children)
? _children.concat(props.children)
: props.children.unshift(_children);
} else { } else {
Array.isArray(_children) && _children.push(props.children) || (_children = [_children].push(props.children)); (Array.isArray(_children) && _children.push(props.children)) ||
(_children = [_children].push(props.children));
} }
} }
// 如果是容器 && 无children && 高宽为空 增加一个占位容器,方便拖动 // 如果是容器 && 无children && 高宽为空 增加一个占位容器,方便拖动
if (leaf?.isContainer() && (_children == null || !_children.length) && (!viewProps.style || Object.keys(viewProps.style).length == 0)){ if (
_children = <div style={{ leaf?.isContainer() &&
height:'66px', (_children == null || !_children.length) &&
backgroundColor:'#f0f0f0', (!viewProps.style || Object.keys(viewProps.style).length == 0)
borderColor:'#a7b1bd', ) {
border: '1px dotted', _children = (
color:'#a7b1bd', <div
textAlign:'center', style={{
lineHeight:'66px' height: '66px',
}}> backgroundColor: '#f0f0f0',
borderColor: '#a7b1bd',
</div> border: '1px dotted',
color: '#a7b1bd',
textAlign: 'center',
lineHeight: '66px',
}}
>
</div>
);
} }
if (viewProps._componentName === 'Menu') { if (viewProps._componentName === 'Menu') {
@ -159,17 +178,13 @@ class Renderer extends Component<{ documentInstance: DocumentInstance }> {
console.info('menuprops', viewProps); console.info('menuprops', viewProps);
} }
return createElement( return createElement(getDeviceView(Component, device, designMode), viewProps, _children);
getDeviceView(Component, device, designMode),
viewProps,
_children,
);
}} }}
onCompGetRef={(schema: any, ref: ReactInstance | null) => { onCompGetRef={(schema: any, ref: ReactInstance | null) => {
documentInstance.mountInstance(schema.id, ref); documentInstance.mountInstance(schema.id, ref);
}} }}
//onCompGetCtx={(schema: any, ctx: object) => { //onCompGetCtx={(schema: any, ctx: object) => {
// renderer.mountContext(schema.id, ctx); // documentInstance.mountContext(schema.id, ctx);
//}} //}}
/> />
); );

View File

@ -9,8 +9,8 @@ import loader from './utils/loader';
import { reactFindDOMNodes, FIBER_KEY } from './utils/react-find-dom-nodes'; import { reactFindDOMNodes, FIBER_KEY } from './utils/react-find-dom-nodes';
import { isESModule, isElement, cursor, setNativeSelection } from '@ali/lowcode-utils'; import { isESModule, isElement, cursor, setNativeSelection } from '@ali/lowcode-utils';
import { RootSchema, NpmInfo, ComponentSchema, TransformStage } from '@ali/lowcode-types'; import { RootSchema, NpmInfo, ComponentSchema, TransformStage } from '@ali/lowcode-types';
// just use types
import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel, Node } from '@ali/lowcode-designer'; import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel, Node } from '@ali/lowcode-designer';
import { createMemoryHistory, MemoryHistory } from 'history';
import Slot from './builtin-components/slot'; import Slot from './builtin-components/slot';
import Leaf from './builtin-components/leaf'; import Leaf from './builtin-components/leaf';
@ -22,13 +22,13 @@ export class DocumentInstance {
return this._schema; return this._schema;
} }
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { private dispose?: () => void;
this.dispose = host.connect(this, () => {
// sync layout config
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
this.dispose = host.autorun(() => {
// sync schema // sync schema
this._schema = host.document.export(1); this._schema = document.export(1);
}) });
} }
@computed get suspended(): any { @computed get suspended(): any {
@ -38,6 +38,14 @@ export class DocumentInstance {
return null; return null;
} }
get path(): string {
return '/' + this.document.fileName;
}
get id() {
return this.document.id;
}
private unmountIntance(id: string, instance: ReactInstance) { private unmountIntance(id: string, instance: ReactInstance) {
const instances = this.instancesMap.get(id); const instances = this.instancesMap.get(id);
if (instances) { if (instances) {
@ -114,62 +122,6 @@ export class DocumentInstance {
// this.ctxMap.set(id, ctx); // this.ctxMap.set(id, ctx);
} }
createComponent(schema: ComponentSchema): Component | null {
const _schema = {
...schema,
};
_schema.methods = {};
_schema.lifeCycles = {};
const processPropsSchema = (propsSchema: any, propsMap: any): any => {
if (!propsSchema) {
return {};
}
const result = {...propsSchema};
const reg = /^(?:this\.props|props)\.(\S+)$/;
Object.keys(propsSchema).map((key: string) => {
if (propsSchema[key].type === 'JSExpression') {
const { value } = propsSchema[key];
const matched = reg.exec(value);
if (matched) {
const propName = matched[1];
result[key] = propsMap[propName];
}
}
});
return result;
};
const getElement = (componentsMap: any, schema: any, propsMap: any): ReactElement => {
const Com = componentsMap[schema.componentName];
let children = null;
if (schema.children && schema.children.length > 0) {
children = schema.children.map((item: any) => getElement(componentsMap, item, propsMap));
}
const _leaf = this.document.designer.currentDocument?.createNode(schema);
const node = this.document.createNode(schema);
let props = processPropsSchema(schema.props, propsMap);
props = this.document.designer.transformProps(props, node, TransformStage.Init);
props = this.document.designer.transformProps(props, node, TransformStage.Render);
return createElement(Com, {...props, _leaf}, children);
}
const container = this.container;
class Com extends React.Component {
render() {
const componentsMap = container.componentsMap;
let children = null;
if (_schema.children && Array.isArray(_schema.children)) {
children = _schema.children?.map((item:any) => getElement(componentsMap, item, this.props));
}
return createElement(React.Fragment, {}, children);
}
}
return Com;
}
getNode(id: string): Node | null { getNode(id: string): Node | null {
return this.document.getNode(id); return this.document.getNode(id);
} }
@ -178,12 +130,14 @@ export class DocumentInstance {
export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
readonly isSimulatorRenderer = true; readonly isSimulatorRenderer = true;
private dispose?: () => void; private dispose?: () => void;
readonly history: MemoryHistory;
@obx.ref private _documentInstances: DocumentInstance[] = [];
get documentInstances() {
return this._documentInstances;
}
constructor() { constructor() {
if (!host) {
return;
}
this.dispose = host.connect(this, () => { this.dispose = host.connect(this, () => {
// sync layout config // sync layout config
// todo: split with others, not all should recompute // todo: split with others, not all should recompute
@ -199,6 +153,27 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
// sync device // sync device
this._device = host.device; this._device = host.device;
}); });
const documentInstanceMap = new Map<string, DocumentInstance>();
host.autorun(() => {
this._documentInstances = host.project.documents.map((doc) => {
let inst = documentInstanceMap.get(doc.id);
if (!inst) {
inst = new DocumentInstance(this, doc);
documentInstanceMap.set(doc.id, inst);
}
return inst;
});
console.info('instances', this._documentInstances);
});
const initialEntry = host.project.currentDocument
? documentInstanceMap.get(host.project.currentDocument.id)!.path
: '/';
this.history = createMemoryHistory({
initialEntries: [initialEntry],
});
this.history.listen((location, action) => {
console.info(location);
});
host.componentsConsumer.consume(async (componentsAsset) => { host.componentsConsumer.consume(async (componentsAsset) => {
if (componentsAsset) { if (componentsAsset) {
await this.load(componentsAsset); await this.load(componentsAsset);
@ -208,10 +183,13 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
host.injectionConsumer.consume((data) => { host.injectionConsumer.consume((data) => {
// sync utils, i18n, contants,... config // sync utils, i18n, contants,... config
this._appContext = { this._appContext = {
utils: {}, utils: {
constants: { router: {
name: 'demo', push() {},
replace() {},
},
}, },
constants: {},
}; };
}); });
} }
@ -255,13 +233,6 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
return loader.load(asset); return loader.load(asset);
} }
private documentInstanceMap = new Map<string, DocumentInstance>();
redirect(path: string) {
}
getComponent(componentName: string) { getComponent(componentName: string) {
const paths = componentName.split('.'); const paths = componentName.split('.');
const subs: string[] = []; const subs: string[] = [];
@ -308,6 +279,66 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
cursor.release(); cursor.release();
} }
createComponent(schema: ComponentSchema): Component | null {
return null;
// TODO: use ComponentEngine refactor
/*
const _schema = {
...schema,
};
_schema.methods = {};
_schema.lifeCycles = {};
const processPropsSchema = (propsSchema: any, propsMap: any): any => {
if (!propsSchema) {
return {};
}
const result = { ...propsSchema };
const reg = /^(?:this\.props|props)\.(\S+)$/;
Object.keys(propsSchema).map((key: string) => {
if (propsSchema[key].type === 'JSExpression') {
const { value } = propsSchema[key];
const matched = reg.exec(value);
if (matched) {
const propName = matched[1];
result[key] = propsMap[propName];
}
}
});
return result;
};
const getElement = (componentsMap: any, schema: any, propsMap: any): ReactElement => {
const Com = componentsMap[schema.componentName];
let children = null;
if (schema.children && schema.children.length > 0) {
children = schema.children.map((item: any) => getElement(componentsMap, item, propsMap));
}
const _leaf = this.document.designer.currentDocument?.createNode(schema);
const node = this.document.createNode(schema);
let props = processPropsSchema(schema.props, propsMap);
props = this.document.designer.transformProps(props, node, TransformStage.Init);
props = this.document.designer.transformProps(props, node, TransformStage.Render);
return createElement(Com, { ...props, _leaf }, children);
};
const container = this;
class Com extends React.Component {
render() {
const componentsMap = container.componentsMap;
let children = null;
if (_schema.children && Array.isArray(_schema.children)) {
children = _schema.children?.map((item: any) => getElement(componentsMap, item, this.props));
}
return createElement(React.Fragment, {}, children);
}
}
return Com;
*/
}
private _running = false; private _running = false;
run() { run() {
if (this._running) { if (this._running) {
@ -321,6 +352,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
document.body.appendChild(container); document.body.appendChild(container);
container.id = containerId; container.id = containerId;
} }
// ==== compatiable vision // ==== compatiable vision
document.documentElement.classList.add('engine-page'); document.documentElement.classList.add('engine-page');
document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends
@ -401,9 +433,12 @@ const builtinComponents = {
Leaf, Leaf,
}; };
function buildComponents(libraryMap: LibraryMap, componentsMap: { [componentName: string]: NpmInfo | ComponentType<any> }) { function buildComponents(
libraryMap: LibraryMap,
componentsMap: { [componentName: string]: NpmInfo | ComponentType<any> },
) {
const components: any = { const components: any = {
...builtinComponents ...builtinComponents,
}; };
Object.keys(componentsMap).forEach((componentName) => { Object.keys(componentsMap).forEach((componentName) => {
let component = componentsMap[componentName]; let component = componentsMap[componentName];

View File

@ -42,7 +42,7 @@ export class Cursor {
} }
} }
private addState(state: string) { addState(state: string) {
if (!this.states.has(state)) { if (!this.states.has(state)) {
this.states.add(state); this.states.add(state);
document.documentElement.classList.add(`lc-cursor-${state}`); document.documentElement.classList.add(`lc-cursor-${state}`);