mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 01:21:58 +00:00
polyfill slot
This commit is contained in:
parent
73a5efe8e1
commit
f1b686bad5
@ -10,7 +10,7 @@ import {
|
||||
isVertical
|
||||
} from '../../designer';
|
||||
import { ISimulatorHost, } from '../../simulator';
|
||||
import {NodeParent } from '../../document';
|
||||
import {ParentalNode } from '../../document';
|
||||
import './insertion.less';
|
||||
|
||||
interface InsertionData {
|
||||
@ -24,7 +24,7 @@ interface InsertionData {
|
||||
/**
|
||||
* 处理拖拽子节点(INode)情况
|
||||
*/
|
||||
function processChildrenDetail(sim: ISimulatorHost, container: NodeParent, detail: LocationChildrenDetail): InsertionData {
|
||||
function processChildrenDetail(sim: ISimulatorHost, container: ParentalNode, detail: LocationChildrenDetail): InsertionData {
|
||||
let edge = detail.edge || null;
|
||||
|
||||
if (!edge) {
|
||||
|
||||
@ -2,7 +2,7 @@ import { obx, autorun, computed } from '@ali/lowcode-globals';
|
||||
import { ISimulatorHost, Component, NodeInstance, ComponentInstance } from '../simulator';
|
||||
import Viewport from './viewport';
|
||||
import { createSimulator } from './create-simulator';
|
||||
import { Node, NodeParent, DocumentModel, isNodeParent, isNode, contains, isRootNode } from '../document';
|
||||
import { Node, ParentalNode, DocumentModel, isNode, contains, isRootNode } from '../document';
|
||||
import ResourceConsumer from './resource-consumer';
|
||||
import { AssetLevel, Asset, AssetList, assetBundle, assetItem, AssetType, getPublicPath } from '@ali/lowcode-globals';
|
||||
import {
|
||||
@ -21,7 +21,7 @@ import {
|
||||
Rect,
|
||||
CanvasPoint,
|
||||
} from '../designer';
|
||||
import { parseProps } from './utils/parse-props';
|
||||
import { parseProps, parseMetadata } from './utils/parse-metadata';
|
||||
import { isElement, hotkey } from '@ali/lowcode-globals';
|
||||
import { ComponentMetadata } from '@ali/lowcode-globals';
|
||||
import { BuiltinSimulatorRenderer } from './renderer';
|
||||
@ -387,16 +387,19 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
const component = this.getComponent(componentName);
|
||||
|
||||
if (component) {
|
||||
parseProps(component as any);
|
||||
if (!component) {
|
||||
return {
|
||||
componentName,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 1. generate builtin div/p/h1/h2
|
||||
// 2. read propTypes
|
||||
|
||||
return {
|
||||
componentName,
|
||||
props: parseProps(this.getComponent(componentName)),
|
||||
...parseMetadata(component),
|
||||
};
|
||||
}
|
||||
|
||||
@ -854,7 +857,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
container = currentRoot;
|
||||
}
|
||||
|
||||
if (!isNodeParent(container)) {
|
||||
if (!container.isParental()) {
|
||||
container = container.parent || currentRoot;
|
||||
}
|
||||
|
||||
@ -943,7 +946,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
return null;
|
||||
}
|
||||
|
||||
isAcceptable(container: NodeParent): boolean {
|
||||
isAcceptable(container: ParentalNode): boolean {
|
||||
return false;
|
||||
/*
|
||||
const meta = container.componentMeta;
|
||||
@ -1006,7 +1009,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* 查找邻近容器
|
||||
*/
|
||||
getNearByContainer(container: NodeParent, e: LocateEvent) {
|
||||
getNearByContainer(container: ParentalNode, e: LocateEvent) {
|
||||
/*
|
||||
const children = container.children;
|
||||
if (!children || children.length < 1) {
|
||||
@ -1110,6 +1113,6 @@ function getMatched(elements: Array<Element | Text>, selector: string): Element
|
||||
}
|
||||
|
||||
interface DropContainer {
|
||||
container: NodeParent;
|
||||
container: ParentalNode;
|
||||
instance: ComponentInstance;
|
||||
}
|
||||
|
||||
@ -198,3 +198,10 @@ export function parseProps(component: any): PropConfig[] {
|
||||
|
||||
return Object.keys(result).map(key => result[key]);
|
||||
}
|
||||
|
||||
export function parseMetadata(component: any): any {
|
||||
return {
|
||||
props: parseProps(component),
|
||||
...component.componentMetadata,
|
||||
};
|
||||
}
|
||||
@ -11,7 +11,7 @@ import {
|
||||
computed,
|
||||
NestingFilter,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { Node, NodeParent } from './document';
|
||||
import { Node, ParentalNode } from './document';
|
||||
import { Designer } from './designer';
|
||||
import { intl } from './locale';
|
||||
import { IconContainer } from './icons/container';
|
||||
@ -194,7 +194,7 @@ export class ComponentMeta {
|
||||
return this._transformedMetadata!;
|
||||
}
|
||||
|
||||
checkNestingUp(my: Node | NodeData, parent: NodeParent) {
|
||||
checkNestingUp(my: Node | NodeData, parent: ParentalNode) {
|
||||
// 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器
|
||||
if (this.parentWhitelist) {
|
||||
return this.parentWhitelist(parent, my);
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
autorun,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { Project } from '../project';
|
||||
import { Node, DocumentModel, insertChildren, isRootNode, NodeParent } from '../document';
|
||||
import { Node, DocumentModel, insertChildren, isRootNode, ParentalNode } from '../document';
|
||||
import { ComponentMeta } from '../component-meta';
|
||||
import { INodeSelector, Component } from '../simulator';
|
||||
import { Scroller, IScrollable } from './scroller';
|
||||
@ -201,7 +201,7 @@ export class Designer {
|
||||
/**
|
||||
* 获得合适的插入位置
|
||||
*/
|
||||
getSuitableInsertion(): { target: NodeParent; index?: number } | null {
|
||||
getSuitableInsertion(): { target: ParentalNode; index?: number } | null {
|
||||
const activedDoc = this.project.currentDocument;
|
||||
if (!activedDoc) {
|
||||
return null;
|
||||
|
||||
@ -88,7 +88,6 @@ export interface DragNodeObject {
|
||||
export interface DragNodeDataObject {
|
||||
type: DragObjectType.NodeData;
|
||||
data: NodeSchema | NodeSchema[];
|
||||
maps?: { [componentName: string]: string };
|
||||
thumbnail?: string;
|
||||
description?: string;
|
||||
[extra: string]: any;
|
||||
@ -233,7 +232,7 @@ export class Dragon {
|
||||
const masterSensors = this.getMasterSensors();
|
||||
const handleEvents = makeEventsHandler(boostEvent, masterSensors);
|
||||
const newBie = !isDragNodeObject(dragObject);
|
||||
const forceCopyState = isDragNodeObject(dragObject) && dragObject.nodes.some((node) => node.isSlotRoot);
|
||||
const forceCopyState = isDragNodeObject(dragObject) && dragObject.nodes.some((node) => node.isSlot());
|
||||
const isBoostFromDragAPI = boostEvent.type.substr(0, 4) === 'drag';
|
||||
let lastSensor: ISensor | undefined;
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { DocumentModel, Node as ComponentNode, NodeParent } from '../document';
|
||||
import { DocumentModel, Node as ComponentNode, ParentalNode } from '../document';
|
||||
import { LocateEvent } from './dragon';
|
||||
|
||||
export interface LocationData {
|
||||
target: NodeParent; // shadowNode | ConditionFlow | ElementNode | RootNode
|
||||
target: ParentalNode; // shadowNode | ConditionFlow | ElementNode | RootNode
|
||||
detail: LocationDetail;
|
||||
source: string;
|
||||
event: LocateEvent;
|
||||
@ -27,7 +27,7 @@ export interface LocationChildrenDetail {
|
||||
rect?: Rect;
|
||||
align?: 'V' | 'H';
|
||||
};
|
||||
focus?: { type: 'slots' } | { type: 'node'; node: NodeParent };
|
||||
focus?: { type: 'slots' } | { type: 'node'; node: ParentalNode };
|
||||
}
|
||||
|
||||
export interface LocationPropDetail {
|
||||
@ -126,7 +126,7 @@ export function getWindow(elem: Element | Document): Window {
|
||||
}
|
||||
|
||||
export class DropLocation {
|
||||
readonly target: NodeParent;
|
||||
readonly target: ParentalNode;
|
||||
readonly detail: LocationDetail;
|
||||
readonly event: LocateEvent;
|
||||
readonly source: string;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import {
|
||||
RootSchema,
|
||||
NodeData,
|
||||
isJSExpression,
|
||||
isDOMText,
|
||||
@ -9,16 +8,26 @@ import {
|
||||
autorun,
|
||||
isNodeSchema,
|
||||
uniqueId,
|
||||
PageSchema,
|
||||
ComponentSchema,
|
||||
RootSchema,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { Project } from '../project';
|
||||
import { ISimulatorHost } from '../simulator';
|
||||
import { ComponentMeta } from '../component-meta';
|
||||
import { isDragNodeDataObject, DragNodeObject, DragNodeDataObject, DropLocation } from '../designer';
|
||||
import { Node, isNodeParent, insertChildren, insertChild, NodeParent, isNode } from './node/node';
|
||||
import { Node, insertChildren, insertChild, isNode, RootNode, ParentalNode } from './node/node';
|
||||
import { Selection } from './selection';
|
||||
import { RootNode } from './node/root-node';
|
||||
import { History } from './history';
|
||||
import { Prop } from './node/props/prop';
|
||||
import { ExportType } from './node';
|
||||
|
||||
export type GetDataType<T, NodeType> = T extends undefined
|
||||
? NodeType extends {
|
||||
schema: infer R;
|
||||
}
|
||||
? R
|
||||
: any
|
||||
: T;
|
||||
|
||||
export class DocumentModel {
|
||||
/**
|
||||
@ -58,7 +67,7 @@ export class DocumentModel {
|
||||
this.rootNode.getExtraProp('fileName', true)?.setValue(fileName);
|
||||
}
|
||||
|
||||
private _modalNode?: NodeParent;
|
||||
private _modalNode?: ParentalNode;
|
||||
private _blank?: boolean;
|
||||
get modalNode() {
|
||||
return this._modalNode;
|
||||
@ -81,8 +90,9 @@ export class DocumentModel {
|
||||
this._blank = true;
|
||||
}
|
||||
|
||||
this.rootNode = this.createRootNode(schema || {
|
||||
this.rootNode = this.createNode<RootNode>(schema || {
|
||||
componentName: 'Page',
|
||||
id: 'root',
|
||||
fileName: ''
|
||||
});
|
||||
|
||||
@ -130,7 +140,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 根据 schema 创建一个节点
|
||||
*/
|
||||
createNode(data: NodeData, slotFor?: Prop): Node {
|
||||
createNode<T extends Node = Node, C = undefined>(data: GetDataType<C, T>): T {
|
||||
let schema: any;
|
||||
if (isDOMText(data) || isJSExpression(data)) {
|
||||
schema = {
|
||||
@ -150,14 +160,13 @@ export class DocumentModel {
|
||||
// will move to another position
|
||||
// todo: this.activeNodes?.push(node);
|
||||
}
|
||||
node.internalSetSlotFor(slotFor);
|
||||
node.import(schema, true);
|
||||
} else if (node) {
|
||||
node = null;
|
||||
}
|
||||
}
|
||||
if (!node) {
|
||||
node = new Node(this, schema, slotFor);
|
||||
node = new Node(this, schema);
|
||||
// will add
|
||||
// todo: this.activeNodes?.push(node);
|
||||
}
|
||||
@ -169,27 +178,20 @@ export class DocumentModel {
|
||||
this.nodesMap.set(node.id, node);
|
||||
this.nodes.add(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private createRootNode(schema: RootSchema) {
|
||||
const node = new RootNode(this, schema);
|
||||
this.nodesMap.set(node.id, node);
|
||||
this.nodes.add(node);
|
||||
return node;
|
||||
return node as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入一个节点
|
||||
*/
|
||||
insertNode(parent: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
insertNode(parent: ParentalNode, 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) {
|
||||
insertNodes(parent: ParentalNode, thing: Node[] | NodeData[], at?: number | null, copy?: boolean) {
|
||||
return insertChildren(parent, thing, at, copy);
|
||||
}
|
||||
|
||||
@ -249,7 +251,7 @@ export class DocumentModel {
|
||||
return null;
|
||||
}
|
||||
const wrapper = this.createNode(schema);
|
||||
if (isNodeParent(wrapper)) {
|
||||
if (wrapper.isParental()) {
|
||||
const first = nodes[0];
|
||||
// TODO: check nesting rules x 2
|
||||
insertChild(first.parent!, wrapper, first.index);
|
||||
@ -270,11 +272,15 @@ export class DocumentModel {
|
||||
}
|
||||
|
||||
import(schema: RootSchema, checkId = false) {
|
||||
this.rootNode.import(schema, checkId);
|
||||
this.rootNode.import(schema as any, checkId);
|
||||
// todo: purge something
|
||||
// todo: select added and active track added
|
||||
}
|
||||
|
||||
export(exportType: ExportType = ExportType.ForSerilize) {
|
||||
return this.rootNode.export(exportType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出节点数据
|
||||
*/
|
||||
@ -409,7 +415,7 @@ export class DocumentModel {
|
||||
// todo:
|
||||
}
|
||||
|
||||
checkNesting(dropTarget: NodeParent, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
checkNesting(dropTarget: ParentalNode, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
let items: Array<Node | NodeSchema>;
|
||||
if (isDragNodeDataObject(dragObject)) {
|
||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||
@ -419,7 +425,7 @@ export class DocumentModel {
|
||||
return items.every((item) => this.checkNestingDown(dropTarget, item));
|
||||
}
|
||||
|
||||
checkDropTarget(dropTarget: NodeParent, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
checkDropTarget(dropTarget: ParentalNode, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
let items: Array<Node | NodeSchema>;
|
||||
if (isDragNodeDataObject(dragObject)) {
|
||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||
@ -432,7 +438,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 检查对象对父级的要求,涉及配置 parentWhitelist
|
||||
*/
|
||||
checkNestingUp(parent: NodeParent, obj: NodeSchema | Node): boolean {
|
||||
checkNestingUp(parent: ParentalNode, obj: NodeSchema | Node): boolean {
|
||||
if (isNode(obj) || isNodeSchema(obj)) {
|
||||
const config = isNode(obj) ? obj.componentMeta : this.getComponentMeta(obj.componentName);
|
||||
if (config) {
|
||||
@ -446,7 +452,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 检查投放位置对子级的要求,涉及配置 childWhitelist
|
||||
*/
|
||||
checkNestingDown(parent: NodeParent, obj: NodeSchema | Node): boolean {
|
||||
checkNestingDown(parent: ParentalNode, obj: NodeSchema | Node): boolean {
|
||||
const config = parent.componentMeta;
|
||||
return config.checkNestingDown(parent, obj) && this.checkNestingUp(parent, obj);
|
||||
}
|
||||
|
||||
5
packages/designer/src/document/node/export-type.ts
Normal file
5
packages/designer/src/document/node/export-type.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export enum ExportType {
|
||||
ForRender = 1,
|
||||
ForSerilize = 2,
|
||||
ForSave = 3,
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
export * from './exclusive-group';
|
||||
export * from './node';
|
||||
export * from './node-children';
|
||||
export * from './root-node';
|
||||
export * from './props/prop';
|
||||
export * from './props/prop-stash';
|
||||
export * from './props/props';
|
||||
export * from './export-type';
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { NodeData, isNodeSchema, obx, computed } from '@ali/lowcode-globals';
|
||||
import { Node, NodeParent } from './node';
|
||||
import { Node, ParentalNode } from './node';
|
||||
import { ExportType } from './export-type';
|
||||
|
||||
export class NodeChildren {
|
||||
@obx.val private children: Node[];
|
||||
constructor(readonly owner: NodeParent, data: NodeData | NodeData[]) {
|
||||
constructor(readonly owner: ParentalNode, data: NodeData | NodeData[]) {
|
||||
this.children = (Array.isArray(data) ? data : [data]).map(child => {
|
||||
return this.owner.document.createNode(child);
|
||||
});
|
||||
@ -15,10 +16,16 @@ export class NodeChildren {
|
||||
|
||||
/**
|
||||
* 导出 schema
|
||||
* @param serialize 序列化,加 id 标识符,用于储存为操作记录
|
||||
*/
|
||||
export(serialize = false): NodeData[] {
|
||||
return this.children.map(node => node.export(serialize));
|
||||
export(exportType: ExportType = ExportType.ForSave): NodeData[] {
|
||||
return this.children.map(node => {
|
||||
const data = node.export(exportType);
|
||||
if (node.isLeaf() && ExportType.ForSave === exportType) {
|
||||
// FIXME: filter empty
|
||||
return data.children as NodeData;
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
import(data?: NodeData | NodeData[], checkId = false) {
|
||||
|
||||
@ -8,6 +8,9 @@ import {
|
||||
TitleContent,
|
||||
obx,
|
||||
computed,
|
||||
SlotSchema,
|
||||
PageSchema,
|
||||
ComponentSchema,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { Props, EXTRA_KEY_PREFIX } from './props/props';
|
||||
import { DocumentModel } from '../document-model';
|
||||
@ -15,6 +18,7 @@ import { NodeChildren } from './node-children';
|
||||
import { Prop } from './props/prop';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group';
|
||||
import { ExportType } from './export-type';
|
||||
|
||||
/**
|
||||
* 基础节点
|
||||
@ -35,8 +39,36 @@ import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group';
|
||||
* locked can not select/hover/ item on canvas but can control on outline
|
||||
* hidden not visible on canvas
|
||||
* slotArgs like loopArgs, for slot node
|
||||
*
|
||||
* 根容器节点
|
||||
*
|
||||
* [Node Properties]
|
||||
* componentName: Page/Block/Component
|
||||
* props
|
||||
* children
|
||||
*
|
||||
* [Root Container Extra Properties]
|
||||
* fileName
|
||||
* meta
|
||||
* state
|
||||
* defaultProps
|
||||
* dataSource
|
||||
* lifeCycles
|
||||
* methods
|
||||
* css
|
||||
*
|
||||
* [Directives **not used**]
|
||||
* loop
|
||||
* loopArgs
|
||||
* condition
|
||||
* ------- future support -----
|
||||
* conditionGroup
|
||||
* title
|
||||
* ignore
|
||||
* locked
|
||||
* hidden
|
||||
*/
|
||||
export class Node {
|
||||
export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
/**
|
||||
* 是节点实例
|
||||
*/
|
||||
@ -63,11 +95,11 @@ export class Node {
|
||||
*/
|
||||
readonly props: Props;
|
||||
protected _children?: NodeChildren;
|
||||
@obx.ref private _parent: NodeParent | null = null;
|
||||
@obx.ref private _parent: ParentalNode | null = null;
|
||||
/**
|
||||
* 父级节点
|
||||
*/
|
||||
get parent(): NodeParent | null {
|
||||
get parent(): ParentalNode | null {
|
||||
return this._parent;
|
||||
}
|
||||
/**
|
||||
@ -100,48 +132,71 @@ export class Node {
|
||||
return this.componentMeta.title;
|
||||
}
|
||||
|
||||
get isSlotRoot(): boolean {
|
||||
return this._slotFor != null;
|
||||
}
|
||||
|
||||
isRoot() {
|
||||
return (this.document.rootNode as any) == this;
|
||||
}
|
||||
|
||||
constructor(readonly document: DocumentModel, nodeSchema: NodeSchema, slotFor?: Prop) {
|
||||
constructor(readonly document: DocumentModel, nodeSchema: Schema) {
|
||||
const { componentName, id, children, props, ...extras } = nodeSchema;
|
||||
this.id = id || `node$${document.nextId()}`;
|
||||
this.componentName = componentName;
|
||||
this._slotFor = slotFor;
|
||||
let _props: Props;
|
||||
if (isNodeParent(this)) {
|
||||
_props = new Props(this, props, extras);
|
||||
this._children = new NodeChildren(this as NodeParent, children || []);
|
||||
this._children.interalInitParent();
|
||||
} else {
|
||||
if (this.componentName === 'Leaf') {
|
||||
_props = new Props(this, {
|
||||
children: isDOMText(children) || isJSExpression(children) ? children : '',
|
||||
});
|
||||
} else {
|
||||
_props = new Props(this, this.buildProps(props), extras);
|
||||
this._children = new NodeChildren(this as ParentalNode, children || []);
|
||||
this._children.interalInitParent();
|
||||
}
|
||||
this.props = _props;
|
||||
}
|
||||
|
||||
private buildProps(props: any): any {
|
||||
// TODO: run componentMeta(initials|initialValue|accessor)
|
||||
return props;
|
||||
}
|
||||
|
||||
isContainer(): boolean {
|
||||
return this.isParental() && this.componentMeta.isContainer;
|
||||
}
|
||||
|
||||
isRoot(): this is RootNode {
|
||||
return this.document.rootNode == this as any;
|
||||
}
|
||||
|
||||
isPage(): this is PageNode {
|
||||
return this.isRoot() && this.componentName === 'Page';
|
||||
}
|
||||
|
||||
isComponent(): this is ComponentNode {
|
||||
return this.isRoot() && this.componentName === 'Component';
|
||||
}
|
||||
|
||||
isSlot(): this is SlotNode {
|
||||
return this._slotFor != null && this.componentName === 'Slot';
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否一个父亲类节点
|
||||
*/
|
||||
get isNodeParent(): boolean {
|
||||
return this.componentName !== 'Leaf';
|
||||
isParental(): this is ParentalNode {
|
||||
return !this.isLeaf();
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端节点,内容一般为 文字 或者 表达式
|
||||
*/
|
||||
isLeaf(): this is LeafNode {
|
||||
return this.componentName === 'Leaf';
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部方法,请勿使用
|
||||
*/
|
||||
internalSetParent(parent: NodeParent | null) {
|
||||
internalSetParent(parent: ParentalNode | null) {
|
||||
if (this._parent === parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._parent && !this.isSlotRoot) {
|
||||
if (!this.isSlot() && this._parent) {
|
||||
this._parent.children.delete(this);
|
||||
}
|
||||
|
||||
@ -160,6 +215,9 @@ export class Node {
|
||||
this._slotFor = slotFor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联属性
|
||||
*/
|
||||
get slotFor() {
|
||||
return this._slotFor;
|
||||
}
|
||||
@ -168,7 +226,7 @@ export class Node {
|
||||
* 移除当前节点
|
||||
*/
|
||||
remove() {
|
||||
if (this.parent && !this.isSlotRoot) {
|
||||
if (!this.isSlot() && this.parent) {
|
||||
this.parent.children.delete(this, true);
|
||||
}
|
||||
}
|
||||
@ -199,17 +257,13 @@ export class Node {
|
||||
}
|
||||
|
||||
@computed get propsData(): PropsMap | PropsList | null {
|
||||
if (!this.isNodeParent || this.componentName === 'Fragment') {
|
||||
if (!this.isParental() || this.componentName === 'Fragment') {
|
||||
return null;
|
||||
}
|
||||
return this.props.export(true).props || null;
|
||||
return this.props.export(ExportType.ForSerilize).props || null;
|
||||
}
|
||||
|
||||
isContainer() {
|
||||
return this.isNodeParent && this.componentMeta.isContainer;
|
||||
}
|
||||
|
||||
@computed isSlotContainer() {
|
||||
@computed hasSlots() {
|
||||
for (const item of this.props) {
|
||||
if (item.type === 'slot') {
|
||||
return true;
|
||||
@ -280,11 +334,11 @@ export class Node {
|
||||
return v != null && v !== '';
|
||||
}
|
||||
|
||||
wrapWith(schema: NodeSchema) {
|
||||
wrapWith(schema: Schema) {
|
||||
// todo
|
||||
}
|
||||
|
||||
replaceWith(schema: NodeSchema, migrate = true) {
|
||||
replaceWith(schema: Schema, migrate = true) {
|
||||
// reuse the same id? or replaceSelection
|
||||
//
|
||||
}
|
||||
@ -366,22 +420,18 @@ export class Node {
|
||||
/**
|
||||
* 获取符合搭建协议-节点 schema 结构
|
||||
*/
|
||||
get schema(): NodeSchema {
|
||||
// FIXME! serilize?
|
||||
// for design - pass to Renderer
|
||||
// for save production data
|
||||
// for serilize mutation record
|
||||
return this.export(true);
|
||||
get schema(): Schema {
|
||||
return this.export(ExportType.ForSave);
|
||||
}
|
||||
|
||||
set schema(data: NodeSchema) {
|
||||
set schema(data: Schema) {
|
||||
this.import(data);
|
||||
}
|
||||
|
||||
import(data: NodeSchema, checkId = false) {
|
||||
import(data: Schema, checkId = false) {
|
||||
const { componentName, id, children, props, ...extras } = data;
|
||||
|
||||
if (isNodeParent(this)) {
|
||||
if (this.isParental()) {
|
||||
this.props.import(props, extras);
|
||||
(this._children as NodeChildren).import(children, checkId);
|
||||
} else {
|
||||
@ -391,32 +441,32 @@ export class Node {
|
||||
|
||||
/**
|
||||
* 导出 schema
|
||||
* @param serialize 序列化,加 id 标识符,用于储存为操作记录
|
||||
*/
|
||||
export(serialize = false): NodeSchema {
|
||||
export(exportType: ExportType = ExportType.ForSave): Schema {
|
||||
// run transducers
|
||||
// run
|
||||
const baseSchema: any = {
|
||||
componentName: this.componentName === 'Leaf' ? 'Fragment' : this.componentName,
|
||||
componentName: this.componentName,
|
||||
};
|
||||
|
||||
if (serialize) {
|
||||
if (exportType !== ExportType.ForSave) {
|
||||
baseSchema.id = this.id;
|
||||
}
|
||||
|
||||
if (!isNodeParent(this)) {
|
||||
baseSchema.children = this.props.get('children')?.export(serialize);
|
||||
// FIXME!
|
||||
return baseSchema.children;
|
||||
if (this.isLeaf()) {
|
||||
baseSchema.children = this.props.get('children')?.export(exportType);
|
||||
return baseSchema;
|
||||
}
|
||||
|
||||
const { props = {}, extras } = this.props.export(serialize) || {};
|
||||
const { props = {}, extras } = this.props.export(exportType) || {};
|
||||
const schema: any = {
|
||||
...baseSchema,
|
||||
props,
|
||||
...extras,
|
||||
};
|
||||
|
||||
if (this.children.size > 0) {
|
||||
schema.children = this.children.export(serialize);
|
||||
if (this.isParental() && this.children.size > 0) {
|
||||
schema.children = this.children.export(exportType);
|
||||
}
|
||||
|
||||
return schema;
|
||||
@ -468,7 +518,7 @@ export class Node {
|
||||
return;
|
||||
}
|
||||
this.purged = true;
|
||||
if (isNodeParent(this)) {
|
||||
if (this.isParental()) {
|
||||
this.children.purge();
|
||||
}
|
||||
this.props.purge();
|
||||
@ -510,7 +560,7 @@ export class Node {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getDOMNode() {
|
||||
getDOMNode(): any {
|
||||
const instance = this.document.simulator?.getComponentInstances(this)?.[0];
|
||||
if (!instance) {
|
||||
return;
|
||||
@ -535,17 +585,24 @@ export class Node {
|
||||
}
|
||||
}
|
||||
|
||||
export interface NodeParent extends Node {
|
||||
export interface ParentalNode<T extends NodeSchema = NodeSchema> extends Node<T> {
|
||||
readonly children: NodeChildren;
|
||||
readonly props: Props;
|
||||
}
|
||||
export interface LeafNode extends Node {
|
||||
readonly children: null;
|
||||
}
|
||||
|
||||
export interface SlotNode extends ParentalNode<SlotSchema> {}
|
||||
export interface PageNode extends ParentalNode<PageSchema> {}
|
||||
export interface ComponentNode extends ParentalNode<ComponentSchema> {}
|
||||
export type RootNode = PageNode | ComponentNode;
|
||||
|
||||
export function isNode(node: any): node is Node {
|
||||
return node && node.isNode;
|
||||
}
|
||||
|
||||
export function isNodeParent(node: Node): node is NodeParent {
|
||||
return node.isNodeParent;
|
||||
export function isRootNode(node: Node): node is RootNode {
|
||||
return node && node.isRoot();
|
||||
}
|
||||
|
||||
export function getZLevelTop(child: Node, zLevel: number): Node | null {
|
||||
@ -568,7 +625,7 @@ export function contains(node1: Node, node2: Node): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!node1.isNodeParent || !node2.parent) {
|
||||
if (!node1.isParental || !node2.parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -617,10 +674,10 @@ export function comparePosition(node1: Node, node2: Node): PositionNO {
|
||||
return PositionNO.BeforeOrAfter;
|
||||
}
|
||||
|
||||
export function insertChild(container: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
export function insertChild(container: ParentalNode, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
let node: Node;
|
||||
if (isNode(thing) && (copy || thing.isSlotRoot)) {
|
||||
thing = thing.export(false);
|
||||
if (isNode(thing) && (copy || thing.isSlot())) {
|
||||
thing = thing.export(ExportType.ForSave);
|
||||
}
|
||||
if (isNode(thing)) {
|
||||
node = thing;
|
||||
@ -634,7 +691,7 @@ export function insertChild(container: NodeParent, thing: Node | NodeData, at?:
|
||||
}
|
||||
|
||||
export function insertChildren(
|
||||
container: NodeParent,
|
||||
container: ParentalNode,
|
||||
nodes: Node[] | NodeData[],
|
||||
at?: number | null,
|
||||
copy?: boolean,
|
||||
|
||||
@ -2,11 +2,11 @@ import {
|
||||
CompositeValue,
|
||||
isJSExpression,
|
||||
isJSSlot,
|
||||
NodeData,
|
||||
isNodeSchema,
|
||||
untracked,
|
||||
computed,
|
||||
obx
|
||||
obx,
|
||||
JSSlot,
|
||||
SlotSchema
|
||||
} from '@ali/lowcode-globals';
|
||||
import { uniqueId } from '@ali/lowcode-globals';
|
||||
import { isPlainObject } from '@ali/lowcode-globals';
|
||||
@ -14,7 +14,8 @@ import { hasOwnProperty } from '@ali/lowcode-globals';
|
||||
import { PropStash } from './prop-stash';
|
||||
import { valueToSource } from './value-to-source';
|
||||
import { Props } from './props';
|
||||
import { Node } from '../node';
|
||||
import { SlotNode } from '../node';
|
||||
import { ExportType } from '../export-type';
|
||||
|
||||
export const UNSET = Symbol.for('unset');
|
||||
export type UNSET = typeof UNSET;
|
||||
@ -45,10 +46,10 @@ export class Prop implements IPropParent {
|
||||
* 属性值
|
||||
*/
|
||||
@computed get value(): CompositeValue | UNSET {
|
||||
return this.export(true);
|
||||
return this.export(ExportType.ForSerilize);
|
||||
}
|
||||
|
||||
export(serialize = false): CompositeValue | UNSET {
|
||||
export(exporType: ExportType = ExportType.ForSave): CompositeValue | UNSET {
|
||||
const type = this._type;
|
||||
|
||||
if (type === 'unset') {
|
||||
@ -60,9 +61,18 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
|
||||
if (type === 'slot') {
|
||||
const schema = this._slotNode!.export(exporType);
|
||||
if (exporType === ExportType.ForSave) {
|
||||
return {
|
||||
type: 'JSSlot',
|
||||
params: schema.params,
|
||||
value: schema.children,
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: 'JSSlot',
|
||||
value: this._slotNode!.export(serialize),
|
||||
params: schema.params,
|
||||
value: schema,
|
||||
};
|
||||
}
|
||||
|
||||
@ -72,7 +82,7 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
const maps: any = {};
|
||||
this.items!.forEach((prop, key) => {
|
||||
const v = prop.export(serialize);
|
||||
const v = prop.export(exporType);
|
||||
if (v !== UNSET) {
|
||||
maps[key] = v;
|
||||
}
|
||||
@ -85,7 +95,7 @@ export class Prop implements IPropParent {
|
||||
return this._value;
|
||||
}
|
||||
return this.items!.map((prop) => {
|
||||
const v = prop.export(serialize);
|
||||
const v = prop.export(exporType);
|
||||
return v === UNSET ? null : v;
|
||||
});
|
||||
}
|
||||
@ -103,7 +113,7 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
// todo: JSFunction ...
|
||||
if (this.type === 'slot') {
|
||||
return JSON.stringify(this._slotNode!.export(false));
|
||||
return JSON.stringify(this._slotNode!.export(ExportType.ForSave));
|
||||
}
|
||||
return this._code != null ? this._code : JSON.stringify(this.value);
|
||||
}
|
||||
@ -161,7 +171,7 @@ export class Prop implements IPropParent {
|
||||
this._type = 'list';
|
||||
} else if (isPlainObject(val)) {
|
||||
if (isJSSlot(val)) {
|
||||
this.setAsSlot(val.value);
|
||||
this.setAsSlot(val);
|
||||
return;
|
||||
}
|
||||
if (isJSExpression(val)) {
|
||||
@ -181,7 +191,7 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
|
||||
@computed getValue(): CompositeValue {
|
||||
const v = this.export(true);
|
||||
const v = this.export(ExportType.ForSerilize);
|
||||
if (v === UNSET) {
|
||||
return null;
|
||||
}
|
||||
@ -204,24 +214,25 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
}
|
||||
|
||||
private _slotNode?: Node;
|
||||
private _slotNode?: SlotNode;
|
||||
get slotNode() {
|
||||
return this._slotNode;
|
||||
}
|
||||
setAsSlot(data: NodeData) {
|
||||
setAsSlot(data: JSSlot) {
|
||||
this._type = 'slot';
|
||||
if (
|
||||
this._slotNode &&
|
||||
isNodeSchema(data) &&
|
||||
(!data.id || this._slotNode.id === data.id) &&
|
||||
this._slotNode.componentName === data.componentName
|
||||
) {
|
||||
this._slotNode.import(data);
|
||||
const slotSchema: SlotSchema = {
|
||||
componentName: 'Slot',
|
||||
title: data.title,
|
||||
params: data.params,
|
||||
children: data.value,
|
||||
};
|
||||
if (this._slotNode) {
|
||||
this._slotNode.import(slotSchema);
|
||||
} else {
|
||||
this._slotNode?.internalSetParent(null);
|
||||
const owner = this.props.owner;
|
||||
this._slotNode = owner.document.createNode(data, this);
|
||||
this._slotNode = owner.document.createNode<SlotNode>(slotSchema);
|
||||
this._slotNode.internalSetParent(owner as any);
|
||||
this._slotNode.internalSetSlotFor(this);
|
||||
}
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { PropsMap, PropsList, CompositeValue, computed, obx, uniqueId } from '@a
|
||||
import { PropStash } from './prop-stash';
|
||||
import { Prop, IPropParent, UNSET } from './prop';
|
||||
import { Node } from '../node';
|
||||
import { ExportType } from '../export-type';
|
||||
|
||||
export const EXTRA_KEY_PREFIX = '__';
|
||||
|
||||
@ -79,7 +80,7 @@ export class Props implements IPropParent {
|
||||
});
|
||||
}
|
||||
|
||||
export(serialize = false): { props?: PropsMap | PropsList; extras?: object } {
|
||||
export(exportType: ExportType = ExportType.ForSave): { props?: PropsMap | PropsList; extras?: object } {
|
||||
if (this.items.length < 1) {
|
||||
return {};
|
||||
}
|
||||
@ -88,7 +89,7 @@ export class Props implements IPropParent {
|
||||
if (this.type === 'list') {
|
||||
props = [];
|
||||
this.items.forEach(item => {
|
||||
let value = item.export(serialize);
|
||||
let value = item.export(exportType);
|
||||
if (value === UNSET) {
|
||||
value = null;
|
||||
}
|
||||
@ -111,7 +112,7 @@ export class Props implements IPropParent {
|
||||
// todo ...spread
|
||||
return;
|
||||
}
|
||||
let value = item.export(serialize);
|
||||
let value = item.export(exportType);
|
||||
if (value === UNSET) {
|
||||
value = null;
|
||||
}
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
import { RootSchema } from '@ali/lowcode-globals';
|
||||
import { Node, NodeParent } from './node';
|
||||
import { DocumentModel } from '../document-model';
|
||||
import { NodeChildren } from './node-children';
|
||||
|
||||
/**
|
||||
* 根容器节点
|
||||
*
|
||||
* [Node Properties]
|
||||
* componentName: Page/Block/Component
|
||||
* props
|
||||
* children
|
||||
*
|
||||
* [Root Container Extra Properties]
|
||||
* fileName
|
||||
* meta
|
||||
* state
|
||||
* defaultProps
|
||||
* dataSource
|
||||
* lifeCycles
|
||||
* methods
|
||||
* css
|
||||
*
|
||||
* [Directives **not used**]
|
||||
* loop
|
||||
* loopArgs
|
||||
* condition
|
||||
* ------- future support -----
|
||||
* conditionGroup
|
||||
* title
|
||||
* ignore
|
||||
* locked
|
||||
* hidden
|
||||
*/
|
||||
export class RootNode extends Node implements NodeParent {
|
||||
readonly isRootNode = true;
|
||||
get isNodeParent() {
|
||||
return true;
|
||||
}
|
||||
get index() {
|
||||
return 0;
|
||||
}
|
||||
get nextSibling() {
|
||||
return null;
|
||||
}
|
||||
get prevSibling() {
|
||||
return null;
|
||||
}
|
||||
get zLevel() {
|
||||
return 0;
|
||||
}
|
||||
get parent() {
|
||||
return null;
|
||||
}
|
||||
get children(): NodeChildren {
|
||||
return this._children as NodeChildren;
|
||||
}
|
||||
internalSetParent(parent: null) {
|
||||
// empty
|
||||
}
|
||||
|
||||
constructor(readonly document: DocumentModel, rootSchema: RootSchema) {
|
||||
super(document, rootSchema);
|
||||
}
|
||||
|
||||
isPage() {
|
||||
return this.componentName === 'Page';
|
||||
}
|
||||
|
||||
isComponent() {
|
||||
return this.componentName === 'Component';
|
||||
}
|
||||
|
||||
isBlock() {
|
||||
return this.componentName === 'Block';
|
||||
}
|
||||
}
|
||||
|
||||
export function isRootNode(node: any): node is RootNode {
|
||||
return node && node.isRootNode;
|
||||
}
|
||||
@ -13,6 +13,13 @@ export interface NodeSchema {
|
||||
loop?: CompositeValue;
|
||||
loopArgs?: [string, string];
|
||||
children?: NodeData | NodeData[];
|
||||
|
||||
// ------- future support -----
|
||||
conditionGroup?: string;
|
||||
title?: string;
|
||||
ignore?: boolean;
|
||||
locked?: boolean;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
export type PropsMap = CompositeObject;
|
||||
@ -30,7 +37,7 @@ export function isDOMText(data: any): data is DOMText {
|
||||
|
||||
export type DOMText = string;
|
||||
|
||||
export interface RootSchema extends NodeSchema {
|
||||
export interface ContainerSchema extends NodeSchema {
|
||||
componentName: string; // 'Block' | 'Page' | 'Component';
|
||||
fileName: string;
|
||||
meta?: object;
|
||||
@ -48,18 +55,24 @@ export interface RootSchema extends NodeSchema {
|
||||
defaultProps?: CompositeObject;
|
||||
}
|
||||
|
||||
export interface BlockSchema extends RootSchema {
|
||||
componentName: 'Block';
|
||||
}
|
||||
|
||||
export interface PageSchema extends RootSchema {
|
||||
export interface PageSchema extends ContainerSchema {
|
||||
componentName: 'Page';
|
||||
}
|
||||
|
||||
export interface ComponentSchema extends RootSchema {
|
||||
export interface ComponentSchema extends ContainerSchema {
|
||||
componentName: 'Component';
|
||||
}
|
||||
|
||||
export type RootSchema = PageSchema | ComponentSchema;
|
||||
|
||||
export interface BlockSchema extends NodeSchema {
|
||||
componentName: 'Block';
|
||||
}
|
||||
export interface SlotSchema extends NodeSchema {
|
||||
componentName: 'Slot';
|
||||
params?: string[];
|
||||
}
|
||||
|
||||
export interface ProjectSchema {
|
||||
version: string;
|
||||
componentsMap: ComponentsMap;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { NodeSchema } from './schema';
|
||||
import { NodeSchema, NodeData } from './schema';
|
||||
|
||||
// 表达式
|
||||
export interface JSExpression {
|
||||
@ -15,9 +15,10 @@ export interface JSExpression {
|
||||
|
||||
export interface JSSlot {
|
||||
type: 'JSSlot';
|
||||
title?: string;
|
||||
// 函数的入参
|
||||
params?: string[];
|
||||
value: NodeSchema[];
|
||||
value?: NodeData[] | NodeData;
|
||||
}
|
||||
|
||||
// JSON 基本类型
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { NodeParent, DropLocation, isLocationChildrenDetail, LocateEvent } from '@ali/lowcode-designer';
|
||||
import { ParentalNode, DropLocation, isLocationChildrenDetail, LocateEvent } from '@ali/lowcode-designer';
|
||||
|
||||
/**
|
||||
* 停留检查计时器
|
||||
*/
|
||||
export default class DwellTimer {
|
||||
private timer: number | undefined;
|
||||
private previous?: NodeParent;
|
||||
private previous?: ParentalNode;
|
||||
private event?: LocateEvent;
|
||||
|
||||
constructor(private decide: (node: NodeParent, event: LocateEvent) => void, private timeout: number = 500) {}
|
||||
constructor(private decide: (node: ParentalNode, event: LocateEvent) => void, private timeout: number = 500) {}
|
||||
|
||||
focus(node: NodeParent, event: LocateEvent) {
|
||||
focus(node: ParentalNode, event: LocateEvent) {
|
||||
this.event = event;
|
||||
if (this.previous === node) {
|
||||
return;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { DropLocation, NodeParent, isLocationChildrenDetail } from '@ali/lowcode-designer';
|
||||
import { DropLocation, ParentalNode, isLocationChildrenDetail } from '@ali/lowcode-designer';
|
||||
|
||||
const IndentSensitive = 15;
|
||||
export class IndentTrack {
|
||||
@ -6,7 +6,7 @@ export class IndentTrack {
|
||||
reset() {
|
||||
this.indentStart = null;
|
||||
}
|
||||
getIndentParent(lastLoc: DropLocation, loc: DropLocation): [NodeParent, number] | null {
|
||||
getIndentParent(lastLoc: DropLocation, loc: DropLocation): [ParentalNode, number] | null {
|
||||
if (
|
||||
lastLoc.target !== loc.target ||
|
||||
!isLocationChildrenDetail(lastLoc.detail) ||
|
||||
@ -33,7 +33,7 @@ export class IndentTrack {
|
||||
const index = loc.detail.index;
|
||||
|
||||
if (direction === 'left') {
|
||||
if (!parent.parent || parent.isSlotRoot || index < parent.children.size) {
|
||||
if (parent.isSlot() || !parent.parent || index < parent.children.size) {
|
||||
return null;
|
||||
}
|
||||
return [parent.parent, parent.index + 1];
|
||||
|
||||
@ -13,7 +13,7 @@ import {
|
||||
isLocationChildrenDetail,
|
||||
LocationChildrenDetail,
|
||||
LocationDetailType,
|
||||
NodeParent,
|
||||
ParentalNode,
|
||||
contains,
|
||||
Node,
|
||||
} from '@ali/lowcode-designer';
|
||||
@ -199,7 +199,7 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
let index: any;
|
||||
let focus: any;
|
||||
let valid = true;
|
||||
if (target.isSlotContainer()) {
|
||||
if (target.hasSlots()) {
|
||||
index = null;
|
||||
focus = { type: 'slots' };
|
||||
} else {
|
||||
@ -301,7 +301,7 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
if (focusSlots) {
|
||||
this.dwell.reset();
|
||||
return designer.createLocation({
|
||||
target: node as NodeParent,
|
||||
target: node as ParentalNode,
|
||||
source: this.id,
|
||||
event: e,
|
||||
detail: {
|
||||
@ -342,9 +342,9 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
index = node.index;
|
||||
}
|
||||
|
||||
if (node.isSlotRoot) {
|
||||
if (node.isSlot()) {
|
||||
// 是个插槽根节点
|
||||
if (!treeNode.isContainer() && !treeNode.isSlotContainer()) {
|
||||
if (!treeNode.isContainer() && !treeNode.hasSlots()) {
|
||||
return designer.createLocation({
|
||||
target: node.parent!,
|
||||
source: this.id,
|
||||
@ -377,7 +377,7 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
|
||||
let focusNode: Node | undefined;
|
||||
// focus
|
||||
if (!expanded && (treeNode.isContainer() || treeNode.isSlotContainer())) {
|
||||
if (!expanded && (treeNode.isContainer() || treeNode.hasSlots())) {
|
||||
focusNode = node;
|
||||
}
|
||||
|
||||
@ -439,7 +439,7 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
return null;
|
||||
}
|
||||
|
||||
const container = treeNode.node as NodeParent;
|
||||
const container = treeNode.node as ParentalNode;
|
||||
const detail: LocationChildrenDetail = {
|
||||
type: LocationDetailType.Children,
|
||||
};
|
||||
@ -449,10 +449,10 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
source: this.id,
|
||||
event: e,
|
||||
};
|
||||
const isSlotContainer = treeNode.isSlotContainer();
|
||||
const isSlotContainer = treeNode.hasSlots();
|
||||
const isContainer = treeNode.isContainer();
|
||||
|
||||
if (container.isSlotRoot && !treeNode.expanded) {
|
||||
if (container.isSlot() && !treeNode.expanded) {
|
||||
// 未展开,直接定位到内部第一个节点
|
||||
if (isSlotContainer) {
|
||||
detail.index = null;
|
||||
@ -693,7 +693,7 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
}
|
||||
}
|
||||
|
||||
function checkRecursion(parent: Node | undefined | null, dragObject: DragObject): parent is NodeParent {
|
||||
function checkRecursion(parent: Node | undefined | null, dragObject: DragObject): parent is ParentalNode {
|
||||
if (!parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ export default class TreeNode {
|
||||
* 是否可以展开
|
||||
*/
|
||||
@computed get expandable(): boolean {
|
||||
return this.hasChildren() || this.isSlotContainer() || this.dropDetail?.index != null;
|
||||
return this.hasChildren() || this.hasSlots() || this.dropDetail?.index != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,51 +169,17 @@ export default class TreeNode {
|
||||
/**
|
||||
* 判断是否有"插槽"
|
||||
*/
|
||||
isSlotContainer(): boolean {
|
||||
return this.node.isSlotContainer();
|
||||
hasSlots(): boolean {
|
||||
return this.node.hasSlots();
|
||||
}
|
||||
|
||||
hasChildren(): boolean {
|
||||
return this.isContainer() && this.node.children?.notEmpty() ? true : false;
|
||||
}
|
||||
|
||||
/*
|
||||
get xForValue() {
|
||||
const node = this.node;
|
||||
return isElementNode(node) && node.xforValue ? node.xforValue : null;
|
||||
}
|
||||
|
||||
get flowHidden() {
|
||||
return (this.node as ElementNode).flowHidden;
|
||||
}
|
||||
|
||||
get flowIndex() {
|
||||
return (this.node as ElementNode).flowIndex;
|
||||
}
|
||||
|
||||
get conditionFlow() {
|
||||
return (this.node as ElementNode).conditionFlow;
|
||||
}
|
||||
|
||||
hasXIf() {
|
||||
return hasConditionFlow(this.node);
|
||||
}
|
||||
|
||||
hasXFor() {
|
||||
const node = this.node;
|
||||
return isElementNode(node) && node.xforFn;
|
||||
}
|
||||
*/
|
||||
|
||||
select(isMulti: boolean) {
|
||||
const node = this.node;
|
||||
|
||||
/*
|
||||
if (this.hasXIf()) {
|
||||
(node as ElementNode).setFlowVisible();
|
||||
}
|
||||
*/
|
||||
|
||||
const selection = node.document.selection;
|
||||
if (isMulti) {
|
||||
selection.add(node.id);
|
||||
|
||||
@ -108,7 +108,7 @@ class TreeNodeSlots extends Component<{
|
||||
}
|
||||
render() {
|
||||
const { treeNode } = this.props;
|
||||
if (!treeNode.isSlotContainer()) {
|
||||
if (!treeNode.hasSlots()) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
|
||||
@ -66,7 +66,7 @@ export default class TreeTitle extends Component<{
|
||||
const { editing } = this.state;
|
||||
const isCNode = !treeNode.isRoot();
|
||||
const { node } = treeNode;
|
||||
const isNodeParent = node.isNodeParent;
|
||||
const isNodeParent = node.isParental();
|
||||
let style: any;
|
||||
if (isCNode) {
|
||||
const depth = treeNode.depth;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
>.next-input {
|
||||
.next-input,.next-date-picker {
|
||||
width: 100%;
|
||||
}
|
||||
&.lc-block-setter {
|
||||
|
||||
@ -386,6 +386,7 @@ export default class BaseEngine extends PureComponent {
|
||||
__parseProps = (props, self, path, info) => {
|
||||
const { schema, Comp, componentInfo = {} } = info;
|
||||
const propInfo = getValue(componentInfo.props, path);
|
||||
// FIXME! 将这行逻辑外置,解耦,线上环境不要验证参数,调试环境可以有,通过传参自定义
|
||||
const propType = propInfo && propInfo.extra && propInfo.extra.propType;
|
||||
const ignoreParse = schema.__ignoreParse || [];
|
||||
const checkProps = (value) => {
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
import { Component } from 'react';
|
||||
|
||||
class Leaf extends Component {
|
||||
static displayName = 'Leaf';
|
||||
static componentMetadata = {
|
||||
componentName: 'Leaf',
|
||||
configure: {
|
||||
props: [{
|
||||
name: 'children',
|
||||
setter: 'StringSetter',
|
||||
}],
|
||||
// events/className/style/general/directives
|
||||
supports: false,
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
export default Leaf;
|
||||
@ -0,0 +1,53 @@
|
||||
import { Component } from 'react';
|
||||
|
||||
class Slot extends Component {
|
||||
static displayName = 'Slot';
|
||||
static componentMetadata = {
|
||||
componentName: 'Slot',
|
||||
configure: {
|
||||
props: [{
|
||||
name: '___title___',
|
||||
title: {
|
||||
type: 'i18n',
|
||||
'en-US': 'Slot Title',
|
||||
'zh-CN': '插槽标题'
|
||||
},
|
||||
setter: 'StringSetter',
|
||||
defaultValue: '插槽容器'
|
||||
}, {
|
||||
name: '___params___',
|
||||
title: {
|
||||
type: 'i18n',
|
||||
'en-US': 'Slot Params',
|
||||
'zh-CN': '插槽入参'
|
||||
},
|
||||
setter: {
|
||||
componentName: 'ArraySetter',
|
||||
props: {
|
||||
itemSetter: {
|
||||
componentName: 'StringSetter',
|
||||
props: {
|
||||
placeholder: {
|
||||
type: 'i18n',
|
||||
'zh-CN': '参数名称',
|
||||
'en-US': 'Argument Name'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}],
|
||||
// events/className/style/general/directives
|
||||
supports: false,
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
return (
|
||||
<div className="lc-container">{children}</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Slot;
|
||||
@ -41,6 +41,7 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> {
|
||||
}
|
||||
render() {
|
||||
const { renderer } = this.props;
|
||||
console.info(renderer.schema)
|
||||
return (
|
||||
<LowCodeRenderer
|
||||
schema={renderer.schema}
|
||||
|
||||
@ -57,6 +57,29 @@ html.engine-blur #engine {
|
||||
-webkit-filter: blur(4px);
|
||||
}
|
||||
|
||||
.lc-container {
|
||||
&:empty {
|
||||
background: #f2f3f5;
|
||||
color: #a7b1bd;
|
||||
outline: 1px dashed rgba(31, 56, 88, 0.2);
|
||||
outline-offset: -1px !important;
|
||||
height: 66px;
|
||||
max-height: 100%;
|
||||
min-width: 140px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&:before {
|
||||
content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC';
|
||||
font-size: 14px;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.engine-empty {
|
||||
background: #f2f3f5;
|
||||
color: #a7b1bd;
|
||||
|
||||
@ -13,6 +13,8 @@ import { cursor } from '@ali/lowcode-globals';
|
||||
import { setNativeSelection } from '@ali/lowcode-globals';
|
||||
import { RootSchema, NpmInfo } from '@ali/lowcode-globals';
|
||||
import { BuiltinSimulatorRenderer, NodeInstance } from '@ali/lowcode-designer';
|
||||
import Slot from './builtin-components/slot';
|
||||
import Leaf from './builtin-components/leaf';
|
||||
|
||||
export class SimulatorRenderer implements BuiltinSimulatorRenderer {
|
||||
readonly isSimulatorRenderer = true;
|
||||
@ -25,7 +27,7 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
|
||||
// sync layout config
|
||||
|
||||
// sync schema
|
||||
this._schema = host.document.schema;
|
||||
this._schema = host.document.export(1);
|
||||
|
||||
// todo: split with others, not all should recompute
|
||||
if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) {
|
||||
@ -311,8 +313,17 @@ export interface LibraryMap {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
// Slot/Leaf and Fragment|FunctionComponent polyfill(ref)
|
||||
|
||||
const builtinComponents = {
|
||||
Slot,
|
||||
Leaf,
|
||||
};
|
||||
|
||||
function buildComponents(libraryMap: LibraryMap, componentsMap: { [componentName: string]: NpmInfo | ComponentType<any> }) {
|
||||
const components: any = {};
|
||||
const components: any = {
|
||||
...builtinComponents
|
||||
};
|
||||
Object.keys(componentsMap).forEach((componentName) => {
|
||||
let component = componentsMap[componentName];
|
||||
if (isReactComponent(component)) {
|
||||
|
||||
@ -304,13 +304,24 @@ export function upgradePropConfig(config: OldPropConfig) {
|
||||
extraProps.defaultValue = initialValue;
|
||||
}
|
||||
|
||||
const initialFn = initial || initialValue;
|
||||
let initialFn = initial || initialValue;
|
||||
|
||||
if (accessor) {
|
||||
extraProps.getValue = (field: Field, fieldValue: any) => {
|
||||
return accessor.call(field, fieldValue);
|
||||
};
|
||||
if (!initialFn) {
|
||||
// FIXME!
|
||||
initialFn
|
||||
}
|
||||
}
|
||||
extraProps.initialValue = (field: Field, defaultValue?: any) => {
|
||||
if (defaultValue === undefined) {
|
||||
defaultValue = extraProps.defaultValue;
|
||||
}
|
||||
|
||||
if (typeof initialFn === 'function') {
|
||||
// ?
|
||||
return initialFn(null, defaultValue);
|
||||
}
|
||||
|
||||
@ -325,11 +336,6 @@ export function upgradePropConfig(config: OldPropConfig) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (accessor) {
|
||||
extraProps.getValue = (field: Field, fieldValue: any) => {
|
||||
return accessor.call(field, fieldValue);
|
||||
};
|
||||
}
|
||||
if (mutator) {
|
||||
extraProps.setValue = (field: Field, value: any) => {
|
||||
mutator.call(field, value);
|
||||
@ -535,9 +541,17 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
||||
experimental.context = context;
|
||||
}
|
||||
if (snippets) {
|
||||
experimental.snippets = snippets;
|
||||
}
|
||||
if (defaultProps || initialChildren) {
|
||||
experimental.snippets = snippets.map(data => {
|
||||
const { schema = {} } = data;
|
||||
if (initialChildren && !schema.children) {
|
||||
schema.children = initialChildren;
|
||||
}
|
||||
return {
|
||||
...data,
|
||||
schema,
|
||||
};
|
||||
});
|
||||
} else if (defaultProps || initialChildren) {
|
||||
const snippet = {
|
||||
screenshot: icon,
|
||||
label: title,
|
||||
|
||||
@ -19,6 +19,7 @@ export class Bus {
|
||||
// alias to unsub
|
||||
off(event: string, func: (...args: any[]) => any) {
|
||||
this.unsub(event, func);
|
||||
|
||||
}
|
||||
|
||||
// alias to pub
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { designer } from './editor';
|
||||
import { DragObjectType, isNode } from '@ali/lowcode-designer';
|
||||
import { DragObjectType, isNode, ExportType } from '@ali/lowcode-designer';
|
||||
|
||||
const dragon = designer.dragon;
|
||||
const DragEngine = {
|
||||
@ -12,14 +12,16 @@ const DragEngine = {
|
||||
if (isNode(r)) {
|
||||
return {
|
||||
type: DragObjectType.NodeData,
|
||||
data: r.export(false),
|
||||
data: r.export(ExportType.ForSave),
|
||||
};
|
||||
|
||||
// FIXME! designer has bug
|
||||
/*
|
||||
return {
|
||||
type: DragObjectType.Node,
|
||||
nodes: [r],
|
||||
};*/
|
||||
};
|
||||
*/
|
||||
} else {
|
||||
return {
|
||||
type: DragObjectType.NodeData,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user