mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-20 01:12:49 +00:00
sim 60%
This commit is contained in:
parent
eb7a7f519f
commit
6cb06d3369
@ -1,105 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
import { observer, obx } from '@ali/recore';
|
|
||||||
import { dragon } from '../../globals/dragon';
|
|
||||||
|
|
||||||
import './ghost.less';
|
|
||||||
import { OutlineBoardID } from '../builtin-panes/outline-pane/outline-board';
|
|
||||||
// import { INode } from '../../document/node';
|
|
||||||
|
|
||||||
type offBinding = () => any;
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export default class Ghost extends Component {
|
|
||||||
private dispose: offBinding[] = [];
|
|
||||||
@obx.ref private dragment: any = null;
|
|
||||||
@obx.ref private x = 0;
|
|
||||||
@obx.ref private y = 0;
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.dispose = [
|
|
||||||
dragon.onDragstart(e => {
|
|
||||||
this.dragment = e.dragTarget;
|
|
||||||
this.x = e.clientX;
|
|
||||||
this.y = e.clientY;
|
|
||||||
}),
|
|
||||||
dragon.onDrag(e => {
|
|
||||||
this.x = e.clientX;
|
|
||||||
this.y = e.clientY;
|
|
||||||
}),
|
|
||||||
dragon.onDragend(() => {
|
|
||||||
this.dragment = null;
|
|
||||||
this.x = 0;
|
|
||||||
this.y = 0;
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if (this.dispose) {
|
|
||||||
this.dispose.forEach(off => off());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderGhostGroup() {
|
|
||||||
const dragment = this.dragment;
|
|
||||||
if (Array.isArray(dragment)) {
|
|
||||||
return dragment.map((node: any, index: number) => {
|
|
||||||
const ghost = (
|
|
||||||
<div className="my-ghost" key={`ghost-${index}`}>
|
|
||||||
<div className="my-ghost-title">{node.tagName}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
return ghost;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<div className="my-ghost">
|
|
||||||
<div className="my-ghost-title">{dragment.tagName}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (!this.dragment) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// let x = this.x;
|
|
||||||
// let y = this.y;
|
|
||||||
|
|
||||||
// todo: 考虑多个图标、title、不同 sensor 区域的形态
|
|
||||||
if (dragon.activeSensor && dragon.activeSensor.id === OutlineBoardID) {
|
|
||||||
// const nodeId = (this.dragment as INode).id;
|
|
||||||
// const elt = document.querySelector(`[data-id="${nodeId}"`) as HTMLDivElement;
|
|
||||||
//
|
|
||||||
// if (elt) {
|
|
||||||
// // do something
|
|
||||||
// // const target = elt.cloneNode(true) as HTMLDivElement;
|
|
||||||
// console.log('>>> target', elt);
|
|
||||||
// elt.classList.remove('hidden');
|
|
||||||
// elt.classList.add('dragging');
|
|
||||||
// elt.style.transform = `translate(${this.x}px, ${this.y}px)`;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return null;
|
|
||||||
// x -= 30;
|
|
||||||
// y += 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="my-ghost-group"
|
|
||||||
style={{
|
|
||||||
transform: `translate(${this.x}px, ${this.y}px)`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.renderGhostGroup()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
.my-canvas {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: 10px;
|
|
||||||
box-shadow: 0 2px 10px 0 rgba(31,56,88,.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
html.my-show-topbar .my-canvas {
|
|
||||||
top: var(--topbar-height);
|
|
||||||
}
|
|
||||||
html.my-show-toolbar .my-canvas {
|
|
||||||
top: var(--toolbar-height);
|
|
||||||
}
|
|
||||||
html.my-show-topbar.my-show-toolbar .my-canvas {
|
|
||||||
top: calc(var(--topbar-height) + var(--topbar-height));
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-screen {
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-doc-shell {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
.my-doc-frame {
|
|
||||||
border: none;
|
|
||||||
transform-origin: 0 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-drag-pane-mode .my-doc-shell {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
import { observer } from '@ali/recore';
|
|
||||||
import { getCurrentDocument, screen, progressing } from '../../globals';
|
|
||||||
import { AutoFit } from '../../document/viewport';
|
|
||||||
import { AuxiliaryView } from '../auxiliary';
|
|
||||||
import { PreLoaderView } from '../widgets/pre-loader';
|
|
||||||
import DocumentContext from '../../document/document-context';
|
|
||||||
import FocusingArea from '../widgets/focusing-area';
|
|
||||||
import './canvas.less';
|
|
||||||
|
|
||||||
const Canvas = () => (
|
|
||||||
<FocusingArea
|
|
||||||
className="my-canvas"
|
|
||||||
id="canvas"
|
|
||||||
onEsc={() => {
|
|
||||||
const doc = getCurrentDocument();
|
|
||||||
if (doc) {
|
|
||||||
doc.selection.clear();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Screen />
|
|
||||||
</FocusingArea>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default Canvas;
|
|
||||||
|
|
||||||
@observer
|
|
||||||
class Screen extends Component {
|
|
||||||
render() {
|
|
||||||
const doc = getCurrentDocument();
|
|
||||||
// TODO: thinkof multi documents
|
|
||||||
return (
|
|
||||||
<div ref={elmt => screen.mount(elmt)} className="my-screen">
|
|
||||||
{progressing.visible ? <PreLoaderView /> : null}
|
|
||||||
<AuxiliaryView />
|
|
||||||
{doc ? <DocumentView key={doc.id} doc={doc} /> : null}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@observer
|
|
||||||
class DocumentView extends Component<{ doc: DocumentContext }> {
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.props.doc.sleep();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { doc } = this.props;
|
|
||||||
const viewport = doc.viewport;
|
|
||||||
let shellStyle = {};
|
|
||||||
let frameStyle = {};
|
|
||||||
if (viewport.width !== AutoFit && viewport.height !== AutoFit) {
|
|
||||||
const shellWidth = viewport.width * viewport.scale;
|
|
||||||
const screenWidth = screen.width;
|
|
||||||
const shellLeft = shellWidth < screenWidth ? `calc((100% - ${shellWidth}px) / 2)` : 0;
|
|
||||||
shellStyle = {
|
|
||||||
width: shellWidth,
|
|
||||||
left: shellLeft,
|
|
||||||
};
|
|
||||||
frameStyle = {
|
|
||||||
transform: `scale(${viewport.scale})`,
|
|
||||||
height: viewport.height,
|
|
||||||
width: viewport.width,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="my-doc-shell" style={shellStyle}>
|
|
||||||
<iframe className="my-doc-frame" style={frameStyle} ref={frame => doc.mountRuntimeFrame(frame)} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,17 +1,149 @@
|
|||||||
class Designer {
|
import Dragon, { isDragNodeObject, isDragNodeDataObject } from "./dragon";
|
||||||
id: string = guid();
|
import Project from './project';
|
||||||
hotkey: Hotkey;
|
import { ProjectSchema } from './schema';
|
||||||
|
import DocumentModel from './document/document-model';
|
||||||
|
import BuiltinSimulatorView from '../builtins/simulator/master';
|
||||||
|
import { Component } from 'react';
|
||||||
|
import { obx, computed } from '@recore/obx';
|
||||||
|
import ActiveTracker from './active-tracker';
|
||||||
|
import Location, { LocationData, isLocationChildrenDetail } from './location';
|
||||||
|
import Node, { insertChildren } from './document/node/node';
|
||||||
|
|
||||||
constructor(options: BuilderOptions): Builder;
|
export interface DesignerProps {
|
||||||
|
className?: string;
|
||||||
|
style?: object;
|
||||||
|
defaultSchema?: ProjectSchema;
|
||||||
|
hotkeys?: object;
|
||||||
|
simulatorProps?: object | ((document: DocumentModel) => object);
|
||||||
|
simulatorComponent?: Component<any>;
|
||||||
|
dragGhostComponent?: Component<any>;
|
||||||
|
suspensed?: boolean;
|
||||||
|
onMount?: (designer: Designer) => void;
|
||||||
|
onDragstart?: (designer: Designer) => void;
|
||||||
|
onDrag?: (designer: Designer) => void;
|
||||||
|
onDragend?: (designer: Designer) => void;
|
||||||
|
// TODO: ...add other events support
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
getValue(): ProjectSchema;
|
export default class Designer {
|
||||||
setValue(schema: ProjectSchema): void;
|
// readonly hotkey: Hotkey;
|
||||||
project: Project;
|
readonly dragon = new Dragon(this);
|
||||||
dragboost(locateEvent: LocateEvent): void;
|
readonly activeTracker = new ActiveTracker();
|
||||||
addDropSensor(dropSensor: DropSensor): void;
|
readonly project: Project;
|
||||||
|
|
||||||
|
constructor(props: DesignerProps) {
|
||||||
|
this.project = new Project(this, props.defaultSchema);
|
||||||
|
|
||||||
private _suspensed: boolean = false;
|
this.dragon.onDragstart(({ dragObject }) => {
|
||||||
|
if (isDragNodeObject(dragObject) && dragObject.nodes.length === 1) {
|
||||||
|
// ensure current selecting
|
||||||
|
dragObject.nodes[0].select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.dragon.onDragend(({ dragObject, copy }) => {
|
||||||
|
const loc = this._dropLocation;
|
||||||
|
if (loc) {
|
||||||
|
if (isLocationChildrenDetail(loc.detail)) {
|
||||||
|
let nodes: Node[] | undefined;
|
||||||
|
if (isDragNodeObject(dragObject)) {
|
||||||
|
nodes = insertChildren(loc.target, dragObject.nodes, loc.detail.index, copy);
|
||||||
|
} else if (isDragNodeDataObject(dragObject)) {
|
||||||
|
// process nodeData
|
||||||
|
const nodeData = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||||
|
nodes = insertChildren(loc.target, nodeData, loc.detail.index);
|
||||||
|
}
|
||||||
|
if (nodes) {
|
||||||
|
loc.document.selection.selectAll(nodes.map(o => o.id));
|
||||||
|
setTimeout(() => this.activeTracker.track(nodes![0]), 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.clearLocation();
|
||||||
|
// this.enableEdging();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.activeTracker.onChange(({ node, detail }) => {
|
||||||
|
node.document.simulator?.scrollToNode(node, detail);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setProps(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _dropLocation?: Location;
|
||||||
|
/**
|
||||||
|
* 创建插入位置
|
||||||
|
*/
|
||||||
|
createLocation(locationData: LocationData): Location {
|
||||||
|
const loc = new Location(locationData);
|
||||||
|
this._dropLocation = loc;
|
||||||
|
loc.document.internalSetDropLocation(loc);
|
||||||
|
this.activeTracker.track({ node: loc.target, detail: loc.detail });
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除插入位置
|
||||||
|
*/
|
||||||
|
private clearLocation() {
|
||||||
|
if (this._dropLocation) {
|
||||||
|
this._dropLocation.document.internalSetDropLocation(null);
|
||||||
|
}
|
||||||
|
this._dropLocation = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private props?: DesignerProps;
|
||||||
|
setProps(props: DesignerProps) {
|
||||||
|
if (this.props) {
|
||||||
|
// check hotkeys
|
||||||
|
// TODO:
|
||||||
|
// check simulatorConfig
|
||||||
|
if (props.simulatorComponent !== this.props.simulatorComponent) {
|
||||||
|
this._simulatorComponent = props.simulatorComponent;
|
||||||
|
}
|
||||||
|
if (props.simulatorProps !== this.props.simulatorProps) {
|
||||||
|
this._simulatorProps = props.simulatorProps;
|
||||||
|
}
|
||||||
|
if (props.suspensed !== this.props.suspensed && props.suspensed != null) {
|
||||||
|
this.suspensed = props.suspensed;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// init hotkeys
|
||||||
|
// todo:
|
||||||
|
// init simulatorConfig
|
||||||
|
if (props.simulatorComponent) {
|
||||||
|
this._simulatorComponent = props.simulatorComponent;
|
||||||
|
}
|
||||||
|
if (props.simulatorProps) {
|
||||||
|
this._simulatorProps = props.simulatorProps;
|
||||||
|
}
|
||||||
|
// init suspensed
|
||||||
|
if (props.suspensed != null) {
|
||||||
|
this.suspensed = props.suspensed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.props = props;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key: string): any {
|
||||||
|
return this.props ? this.props[key] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@obx.ref private _simulatorComponent?: Component<any>;
|
||||||
|
@obx.ref private _simulatorProps?: object;
|
||||||
|
@computed get simulatorConfig(): {
|
||||||
|
Component: Component<any>;
|
||||||
|
props: object;
|
||||||
|
} {
|
||||||
|
const config: any = {
|
||||||
|
Component: this._simulatorComponent || BuiltinSimulatorView,
|
||||||
|
props: this._simulatorProps || {},
|
||||||
|
};
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@obx.ref private _suspensed: boolean = false;
|
||||||
|
|
||||||
get suspensed(): boolean {
|
get suspensed(): boolean {
|
||||||
return this._suspensed;
|
return this._suspensed;
|
||||||
@ -25,9 +157,15 @@ class Designer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 事件 & 消息
|
get schema(): ProjectSchema {
|
||||||
onActiveChange(): () => void;
|
return this.project.schema;
|
||||||
onDragstart(): void;
|
}
|
||||||
onDragend(): void;
|
|
||||||
//....
|
set schema(schema: ProjectSchema) {
|
||||||
|
// todo:
|
||||||
|
}
|
||||||
|
|
||||||
|
purge() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,300 +0,0 @@
|
|||||||
import Project from '../project';
|
|
||||||
import { RootSchema, NodeData, isDOMText, isJSExpression, NodeSchema } from '../schema';
|
|
||||||
import Node, { isNodeParent, insertChildren, insertChild, NodeParent } from './node/node';
|
|
||||||
import { Selection } from './selection';
|
|
||||||
import RootNode from './node/root-node';
|
|
||||||
import { SimulatorInterface } from '../simulator-interface';
|
|
||||||
import { computed } from '@recore/obx';
|
|
||||||
|
|
||||||
export default class DocumentContext {
|
|
||||||
/**
|
|
||||||
* 根节点 类型有:Page/Component/Block
|
|
||||||
*/
|
|
||||||
readonly rootNode: RootNode;
|
|
||||||
/**
|
|
||||||
* 文档编号
|
|
||||||
*/
|
|
||||||
readonly id: string;
|
|
||||||
/**
|
|
||||||
* 选区控制
|
|
||||||
*/
|
|
||||||
readonly selection: Selection = new Selection(this);
|
|
||||||
/**
|
|
||||||
* 操作记录控制
|
|
||||||
*/
|
|
||||||
// TODO
|
|
||||||
// readonly history: History = new History(this);
|
|
||||||
|
|
||||||
private nodesMap = new Map<string, Node>();
|
|
||||||
private nodes = new Set<Node>();
|
|
||||||
private seqId = 0;
|
|
||||||
private _simulator?: SimulatorInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模拟器
|
|
||||||
*/
|
|
||||||
get simulator(): SimulatorInterface | null {
|
|
||||||
return this._simulator || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
get fileName() {
|
|
||||||
return this.rootNode.extras.get('fileName')?.value as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
set fileName(fileName: string) {
|
|
||||||
this.rootNode.extras.get('fileName', true).value = fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(readonly project: Project, schema: RootSchema) {
|
|
||||||
this.rootNode = new RootNode(this, schema);
|
|
||||||
this.id = this.rootNode.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成唯一id
|
|
||||||
*/
|
|
||||||
nextId() {
|
|
||||||
return (++this.seqId).toString(36).toLocaleLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 id 获取节点
|
|
||||||
*/
|
|
||||||
getNode(id: string): Node | null {
|
|
||||||
return this.nodesMap.get(id) || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否存在节点
|
|
||||||
*/
|
|
||||||
hasNode(id: string): boolean {
|
|
||||||
const node = this.getNode(id);
|
|
||||||
return node ? !node.isPurged : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 schema 创建一个节点
|
|
||||||
*/
|
|
||||||
createNode(data: NodeData): Node {
|
|
||||||
let schema: any;
|
|
||||||
if (isDOMText(data) || isJSExpression(data)) {
|
|
||||||
schema = {
|
|
||||||
componentName: '#frag',
|
|
||||||
children: data,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
schema = data;
|
|
||||||
}
|
|
||||||
const node = new Node(this, schema);
|
|
||||||
this.nodesMap.set(node.id, node);
|
|
||||||
this.nodes.add(node);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插入一个节点
|
|
||||||
*/
|
|
||||||
insertNode(parent: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
|
||||||
return insertChild(parent, thing, at, copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插入多个节点
|
|
||||||
*/
|
|
||||||
insertNodes(parent: NodeParent, thing: Node[] | NodeData[], at?: number | null, copy?: boolean) {
|
|
||||||
return insertChildren(parent, thing, at, copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移除一个节点
|
|
||||||
*/
|
|
||||||
removeNode(idOrNode: string | Node) {
|
|
||||||
let id: string;
|
|
||||||
let node: Node | null;
|
|
||||||
if (typeof idOrNode === 'string') {
|
|
||||||
id = idOrNode;
|
|
||||||
node = this.getNode(id);
|
|
||||||
} else {
|
|
||||||
node = idOrNode;
|
|
||||||
id = node.id;
|
|
||||||
}
|
|
||||||
if (!node) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.internalRemoveAndPurgeNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 内部方法,请勿调用
|
|
||||||
*/
|
|
||||||
internalRemoveAndPurgeNode(node: Node) {
|
|
||||||
if (!this.nodes.has(node)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.nodesMap.delete(node.id);
|
|
||||||
this.nodes.delete(node);
|
|
||||||
node.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 包裹当前选区中的节点
|
|
||||||
*/
|
|
||||||
wrapWith(schema: NodeSchema): Node | null {
|
|
||||||
const nodes = this.selection.getTopNodes();
|
|
||||||
if (nodes.length < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const wrapper = this.createNode(schema);
|
|
||||||
if (isNodeParent(wrapper)) {
|
|
||||||
const first = nodes[0];
|
|
||||||
// TODO: check nesting rules x 2
|
|
||||||
insertChild(first.parent!, wrapper, first.index);
|
|
||||||
insertChildren(wrapper, nodes);
|
|
||||||
this.selection.select(wrapper.id);
|
|
||||||
return wrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeNode(wrapper);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出 schema 数据
|
|
||||||
*/
|
|
||||||
get schema(): NodeSchema {
|
|
||||||
return this.rootNode.schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出节点数据
|
|
||||||
*/
|
|
||||||
getNodeSchema(id: string): NodeData | null {
|
|
||||||
const node = this.getNode(id);
|
|
||||||
if (node) {
|
|
||||||
return node.schema;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否已修改
|
|
||||||
*/
|
|
||||||
isModified() {
|
|
||||||
// return !this.history.isSavePoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供给模拟器的参数
|
|
||||||
*/
|
|
||||||
@computed get simulatorProps(): object {
|
|
||||||
let simulatorProps = this.project.simulatorProps;
|
|
||||||
if (typeof simulatorProps === 'function') {
|
|
||||||
simulatorProps = simulatorProps(this);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...simulatorProps,
|
|
||||||
documentContext: this,
|
|
||||||
onMount: this.mountSimulator.bind(this),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private mountSimulator(simulator: SimulatorInterface) {
|
|
||||||
this._simulator = simulator;
|
|
||||||
// TODO: emit simulator mounted
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据节点取得视图实例,在循环等场景会有多个,依赖 simulator 的接口
|
|
||||||
*/
|
|
||||||
getViewInstance(node: Node): ViewInstance[] | null {
|
|
||||||
if (this.simulator) {
|
|
||||||
this.simulator.getViewInstance(node.id);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过 DOM 节点获取节点,依赖 simulator 的接口
|
|
||||||
*/
|
|
||||||
getNodeFromElement(target: Element | null): Node | null {
|
|
||||||
if (!this.simulator || !target) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = this.simulator.getClosestNodeId(target);
|
|
||||||
if (!id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.getNode(id) as Node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得到的结果是一个数组
|
|
||||||
* 表示一个实例对应多个外层 DOM 节点,依赖 simulator 的接口
|
|
||||||
*/
|
|
||||||
getDOMNodes(viewInstance: ViewInstance): Array<Element | Text> | null {
|
|
||||||
if (!this.simulator) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isElement(viewInstance)) {
|
|
||||||
return [viewInstance];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.simulator.findDOMNodes(viewInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
getComponent(componentName: string): any {
|
|
||||||
return this.simulator!.getCurrentComponent(componentName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _opened: boolean = true;
|
|
||||||
private _suspensed: boolean = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否不是激活的
|
|
||||||
*/
|
|
||||||
get suspensed(): boolean {
|
|
||||||
return this._suspensed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 与 suspensed 相反,是否是激活的,这个函数可能用的更多一点
|
|
||||||
*/
|
|
||||||
get actived(): boolean {
|
|
||||||
return !this._suspensed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 切换激活,只有打开的才能激活
|
|
||||||
* 不激活,打开之后切换到另外一个时发生,比如 tab 视图,切换到另外一个标签页
|
|
||||||
*/
|
|
||||||
set suspensed(flag: boolean) {
|
|
||||||
if (!this._opened && !flag) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._suspensed = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开,已载入,默认建立时就打开状态,除非手动关闭
|
|
||||||
*/
|
|
||||||
open(): void {
|
|
||||||
this._opened = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭,相当于 sleep,仍然缓存,停止一切响应,如果有发生的变更没被保存,仍然需要去取数据保存
|
|
||||||
*/
|
|
||||||
close(): void {
|
|
||||||
this.suspensed = true;
|
|
||||||
this._opened = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从项目中移除
|
|
||||||
*/
|
|
||||||
remove() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
import { Component, createContext } from 'react';
|
||||||
|
import DocumentModel from './document-model';
|
||||||
|
|
||||||
|
export const DocumentContext = createContext<DocumentModel>(null as any);
|
||||||
|
|
||||||
|
export default class DocumentView extends Component<{ documentModel: DocumentModel }> {
|
||||||
|
render() {
|
||||||
|
const { documentModel } = this.props;
|
||||||
|
return (
|
||||||
|
<div className="lc-document">
|
||||||
|
<DocumentContext.Provider value={documentModel}>
|
||||||
|
{/* 这一层将来做缩放用途 */}
|
||||||
|
<div className="lc-simulator-shell">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<DocumentInfoView />
|
||||||
|
</DocumentContext.Provider>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DocumentInfoView extends Component {
|
||||||
|
render() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,123 +0,0 @@
|
|||||||
import ComponentNode, { NodeParent } from './node/node';
|
|
||||||
import DocumentContext from './document-context';
|
|
||||||
|
|
||||||
export interface LocationData {
|
|
||||||
target: NodeParent; // shadowNode | ConditionFlow | ElementNode | RootNode
|
|
||||||
detail: LocationDetail;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum LocationDetailType {
|
|
||||||
Children = 'Children',
|
|
||||||
Prop = 'Prop',
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LocationChildrenDetail {
|
|
||||||
type: LocationDetailType.Children;
|
|
||||||
index: number;
|
|
||||||
near?: {
|
|
||||||
node: ComponentNode;
|
|
||||||
pos: 'before' | 'after';
|
|
||||||
rect?: Rect;
|
|
||||||
align?: 'V' | 'H';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LocationPropDetail {
|
|
||||||
// cover 形态,高亮 domNode,如果 domNode 为空,取 container 的值
|
|
||||||
type: LocationDetailType.Prop;
|
|
||||||
name: string;
|
|
||||||
domNode?: HTMLElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LocationDetail = LocationChildrenDetail | LocationPropDetail | { type: string; [key: string]: any };
|
|
||||||
|
|
||||||
export interface Point {
|
|
||||||
clientX: number;
|
|
||||||
clientY: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Rects = Array<ClientRect | DOMRect> & {
|
|
||||||
elements: Array<Element | Text>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Rect = (ClientRect | DOMRect) & {
|
|
||||||
elements: Array<Element | Text>;
|
|
||||||
computed?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function isLocationData(obj: any): obj is LocationData {
|
|
||||||
return obj && obj.target && obj.detail;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isLocationChildrenDetail(obj: any): obj is LocationChildrenDetail {
|
|
||||||
return obj && obj.type === LocationDetailType.Children;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isRowContainer(container: Element | Text, win?: Window) {
|
|
||||||
if (isText(container)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const style = (win || getWindow(container)).getComputedStyle(container);
|
|
||||||
const display = style.getPropertyValue('display');
|
|
||||||
if (/flex$/.test(display)) {
|
|
||||||
const direction = style.getPropertyValue('flex-direction') || 'row';
|
|
||||||
if (direction === 'row' || direction === 'row-reverse') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isChildInline(child: Element | Text, win?: Window) {
|
|
||||||
if (isText(child)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const style = (win || getWindow(child)).getComputedStyle(child);
|
|
||||||
return /^inline/.test(style.getPropertyValue('display'));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRectTarget(rect: Rect | null) {
|
|
||||||
if (!rect || rect.computed) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const els = rect.elements;
|
|
||||||
return els && els.length > 0 ? els[0]! : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isVerticalContainer(rect: Rect | null) {
|
|
||||||
const el = getRectTarget(rect);
|
|
||||||
if (!el) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return isRowContainer(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isVertical(rect: Rect | null) {
|
|
||||||
const el = getRectTarget(rect);
|
|
||||||
if (!el) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return isChildInline(el) || (el.parentElement ? isRowContainer(el.parentElement) : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isText(elem: any): elem is Text {
|
|
||||||
return elem.nodeType === Node.TEXT_NODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isDocument(elem: any): elem is Document {
|
|
||||||
return elem.nodeType === Node.DOCUMENT_NODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getWindow(elem: Element | Document): Window {
|
|
||||||
return (isDocument(elem) ? elem : elem.ownerDocument!).defaultView!;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Location {
|
|
||||||
readonly target: NodeParent;
|
|
||||||
readonly detail: LocationDetail;
|
|
||||||
|
|
||||||
constructor(readonly document: DocumentContext, { target, detail }: LocationData) {
|
|
||||||
this.target = target;
|
|
||||||
this.detail = detail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import Node, { comparePosition } from './node/node';
|
import Node, { comparePosition } from './node/node';
|
||||||
import { obx } from '@recore/obx';
|
import { obx } from '@recore/obx';
|
||||||
import DocumentContext from './document-context';
|
import DocumentModel from './document-model';
|
||||||
|
|
||||||
export class Selection {
|
export class Selection {
|
||||||
@obx.val private selected: string[] = [];
|
@obx.val private selected: string[] = [];
|
||||||
|
|
||||||
constructor(private doc: DocumentContext) {}
|
constructor(private doc: DocumentModel) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选中
|
* 选中
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { obx } from '@recore/obx';
|
import { obx } from '@recore/obx';
|
||||||
import Location from './document/location';
|
import Location from './location';
|
||||||
import Project from './project';
|
import DocumentModel from './document/document-model';
|
||||||
import DocumentContext from './document/document-context';
|
|
||||||
import { NodeData } from './schema';
|
import { NodeData } from './schema';
|
||||||
import { SimulatorInterface } from './simulator-interface';
|
import { SimulatorInterface } from './simulator-interface';
|
||||||
import Node from './document/node/node';
|
import Node from './document/node/node';
|
||||||
|
import Designer from './designer';
|
||||||
|
|
||||||
export interface LocateEvent {
|
export interface LocateEvent {
|
||||||
readonly type: 'LocateEvent';
|
readonly type: 'LocateEvent';
|
||||||
@ -34,7 +34,7 @@ export interface LocateEvent {
|
|||||||
/**
|
/**
|
||||||
* 激活或目标文档
|
* 激活或目标文档
|
||||||
*/
|
*/
|
||||||
document?: DocumentContext;
|
document?: DocumentModel;
|
||||||
/**
|
/**
|
||||||
* 事件订正标识,初始构造时,从发起端构造,缺少 canvasX,canvasY, 需要经过订正才有
|
* 事件订正标识,初始构造时,从发起端构造,缺少 canvasX,canvasY, 需要经过订正才有
|
||||||
*/
|
*/
|
||||||
@ -44,7 +44,7 @@ export interface LocateEvent {
|
|||||||
/**
|
/**
|
||||||
* 拖拽敏感板
|
* 拖拽敏感板
|
||||||
*/
|
*/
|
||||||
export interface SensorInterface {
|
export interface ISensor {
|
||||||
/**
|
/**
|
||||||
* 是否可响应,比如面板被隐藏,可设置该值 false
|
* 是否可响应,比如面板被隐藏,可设置该值 false
|
||||||
*/
|
*/
|
||||||
@ -76,7 +76,7 @@ export enum DragObjectType {
|
|||||||
|
|
||||||
export interface DragNodeObject {
|
export interface DragNodeObject {
|
||||||
type: DragObjectType.Node;
|
type: DragObjectType.Node;
|
||||||
node: Node | Node[];
|
nodes: Node[];
|
||||||
}
|
}
|
||||||
export interface DragNodeDataObject {
|
export interface DragNodeDataObject {
|
||||||
type: DragObjectType.NodeData;
|
type: DragObjectType.NodeData;
|
||||||
@ -126,32 +126,25 @@ export function setShaken(e: any) {
|
|||||||
e.shaken = true;
|
e.shaken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTopDocument(e: MouseEvent, local: Document) {
|
function isFromTopDocument(e: MouseEvent) {
|
||||||
return e.view!.document === local ? null : document;
|
return e.view!.document === document;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Dragon {
|
export default class Dragon {
|
||||||
private sensors: ISenseAble[] = [];
|
private sensors: ISensor[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* current actived sensor
|
* current actived sensor
|
||||||
*/
|
*/
|
||||||
private _activeSensor: ISenseAble | undefined;
|
private _activeSensor: ISensor | undefined;
|
||||||
get activeSensor(): ISenseAble | undefined {
|
get activeSensor(): ISensor | undefined {
|
||||||
return this._activeSensor;
|
return this._activeSensor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@obx.ref dragging = false;
|
@obx.ref dragging = false;
|
||||||
private emitter = new EventEmitter();
|
private emitter = new EventEmitter();
|
||||||
private get master(): MasterBoard | undefined {
|
|
||||||
const doc = getCurrentDocument();
|
|
||||||
if (!doc) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return doc.masterBoard;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(readonly project: Project) {}
|
constructor(readonly designer: Designer) {}
|
||||||
|
|
||||||
from(shell: Element, boost: (e: MouseEvent) => DragObject | null) {
|
from(shell: Element, boost: (e: MouseEvent) => DragObject | null) {
|
||||||
const mousedown = (e: MouseEvent) => {
|
const mousedown = (e: MouseEvent) => {
|
||||||
@ -174,22 +167,28 @@ export default class Dragon {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMasterSensors(): SimulatorInterface[] {
|
||||||
|
return this.designer.project.documents.map(doc => (doc.actived && doc.simulator) || null).filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
get master(): DocumentModel {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dragTarget should be a INode | INode[] | NodeData | NodeData[]
|
* dragTarget should be a INode | INode[] | NodeData | NodeData[]
|
||||||
*/
|
*/
|
||||||
boost(dragObject: DragObject, boostEvent: MouseEvent) {
|
boost(dragObject: DragObject, boostEvent: MouseEvent) {
|
||||||
if (!this.master) {
|
const doc = document;
|
||||||
return;
|
const fromTop = isFromTopDocument(boostEvent);
|
||||||
}
|
|
||||||
const master = this.master;
|
|
||||||
const doc = master.contentDocument;
|
|
||||||
const viewport = master.document.viewport;
|
|
||||||
const topDoc = getTopDocument(boostEvent, doc);
|
|
||||||
const newBie = dragObject.type !== DragTargetType.Nodes;
|
|
||||||
let lastLocation: any = null;
|
let lastLocation: any = null;
|
||||||
let lastSensor: ISenseAble | undefined;
|
let lastSensor: ISensor | undefined;
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
master.setNativeSelection(false);
|
const masterSensors = this.getMasterSensors();
|
||||||
|
masterSensors.forEach((sensor) => {
|
||||||
|
sensor.setNativeSelection(false);
|
||||||
|
});
|
||||||
|
//
|
||||||
|
|
||||||
const checkesc = (e: KeyboardEvent) => {
|
const checkesc = (e: KeyboardEvent) => {
|
||||||
if (e.keyCode === 27) {
|
if (e.keyCode === 27) {
|
||||||
@ -269,19 +268,25 @@ export default class Dragon {
|
|||||||
|
|
||||||
master.releaseCursor();
|
master.releaseCursor();
|
||||||
|
|
||||||
|
if (fromTop) {
|
||||||
doc.removeEventListener('mousemove', move, true);
|
doc.removeEventListener('mousemove', move, true);
|
||||||
doc.removeEventListener('mouseup', over, true);
|
doc.removeEventListener('mouseup', over, true);
|
||||||
doc.removeEventListener('mousedown', over, true);
|
doc.removeEventListener('mousedown', over, true);
|
||||||
doc.removeEventListener('keydown', checkesc, false);
|
doc.removeEventListener('keydown', checkesc, false);
|
||||||
doc.removeEventListener('keydown', checkcopy as any, false);
|
doc.removeEventListener('keydown', checkcopy as any, false);
|
||||||
doc.removeEventListener('keyup', checkcopy as any, false);
|
doc.removeEventListener('keyup', checkcopy as any, false);
|
||||||
if (topDoc) {
|
} else {
|
||||||
topDoc.removeEventListener('mousemove', move, true);
|
masterSensors.forEach(item => {
|
||||||
topDoc.removeEventListener('mouseup', over, true);
|
const odoc = item.ownerDocument;
|
||||||
topDoc.removeEventListener('mousedown', over, true);
|
if (odoc && odoc !== doc) {
|
||||||
topDoc.removeEventListener('keydown', checkesc, false);
|
odoc.removeEventListener('mousemove', move, true);
|
||||||
topDoc.removeEventListener('keydown', checkcopy as any, false);
|
odoc.removeEventListener('mouseup', over, true);
|
||||||
topDoc.removeEventListener('keyup', checkcopy as any, false);
|
odoc.removeEventListener('mousedown', over, true);
|
||||||
|
odoc.removeEventListener('keydown', checkesc, false);
|
||||||
|
odoc.removeEventListener('keydown', checkcopy as any, false);
|
||||||
|
odoc.removeEventListener('keyup', checkcopy as any, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (exception) {
|
if (exception) {
|
||||||
throw exception;
|
throw exception;
|
||||||
@ -318,13 +323,13 @@ export default class Dragon {
|
|||||||
if (!isDragNodeObject(dragObject)) {
|
if (!isDragNodeObject(dragObject)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (Array.isArray(dragObject.node) ? dragObject.node[0] : dragObject.node)?.document.simulator || null;
|
return (Array.isArray(dragObject.nodes) ? dragObject.nodes[0] : dragObject.nodes)?.document.simulator || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const simSensors = this.project.documents.map(doc => (doc.actived && doc.simulator) || null).filter(Boolean);
|
const simSensors = this.project.documents.map(doc => (doc.actived && doc.simulator) || null).filter(Boolean);
|
||||||
const sourceSensor = getSourceSensor(dragObject);
|
const sourceSensor = getSourceSensor(dragObject);
|
||||||
// check simulator is empty
|
// check simulator is empty
|
||||||
const sensors: SensorInterface[] = simSensors.concat(this.sensors);
|
const sensors: ISensor[] = simSensors.concat(this.sensors);
|
||||||
const chooseSensor = (e: LocateEvent) => {
|
const chooseSensor = (e: LocateEvent) => {
|
||||||
let sensor = sensors.find(s => s.sensorAvailable && s.isEnter(e));
|
let sensor = sensors.find(s => s.sensorAvailable && s.isEnter(e));
|
||||||
if (!sensor) {
|
if (!sensor) {
|
||||||
@ -390,7 +395,7 @@ export default class Dragon {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onDragend(func: (x: { dragTarget: DragObject; copy: boolean }, location: Location) => any) {
|
onDragend(func: (x: { dragObject: DragObject; copy: boolean }, location: Location) => any) {
|
||||||
this.emitter.on('dragend', func);
|
this.emitter.on('dragend', func);
|
||||||
return () => {
|
return () => {
|
||||||
this.emitter.removeListener('dragend', func);
|
this.emitter.removeListener('dragend', func);
|
||||||
|
|||||||
@ -1,17 +1,25 @@
|
|||||||
import { obx } from '@recore/obx';
|
import { obx } from '@recore/obx';
|
||||||
import { DocumentSchema, ProjectSchema } from './schema';
|
import { ProjectSchema } from './schema';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
import Designer from './designer';
|
||||||
|
import DocumentModel from './document/document-model';
|
||||||
|
|
||||||
export default class Project {
|
export default class Project {
|
||||||
@obx documents: DocumentContext[];
|
|
||||||
displayMode: 'exclusive' | 'tabbed' | 'split'; // P2
|
|
||||||
private emitter = new EventEmitter();
|
private emitter = new EventEmitter();
|
||||||
|
@obx.val readonly documents: DocumentModel[] = [];
|
||||||
private data: ProjectSchema = {};
|
private data: ProjectSchema = {};
|
||||||
|
|
||||||
|
@obx.ref displayMode: 'exclusive' | 'tabbed' | 'split' = 'exclusive';
|
||||||
|
|
||||||
// 考虑项目级别 History
|
// 考虑项目级别 History
|
||||||
|
|
||||||
constructor(schema: ProjectSchema) {
|
constructor(readonly designer: Designer, schema?: ProjectSchema) {
|
||||||
this.data = { ...schema };
|
this.data = {
|
||||||
|
version: '1.0.0',
|
||||||
|
componentsMap: [],
|
||||||
|
componentsTree: [],
|
||||||
|
...schema
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getDocument(fileName: string): DocumentContext {}
|
getDocument(fileName: string): DocumentContext {}
|
||||||
@ -23,16 +31,19 @@ export default class Project {
|
|||||||
/**
|
/**
|
||||||
* 获取项目整体 schema
|
* 获取项目整体 schema
|
||||||
*/
|
*/
|
||||||
getSchema(): ProjectSchema {
|
get schema(): ProjectSchema {
|
||||||
return {
|
return {
|
||||||
...this.data,
|
...this.data,
|
||||||
componentsTree: this.documents.map(doc => doc.getSchema()),
|
componentsTree: this.documents.map(doc => doc.getSchema()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 整体设置项目 schema
|
* 整体设置项目 schema
|
||||||
*/
|
*/
|
||||||
setSchema(schema: ProjectSchema): void {}
|
set schema(schema: ProjectSchema) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分字段设置储存数据,不记录操作记录
|
* 分字段设置储存数据,不记录操作记录
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { NpmInfo } from './schema';
|
import { NpmInfo } from './schema';
|
||||||
import { ComponentClass as ReactComponentClass, Component } from 'react';
|
import { ComponentClass as ReactComponentClass, Component } from 'react';
|
||||||
import { LocateEvent, SensorInterface } from './dragon';
|
import { LocateEvent, ISensor } from './dragon';
|
||||||
import { Point } from './document/location';
|
import { Point } from './location';
|
||||||
|
import Node from './document/node/node';
|
||||||
|
|
||||||
export interface SimulatorInterface<P = object> extends SensorInterface {
|
export interface SimulatorInterface<P = object> extends ISensor {
|
||||||
/**
|
/**
|
||||||
* 获得边界维度等信息
|
* 获得边界维度等信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user