Merge branch 'feat/joint-editor' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into feat/joint-editor

This commit is contained in:
下羊 2020-03-16 20:26:43 +08:00
commit 63c99bfaec
14 changed files with 433 additions and 264 deletions

View File

@ -8,17 +8,17 @@ import OffsetObserver from '../../../../designer/helper/offset-observer';
import Node from '../../../../designer/document/node/node'; import Node from '../../../../designer/document/node/node';
@observer @observer
export class OutlineSelectingInstance extends Component<{ observed: OffsetObserver; highlight?: boolean }> { export class OutlineSelectingInstance extends Component<{
shouldComponentUpdate() { observed: OffsetObserver;
return false; highlight?: boolean;
} dragging?: boolean;
}> {
componentWillUnmount() { componentWillUnmount() {
this.props.observed.purge(); this.props.observed.purge();
} }
render() { render() {
const { observed, highlight } = this.props; const { observed, highlight, dragging } = this.props;
if (!observed.hasOffset) { if (!observed.hasOffset) {
return null; return null;
} }
@ -33,6 +33,7 @@ export class OutlineSelectingInstance extends Component<{ observed: OffsetObserv
const className = classNames('lc-outlines lc-outlines-selecting', { const className = classNames('lc-outlines lc-outlines-selecting', {
highlight, highlight,
dragging,
}); });
return ( return (
@ -51,6 +52,10 @@ export class OutlineSelectingForNode extends Component<{ node: Node }> {
return this.context; return this.context;
} }
get dragging(): boolean {
return this.host.designer.dragon.dragging;
}
@computed get instances() { @computed get instances() {
return this.host.getComponentInstances(this.props.node); return this.host.getComponentInstances(this.props.node);
} }
@ -77,7 +82,7 @@ export class OutlineSelectingForNode extends Component<{ node: Node }> {
if (!observed) { if (!observed) {
return null; return null;
} }
return <OutlineSelectingInstance key={observed.id} observed={observed} />; return <OutlineSelectingInstance key={observed.id} dragging={this.dragging} observed={observed} />;
})} })}
</Fragment> </Fragment>
); );
@ -92,12 +97,17 @@ export class OutlineSelecting extends Component {
return this.context; return this.context;
} }
get dragging(): boolean {
return this.host.designer.dragon.dragging;
}
@computed get selecting() { @computed get selecting() {
const doc = this.host.document; const doc = this.host.document;
if (doc.suspensed) { if (doc.suspensed) {
return null; return null;
} }
return doc.selection.getNodes(); const selection = doc.selection;
return this.dragging ? selection.getTopNodes() : selection.getNodes();
} }
shouldComponentUpdate() { shouldComponentUpdate() {

View File

@ -22,7 +22,7 @@
&&-hovering { &&-hovering {
z-index: 1; z-index: 1;
border-style: dashed; border-style: dashed;
background: rgba(95, 240, 114, 0.04); background: rgba(0,121,242,.04);
&.x-loop { &.x-loop {
border-color: rgba(138, 93, 226, 0.8); border-color: rgba(138, 93, 226, 0.8);
@ -44,6 +44,7 @@
&&-selecting { &&-selecting {
z-index: 2; z-index: 2;
border-width: 2px;
&.x-loop { &.x-loop {
border-color: rgba(147, 112, 219, 1.0); border-color: rgba(147, 112, 219, 1.0);
@ -67,7 +68,6 @@
&.dragging { &.dragging {
background: rgba(182, 178, 178, 0.8); background: rgba(182, 178, 178, 0.8);
border: none; border: none;
pointer-events: all;
} }
} }
} }

View File

@ -145,9 +145,6 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
readonly scroller = this.designer.createScroller(this.viewport); readonly scroller = this.designer.createScroller(this.viewport);
mountViewport(viewport: Element | null) { mountViewport(viewport: Element | null) {
if (!viewport) {
return;
}
this.viewport.mount(viewport); this.viewport.mount(viewport);
} }
@ -174,10 +171,12 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
readonly libraryMap: { [key: string]: string } = {}; readonly libraryMap: { [key: string]: string } = {};
private _iframe?: HTMLIFrameElement;
async mountContentFrame(iframe: HTMLIFrameElement | null) { async mountContentFrame(iframe: HTMLIFrameElement | null) {
if (!iframe) { if (!iframe || this._iframe === iframe) {
return; return;
} }
this._iframe = iframe;
this._contentWindow = iframe.contentWindow!; this._contentWindow = iframe.contentWindow!;
@ -234,63 +233,88 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
// TODO: think of lock when edit a node // TODO: think of lock when edit a node
// 事件路由 // 事件路由
doc.addEventListener('mousedown', (downEvent: MouseEvent) => { doc.addEventListener(
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element); 'mousedown',
const node = nodeInst?.node || this.document.rootNode; (downEvent: MouseEvent) => {
const isMulti = downEvent.metaKey || downEvent.ctrlKey; // stop response document focus event
const isLeftButton = downEvent.which === 1 || downEvent.button === 0; downEvent.stopPropagation();
const checkSelect = (e: MouseEvent) => { downEvent.preventDefault();
doc.removeEventListener('mouseup', checkSelect, true);
if (!isShaken(downEvent, e)) {
const id = node.id;
designer.activeTracker.track(node);
if (isMulti && !isRootNode(node) && selection.has(id)) {
selection.remove(id);
} else {
selection.select(id);
}
}
};
if (isLeftButton && !isRootNode(node)) { const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
let nodes: Node[] = [node]; const node = nodeInst?.node || this.document.rootNode;
let ignoreUpSelected = false; const isMulti = downEvent.metaKey || downEvent.ctrlKey;
// 排除根节点拖拽 const isLeftButton = downEvent.which === 1 || downEvent.button === 0;
selection.remove(this.document.rootNode.id); const checkSelect = (e: MouseEvent) => {
if (isMulti) { doc.removeEventListener('mouseup', checkSelect, true);
// multi select mode, directily add if (!isShaken(downEvent, e)) {
if (!selection.has(node.id)) { const id = node.id;
designer.activeTracker.track(node); designer.activeTracker.track(node);
selection.add(node.id); if (isMulti && !isRootNode(node) && selection.has(id)) {
ignoreUpSelected = true; selection.remove(id);
} else {
selection.select(id);
}
} }
// 获得顶层 nodes };
nodes = selection.getTopNodes();
} else if (selection.containsNode(node)) {
nodes = selection.getTopNodes();
} else {
// will clear current selection & select dragment in dragstart
}
designer.dragon.boost(
{
type: DragObjectType.Node,
nodes,
},
downEvent,
);
if (ignoreUpSelected) {
// multi select mode has add selected, should return
return;
}
}
doc.addEventListener('mouseup', checkSelect, true); if (isLeftButton && !isRootNode(node)) {
}); let nodes: Node[] = [node];
let ignoreUpSelected = false;
if (isMulti) {
// multi select mode, directily add
if (!selection.has(node.id)) {
designer.activeTracker.track(node);
selection.add(node.id);
ignoreUpSelected = true;
}
selection.remove(this.document.rootNode.id);
// 获得顶层 nodes
nodes = selection.getTopNodes();
} else if (selection.containsNode(node, true)) {
nodes = selection.getTopNodes();
} else {
// will clear current selection & select dragment in dragstart
}
designer.dragon.boost(
{
type: DragObjectType.Node,
nodes,
},
downEvent,
);
if (ignoreUpSelected) {
// multi select mode has add selected, should return
return;
}
}
doc.addEventListener('mouseup', checkSelect, true);
},
true,
);
doc.addEventListener(
'click',
e => {
// stop response document click event
e.preventDefault();
e.stopPropagation();
// todo: catch link redirect
},
true,
);
// cause edit // cause edit
doc.addEventListener('dblclick', (e: MouseEvent) => { doc.addEventListener(
// TODO: 'dblclick',
}); (e: MouseEvent) => {
// stop response document dblclick event
e.stopPropagation();
e.preventDefault();
// todo: quick editing
},
true,
);
} }
private disableHovering?: () => void; private disableHovering?: () => void;
@ -443,18 +467,28 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
let last: { x: number; y: number; r: number; b: number } | undefined; let last: { x: number; y: number; r: number; b: number } | undefined;
let computed = false; let computed = false;
const elems = elements.slice(); const elems = elements.slice();
const commonParent: Element | null = null;
while (true) { while (true) {
if (!rects || rects.length < 1) { if (!rects || rects.length < 1) {
const elem = elems.pop(); const elem = elems.pop();
if (!elem) { if (!elem) {
break; break;
} }
/*
if (!commonParent) {
commonParent = elem.parentElement;
} else if (elem.parentElement !== commonParent) {
continue;
}*/
rects = renderer.getClientRects(elem); rects = renderer.getClientRects(elem);
} }
const rect = rects.pop(); const rect = rects.pop();
if (!rect) { if (!rect) {
break; break;
} }
if (rect.width === 0 && rect.height === 0) {
continue;
}
if (!last) { if (!last) {
last = { last = {
x: rect.left, x: rect.left,
@ -677,8 +711,10 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
} }
const target = dropTarget; const target = dropTarget;
const targetInstance = e.targetInstance as ReactInstance;
// FIXME: e.target is #document, etc., does not has e.targetInstance
const targetInstance = e.targetInstance as ReactInstance;
const parentInstance = this.getClosestNodeInstance(targetInstance, target.id); const parentInstance = this.getClosestNodeInstance(targetInstance, target.id);
const edge = this.computeComponentInstanceRect(parentInstance?.instance as any); const edge = this.computeComponentInstanceRect(parentInstance?.instance as any);

View File

@ -25,7 +25,7 @@ export default class Viewport implements IViewport {
private viewportElement?: Element; private viewportElement?: Element;
mount(viewportElement: Element | null) { mount(viewportElement: Element | null) {
if (!viewportElement) { if (!viewportElement || this.viewportElement === viewportElement) {
return; return;
} }
this.viewportElement = viewportElement; this.viewportElement = viewportElement;
@ -54,7 +54,7 @@ export default class Viewport implements IViewport {
/** /**
* *
*/ */
get scale(): number { @computed get scale(): number {
if (!this.rect || this.contentWidth === AutoFit) { if (!this.rect || this.contentWidth === AutoFit) {
return 1; return 1;
} }
@ -63,14 +63,14 @@ export default class Viewport implements IViewport {
@obx.ref private _contentWidth: number | AutoFit = AutoFit; @obx.ref private _contentWidth: number | AutoFit = AutoFit;
get contentHeight(): number | AutoFit { @computed get contentHeight(): number | AutoFit {
if (!this.rect || this.scale === 1) { if (!this.rect || this.scale === 1) {
return AutoFit; return AutoFit;
} }
return this.height / this.scale; return this.height / this.scale;
} }
get contentWidth(): number | AutoFit { @computed get contentWidth(): number | AutoFit {
if (!this.rect || (this._contentWidth !== AutoFit && this._contentWidth <= this.width)) { if (!this.rect || (this._contentWidth !== AutoFit && this._contentWidth <= this.width)) {
return AutoFit; return AutoFit;
} }
@ -98,7 +98,7 @@ export default class Viewport implements IViewport {
return this._scrollTarget; return this._scrollTarget;
} }
@obx private _scrolling: boolean = false; @obx private _scrolling = false;
get scrolling(): boolean { get scrolling(): boolean {
return this._scrolling; return this._scrolling;
} }
@ -120,6 +120,7 @@ export default class Viewport implements IViewport {
this._scrolling = false; this._scrolling = false;
}, 80); }, 80);
}); });
target.addEventListener('resize', () => this.touch());
this._scrollTarget = scrollTarget; this._scrollTarget = scrollTarget;
} }

View File

@ -8,7 +8,9 @@
--font-size-btn-medium: @fontSize-4; --font-size-btn-medium: @fontSize-4;
--font-size-btn-small: @fontSize-5; --font-size-btn-small: @fontSize-5;
--color-brand-light: rgb(102, 188, 92); --color-brand: #006cff;
--color-brand-light: #197aff;
--color-brand-dark: #0060e5;
--color-icon: rgba(255, 255, 255, 0.8); --color-icon: rgba(255, 255, 255, 0.8);
--color-visited: rgba(179, 182, 201, 0.4); --color-visited: rgba(179, 182, 201, 0.4);
--color-actived: #498ee6; --color-actived: #498ee6;

View File

@ -61,9 +61,13 @@ export default class Designer {
this.dragon.onDragstart(e => { this.dragon.onDragstart(e => {
this.hovering.enable = false; this.hovering.enable = false;
const { dragObject } = e; const { dragObject } = e;
if (isDragNodeObject(dragObject) && dragObject.nodes.length === 1) { if (isDragNodeObject(dragObject)) {
// ensure current selecting if (dragObject.nodes.length === 1) {
dragObject.nodes[0].select(); // ensure current selecting
dragObject.nodes[0].select();
}
} else {
this.currentSelection?.clear();
} }
if (this.props?.onDragstart) { if (this.props?.onDragstart) {
this.props.onDragstart(e); this.props.onDragstart(e);

View File

@ -374,7 +374,7 @@ export default class Node {
* 2 thisNode before or after otherNode * 2 thisNode before or after otherNode
* 0 thisNode same as otherNode * 0 thisNode same as otherNode
*/ */
comparePosition(otherNode: Node): number { comparePosition(otherNode: Node): PositionNO {
return comparePosition(this, otherNode); return comparePosition(this, otherNode);
} }
@ -455,31 +455,37 @@ export function contains(node1: Node, node2: Node): boolean {
// 8 node1 contained_by node2 // 8 node1 contained_by node2
// 2 node1 before or after node2 // 2 node1 before or after node2
// 0 node1 same as node2 // 0 node1 same as node2
export function comparePosition(node1: Node, node2: Node): number { export enum PositionNO {
Contains = 16,
ContainedBy = 8,
BeforeOrAfter = 2,
TheSame = 0,
}
export function comparePosition(node1: Node, node2: Node): PositionNO {
if (node1 === node2) { if (node1 === node2) {
return 0; return PositionNO.TheSame;
} }
const l1 = node1.zLevel; const l1 = node1.zLevel;
const l2 = node2.zLevel; const l2 = node2.zLevel;
if (l1 === l2) { if (l1 === l2) {
return 2; return PositionNO.BeforeOrAfter;
} }
let p: any; let p: any;
if (l1 > l2) { if (l1 < l2) {
p = getZLevelTop(node2, l1); p = getZLevelTop(node2, l1);
if (p && p === node1) { if (p && p === node1) {
return 16; return PositionNO.Contains;
} }
return 2; return PositionNO.BeforeOrAfter;
} }
p = getZLevelTop(node1, l2); p = getZLevelTop(node1, l2);
if (p && p === node2) { if (p && p === node2) {
return 8; return PositionNO.ContainedBy;
} }
return 2; return PositionNO.BeforeOrAfter;
} }
export function insertChild(container: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node { export function insertChild(container: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {

View File

@ -23,7 +23,7 @@ export default class PropStash implements IPropParent {
} }
const pending: Prop[] = []; const pending: Prop[] = [];
for (const prop of this.space) { for (const prop of this.space) {
if (!prop.isUnset()) { if (!prop.isUnset() && !prop.isVirtual()) {
this.space.delete(prop); this.space.delete(prop);
pending.push(prop); pending.push(prop);
} }

View File

@ -225,6 +225,10 @@ export default class Prop implements IPropParent {
return this._type === 'unset'; return this._type === 'unset';
} }
isVirtual() {
return typeof this.key === 'string' && this.key.charAt(0) === '!';
}
// TODO: improve this logic // TODO: improve this logic
compare(other: Prop | null): number { compare(other: Prop | null): number {
if (!other || other.isUnset()) { if (!other || other.isUnset()) {

View File

@ -1,4 +1,4 @@
import Node, { comparePosition } from './node/node'; import Node, { comparePosition, PositionNO } from './node/node';
import { obx } from '@recore/obx'; import { obx } from '@recore/obx';
import DocumentModel from './document-model'; import DocumentModel from './document-model';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
@ -97,9 +97,12 @@ export class Selection {
/** /**
* *
*/ */
containsNode(node: Node) { containsNode(node: Node, excludeRoot = false) {
for (const id of this._selected) { for (const id of this._selected) {
const parent = this.doc.getNode(id); const parent = this.doc.getNode(id);
if (excludeRoot && parent === this.doc.rootNode) {
continue;
}
if (parent?.contains(node)) { if (parent?.contains(node)) {
return true; return true;
} }
@ -124,11 +127,12 @@ export class Selection {
/** /**
* , * ,
*/ */
getTopNodes() { getTopNodes(includeRoot = false) {
const nodes = []; const nodes = [];
for (const id of this._selected) { for (const id of this._selected) {
const node = this.doc.getNode(id); const node = this.doc.getNode(id);
if (!node) { // 排除根节点
if (!node || (!includeRoot && node === this.doc.rootNode)) {
continue; continue;
} }
let i = nodes.length; let i = nodes.length;
@ -136,12 +140,12 @@ export class Selection {
while (i-- > 0) { while (i-- > 0) {
const n = comparePosition(nodes[i], node); const n = comparePosition(nodes[i], node);
// nodes[i] contains node // nodes[i] contains node
if (n === 16 || n === 0) { if (n === PositionNO.Contains || n === PositionNO.TheSame) {
isTop = false; isTop = false;
break; break;
} }
// node contains nodes[i], delete nodes[i] // node contains nodes[i], delete nodes[i]
if (n === 8) { if (n === PositionNO.ContainedBy) {
nodes.splice(i, 1); nodes.splice(i, 1);
} }
} }

View File

@ -28,6 +28,10 @@ export default {
name: 'type', name: 'type',
propType: 'string' propType: 'string'
}, },
{
name: 'onClick',
propType: 'func'
},
{ {
name: 'children', name: 'children',
propType: 'string' propType: 'string'
@ -66,6 +70,22 @@ export default {
{ {
name: 'placeholder', name: 'placeholder',
propType: 'string' propType: 'string'
},
{
name: 'onChange',
propType: 'func'
},
{
name: 'onKeyDown',
propType: 'func'
},
{
name: 'onFocus',
propType: 'func'
},
{
name: 'onBlur',
propType: 'func'
} }
], ],
}, },
@ -83,7 +103,11 @@ export default {
{ {
name: 'device', name: 'device',
propType: 'string' propType: 'string'
} },
{
name: 'onChange',
propType: 'func'
},
], ],
}, },
'Form.Item': { 'Form.Item': {
@ -126,6 +150,26 @@ export default {
{ {
name: 'defaultValue', name: 'defaultValue',
propType: 'number' propType: 'number'
},
{
name: 'onChange',
propType: 'func'
},
{
name: 'onKeyDown',
propType: 'func'
},
{
name: 'onFocus',
propType: 'func'
},
{
name: 'onBlur',
propType: 'func'
},
{
name: 'onCorrect',
propType: 'func'
} }
], ],
}, },
@ -151,6 +195,38 @@ export default {
{ {
name: 'placeholder', name: 'placeholder',
propType: 'string' propType: 'string'
},
{
name: 'onChange',
propType: 'func'
},
{
name: 'onVisibleChange',
propType: 'func'
},
{
name: 'onToggleHighlightItem',
propType: 'func'
},
{
name: 'onSearch',
propType: 'func'
},
{
name: 'onSearchClear',
propType: 'func'
},
{
name: 'onRemove',
propType: 'func'
},
{
name: 'onFocus',
propType: 'func'
},
{
name: 'onBlur',
propType: 'func'
} }
], ],
} }

View File

@ -1,5 +1,6 @@
import { Component, isValidElement, ReactElement, ReactNode } from 'react'; import { Component, isValidElement, ReactElement, ReactNode } from 'react';
import { Radio, Menu, Table, Icon, Dialog } from '@alifd/next'; import { Radio, Menu, Table, Icon, Dialog } from '@alifd/next';
import {SettingField} from './main';
import nativeEvents from './native-events'; import nativeEvents from './native-events';
import './style.less'; import './style.less';
@ -19,7 +20,10 @@ const DEFINITION_EVENT_TYPE = {
LIFE_CYCLE_EVENT: 'lifeCycleEvent', LIFE_CYCLE_EVENT: 'lifeCycleEvent',
}; };
export default class EventsSetter extends Component<{}> { export default class EventsSetter extends Component<{
value: any[];
onChange: (eventList: any[]) => void;
}> {
state = { state = {
showEventList: false, showEventList: false,
eventBtns: [], eventBtns: [],
@ -34,6 +38,7 @@ export default class EventsSetter extends Component<{}> {
}; };
componentWillMount() { componentWillMount() {
console.log(this.props);
this.initEventBtns(); this.initEventBtns();
this.initEventList(); this.initEventList();
} }
@ -42,8 +47,7 @@ export default class EventsSetter extends Component<{}> {
* *
*/ */
initEventBtns() { initEventBtns() {
const { prop } = this.props; const { definition } = this.props;
const { definition } = prop.extraProps;
let isRoot = false; let isRoot = false;
definition.map(item => { definition.map(item => {
if (item.type === DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT) { if (item.type === DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT) {
@ -73,7 +77,7 @@ export default class EventsSetter extends Component<{}> {
} }
initEventList() { initEventList() {
const { definition } = this.props.prop.extraProps; const { definition } = this.props;
let nativeEventList = []; let nativeEventList = [];
definition.map(item => { definition.map(item => {
if (item.type === DEFINITION_EVENT_TYPE.EVENTS) { if (item.type === DEFINITION_EVENT_TYPE.EVENTS) {
@ -229,14 +233,18 @@ export default class EventsSetter extends Component<{}> {
}; };
submitDialog = (relatedEventName: String) => { submitDialog = (relatedEventName: String) => {
const { bindEventName } = this.state; const { bindEventName,eventDataList} = this.state;
const { eventDataList } = this.state;
eventDataList.map(item => { eventDataList.map(item => {
if (item.name === bindEventName) { if (item.name === bindEventName) {
item.relatedEventName = relatedEventName; item.relatedEventName = relatedEventName;
} }
}); });
debugger;
this.props.onChange(eventDataList);
// field.setValue(eventDataList);
this.closeDialog(); this.closeDialog();
}; };
@ -270,7 +278,7 @@ export default class EventsSetter extends Component<{}> {
{selectType && selectType != EVENT_CONTENTS.NATIVE_EVENT && ( {selectType && selectType != EVENT_CONTENTS.NATIVE_EVENT && (
<Menu defaultOpenKeys="sub-menu" className="event-menu" onItemClick={this.onEventMenuClick}> <Menu defaultOpenKeys="sub-menu" className="event-menu" onItemClick={this.onEventMenuClick}>
{showEventList.map((item, index) => ( {showEventList.map((item, index) => (
<Item key={item.name} helper={item.title} disabled={item.disabled}> <Item key={item.name} helper={item.description} disabled={item.disabled}>
{item.name} {item.name}
</Item> </Item>
))} ))}

View File

@ -159,7 +159,7 @@ export interface FieldConfig extends FieldExtraProps {
export class SettingField implements SettingTarget { export class SettingField implements SettingTarget {
readonly isSettingField = true; readonly isSettingField = true;
readonly id = uniqueId('field'); readonly id = uniqueId('field');
readonly type: 'field' | 'virtual-field' | 'group'; readonly type: 'field' | 'group';
readonly isRequired: boolean = false; readonly isRequired: boolean = false;
readonly isGroup: boolean; readonly isGroup: boolean;
private _name: string | number; private _name: string | number;
@ -193,8 +193,6 @@ export class SettingField implements SettingTarget {
const c = typeof name === 'string' ? name.substr(0, 1) : ''; const c = typeof name === 'string' ? name.substr(0, 1) : '';
if (c === '#') { if (c === '#') {
this.type = 'group'; this.type = 'group';
} else if (c === '!') {
this.type = 'virtual-field';
} else { } else {
this.type = 'field'; this.type = 'field';
} }

View File

@ -178,7 +178,10 @@ registerMetadataTransducer(metadata => {
metadata.props.forEach(prop => { metadata.props.forEach(prop => {
const { name, propType } = prop; const { name, propType } = prop;
if (name === 'children' && (component.isContainer || (propType === 'node' || propType === 'element' || propType === 'any'))) { if (
name === 'children' &&
(component.isContainer || propType === 'node' || propType === 'element' || propType === 'any')
) {
if (component.isContainer !== false) { if (component.isContainer !== false) {
component.isContainer = true; component.isContainer = true;
return; return;
@ -188,6 +191,7 @@ registerMetadataTransducer(metadata => {
if (EVENT_RE.test(name) && (propType === 'func' || propType === 'any')) { if (EVENT_RE.test(name) && (propType === 'func' || propType === 'any')) {
if (supportEvents) { if (supportEvents) {
supportEvents.push(name); supportEvents.push(name);
(events as any).supportEvents = supportEvents;
} }
return; return;
} }
@ -209,7 +213,6 @@ registerMetadataTransducer(metadata => {
props.push(propConfigToFieldConfig(prop)); props.push(propConfigToFieldConfig(prop));
}); });
return { return {
...metadata, ...metadata,
configure: { configure: {
@ -222,7 +225,7 @@ registerMetadataTransducer(metadata => {
}; };
}); });
registerMetadataTransducer((metadata) => { registerMetadataTransducer(metadata => {
const { configure = {}, componentName } = metadata; const { configure = {}, componentName } = metadata;
const { component = {} } = configure as any; const { component = {} } = configure as any;
if (!component.nestingRule) { if (!component.nestingRule) {
@ -262,107 +265,133 @@ registerMetadataTransducer((metadata) => {
}; };
}); });
registerMetadataTransducer((metadata) => { registerMetadataTransducer(metadata => {
const { componentName, configure = {} } = metadata; const { componentName, configure = {} } = metadata;
if (componentName === 'Leaf') { if (componentName === 'Leaf') {
return { return {
...metadata, ...metadata,
configure: { configure: {
...configure, ...configure,
combined: [{ combined: [
name: 'children', {
title: '内容设置', name: 'children',
setter: { title: '内容设置',
componentName: 'MixinSetter', setter: {
props: { componentName: 'MixinSetter',
setters: [{ props: {
componentName: 'StringSetter', setters: [
props: { {
// todo: componentName: 'StringSetter',
multiline: true, props: {
}, // todo:
initialValue: '', multiline: true,
}, { },
componentName: 'ExpressionSetter', initialValue: '',
initialValue: { },
type: 'JSExpression', {
value: '', componentName: 'ExpressionSetter',
}, initialValue: {
}], type: 'JSExpression',
value: '',
},
},
],
},
}, },
}, },
}], ],
}, },
}; };
} }
const { props, events, styles } = configure as any; const { props, events, styles } = configure as any;
let supportEvents: any; let eventsDefinition: any;
let isRoot: boolean = false; let isRoot: boolean = false;
if (componentName === 'Page' || componentName === 'Component') { if (componentName === 'Page' || componentName === 'Component') {
isRoot = true; isRoot = true;
supportEvents = [{ // 平台配置的,一般只有根节点才会配置
description: '初始化时', eventsDefinition = [
name: 'constructor' {
}, { type: 'lifeCycleEvent',
description: '装载后', title: '生命周期',
name: 'componentDidMount' list: [
}, { {
description: '更新时', description: '初始化时',
name: 'componentDidMount' name: 'constructor',
}, { },
description: '卸载时', {
name: 'componentWillUnmount' description: '装载后',
}] name: 'componentDidMount',
},
{
description: '更新时',
name: 'componentDidMount',
},
{
description: '卸载时',
name: 'componentWillUnmount',
},
],
},
];
} else { } else {
supportEvents = (events?.supportEvents || []).map((event: any) => { eventsDefinition = [
return typeof event === 'string' ? { {
name: event, type: 'events',
} : event; title: '事件',
}); list: (events?.supportEvents || []).map((event: any) => (typeof event === 'string' ? { name: event } : event)),
},
];
} }
// 通用设置 // 通用设置
const propsGroup = props || []; const propsGroup = props || [];
propsGroup.push({ propsGroup.push({
name: '#generals', name: '#generals',
title: '通用', title: '通用',
items: [{ items: [
name: 'id', {
title: 'ID', name: 'id',
setter: 'StringSetter', title: 'ID',
}, { setter: 'StringSetter',
name: 'key', },
title: 'Key', {
// todo: use Mixin name: 'key',
setter: 'StringSetter', title: 'Key',
}, { // todo: use Mixin
name: 'ref', setter: 'StringSetter',
title: 'Ref', },
setter: 'StringSetter', {
}, { name: 'ref',
name: '!more', title: 'Ref',
title: '更多', setter: 'StringSetter',
setter: 'PropertiesSetter' },
}] {
name: '!more',
title: '更多',
setter: 'PropertiesSetter',
},
],
}); });
const combined = [{ const combined = [
title: '属性', {
name: '#props', title: '属性',
items: propsGroup, name: '#props',
}]; items: propsGroup,
},
];
const stylesGroup = []; const stylesGroup = [];
if (styles?.supportClassName) { if (styles?.supportClassName) {
stylesGroup.push({ stylesGroup.push({
name: 'className', name: 'className',
title: '类名绑定', title: '类名绑定',
setter: 'ClassNameSetter' setter: 'ClassNameSetter',
}); });
} }
if (styles?.supportInlineStyle) { if (styles?.supportInlineStyle) {
stylesGroup.push({ stylesGroup.push({
name: 'style', name: 'style',
title: '行内样式', title: '行内样式',
setter: 'StyleSetter' setter: 'StyleSetter',
}); });
} }
if (stylesGroup.length > 0) { if (stylesGroup.length > 0) {
@ -373,55 +402,35 @@ registerMetadataTransducer((metadata) => {
}); });
} }
if (supportEvents) { if (eventsDefinition) {
combined.push({ combined.push({
name: '#events', name: '#events',
title: '事件', title: '事件',
items: [{ items: [
name: '!events', {
title: '事件设置', name: '!events',
setter: { title: '事件设置',
componentName: 'EventsSetter', setter: {
props: { componentName: 'EventsSetter',
definition: [] props: {
} definition: eventsDefinition,
},
},
getValue(field: SettingField,val?:any[]) {
//console.log(value);
//return value;
return field.parent.getPropValue('eventDataList');
//return val;
},
setValue(field: SettingField, eventDataList: any[]) {
//return;
//console.info(eventDataList);
field.parent.setPropValue('eventDataList', eventDataList);
},
}, },
],
// 先简单mock一下
definition:[
// {
// type: 'lifeCycleEvent', // 平台配置的,一般只有根节点才会配置
// title: '生命周期',
// list: [{
// title: '装载时',
// name: 'componentDidMount'
// },{
// title: '卸载时',
// name: 'componentWillUnmount'
// }]
// },
{
type: 'events', // 组件自定义的
list: [{
name:'onClick',
title:'点击回调'
},
{
name:'onChange',
title:'变更回调'
},
{
name:'onSubmit'
}]
}],
getValue(field: SettingField) {
return [];
},
setValue(field: SettingField) {
}
}]
}); });
} }
@ -430,60 +439,71 @@ registerMetadataTransducer((metadata) => {
combined.push({ combined.push({
name: '#advanced', name: '#advanced',
title: '高级', title: '高级',
items: [] items: [],
}); });
} else { } else {
combined.push({ combined.push({
name: '#advanced', name: '#advanced',
title: '高级', title: '高级',
items: [{ items: [
name: '__condition', {
title: '条件显示', name: '__condition',
setter: 'ExpressionSetter' title: '条件显示',
}, {
name: '#loop',
title: '循环',
items: [{
name: '__loop',
title: '循环数据',
setter: {
componentName: 'MixinSetter',
props: {
setters: [{
componentName: 'JSONSetter',
props: {
mode: 'popup',
placeholder: '编辑数据'
}
}, {
componentName: 'ExpressionSetter',
props: {
placeholder: '绑定数据'
}
}]
}
}
}, {
name: '__loopArgs.0',
title: '迭代变量名',
setter: {
componentName: 'StringSetter',
placeholder: '默认为 item'
}
}, {
name: '__loopArgs.1',
title: '索引变量名',
setter: {
componentName: 'StringSetter',
placeholder: '默认为 index'
}
}, {
name: 'key',
title: 'Key',
setter: 'ExpressionSetter', setter: 'ExpressionSetter',
}] },
}] {
}) name: '#loop',
title: '循环',
items: [
{
name: '__loop',
title: '循环数据',
setter: {
componentName: 'MixinSetter',
props: {
setters: [
{
componentName: 'JSONSetter',
props: {
mode: 'popup',
placeholder: '编辑数据',
},
},
{
componentName: 'ExpressionSetter',
props: {
placeholder: '绑定数据',
},
},
],
},
},
},
{
name: '__loopArgs.0',
title: '迭代变量名',
setter: {
componentName: 'StringSetter',
placeholder: '默认为 item',
},
},
{
name: '__loopArgs.1',
title: '索引变量名',
setter: {
componentName: 'StringSetter',
placeholder: '默认为 index',
},
},
{
name: 'key',
title: 'Key',
setter: 'ExpressionSetter',
},
],
},
],
});
} }
return { return {