diff --git a/packages/designer/src/designer/document/document-context.ts b/packages/designer/src/designer/document/document-context.ts index 5ede0d7f5..f6c2ffc7f 100644 --- a/packages/designer/src/designer/document/document-context.ts +++ b/packages/designer/src/designer/document/document-context.ts @@ -1,6 +1,6 @@ import Project from '../project'; import { RootSchema, NodeData, isDOMText, isJSExpression } from '../schema'; -import Node from './node'; +import Node from './node/node'; export default class DocumentContext { /** @@ -85,6 +85,7 @@ export default class DocumentContext { if (!node || !node.parent) { return; } + // TODO: 考虑留着缓存 this.nodesMap.delete(id); this.nodes.delete(node); node.parent.removeChild(node); diff --git a/packages/designer/src/designer/document/location.ts b/packages/designer/src/designer/document/location.ts index 5d309bbe1..030565920 100644 --- a/packages/designer/src/designer/document/location.ts +++ b/packages/designer/src/designer/document/location.ts @@ -1,4 +1,4 @@ -import { INode, INodeParent } from './node'; +import { INode, INodeParent } from './node/node'; import DocumentContext from './document-context'; export interface LocationData { diff --git a/packages/designer/src/designer/document/master-board.ts b/packages/designer/src/designer/document/master-board.ts index 79ecc7702..b9c53879b 100644 --- a/packages/designer/src/designer/document/master-board.ts +++ b/packages/designer/src/designer/document/master-board.ts @@ -23,7 +23,7 @@ import { contains, isRootNode, isConfettiNode, -} from './node'; +} from './node/node'; import { Point, Rect, diff --git a/packages/designer/src/designer/document/node.ts b/packages/designer/src/designer/document/node.ts deleted file mode 100644 index 21a69d88d..000000000 --- a/packages/designer/src/designer/document/node.ts +++ /dev/null @@ -1,490 +0,0 @@ -import { obx } from '@recore/obx'; -import { NodeSchema, NodeData, PropsMap, PropsList } from '../schema'; -import Props, { Prop } from './props'; -import DocumentContext from './document-context'; - -/** - * nodeSchema are: - * [basic] - * .componentName - * .props - * .children - * [directive] - * .condition - * .loop - * .loopArgs - * [addon] - * .conditionGroup = 'abc' // 当移动时值会改 - * .title - * .ignore - * .hidden - * .locked - */ -const DIRECTIVES = ['condition', 'conditionGroup', 'loop', 'loopArgs', 'title', 'ignore', 'hidden', 'locked']; -export default class Node { - /** - * 是节点实例 - */ - readonly isNode = true; - - /** - * 节点 id - */ - readonly id: string; - - /** - * 节点组件类型 - * 特殊节点: - * * #text 文字节点 - * * #expression 表达式节点 - * * Page 页面 - * * Block/Fragment 区块 - * * Component 组件/元件 - */ - readonly componentName: string; - - readonly props?: Props; - readonly directives?: Props; - readonly extras?: Props; - - constructor(readonly document: DocumentContext, private nodeSchema: NodeSchema) { - const { componentName, id, children, props, ...extras } = nodeSchema; - this.id = id || `node$${document.nextId()}`; - this.componentName = componentName; - if (this.isNodeParent()) { - this.props = new Props(this, props); - this.directives = new Props(this, {}); - Object.keys(extras).forEach(key => { - this.directives!.add((extras as any)[key], key); - delete (extras as any)[key]; - }); - this.extras = new Props(this, extras as any); - if (children) { - this._children = (Array.isArray(children) ? children : [children]).map(child => { - const node = this.document.createNode(child); - node.internalSetParent(this as INodeParent); - return node; - }); - } - } - } - - /** - * 是否一个父亲类节点 - */ - isNodeParent(): boolean { - return this.componentName.charAt(0) !== '#'; - } - - private _parent: INodeParent | null = null; - - /** - * 父级节点 - */ - get parent(): INodeParent | null { - return this._parent; - } - /** - * 内部方法,请勿使用 - * - * @ignore - */ - internalSetParent(parent: INodeParent | null) { - if (this._parent === parent) { - return; - } - if (this._parent) { - removeChild(this._parent, this); - } - - this._parent = parent; - if (parent) { - this._zLevel = parent.zLevel + 1; - } else { - this._zLevel = -1; - } - } - - private _zLevel = 0; - /** - * 当前节点深度 - */ - get zLevel(): number { - return this._zLevel; - } - - private _children: Node[] | null = null; - /** - * 当前节点子集 - */ - get children(): Node[] | null { - if (this.purged) { - return null; - } - return this._children; - } - - /* - @obx.ref get component(): ReactType { - return this.document.getComponent(this.tagName); - } - @obx.ref get prototype(): Prototype { - return this.document.getPrototype(this.component, this.tagName); - } - */ - - @obx.ref get propsData(): PropsMap | PropsList | null { - if (!this.isNodeParent() || this.componentName === 'Fragment') { - return null; - } - return this.props?.value || null; - } - - get directivesData(): PropsMap | null { - if (!this.isNodeParent()) { - return null; - } - return this.directives?.value as PropsMap || null; - } - - private _conditionGroup: string | null = null; - /** - * 条件组 - */ - get conditionGroup(): string | null { - if (this._conditionGroup) { - return this._conditionGroup; - } - // 如果 condition 有值,且没有 group - if (this._condition) { - return this.id; - } - return null; - } - set conditionGroup(val) { - this._conditionGroup = val; - } - - private _condition: any; - /** - * - */ - get condition() { - if (this._condition == null) { - if (this._conditionGroup) { - // FIXME: should be expression - return true; - } - return null; - } - return this._condition; - } - - /* - // TODO - // 外部修改,merge 进来,产生一次可恢复的历史数据 - merge(data: ElementData) { - this.elementData = data; - const { leadingComments } = data; - this.leadingComments = leadingComments ? leadingComments.slice() : []; - this.parse(); - this.mergeChildren(data.children || []); - } - - private mergeChildren(data: NodeData[]) { - for (let i = 0, l = data.length; i < l; i++) { - const item = this.children[i]; - if (item && isMergeable(item) && item.tagName === data[i].tagName) { - item.merge(data[i]); - } else { - if (item) { - item.purge(); - } - this.children[i] = this.document.createNode(data[i]); - this.children[i].internalSetParent(this); - } - } - if (this.children.length > data.length) { - this.children.splice(data.length).forEach(child => child.purge()); - } - } - */ - - getProp(path: string, useStash: boolean = true): Prop | null { - return this.props?.query(path, useStash as any) || null; - } - - getDirective(name: string, useStash: boolean = true): Prop | null { - return this.directives?.get(name, useStash as any) || null; - } - - /** - * 获取节点在父容器中的索引 - */ - get index(): number { - if (!this.parent) { - return -1; - } - return indexOf(this.parent, this); - } - - /** - * 获取下一个兄弟节点 - */ - get nextSibling(): Node | null { - if (!this.parent) { - return null; - } - const index = this.index; - if (index < 0) { - return null; - } - return getChildAt(this.parent, index + 1); - } - - /** - * 获取上一个兄弟节点 - */ - get prevSibling(): Node | null { - if (!this.parent) { - return null; - } - const index = this.index; - if (index < 1) { - return null; - } - return getChildAt(this.parent, index - 1); - } - - /** - * 获取符合搭建协议-节点 schema 结构 - */ - get schema(): NodeSchema { - return this.exportSchema(); - } - - /** - * 导出 schema - * @param serialize 序列化,加 id 标识符,用于储存为操作记录 - */ - exportSchema(serialize = false): NodeSchema { - const schema: any = { - componentName: this.componentName, - props: this.props, - condition: this.condition, - conditionGroup: this.conditionGroup, - ...this.directives, - }; - if (serialize) { - schema.id = this.id; - } - const children = this.children; - if (children && children.length > 0) { - schema.children = children.map(node => node.exportSchema(serialize)); - } - return schema; - } - - // TODO: 再利用历史数据,不产生历史数据 - reuse(timelineData: NodeSchema) {} - - /** - * 判断是否包含特定节点 - */ - contains(node: Node): boolean { - return contains(this, node); - } - - /** - * 获取特定深度的父亲节点 - */ - getZLevelTop(zLevel: number): Node | null { - return getZLevelTop(this, zLevel); - } - - /** - * 判断与其它节点的位置关系 - * - * 16 thisNode contains otherNode - * 8 thisNode contained_by otherNode - * 2 thisNode before or after otherNode - * 0 thisNode same as otherNode - */ - comparePosition(otherNode: Node): number { - return comparePosition(this, otherNode); - } - - private purged = false; - /** - * 销毁 - */ - purge() { - if (this.purged) { - return; - } - this.purged = true; - if (this._children) { - this._children.forEach(child => child.purge()); - } - // TODO: others dispose... - } -} - -export interface INodeParent extends Node { - readonly children: Node[]; -} - -export function isNode(node: any): node is Node { - return node && node.isNode; -} - -export function getZLevelTop(child: Node, zLevel: number): Node | null { - let l = child.zLevel; - if (l < zLevel || zLevel < 0) { - return null; - } - if (l === zLevel) { - return child; - } - let r: any = child; - while (r && l-- > zLevel) { - r = r.parent; - } - return r; -} - -export function contains(node1: Node, node2: Node): boolean { - if (node1 === node2) { - return true; - } - - if (!node1.isNodeParent() || !node1.children || !node2.parent) { - return false; - } - - const p = getZLevelTop(node2, node1.zLevel); - if (!p) { - return false; - } - - return node1 === p; -} - -// 16 node1 contains node2 -// 8 node1 contained_by node2 -// 2 node1 before or after node2 -// 0 node1 same as node2 -export function comparePosition(node1: Node, node2: Node): number { - if (node1 === node2) { - return 0; - } - const l1 = node1.zLevel; - const l2 = node2.zLevel; - if (l1 === l2) { - return 2; - } - - let p: any; - if (l1 > l2) { - p = getZLevelTop(node2, l1); - if (p && p === node1) { - return 16; - } - return 2; - } - - p = getZLevelTop(node1, l2); - if (p && p === node2) { - return 8; - } - - return 2; -} - -export function insertChild(container: INodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node { - let node: Node; - if (copy && isNode(thing)) { - thing = thing.schema; - } - if (isNode(thing)) { - node = thing; - } else { - node = container.document.createNode(thing); - } - const children = container.children; - let index = at == null ? children.length : at; - - const i = children.indexOf(node); - - if (i < 0) { - if (index < children.length) { - children.splice(index, 0, node); - } else { - children.push(node); - } - node.internalSetParent(container); - } else { - if (index > i) { - index -= 1; - } - - if (index === i) { - return node; - } - - children.splice(i, 1); - children.splice(index, 0, node); - } - - // check condition group - node.conditionGroup = null; - if (node.prevSibling && node.nextSibling) { - const conditionGroup = node.prevSibling.conditionGroup; - if (conditionGroup && conditionGroup === node.nextSibling.conditionGroup) { - node.conditionGroup = conditionGroup; - } - } - - return node; -} - -export function insertChildren( - container: INodeParent, - nodes: Node[] | NodeSchema[], - at?: number | null, - copy?: boolean, -): Node[] { - let index = at; - let node: any; - const results: Node[] = []; - // tslint:disable-next-line - while ((node = nodes.pop())) { - results.push(insertChild(container, node, index, copy)); - index = node.index; - } - return results; -} - -export function getChildAt(parent: INodeParent, index: number): Node | null { - if (!parent.children) { - return null; - } - return parent.children[index]; -} - -export function indexOf(parent: INodeParent, child: Node): number { - if (!parent.children) { - return -1; - } - return parent.children.indexOf(child); -} - -export function removeChild(parent: INodeParent, child: Node) { - if (!parent.children) { - return; - } - const i = parent.children.indexOf(child); - if (i > -1) { - parent.children.splice(i, 1); - } -} diff --git a/packages/designer/src/designer/document/props.ts b/packages/designer/src/designer/document/props.ts deleted file mode 100644 index 6e48015e4..000000000 --- a/packages/designer/src/designer/document/props.ts +++ /dev/null @@ -1,683 +0,0 @@ -import { untracked, computed, obx } from '@recore/obx'; -import { uniqueId, isPlainObject, hasOwnProperty } from '../../utils'; -import { valueToSource } from '../../utils/value-to-source'; -import { CompositeValue, isJSExpression, PropsList, PropsMap } from '../schema'; -import StashSpace from './stash-space'; - -export const UNSET = Symbol.for('unset'); -export type UNSET = typeof UNSET; - -export interface IPropParent { - delete(prop: Prop): void; -} - -export class Prop implements IPropParent { - readonly isProp = true; - - readonly id = uniqueId('prop$'); - - private _type: 'unset' | 'literal' | 'map' | 'list' | 'expression' = 'unset'; - /** - * 属性类型 - */ - get type(): 'unset' | 'literal' | 'map' | 'list' | 'expression' { - return this._type; - } - - @obx.ref private _value: any = UNSET; - - /** - * 属性值 - */ - @computed get value(): CompositeValue { - if (this._type === 'unset') { - return null; - } - - const type = this._type; - if (type === 'literal' || type === 'expression') { - return this._value; - } - - if (type === 'map') { - if (!this._items) { - return this._value; - } - const maps: any = {}; - this.items!.forEach((prop, key) => { - maps[key] = prop.value; - }); - return maps; - } - - if (type === 'list') { - if (!this._items) { - return this._items; - } - return this.items!.map(prop => prop.value); - } - - return null; - } - - /** - * set value, val should be JSON Object - */ - set value(val: CompositeValue) { - this._value = val; - const t = typeof val; - if (val == null) { - this._value = null; - this._type = 'literal'; - } else if (t === 'string' || t === 'number' || t === 'boolean') { - this._value = val; - this._type = 'literal'; - } else if (Array.isArray(val)) { - this._type = 'list'; - } else if (isPlainObject(val)) { - if (isJSExpression(val)) { - this._type = 'expression'; - } else { - this._type = 'map'; - } - this._type = 'map'; - } else { - this._type = 'expression'; - this._value = { - type: 'JSExpression', - value: valueToSource(val), - }; - } - if (untracked(() => this._items)) { - this._items!.forEach(prop => prop.purge()); - this._items = null; - } - this._maps = null; - if (this.stash) { - this.stash.clear(); - } - } - - /** - * 取消设置值 - */ - unset() { - this._type = 'unset'; - } - - /** - * 是否未设置值 - */ - isUnset() { - return this._type === 'unset'; - } - - /** - * 值是否包含表达式 - * 包含 JSExpresion | JSSlot 等值 - */ - isContainJSExpression(): boolean { - const type = this._type; - if (type === 'expression') { - return true; - } - if (type === 'literal' || type === 'unset') { - return false; - } - if ((type === 'list' || type === 'map') && this.items) { - return this.items.some(item => item.isContainJSExpression()); - } - return false; - } - - /** - * 是否简单 JSON 数据 - */ - isJSON() { - return !this.isContainJSExpression(); - } - - private _items: Prop[] | null = null; - private _maps: Map | null = null; - @computed private get items(): Prop[] | null { - let _items: any; - untracked(() => { - _items = this._items; - }); - if (!_items) { - if (this._type === 'list') { - const data = this._value; - const items = []; - for (const item of data) { - items.push(new Prop(this, item)); - } - _items = items; - this._maps = null; - } else if (this._type === 'map') { - const data = this._value; - const items = []; - const maps = new Map(); - const keys = Object.keys(data); - for (const key of keys) { - const prop = new Prop(this, data[key], key); - items.push(prop); - maps.set(key, prop); - } - _items = items; - this._maps = maps; - } else { - _items = null; - this._maps = null; - } - this._items = _items; - } - return _items; - } - @computed private get maps(): Map | null { - if (!this.items || this.items.length < 1) { - return null; - } - return this._maps; - } - - private stash: StashSpace | undefined; - - /** - * 键值 - */ - @obx key: string | number | undefined; - /** - * 扩展值 - */ - @obx spread: boolean; - - constructor( - public parent: IPropParent, - value: CompositeValue | UNSET = UNSET, - key?: string | number, - spread = false, - ) { - if (value !== UNSET) { - this.value = value; - } - this.key = key; - this.spread = spread; - } - - /** - * 获取某个属性 - * @param stash 强制 - */ - get(path: string, stash: false): Prop | null; - /** - * 获取某个属性, 如果不存在,临时获取一个待写入 - * @param stash 强制 - */ - get(path: string, stash: true): Prop; - /** - * 获取某个属性, 如果不存在,临时获取一个待写入 - */ - get(path: string): Prop; - get(path: string, stash = true) { - const type = this._type; - if (type !== 'map' && type !== 'unset' && !stash) { - return null; - } - - const maps = type === 'map' ? this.maps : null; - - let prop: any = maps ? maps.get(path) : null; - - if (prop) { - return prop; - } - - const i = path.indexOf('.'); - let entry = path; - let nest = ''; - if (i > 0) { - nest = path.slice(i + 1); - if (nest) { - entry = path.slice(0, i); - prop = maps ? maps.get(entry) : null; - if (prop) { - return prop.get(nest, stash); - } - } - } - - if (stash) { - if (!this.stash) { - this.stash = new StashSpace( - item => { - // item take effect - this.set(String(item.key), item); - item.parent = this; - }, - () => { - return true; - }, - ); - } - prop = this.stash.get(entry); - if (nest) { - return prop.get(nest, true); - } - - return prop; - } - - return null; - } - - /** - * 从父级移除本身 - */ - remove() { - this.parent.delete(this); - } - - /** - * 删除项 - */ - delete(prop: Prop): void { - if (this.items) { - const i = this.items.indexOf(prop); - if (i > -1) { - this.items.slice(i, 1); - prop.purge(); - } - if (this._maps && prop.key) { - this._maps.delete(String(prop.key)); - } - } - } - - /** - * 删除 key - */ - deleteKey(key: string): void { - if (this.maps) { - const prop = this.maps.get(key); - if (prop) { - this.delete(prop); - } - } - } - - /** - * 元素个数 - */ - size(): number { - return this.items?.length || 0; - } - - /** - * 添加值到列表 - * - * @param force 强制 - */ - add(value: CompositeValue, force = false): Prop | null { - const type = this._type; - if (type !== 'list' && type !== 'unset' && !force) { - return null; - } - if (type === 'unset' || (force && type !== 'list')) { - this.value = []; - } - const prop = new Prop(this, value); - this.items!.push(prop); - return prop; - } - - /** - * 设置值到字典 - * - * @param force 强制 - */ - set(key: string, value: CompositeValue | Prop, force = false) { - const type = this._type; - if (type !== 'map' && type !== 'unset' && !force) { - return null; - } - if (type === 'unset' || (force && type !== 'map')) { - this.value = {}; - } - const prop = isProp(value) ? value : new Prop(this, value, key); - const items = this.items!; - const maps = this.maps!; - const orig = maps.get(key); - if (orig) { - // replace - const i = items.indexOf(orig); - if (i > -1) { - items.splice(i, 1, prop)[0].purge(); - } - maps.set(key, prop); - } else { - // push - items.push(prop); - maps.set(key, prop); - } - - return prop; - } - - /** - * 是否存在 key - */ - has(key: string): boolean { - if (this._type !== 'map') { - return false; - } - if (this._maps) { - return this._maps.has(key); - } - return hasOwnProperty(this._value, key); - } - - private purged = false; - /** - * 回收销毁 - */ - purge() { - if (this.purged) { - return; - } - this.purged = true; - if (this.stash) { - this.stash.purge(); - } - if (this._items) { - this._items.forEach(item => item.purge()); - } - this._maps = null; - } - - /** - * 迭代器 - */ - [Symbol.iterator](): { next(): { value: Prop } } { - let index = 0; - const items = this.items; - const length = items?.length || 0; - return { - next() { - if (index < length) { - return { - value: items![index++], - done: false, - }; - } - return { - value: undefined as any, - done: true, - }; - }, - }; - } - - /** - * 遍历 - */ - forEach(fn: (item: Prop, key: number | string | undefined) => void): void { - const items = this.items; - if (!items) { - return; - } - const isMap = this._type === 'map'; - items.forEach((item, index) => { - return isMap ? fn(item, item.key) : fn(item, index); - }); - } - - /** - * 遍历 - */ - map(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { - const items = this.items; - if (!items) { - return null; - } - const isMap = this._type === 'map'; - return items.map((item, index) => { - return isMap ? fn(item, item.key) : fn(item, index); - }); - } -} - -export function isProp(obj: any): obj is Prop { - return obj && obj.isProp; -} - -export default class Props implements IPropParent { - @obx.val private items: Prop[] = []; - @obx.ref private get maps(): Map { - const maps = new Map(); - if (this.items.length > 0) { - this.items.forEach(prop => { - if (prop.key) { - maps.set(prop.key, prop); - } - }); - } - return maps; - } - - private stash = new StashSpace( - prop => { - this.items.push(prop); - prop.parent = this; - }, - () => { - return true; - }, - ); - - /** - * 元素个数 - */ - get size() { - return this.items.length; - } - - @computed get value(): PropsMap | PropsList | null { - if (this.items.length < 1) { - return null; - } - if (this.type === 'list') { - return this.items.map(item => ({ - spread: item.spread, - name: item.key as string, - value: item.value, - })); - } - const maps: any = {}; - this.items.forEach(prop => { - if (prop.key) { - maps[prop.key] = prop.value; - } - }); - return maps; - } - - @obx type: 'map' | 'list' = 'map'; - - constructor(readonly owner: O, value?: PropsMap | PropsList | null) { - if (Array.isArray(value)) { - this.type = 'list'; - value.forEach(item => {}); - } else if (value != null) { - this.type = 'map'; - } - } - - /** - * 根据 path 路径查询属性,如果没有则临时生成一个 - */ - query(path: string): Prop; - /** - * 根据 path 路径查询属性 - * - * @useStash 如果没有则临时生成一个 - */ - query(path: string, useStash: true): Prop; - /** - * 根据 path 路径查询属性 - */ - query(path: string, useStash: false): Prop | null; - /** - * 根据 path 路径查询属性 - * - * @useStash 如果没有则临时生成一个 - */ - query(path: string, useStash: boolean = true) { - let matchedLength = 0; - let firstMatched = null; - if (this.items) { - // target: a.b.c - // trys: a.b.c, a.b, a - let i = this.items.length; - while (i-- > 0) { - const expr = this.items[i]; - if (!expr.key) { - continue; - } - const name = String(expr.key); - if (name === path) { - // completely match - return expr; - } - - // fisrt match - const l = name.length; - if (path.slice(0, l + 1) === `${name}.`) { - matchedLength = l; - firstMatched = expr; - } - } - } - - let ret = null; - if (firstMatched) { - ret = firstMatched.get(path.slice(matchedLength + 1), true); - } - if (!ret && useStash) { - return this.stash.get(path); - } - - return ret; - } - - /** - * 获取某个属性, 如果不存在,临时获取一个待写入 - * @param useStash 强制 - */ - get(path: string, useStash: true): Prop; - /** - * 获取某个属性 - * @param useStash 强制 - */ - get(path: string, useStash: false): Prop | null; - /** - * 获取某个属性 - */ - get(path: string): Prop | null; - get(name: string, useStash = false) { - return this.maps.get(name) || (useStash && this.stash.get(name)) || null; - } - - /** - * 删除项 - */ - delete(prop: Prop): void { - const i = this.items.indexOf(prop); - if (i > -1) { - this.items.splice(i, 1); - prop.purge(); - } - } - - /** - * 删除 key - */ - deleteKey(key: string): void { - this.items = this.items.filter(item => { - if (item.key === key) { - item.purge(); - return false; - } - return true; - }); - } - - /** - * 添加值 - */ - add(value: CompositeValue | null, key?: string | number, spread = false): Prop { - const prop = new Prop(this, value, key, spread); - this.items.push(prop); - return prop; - } - - /** - * 是否存在 key - */ - has(key: string): boolean { - return this.maps.has(key); - } - - /** - * 迭代器 - */ - [Symbol.iterator](): { next(): { value: Prop } } { - let index = 0; - const items = this.items; - const length = items.length || 0; - return { - next() { - if (index < length) { - return { - value: items[index++], - done: false, - }; - } - return { - value: undefined as any, - done: true, - }; - }, - }; - } - - /** - * 遍历 - */ - forEach(fn: (item: Prop, key: number | string | undefined) => void): void { - this.items.forEach(item => { - return fn(item, item.key); - }); - } - - /** - * 遍历 - */ - map(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { - return this.items.map(item => { - return fn(item, item.key); - }); - } - - private purged = false; - /** - * 回收销毁 - */ - purge() { - if (this.purged) { - return; - } - this.purged = true; - this.stash.purge(); - this.items.forEach(item => item.purge()); - } -} diff --git a/packages/designer/src/designer/document/root-node.ts b/packages/designer/src/designer/document/root-node.ts deleted file mode 100644 index 23b2c4e4e..000000000 --- a/packages/designer/src/designer/document/root-node.ts +++ /dev/null @@ -1,133 +0,0 @@ -import Node from './node'; - -/** - * state - * lifeCycles - * fileName - * meta - * methods - * dataSource - * css - * defaultProps - */ -export default class RootNode extends Node { - readonly isRootNode = true; - readonly index = 0; - readonly props: object = {}; - readonly nextSibling = null; - readonly prevSibling = null; - readonly zLevel = 0; - readonly parent = null; - internalSetParent(parent: null) {} - - get viewData(): ViewData { - return { - file: this.file, - children: this.nodeData, - }; - } - - readonly fileName: string; - readonly viewType: string; - readonly viewVersion: string; - - get ready() { - return this.document.ready; - } - - get nodeData(): NodeData[] { - if (!this.ready) { - // TODO: add mocks data - return this.childrenData; - } - const children = this.children; - if (!children || children.length < 1) { - return []; - } - return children.map(node => node.nodeData as NodeData); - } - - private childrenData: NodeData[]; - private _children: INode[] | null = null; - @obx.val get children(): INode[] { - if (this._children) { - return this._children; - } - if (!this.ready || this.purged) { - return []; - } - const children = this.childrenData; - /* eslint-disable */ - this._children = children - ? untracked(() => - children.map(child => { - const node = this.document.createNode(child); - node.internalSetParent(this); - return node; - }), - ) - : []; - /* eslint-enable */ - return this._children; - } - - get scope() { - return this.mocks.scope; - } - - constructor(readonly document: DocumentContext, { children, file, viewType, viewVersion }: ViewData) { - this.file = file; - this.viewType = viewType || ''; - this.viewVersion = viewVersion || ''; - - const expr = getMockExpr(children); - if (expr) { - this.childrenData = children.slice(0, -1); - this.mocksExpr = expr; - } else { - this.childrenData = children.slice(); - } - } - - merge(schema: DocumentSchema) { - for (let i = 0, l = data.length; i < l; i++) { - const item = this.children[i]; - if (item && isMergeable(item) && item.tagName === data[i].tagName) { - item.merge(data[i]); - } else { - if (item) { - item.purge(); - } - this.children[i] = this.document.createNode(data[i]); - this.children[i].internalSetParent(this); - } - } - if (this.children.length > data.length) { - this.children.splice(data.length).forEach(child => child.purge()); - } - } - - // todo: - reuse() {} - - private purged = false; - - purge() { - if (this.purged) { - return; - } - this.purged = true; - if (this._children) { - this._children.forEach(child => child.purge()); - } - } - - receiveViewData({ children }: ViewData) { - this.merge(children); - // this.selection.dispose(); - } -} - -export function isRootNode(node: any): node is RootNode { - return node && node.isRootNode; -} diff --git a/packages/designer/src/designer/document/selection.ts b/packages/designer/src/designer/document/selection.ts index 8e962c05d..3d64cb356 100644 --- a/packages/designer/src/designer/document/selection.ts +++ b/packages/designer/src/designer/document/selection.ts @@ -1,4 +1,4 @@ -import { INode, contains, isNode, comparePosition } from './node'; +import { INode, contains, isNode, comparePosition } from './node/node'; import { obx } from '@ali/recore'; import DocumentContext from './document-context'; diff --git a/packages/designer/src/designer/document/stash-space.ts b/packages/designer/src/designer/document/stash-space.ts deleted file mode 100644 index 2bd1361e6..000000000 --- a/packages/designer/src/designer/document/stash-space.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { obx, autorun, untracked } from '@recore/obx'; -import { Prop, IPropParent } from './props'; - -export type PendingItem = Prop[]; -export default class StashSpace implements IPropParent { - @obx.val private space: Set = new Set(); - @obx.ref private get maps(): Map { - const maps = new Map(); - if (this.space.size > 0) { - this.space.forEach(prop => { - maps.set(prop.key, prop); - }); - } - return maps; - } - private willPurge: () => void; - - constructor(write: (item: Prop) => void, before: () => boolean) { - this.willPurge = autorun(() => { - if (this.space.size < 1) { - return; - } - const pending: Prop[] = []; - for (const prop of this.space) { - if (!prop.isUnset()) { - this.space.delete(prop); - pending.push(prop); - } - } - if (pending.length > 0) { - untracked(() => { - if (before()) { - for (const item of pending) { - write(item); - } - } - }); - } - }); - } - - get(key: string): Prop { - let prop = this.maps.get(key); - if (!prop) { - prop = new Prop(this, null, key); - this.space.add(prop); - } - return prop; - } - - delete(prop: Prop) { - this.space.delete(prop); - prop.purge(); - } - - clear() { - this.space.forEach(item => item.purge()); - this.space.clear(); - } - - purge() { - this.willPurge(); - this.space.clear(); - } -}