Merge commit 'f8584e101afb89b672fca8ea6a1836db7626c67e' into def_releases_2021091314071919_ali-lowcode_ali-lowcode-engine/1.0.67

This commit is contained in:
tbfed 2021-09-14 11:21:45 +08:00
commit 6aea8224d7
76 changed files with 382 additions and 427 deletions

View File

@ -6,7 +6,7 @@ module.exports = {
// // '^.+\\.(ts|tsx)$': 'ts-jest', // // '^.+\\.(ts|tsx)$': 'ts-jest',
// // '^.+\\.(js|jsx)$': 'babel-jest', // // '^.+\\.(js|jsx)$': 'babel-jest',
// }, // },
// testMatch: ['**/node.test.ts'], // testMatch: ['**/prop.test.ts'],
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'], // testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
transformIgnorePatterns: [ transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`, `/node_modules/(?!${esModules})/`,

View File

@ -46,10 +46,6 @@ export class BorderDetectingInstance extends PureComponent<{
@observer @observer
export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {
shouldComponentUpdate() {
return false;
}
@computed get scale() { @computed get scale() {
return this.props.host.viewport.scale; return this.props.host.viewport.scale;
} }

View File

@ -28,10 +28,6 @@ export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost
return this.dragging ? selection.getTopNodes() : selection.getNodes(); return this.dragging ? selection.getTopNodes() : selection.getNodes();
} }
shouldComponentUpdate() {
return false;
}
componentDidUpdate() { componentDidUpdate() {
// this.hoveringCapture.setBoundary(this.outline); // this.hoveringCapture.setBoundary(this.outline);
// this.willBind(); // this.willBind();
@ -73,10 +69,6 @@ export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost;
return this.host.getComponentInstances(this.props.node); return this.host.getComponentInstances(this.props.node);
} }
shouldComponentUpdate() {
return false;
}
render() { render() {
const { instances } = this; const { instances } = this;
const { node } = this.props; const { node } = this.props;

View File

@ -9,7 +9,7 @@ import {
ComponentType, ComponentType,
} from 'react'; } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { observer, computed, Tip, globalContext, Editor } from '@ali/lowcode-editor-core'; import { observer, computed, Tip, globalContext, makeObservable } from '@ali/lowcode-editor-core';
import { createIcon, isReactComponent } from '@ali/lowcode-utils'; import { createIcon, isReactComponent } from '@ali/lowcode-utils';
import { ActionContentObject, isActionContentObject } from '@ali/lowcode-types'; import { ActionContentObject, isActionContentObject } from '@ali/lowcode-types';
import { BuiltinSimulatorHost } from '../host'; import { BuiltinSimulatorHost } from '../host';
@ -62,10 +62,6 @@ export class BorderSelectingInstance extends Component<{
@observer @observer
class Toolbar extends Component<{ observed: OffsetObserver }> { class Toolbar extends Component<{ observed: OffsetObserver }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { observed } = this.props; const { observed } = this.props;
const { height, width } = observed.viewport; const { height, width } = observed.viewport;
@ -169,10 +165,6 @@ export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHo
return this.host.getComponentInstances(this.props.node); return this.host.getComponentInstances(this.props.node);
} }
shouldComponentUpdate() {
return false;
}
render() { render() {
const { instances } = this; const { instances } = this;
const { node } = this.props; const { node } = this.props;
@ -217,10 +209,6 @@ export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> {
return this.dragging ? selection.getTopNodes() : selection.getNodes(); return this.dragging ? selection.getTopNodes() : selection.getNodes();
} }
shouldComponentUpdate() {
return false;
}
render() { render() {
const { selecting } = this; const { selecting } = this;
if (!selecting || selecting.length < 1) { if (!selecting || selecting.length < 1) {

View File

@ -11,10 +11,6 @@ import './borders.less';
@observer @observer
export class BemTools extends Component<{ host: BuiltinSimulatorHost }> { export class BemTools extends Component<{ host: BuiltinSimulatorHost }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { host } = this.props; const { host } = this.props;
const { designMode } = host; const { designMode } = host;

View File

@ -116,10 +116,6 @@ function processDetail({ target, detail, document }: DropLocation): InsertionDat
@observer @observer
export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> { export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { host } = this.props; const { host } = this.props;
const loc = host.currentDocument?.dropLocation; const loc = host.currentDocument?.dropLocation;

View File

@ -1,11 +1,16 @@
import { import {
obx, obx,
autorun, autorun,
reaction,
computed, computed,
getPublicPath, getPublicPath,
hotkey, hotkey,
focusTracker, focusTracker,
engineConfig, engineConfig,
IReactionPublic,
IReactionOptions,
IReactionDisposer,
makeObservable,
} from '@ali/lowcode-editor-core'; } from '@ali/lowcode-editor-core';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { import {
@ -164,16 +169,27 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
readonly emitter: EventEmitter = new EventEmitter(); readonly emitter: EventEmitter = new EventEmitter();
readonly componentsConsumer: ResourceConsumer;
readonly injectionConsumer: ResourceConsumer;
/** /**
* *
*/ */
autoRender = true; autoRender = true;
constructor(project: Project) { constructor(project: Project) {
makeObservable(this);
this.project = project; this.project = project;
this.designer = project?.designer; this.designer = project?.designer;
this.scroller = this.designer.createScroller(this.viewport); this.scroller = this.designer.createScroller(this.viewport);
this.autoRender = !engineConfig.get('disableAutoRender', false); this.autoRender = !engineConfig.get('disableAutoRender', false);
this.componentsConsumer = new ResourceConsumer<Asset | undefined>(() => this.componentsAsset);
this.injectionConsumer = new ResourceConsumer(() => {
return {
i18n: this.project.i18n,
};
});
} }
get currentDocument() { get currentDocument() {
@ -256,22 +272,25 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
*/ */
connect( connect(
renderer: BuiltinSimulatorRenderer, renderer: BuiltinSimulatorRenderer,
fn: (context: { dispose: () => void; firstRun: boolean }) => void, effect: (reaction: IReactionPublic) => void, options?: IReactionOptions,
) { ) {
this._renderer = renderer; this._renderer = renderer;
return autorun(fn as any, true); return autorun(effect, options);
} }
autorun(fn: (context: { dispose: () => void; firstRun: boolean }) => void) { reaction(expression: (reaction: IReactionPublic) => unknown, effect: (value: unknown, prev: unknown, reaction: IReactionPublic) => void,
return autorun(fn as any, true); opts?: IReactionOptions | undefined): IReactionDisposer {
return reaction(expression, effect, opts);
}
autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer {
return autorun(effect, options);
} }
purge(): void { purge(): void {
// todo // todo
} }
readonly viewport = new Viewport();
mountViewport(viewport: Element | null) { mountViewport(viewport: Element | null) {
this.viewport.mount(viewport); this.viewport.mount(viewport);
} }
@ -294,14 +313,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return this._renderer; return this._renderer;
} }
readonly componentsConsumer = new ResourceConsumer<Asset | undefined>(() => this.componentsAsset);
readonly injectionConsumer = new ResourceConsumer(() => {
return {
i18n: this.project.i18n,
};
});
readonly asyncLibraryMap: { [key: string]: {} } = {}; readonly asyncLibraryMap: { [key: string]: {} } = {};
readonly libraryMap: { [key: string]: string } = {}; readonly libraryMap: { [key: string]: string } = {};

View File

@ -1,4 +1,4 @@
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable } from '@ali/lowcode-editor-core';
import { Point, ScrollTarget } from '../designer'; import { Point, ScrollTarget } from '../designer';
import { AutoFit, IViewport } from '../simulator'; import { AutoFit, IViewport } from '../simulator';
@ -25,6 +25,10 @@ export default class Viewport implements IViewport {
private viewportElement?: HTMLElement; private viewportElement?: HTMLElement;
constructor() {
makeObservable(this);
}
mount(viewportElement: HTMLElement | null) { mount(viewportElement: HTMLElement | null) {
if (!viewportElement || this.viewportElement === viewportElement) { if (!viewportElement || this.viewportElement === viewportElement) {
return; return;

View File

@ -1,5 +1,5 @@
import { ComponentType } from 'react'; import { ComponentType } from 'react';
import { obx, computed, autorun } from '@ali/lowcode-editor-core'; import { obx, computed, autorun, makeObservable, IReactionPublic, IReactionOptions, IReactionDisposer } from '@ali/lowcode-editor-core';
import { import {
ProjectSchema, ProjectSchema,
ComponentMetadata, ComponentMetadata,
@ -71,6 +71,7 @@ export class Designer {
} }
constructor(props: DesignerProps) { constructor(props: DesignerProps) {
makeObservable(this);
const { editor } = props; const { editor } = props;
this.editor = editor; this.editor = editor;
this.setProps(props); this.setProps(props);
@ -563,12 +564,12 @@ export class Designer {
} }
} }
autorun(action: (context: { firstRun: boolean }) => void, sync = false): () => void { autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer {
return autorun(action, sync as true); return autorun(effect, options);
} }
purge() { purge() {
// todo: // TODO:
} }
} }

View File

@ -1,4 +1,4 @@
import { obx } from '@ali/lowcode-editor-core'; import { makeObservable, obx } from '@ali/lowcode-editor-core';
import { Node, DocumentModel } from '../document'; import { Node, DocumentModel } from '../document';
export class Detecting { export class Detecting {
@ -19,6 +19,10 @@ export class Detecting {
@obx.ref private _current: Node | null = null; @obx.ref private _current: Node | null = null;
constructor() {
makeObservable(this);
}
get current() { get current() {
return this._current; return this._current;
} }

View File

@ -1,5 +1,5 @@
import { Component } from 'react'; import { Component } from 'react';
import { observer, obx, Title } from '@ali/lowcode-editor-core'; import { observer, obx, Title, makeObservable } from '@ali/lowcode-editor-core';
import { Designer } from '../designer'; import { Designer } from '../designer';
import { DragObject, isDragNodeObject, isDragNodeDataObject } from '../dragon'; import { DragObject, isDragNodeObject, isDragNodeDataObject } from '../dragon';
import { isSimulatorHost } from '../../simulator'; import { isSimulatorHost } from '../../simulator';
@ -23,6 +23,7 @@ export default class DragGhost extends Component<{ designer: Designer }> {
constructor(props: any) { constructor(props: any) {
super(props); super(props);
makeObservable(this);
this.dispose = [ this.dispose = [
this.dragon.onDragstart(e => { this.dragon.onDragstart(e => {
if (e.originalEvent.type.substr(0, 4) === 'drag') { if (e.originalEvent.type.substr(0, 4) === 'drag') {
@ -52,10 +53,6 @@ export default class DragGhost extends Component<{ designer: Designer }> {
]; ];
} }
shouldComponentUpdate() {
return false;
}
componentWillUnmount() { componentWillUnmount() {
if (this.dispose) { if (this.dispose) {
this.dispose.forEach(off => off()); this.dispose.forEach(off => off());

View File

@ -1,5 +1,5 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { obx } from '@ali/lowcode-editor-core'; import { obx, makeObservable } from '@ali/lowcode-editor-core';
import { NodeSchema } from '@ali/lowcode-types'; import { NodeSchema } from '@ali/lowcode-types';
import { setNativeSelection, cursor } from '@ali/lowcode-utils'; import { setNativeSelection, cursor } from '@ali/lowcode-utils';
import { DropLocation } from './location'; import { DropLocation } from './location';
@ -213,7 +213,9 @@ export class Dragon {
private emitter = new EventEmitter(); private emitter = new EventEmitter();
constructor(readonly designer: Designer) {} constructor(readonly designer: Designer) {
makeObservable(this);
}
/** /**
* Quick listen a shell(container element) drag behavior * Quick listen a shell(container element) drag behavior

View File

@ -1,4 +1,4 @@
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable } from '@ali/lowcode-editor-core';
import { uniqueId } from '@ali/lowcode-utils'; import { uniqueId } from '@ali/lowcode-utils';
import { INodeSelector, IViewport } from '../simulator'; import { INodeSelector, IViewport } from '../simulator';
import { isRootNode, Node } from '../document'; import { isRootNode, Node } from '../document';
@ -106,8 +106,9 @@ export class OffsetObserver {
const doc = node.document; const doc = node.document;
const host = doc.simulator!; const host = doc.simulator!;
const focusNode = doc.focusNode; const focusNode = doc.focusNode;
this.isRoot = node.contains(focusNode); this.isRoot = node.contains(focusNode!);
this.viewport = host.viewport; this.viewport = host.viewport;
makeObservable(this);
if (this.isRoot) { if (this.isRoot) {
this.hasOffset = true; this.hasOffset = true;
return; return;

View File

@ -2,7 +2,7 @@ import { TitleContent, isDynamicSetter, SetterType, DynamicSetter, FieldExtraPro
import { Transducer } from './utils'; import { Transducer } from './utils';
import { SettingPropEntry } from './setting-prop-entry'; import { SettingPropEntry } from './setting-prop-entry';
import { SettingEntry } from './setting-entry'; import { SettingEntry } from './setting-entry';
import { computed, obx } from '@ali/lowcode-editor-core'; import { computed, obx, makeObservable, action } from '@ali/lowcode-editor-core';
import { cloneDeep } from '@ali/lowcode-utils'; import { cloneDeep } from '@ali/lowcode-utils';
import { ISetValueOptions } from '../../types'; import { ISetValueOptions } from '../../types';
@ -63,7 +63,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
constructor(parent: SettingEntry, config: FieldConfig, settingFieldCollector?: (name: string | number, field: SettingField) => void) { constructor(parent: SettingEntry, config: FieldConfig, settingFieldCollector?: (name: string | number, field: SettingField) => void) {
super(parent, config.name, config.type); super(parent, config.name, config.type);
makeObservable(this);
const { title, items, setter, extraProps, ...rest } = config; const { title, items, setter, extraProps, ...rest } = config;
this.parent = parent; this.parent = parent;
this._config = config; this._config = config;
@ -141,6 +141,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
private hotValue: any; private hotValue: any;
@action
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: ISetValueOptions) { setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: ISetValueOptions) {
if (isHotValue) { if (isHotValue) {
this.setHotValue(val, extraOptions); this.setHotValue(val, extraOptions);
@ -162,6 +163,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
} }
/* istanbul ignore next */ /* istanbul ignore next */
@action
setMiniAppDataSourceValue(data: any, options?: any) { setMiniAppDataSourceValue(data: any, options?: any) {
this.hotValue = data; this.hotValue = data;
const v = this.transducer.toNative(data); const v = this.transducer.toNative(data);
@ -174,6 +176,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
this.valueChange(); this.valueChange();
} }
@action
setHotValue(data: any, options?: ISetValueOptions) { setHotValue(data: any, options?: ISetValueOptions) {
this.hotValue = data; this.hotValue = data;
const value = this.transducer.toNative(data); const value = this.transducer.toNative(data);

View File

@ -1,4 +1,4 @@
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable, runInAction } from '@ali/lowcode-editor-core';
import { IEditor, isJSExpression } from '@ali/lowcode-types'; import { IEditor, isJSExpression } from '@ali/lowcode-types';
import { uniqueId } from '@ali/lowcode-utils'; import { uniqueId } from '@ali/lowcode-utils';
import { SettingEntry } from './setting-entry'; import { SettingEntry } from './setting-entry';
@ -53,6 +53,7 @@ export class SettingPropEntry implements SettingEntry {
extraProps: any = {}; extraProps: any = {};
constructor(readonly parent: SettingEntry, name: string | number, type?: 'field' | 'group') { constructor(readonly parent: SettingEntry, name: string | number, type?: 'field' | 'group') {
makeObservable(this);
if (type == null) { if (type == null) {
const c = typeof name === 'string' ? name.substr(0, 1) : ''; const c = typeof name === 'string' ? name.substr(0, 1) : '';
if (c === '#') { if (c === '#') {
@ -120,6 +121,7 @@ export class SettingPropEntry implements SettingEntry {
*/ */
/* istanbul ignore next */ /* istanbul ignore next */
@computed get valueState(): number { @computed get valueState(): number {
return runInAction(() => {
if (this.type !== 'field') { if (this.type !== 'field') {
const { getValue } = this.extraProps; const { getValue } = this.extraProps;
return getValue ? (getValue(this, undefined) === undefined ? 0 : 1) : 0; return getValue ? (getValue(this, undefined) === undefined ? 0 : 1) : 0;
@ -128,7 +130,7 @@ export class SettingPropEntry implements SettingEntry {
const first = this.nodes[0].getProp(propName)!; const first = this.nodes[0].getProp(propName)!;
let l = this.nodes.length; let l = this.nodes.length;
let state = 2; let state = 2;
while (l-- > 1) { while (--l > 0) {
const next = this.nodes[l].getProp(propName, false); const next = this.nodes[l].getProp(propName, false);
const s = first.compare(next); const s = first.compare(next);
if (s > 1) { if (s > 1) {
@ -142,12 +144,13 @@ export class SettingPropEntry implements SettingEntry {
return 0; return 0;
} }
return state; return state;
});
} }
/** /**
* *
*/ */
@computed getValue(): any { getValue(): any {
let val: any; let val: any;
if (this.type === 'field') { if (this.type === 'field') {
val = this.parent.getPropValue(this.name); val = this.parent.getPropValue(this.name);

View File

@ -1,4 +1,4 @@
import { computed, obx } from '@ali/lowcode-editor-core'; import { computed, makeObservable, obx, action } from '@ali/lowcode-editor-core';
import { NodeData, isJSExpression, isDOMText, NodeSchema, isNodeSchema, RootSchema, PageSchema } from '@ali/lowcode-types'; import { NodeData, isJSExpression, isDOMText, NodeSchema, isNodeSchema, RootSchema, PageSchema } from '@ali/lowcode-types';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Project } from '../project'; import { Project } from '../project';
@ -61,7 +61,7 @@ export class DocumentModel {
readonly designer: Designer; readonly designer: Designer;
@obx.val private nodes = new Set<Node>(); @obx.shallow private nodes = new Set<Node>();
private seqId = 0; private seqId = 0;
@ -117,13 +117,7 @@ export class DocumentModel {
private inited = false; private inited = false;
constructor(project: Project, schema?: RootSchema) { constructor(project: Project, schema?: RootSchema) {
/* makeObservable(this);
// TODO
// use special purge process
autorun(() => {
console.info(this.willPurgeSpace);
}, true);
*/
this.project = project; this.project = project;
this.designer = this.project?.designer; this.designer = this.project?.designer;
this.emitter = new EventEmitter(); this.emitter = new EventEmitter();
@ -161,7 +155,7 @@ export class DocumentModel {
this.inited = true; this.inited = true;
} }
@obx.val private willPurgeSpace: Node[] = []; @obx.shallow private willPurgeSpace: Node[] = [];
get modalNode() { get modalNode() {
return this._modalNode; return this._modalNode;
@ -182,7 +176,7 @@ export class DocumentModel {
} }
} }
@computed isBlank() { isBlank() {
return this._blank && !this.isModified(); return this._blank && !this.isModified();
} }
@ -213,7 +207,7 @@ export class DocumentModel {
return node ? !node.isPurged : false; return node ? !node.isPurged : false;
} }
@obx.val private activeNodes?: Node[]; @obx.shallow private activeNodes?: Node[];
/** /**
* schema * schema
@ -362,6 +356,7 @@ export class DocumentModel {
return this.rootNode?.schema as any; return this.rootNode?.schema as any;
} }
@action
import(schema: RootSchema, checkId = false) { import(schema: RootSchema, checkId = false) {
const drillDownNodeId = this._drillDownNode?.id; const drillDownNodeId = this._drillDownNode?.id;
// TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除 // TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除

View File

@ -6,10 +6,6 @@ import { BuiltinSimulatorHostView } from '../builtin-simulator';
@observer @observer
export class DocumentView extends Component<{ document: DocumentModel }> { export class DocumentView extends Component<{ document: DocumentModel }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { document } = this.props; const { document } = this.props;
const { simulatorProps } = document; const { simulatorProps } = document;

View File

@ -31,20 +31,16 @@ export class History {
private emitter = new EventEmitter(); private emitter = new EventEmitter();
private obx: Reaction; private asleep = false;
private justWokeup = false;
constructor(logger: () => any, private redoer: (data: NodeSchema) => void, private timeGap: number = 1000) { constructor(logger: () => any, private redoer: (data: NodeSchema) => void, private timeGap: number = 1000) {
this.session = new Session(0, null, this.timeGap); this.session = new Session(0, null, this.timeGap);
this.records = [this.session]; this.records = [this.session];
this.obx = autorun(() => { autorun(() => {
if (this.asleep) return;
const data = logger(); const data = logger();
if (this.justWokeup) {
this.justWokeup = false;
return;
}
untracked(() => { untracked(() => {
const log = currentSerialization.serialize(data); const log = currentSerialization.serialize(data);
if (this.session.cursor === 0 && this.session.isActive()) { if (this.session.cursor === 0 && this.session.isActive()) {
@ -68,7 +64,7 @@ export class History {
} }
} }
}); });
}, true).$obx; });
} }
get hotData() { get hotData() {
@ -79,6 +75,14 @@ export class History {
return this.point !== this.session.cursor; return this.point !== this.session.cursor;
} }
private sleep() {
this.asleep = true;
}
private wakeup() {
this.asleep = false;
}
go(cursor: number) { go(cursor: number) {
this.session.end(); this.session.end();
@ -96,7 +100,7 @@ export class History {
const session = this.records[cursor]; const session = this.records[cursor];
const hotData = session.data; const hotData = session.data;
this.obx.sleep(); this.sleep();
try { try {
this.redoer(currentSerialization.unserialize(hotData)); this.redoer(currentSerialization.unserialize(hotData));
this.emitter.emit('cursor', hotData); this.emitter.emit('cursor', hotData);
@ -104,8 +108,7 @@ export class History {
// //
} }
this.justWokeup = true; this.wakeup();
this.obx.wakeup();
this.session = session; this.session = session;
this.emitter.emit('statechange', this.getState()); this.emitter.emit('statechange', this.getState());

View File

@ -1,4 +1,4 @@
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable } from '@ali/lowcode-editor-core';
import { uniqueId } from '@ali/lowcode-utils'; import { uniqueId } from '@ali/lowcode-utils';
import { TitleContent } from '@ali/lowcode-types'; import { TitleContent } from '@ali/lowcode-types';
import { Node } from './node'; import { Node } from './node';
@ -11,7 +11,7 @@ export class ExclusiveGroup {
readonly id = uniqueId('exclusive'); readonly id = uniqueId('exclusive');
@obx.val readonly children: Node[] = []; @obx.shallow readonly children: Node[] = [];
@obx private visibleIndex = 0; @obx private visibleIndex = 0;
@ -75,6 +75,7 @@ export class ExclusiveGroup {
readonly title: TitleContent; readonly title: TitleContent;
constructor(readonly name: string, title?: TitleContent) { constructor(readonly name: string, title?: TitleContent) {
makeObservable(this);
this.title = title || { this.title = title || {
type: 'i18n', type: 'i18n',
intl: intl('Condition Group'), intl: intl('Condition Group'),

View File

@ -1,4 +1,4 @@
import { obx, computed, globalContext } from '@ali/lowcode-editor-core'; import { obx, computed, globalContext, makeObservable } from '@ali/lowcode-editor-core';
import { Node, ParentalNode } from './node'; import { Node, ParentalNode } from './node';
import { TransformStage } from './transform-stage'; import { TransformStage } from './transform-stage';
import { NodeData, isNodeSchema } from '@ali/lowcode-types'; import { NodeData, isNodeSchema } from '@ali/lowcode-types';
@ -8,11 +8,12 @@ import { foreachReverse } from '../../utils/tree';
import { NodeRemoveOptions } from '../../types'; import { NodeRemoveOptions } from '../../types';
export class NodeChildren { export class NodeChildren {
@obx.val private children: Node[]; @obx.shallow private children: Node[];
private emitter = new EventEmitter(); private emitter = new EventEmitter();
constructor(readonly owner: ParentalNode, data: NodeData | NodeData[], options: any = {}) { constructor(readonly owner: ParentalNode, data: NodeData | NodeData[], options: any = {}) {
makeObservable(this);
this.children = (Array.isArray(data) ? data : [data]).map(child => { this.children = (Array.isArray(data) ? data : [data]).map(child => {
return this.owner.document.createNode(child, options.checkId); return this.owner.document.createNode(child, options.checkId);
}); });
@ -83,11 +84,11 @@ export class NodeChildren {
/** /**
* *
*/ */
@computed isEmpty() { isEmpty() {
return this.size < 1; return this.size < 1;
} }
@computed notEmpty() { notEmpty() {
return this.size > 0; return this.size > 0;
} }
@ -387,7 +388,7 @@ export class NodeChildren {
} }
if (owner.parent && !owner.parent.isRoot()) { if (owner.parent && !owner.parent.isRoot()) {
this.reportModified(node, owner.parent, { ...options, propagated: true, }); this.reportModified(node, owner.parent, { ...options, propagated: true });
} }
} }
} }

View File

@ -1,6 +1,6 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { obx, computed, autorun } from '@ali/lowcode-editor-core'; import { obx, computed, autorun, makeObservable, runInAction, getObserverTree } from '@ali/lowcode-editor-core';
import { import {
isDOMText, isDOMText,
isJSExpression, isJSExpression,
@ -160,6 +160,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
isInited = false; isInited = false;
constructor(readonly document: DocumentModel, nodeSchema: Schema, options: any = {}) { constructor(readonly document: DocumentModel, nodeSchema: Schema, options: any = {}) {
makeObservable(this);
const { componentName, id, children, props, ...extras } = nodeSchema; const { componentName, id, children, props, ...extras } = nodeSchema;
this.id = document.nextId(id); this.id = document.nextId(id);
this.componentName = componentName; this.componentName = componentName;
@ -208,7 +209,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this.autoruns = autoruns.map((item) => { this.autoruns = autoruns.map((item) => {
return autorun(() => { return autorun(() => {
item.autorun(this.props.get(item.name, true) as any); item.autorun(this.props.get(item.name, true) as any);
}, true); });
}); });
} }
@ -382,7 +383,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
* *
*/ */
get isLocked(): boolean { get isLocked(): boolean {
return !!this.getExtraProp('isLocked', false)?.getValue(); return !!this.getExtraProp('isLocked')?.getValue();
} }
/** /**
@ -417,9 +418,9 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
return this.props.export(TransformStage.Serilize).props || null; return this.props.export(TransformStage.Serilize).props || null;
} }
@obx.val _slots: Node[] = []; @obx.shallow _slots: Node[] = [];
@computed hasSlots() { hasSlots() {
return this._slots.length > 0; return this._slots.length > 0;
} }
@ -465,7 +466,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
} }
/* istanbul ignore next */ /* istanbul ignore next */
@computed isConditionalVisible(): boolean | undefined { isConditionalVisible(): boolean | undefined {
return this._conditionGroup?.isVisible(this); return this._conditionGroup?.isVisible(this);
} }
@ -474,7 +475,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this._conditionGroup?.setVisible(this); this._conditionGroup?.setVisible(this);
} }
@computed hasCondition() { hasCondition() {
const v = this.getExtraProp('condition', false)?.getValue(); const v = this.getExtraProp('condition', false)?.getValue();
return v != null && v !== '' && v !== true; return v != null && v !== '' && v !== true;
} }
@ -483,7 +484,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
* has loop when 1. loop is validArray with length > 1 ; OR 2. loop is variable object * has loop when 1. loop is validArray with length > 1 ; OR 2. loop is variable object
* @return boolean, has loop config or not * @return boolean, has loop config or not
*/ */
@computed hasLoop() { hasLoop() {
const value = this.getExtraProp('loop', false)?.getValue(); const value = this.getExtraProp('loop', false)?.getValue();
if (value === undefined || value === null) { if (value === undefined || value === null) {
return false; return false;
@ -550,12 +551,12 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
}; };
} }
getProp(path: string, stash = true): Prop | null { getProp(path: string, createIfNone = true): Prop | null {
return this.props.query(path, stash as any) || null; return this.props.query(path, createIfNone) || null;
} }
getExtraProp(key: string, stash = true): Prop | null { getExtraProp(key: string, createIfNone = true): Prop | null {
return this.props.get(getConvertedExtraKey(key), stash) || null; return this.props.get(getConvertedExtraKey(key), createIfNone) || null;
} }
setExtraProp(key: string, value: CompositeValue) { setExtraProp(key: string, value: CompositeValue) {
@ -647,7 +648,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
} }
set schema(data: Schema) { set schema(data: Schema) {
this.import(data); runInAction(() => this.import(data));
} }
import(data: Schema, checkId = false) { import(data: Schema, checkId = false) {
@ -865,9 +866,6 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
return this.componentName; return this.componentName;
} }
/**
* @deprecated
*/
insert(node: Node, ref?: Node, useMutator = true) { insert(node: Node, ref?: Node, useMutator = true) {
this.insertAfter(node, ref, useMutator); this.insertAfter(node, ref, useMutator);
} }
@ -918,7 +916,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this.children?.mergeChildren(remover, adder, sorter); this.children?.mergeChildren(remover, adder, sorter);
} }
@obx.val status: NodeStatus = { @obx.shallow status: NodeStatus = {
inPlaceEditing: false, inPlaceEditing: false,
locking: false, locking: false,
pseudo: false, pseudo: false,

View File

@ -1,4 +1,4 @@
import { obx, autorun, untracked, computed } from '@ali/lowcode-editor-core'; import { obx, autorun, untracked, computed, makeObservable, action } from '@ali/lowcode-editor-core';
import { Prop, IPropParent, UNSET } from './prop'; import { Prop, IPropParent, UNSET } from './prop';
import { Props } from './props'; import { Props } from './props';
import { Node } from '../node'; import { Node } from '../node';
@ -7,7 +7,7 @@ export type PendingItem = Prop[];
export class PropStash implements IPropParent { export class PropStash implements IPropParent {
readonly isPropStash = true; readonly isPropStash = true;
@obx.val private space: Set<Prop> = new Set(); @obx.shallow private space: Set<Prop> = new Set();
@computed private get maps(): Map<string | number, Prop> { @computed private get maps(): Map<string | number, Prop> {
const maps = new Map(); const maps = new Map();
@ -24,6 +24,7 @@ export class PropStash implements IPropParent {
readonly owner: Node; readonly owner: Node;
constructor(readonly props: Props, write: (item: Prop) => void) { constructor(readonly props: Props, write: (item: Prop) => void) {
makeObservable(this);
this.owner = props.owner; this.owner = props.owner;
this.willPurge = autorun(() => { this.willPurge = autorun(() => {
if (this.space.size < 1) { if (this.space.size < 1) {
@ -46,6 +47,7 @@ export class PropStash implements IPropParent {
}); });
} }
@action
get(key: string | number): Prop { get(key: string | number): Prop {
let prop = this.maps.get(key); let prop = this.maps.get(key);
if (!prop) { if (!prop) {
@ -55,16 +57,19 @@ export class PropStash implements IPropParent {
return prop; return prop;
} }
@action
delete(prop: Prop) { delete(prop: Prop) {
this.space.delete(prop); this.space.delete(prop);
prop.purge(); prop.purge();
} }
@action
clear() { clear() {
this.space.forEach(item => item.purge()); this.space.forEach(item => item.purge());
this.space.clear(); this.space.clear();
} }
@action
purge() { purge() {
this.willPurge(); this.willPurge();
this.space.clear(); this.space.clear();

View File

@ -1,12 +1,12 @@
import { untracked, computed, obx, engineConfig } from '@ali/lowcode-editor-core'; import { untracked, computed, obx, engineConfig, action, makeObservable, mobx } from '@ali/lowcode-editor-core';
import { CompositeValue, FieldConfig, isJSExpression, isJSSlot, JSSlot, SlotSchema } from '@ali/lowcode-types'; import { CompositeValue, FieldConfig, isJSExpression, isJSSlot, JSSlot, SlotSchema } from '@ali/lowcode-types';
import { uniqueId, isPlainObject, hasOwnProperty, compatStage } from '@ali/lowcode-utils'; import { uniqueId, isPlainObject, hasOwnProperty, compatStage } from '@ali/lowcode-utils';
import { PropStash } from './prop-stash';
import { valueToSource } from './value-to-source'; import { valueToSource } from './value-to-source';
import { Props } from './props'; import { Props } from './props';
import { SlotNode, Node } from '../node'; import { SlotNode, Node } from '../node';
import { TransformStage } from '../transform-stage'; import { TransformStage } from '../transform-stage';
const { set: mobxSet, isObservableArray } = mobx;
export const UNSET = Symbol.for('unset'); export const UNSET = Symbol.for('unset');
export type UNSET = typeof UNSET; export type UNSET = typeof UNSET;
@ -24,8 +24,6 @@ export class Prop implements IPropParent {
readonly owner: Node; readonly owner: Node;
private stash: PropStash | undefined;
/** /**
* *
*/ */
@ -47,6 +45,7 @@ export class Prop implements IPropParent {
spread = false, spread = false,
options = {}, options = {},
) { ) {
makeObservable(this);
this.owner = parent.owner; this.owner = parent.owner;
this.props = parent.props; this.props = parent.props;
this.key = key; this.key = key;
@ -59,6 +58,7 @@ export class Prop implements IPropParent {
} }
// TODO: 先用调用方式触发子 prop 的初始化,后续须重构 // TODO: 先用调用方式触发子 prop 的初始化,后续须重构
@action
private setupItems() { private setupItems() {
return this.items; return this.items;
} }
@ -66,6 +66,7 @@ export class Prop implements IPropParent {
/** /**
* @see SettingTarget * @see SettingTarget
*/ */
@action
getPropValue(propName: string | number): any { getPropValue(propName: string | number): any {
return this.get(propName)!.getValue(); return this.get(propName)!.getValue();
} }
@ -73,6 +74,7 @@ export class Prop implements IPropParent {
/** /**
* @see SettingTarget * @see SettingTarget
*/ */
@action
setPropValue(propName: string | number, value: any): void { setPropValue(propName: string | number, value: any): void {
this.set(propName, value); this.set(propName, value);
} }
@ -80,6 +82,7 @@ export class Prop implements IPropParent {
/** /**
* @see SettingTarget * @see SettingTarget
*/ */
@action
clearPropValue(propName: string | number): void { clearPropValue(propName: string | number): void {
this.get(propName, false)?.unset(); this.get(propName, false)?.unset();
} }
@ -95,7 +98,7 @@ export class Prop implements IPropParent {
return this._type; return this._type;
} }
@obx.ref private _value: any = UNSET; @obx private _value: any = UNSET;
/** /**
* *
@ -213,7 +216,7 @@ export class Prop implements IPropParent {
this._code = code; this._code = code;
} }
@computed getAsString(): string { getAsString(): string {
if (this.type === 'literal') { if (this.type === 'literal') {
return this._value ? String(this._value) : ''; return this._value ? String(this._value) : '';
} }
@ -223,6 +226,7 @@ export class Prop implements IPropParent {
/** /**
* set value, val should be JSON Object * set value, val should be JSON Object
*/ */
@action
setValue(val: CompositeValue) { setValue(val: CompositeValue) {
if (val === this._value) return; if (val === this._value) return;
const editor = this.owner.document?.designer.editor; const editor = this.owner.document?.designer.editor;
@ -267,10 +271,11 @@ export class Prop implements IPropParent {
} }
} }
@computed getValue(): CompositeValue { getValue(): CompositeValue {
return this.export(TransformStage.Serilize); return this.export(TransformStage.Serilize);
} }
@action
private dispose() { private dispose() {
const items = untracked(() => this._items); const items = untracked(() => this._items);
if (items) { if (items) {
@ -278,9 +283,6 @@ export class Prop implements IPropParent {
} }
this._items = null; this._items = null;
this._maps = null; this._maps = null;
if (this.stash) {
this.stash.clear();
}
if (this._type !== 'slot' && this._slotNode) { if (this._type !== 'slot' && this._slotNode) {
this._slotNode.remove(); this._slotNode.remove();
this._slotNode = undefined; this._slotNode = undefined;
@ -293,6 +295,7 @@ export class Prop implements IPropParent {
return this._slotNode; return this._slotNode;
} }
@action
setAsSlot(data: JSSlot) { setAsSlot(data: JSSlot) {
this._type = 'slot'; this._type = 'slot';
const slotSchema: SlotSchema = { const slotSchema: SlotSchema = {
@ -315,6 +318,7 @@ export class Prop implements IPropParent {
/** /**
* *
*/ */
@action
unset() { unset() {
this._type = 'unset'; this._type = 'unset';
} }
@ -322,6 +326,7 @@ export class Prop implements IPropParent {
/** /**
* *
*/ */
@action
isUnset() { isUnset() {
return this._type === 'unset'; return this._type === 'unset';
} }
@ -352,9 +357,9 @@ export class Prop implements IPropParent {
return this.code === other.code ? 0 : 2; return this.code === other.code ? 0 : 2;
} }
@obx.val private _items: Prop[] | null = null; @obx.shallow private _items: Prop[] | null = null;
@obx.val private _maps: Map<string | number, Prop> | null = null; @obx.shallow private _maps: Map<string | number, Prop> | null = null;
get path(): string[] { get path(): string[] {
return (this.parent.path || []).concat(this.key as string); return (this.parent.path || []).concat(this.key as string);
@ -401,11 +406,12 @@ export class Prop implements IPropParent {
/** /**
* *
* @param stash * @param createIfNone
*/ */
get(path: string | number, stash = true): Prop | null { @action
get(path: string | number, createIfNone = true): Prop | null {
const type = this._type; const type = this._type;
if (type !== 'map' && type !== 'list' && type !== 'unset' && !stash) { if (type !== 'map' && type !== 'list' && type !== 'unset' && !createIfNone) {
return null; return null;
} }
@ -434,20 +440,12 @@ export class Prop implements IPropParent {
} }
if (prop) { if (prop) {
return nest ? prop.get(nest, stash) : prop; return nest ? prop.get(nest, createIfNone) : prop;
} }
if (stash) { if (createIfNone) {
if (!this.stash) { prop = new Prop(this, UNSET, entry);
this.stash = new PropStash(this.props, (item) => { this.set(entry, prop, true);
// item take effect
if (item.key) {
this.set(item.key, item, true);
}
item.parent = this;
});
}
prop = this.stash.get(entry);
if (nest) { if (nest) {
return prop.get(nest, true); return prop.get(nest, true);
} }
@ -461,6 +459,7 @@ export class Prop implements IPropParent {
/** /**
* *
*/ */
@action
remove() { remove() {
this.parent.delete(this); this.parent.delete(this);
} }
@ -468,6 +467,7 @@ export class Prop implements IPropParent {
/** /**
* *
*/ */
@action
delete(prop: Prop): void { delete(prop: Prop): void {
if (this.items) { if (this.items) {
const i = this.items.indexOf(prop); const i = this.items.indexOf(prop);
@ -484,6 +484,7 @@ export class Prop implements IPropParent {
/** /**
* key * key
*/ */
@action
deleteKey(key: string): void { deleteKey(key: string): void {
if (this.maps) { if (this.maps) {
const prop = this.maps.get(key); const prop = this.maps.get(key);
@ -505,6 +506,7 @@ export class Prop implements IPropParent {
* *
* @param force * @param force
*/ */
@action
add(value: CompositeValue, force = false): Prop | null { add(value: CompositeValue, force = false): Prop | null {
const type = this._type; const type = this._type;
if (type !== 'list' && type !== 'unset' && !force) { if (type !== 'list' && type !== 'unset' && !force) {
@ -523,6 +525,7 @@ export class Prop implements IPropParent {
* *
* @param force * @param force
*/ */
@action
set(key: string | number, value: CompositeValue | Prop, force = false) { set(key: string | number, value: CompositeValue | Prop, force = false) {
const type = this._type; const type = this._type;
if (type !== 'map' && type !== 'list' && type !== 'unset' && !force) { if (type !== 'map' && type !== 'list' && type !== 'unset' && !force) {
@ -543,7 +546,11 @@ export class Prop implements IPropParent {
if (!isValidArrayIndex(key)) { if (!isValidArrayIndex(key)) {
return null; return null;
} }
if (isObservableArray(items)) {
mobxSet(items, key, prop);
} else {
items[key] = prop; items[key] = prop;
}
} else if (this.maps) { } else if (this.maps) {
const { maps } = this; const { maps } = this;
const orig = maps.get(key); const orig = maps.get(key);
@ -584,14 +591,12 @@ export class Prop implements IPropParent {
/** /**
* *
*/ */
@action
purge() { purge() {
if (this.purged) { if (this.purged) {
return; return;
} }
this.purged = true; this.purged = true;
if (this.stash) {
this.stash.purge();
}
if (this._items) { if (this._items) {
this._items.forEach((item) => item.purge()); this._items.forEach((item) => item.purge());
} }
@ -627,6 +632,7 @@ export class Prop implements IPropParent {
/** /**
* *
*/ */
@action
forEach(fn: (item: Prop, key: number | string | undefined) => void): void { forEach(fn: (item: Prop, key: number | string | undefined) => void): void {
const { items } = this; const { items } = this;
if (!items) { if (!items) {
@ -641,6 +647,7 @@ export class Prop implements IPropParent {
/** /**
* *
*/ */
@action
map<T>(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { map<T>(fn: (item: Prop, key: number | string | undefined) => T): T[] | null {
const { items } = this; const { items } = this;
if (!items) { if (!items) {

View File

@ -1,7 +1,6 @@
import { computed, obx } from '@ali/lowcode-editor-core'; import { computed, makeObservable, obx, action } from '@ali/lowcode-editor-core';
import { PropsMap, PropsList, CompositeValue } from '@ali/lowcode-types'; import { PropsMap, PropsList, CompositeValue } from '@ali/lowcode-types';
import { uniqueId, compatStage } from '@ali/lowcode-utils'; import { uniqueId, compatStage } from '@ali/lowcode-utils';
import { PropStash } from './prop-stash';
import { Prop, IPropParent, UNSET } from './prop'; import { Prop, IPropParent, UNSET } from './prop';
import { Node } from '../node'; import { Node } from '../node';
import { TransformStage } from '../transform-stage'; import { TransformStage } from '../transform-stage';
@ -23,7 +22,7 @@ export function getOriginalExtraKey(key: string): string {
export class Props implements IPropParent { export class Props implements IPropParent {
readonly id = uniqueId('props'); readonly id = uniqueId('props');
@obx.val private items: Prop[] = []; @obx.shallow private items: Prop[] = [];
@computed private get maps(): Map<string, Prop> { @computed private get maps(): Map<string, Prop> {
const maps = new Map(); const maps = new Map();
@ -45,8 +44,6 @@ export class Props implements IPropParent {
readonly owner: Node; readonly owner: Node;
private stash: PropStash;
/** /**
* *
*/ */
@ -57,11 +54,8 @@ export class Props implements IPropParent {
@obx type: 'map' | 'list' = 'map'; @obx type: 'map' | 'list' = 'map';
constructor(owner: Node, value?: PropsMap | PropsList | null, extras?: object) { constructor(owner: Node, value?: PropsMap | PropsList | null, extras?: object) {
makeObservable(this);
this.owner = owner; this.owner = owner;
this.stash = new PropStash(this, prop => {
this.items.push(prop);
prop.parent = this;
});
if (Array.isArray(value)) { if (Array.isArray(value)) {
this.type = 'list'; this.type = 'list';
this.items = value.map(item => new Prop(this, item.value, item.name, item.spread)); this.items = value.map(item => new Prop(this, item.value, item.name, item.spread));
@ -75,8 +69,8 @@ export class Props implements IPropParent {
} }
} }
@action
import(value?: PropsMap | PropsList | null, extras?: object) { import(value?: PropsMap | PropsList | null, extras?: object) {
this.stash.clear();
const originItems = this.items; const originItems = this.items;
if (Array.isArray(value)) { if (Array.isArray(value)) {
this.type = 'list'; this.type = 'list';
@ -96,6 +90,7 @@ export class Props implements IPropParent {
originItems.forEach(item => item.purge()); originItems.forEach(item => item.purge());
} }
@action
merge(value: PropsMap, extras?: PropsMap) { merge(value: PropsMap, extras?: PropsMap) {
Object.keys(value).forEach(key => { Object.keys(value).forEach(key => {
this.query(key, true)!.setValue(value[key]); this.query(key, true)!.setValue(value[key]);
@ -119,9 +114,6 @@ export class Props implements IPropParent {
props = []; props = [];
this.items.forEach(item => { this.items.forEach(item => {
let value = item.export(stage); let value = item.export(stage);
if (value === UNSET) {
value = undefined;
}
let name = item.key as string; let name = item.key as string;
if (name && typeof name === 'string' && name.startsWith(EXTRA_KEY_PREFIX)) { if (name && typeof name === 'string' && name.startsWith(EXTRA_KEY_PREFIX)) {
name = getOriginalExtraKey(name); name = getOriginalExtraKey(name);
@ -142,9 +134,6 @@ export class Props implements IPropParent {
return; return;
} }
let value = item.export(stage); let value = item.export(stage);
if (value === UNSET) {
value = undefined;
}
allProps[name] = value; allProps[name] = value;
}); });
// compatible vision // compatible vision
@ -187,53 +176,19 @@ export class Props implements IPropParent {
/** /**
* path * path
* *
* @param stash * @param createIfNone
*/ */
query(path: string, stash = true): Prop | null { @action
return this.get(path, stash); query(path: string, createIfNone = true): Prop | null {
// todo: future support list search return this.get(path, createIfNone);
// 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 && stash) {
// return this.stash.get(path);
// }
// return ret;
} }
/** /**
* , * ,
* @param stash * @param createIfNone
*/ */
get(path: string, stash = false): Prop | null { @action
get(path: string, createIfNone = false): Prop | null {
let entry = path; let entry = path;
let nest = ''; let nest = '';
const i = path.indexOf('.'); const i = path.indexOf('.');
@ -244,10 +199,14 @@ export class Props implements IPropParent {
} }
} }
const prop = this.maps.get(entry) || (stash && this.stash.get(entry)) || null; let prop = this.maps.get(entry);
if (!prop && createIfNone) {
prop = new Prop(this, UNSET, entry);
this.items.push(prop);
}
if (prop) { if (prop) {
return nest ? prop.get(nest, stash) : prop; return nest ? prop.get(nest, createIfNone) : prop;
} }
return null; return null;
@ -256,6 +215,7 @@ export class Props implements IPropParent {
/** /**
* *
*/ */
@action
delete(prop: Prop): void { delete(prop: Prop): void {
const i = this.items.indexOf(prop); const i = this.items.indexOf(prop);
if (i > -1) { if (i > -1) {
@ -267,6 +227,7 @@ export class Props implements IPropParent {
/** /**
* key * key
*/ */
@action
deleteKey(key: string): void { deleteKey(key: string): void {
this.items = this.items.filter(item => { this.items = this.items.filter(item => {
if (item.key === key) { if (item.key === key) {
@ -280,6 +241,7 @@ export class Props implements IPropParent {
/** /**
* *
*/ */
@action
add(value: CompositeValue | null, key?: string | number, spread = false, options: any = {}): Prop { add(value: CompositeValue | null, key?: string | number, spread = false, options: any = {}): Prop {
const prop = new Prop(this, value, key, spread, options); const prop = new Prop(this, value, key, spread, options);
this.items.push(prop); this.items.push(prop);
@ -319,6 +281,7 @@ export class Props implements IPropParent {
/** /**
* *
*/ */
@action
forEach(fn: (item: Prop, key: number | string | undefined) => void): void { forEach(fn: (item: Prop, key: number | string | undefined) => void): void {
this.items.forEach(item => { this.items.forEach(item => {
return fn(item, item.key); return fn(item, item.key);
@ -328,12 +291,14 @@ export class Props implements IPropParent {
/** /**
* *
*/ */
@action
map<T>(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { map<T>(fn: (item: Prop, key: number | string | undefined) => T): T[] | null {
return this.items.map(item => { return this.items.map(item => {
return fn(item, item.key); return fn(item, item.key);
}); });
} }
@action
filter(fn: (item: Prop, key: number | string | undefined) => boolean) { filter(fn: (item: Prop, key: number | string | undefined) => boolean) {
return this.items.filter(item => { return this.items.filter(item => {
return fn(item, item.key); return fn(item, item.key);
@ -345,22 +310,28 @@ export class Props implements IPropParent {
/** /**
* *
*/ */
@action
purge() { purge() {
if (this.purged) { if (this.purged) {
return; return;
} }
this.purged = true; this.purged = true;
this.stash.purge();
this.items.forEach(item => item.purge()); this.items.forEach(item => item.purge());
} }
getProp(path: string, stash = true): Prop | null { /**
return this.query(path, stash as any) || null; * ,
* @param createIfNone
*/
@action
getProp(path: string, createIfNone = true): Prop | null {
return this.query(path, createIfNone) || null;
} }
/** /**
* *
*/ */
@action
getPropValue(path: string): any { getPropValue(path: string): any {
return this.getProp(path, false)?.value; return this.getProp(path, false)?.value;
} }
@ -368,6 +339,7 @@ export class Props implements IPropParent {
/** /**
* *
*/ */
@action
setPropValue(path: string, value: any) { setPropValue(path: string, value: any) {
this.getProp(path, true)!.setValue(value); this.getProp(path, true)!.setValue(value);
} }
@ -383,6 +355,7 @@ export class Props implements IPropParent {
* @deprecated * @deprecated
* props node * props node
*/ */
@action
toData() { toData() {
return this.export()?.props; return this.export()?.props;
} }

View File

@ -1,14 +1,16 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { obx } from '@ali/lowcode-editor-core'; import { obx, makeObservable } from '@ali/lowcode-editor-core';
import { Node, comparePosition, PositionNO } from './node/node'; import { Node, comparePosition, PositionNO } from './node/node';
import { DocumentModel } from './document-model'; import { DocumentModel } from './document-model';
export class Selection { export class Selection {
private emitter = new EventEmitter(); private emitter = new EventEmitter();
@obx.val private _selected: string[] = []; @obx.shallow private _selected: string[] = [];
constructor(readonly doc: DocumentModel) {} constructor(readonly doc: DocumentModel) {
makeObservable(this);
}
/** /**
* id * id

View File

@ -1,10 +1,10 @@
import { Component } from 'react'; import { Component } from 'react';
import { observer } from '@ali/lowcode-editor-core'; import { observer, engineConfig } from '@ali/lowcode-editor-core';
import { Designer } from '../designer'; import { Designer } from '../designer';
import { BuiltinSimulatorHostView } from '../builtin-simulator'; import { BuiltinSimulatorHostView } from '../builtin-simulator';
import './project.less'; import './project.less';
class Loading extends Component { class BuiltinLoading extends Component {
render() { render() {
return ( return (
<div id="engine-loading-wrapper"> <div id="engine-loading-wrapper">
@ -29,6 +29,7 @@ export class ProjectView extends Component<{ designer: Designer }> {
const { project } = designer; const { project } = designer;
const { simulatorProps } = project; const { simulatorProps } = project;
const Simulator = designer.simulatorComponent || BuiltinSimulatorHostView; const Simulator = designer.simulatorComponent || BuiltinSimulatorHostView;
const Loading = engineConfig.get('loadingComponent', BuiltinLoading);
return ( return (
<div className="lc-project"> <div className="lc-project">

View File

@ -1,5 +1,5 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable, action } from '@ali/lowcode-editor-core';
import { Designer } from '../designer'; import { Designer } from '../designer';
import { DocumentModel, isDocumentModel, isPageSchema } from '../document'; import { DocumentModel, isDocumentModel, isPageSchema } from '../document';
import { ProjectSchema, RootSchema } from '@ali/lowcode-types'; import { ProjectSchema, RootSchema } from '@ali/lowcode-types';
@ -8,7 +8,7 @@ import { ISimulatorHost } from '../simulator';
export class Project { export class Project {
private emitter = new EventEmitter(); private emitter = new EventEmitter();
@obx.val readonly documents: DocumentModel[] = []; @obx.shallow readonly documents: DocumentModel[] = [];
private data: ProjectSchema = { version: '1.0.0', componentsMap: [], componentsTree: [], i18n: {} }; private data: ProjectSchema = { version: '1.0.0', componentsMap: [], componentsTree: [], i18n: {} };
@ -24,6 +24,7 @@ export class Project {
// TODO: 考虑项目级别 History // TODO: 考虑项目级别 History
constructor(readonly designer: Designer, schema?: ProjectSchema) { constructor(readonly designer: Designer, schema?: ProjectSchema) {
makeObservable(this);
this.load(schema); this.load(schema);
} }
@ -76,6 +77,7 @@ export class Project {
* *
* @param autoOpen true string * @param autoOpen true string
*/ */
@action
load(schema?: ProjectSchema, autoOpen?: boolean | string) { load(schema?: ProjectSchema, autoOpen?: boolean | string) {
this.unload(); this.unload();
// load new document // load new document

View File

@ -105,7 +105,7 @@ describe('Host 测试', () => {
type: AssetType.CSSText, type: AssetType.CSSText,
content: '.theme {font-size: 50px;}', content: '.theme {font-size: 50px;}',
}); });
expect(host.componentsMap).toBe(designer.componentsMap); expect(host.componentsMap).toEqual(designer.componentsMap);
expect(host.requestHandlersMap).toEqual({}); expect(host.requestHandlersMap).toEqual({});
host.set('renderEnv', 'vue'); host.set('renderEnv', 'vue');

View File

@ -85,7 +85,7 @@ describe('Prop 类测试', () => {
strProp.unset(); strProp.unset();
strProp.add(2, true); strProp.add(2, true);
strProp.set(1); strProp.set(0);
expect(numProp.set()).toBeNull(); expect(numProp.set()).toBeNull();
expect(numProp.has()).toBeFalsy(); expect(numProp.has()).toBeFalsy();
@ -391,7 +391,7 @@ describe('Prop 类测试', () => {
prop.unset(); prop.unset();
prop.set(0, true); prop.set(0, true);
expect(prop.set('x', 'invalid')).toBeNull(); expect(prop.set('x', 'invalid')).toBeNull();
expect(prop.get(0).getValue()).toBeTruthy(); expect(prop.get(0).getValue()).toBeUndefined();
}); });
it('export', () => { it('export', () => {

View File

@ -50,10 +50,9 @@ describe('组件元数据处理', () => {
expect(meta.availableActions[2].name).toBe('copy'); expect(meta.availableActions[2].name).toBe('copy');
removeBuiltinComponentAction('remove'); removeBuiltinComponentAction('remove');
// availableActions 有 computed 缓存 expect(meta.availableActions).toHaveLength(4);
expect(meta.availableActions[0].name).toBe('remove'); expect(meta.availableActions[0].name).toBe('hide');
expect(meta.availableActions[1].name).toBe('hide'); expect(meta.availableActions[1].name).toBe('copy');
expect(meta.availableActions[2].name).toBe('copy');
addBuiltinComponentAction({ addBuiltinComponentAction({
name: 'new', name: 'new',
@ -61,10 +60,9 @@ describe('组件元数据处理', () => {
action() {}, action() {},
}, },
}); });
// availableActions 有 computed 缓存
expect(meta.availableActions).toHaveLength(5); expect(meta.availableActions).toHaveLength(5);
expect(meta.availableActions[0].name).toBe('remove'); expect(meta.availableActions[0].name).toBe('hide');
expect(meta.availableActions[1].name).toBe('hide'); expect(meta.availableActions[1].name).toBe('copy');
expect(meta.availableActions[2].name).toBe('copy'); expect(meta.availableActions[4].name).toBe('new');
}); });
}); });

View File

@ -16,8 +16,6 @@
"@ali/lowcode-types": "1.0.66", "@ali/lowcode-types": "1.0.66",
"@ali/lowcode-utils": "1.0.66", "@ali/lowcode-utils": "1.0.66",
"@alifd/next": "^1.19.16", "@alifd/next": "^1.19.16",
"@recore/obx": "^1.0.9",
"@recore/obx-react": "^1.0.8",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"debug": "^4.1.1", "debug": "^4.1.1",
"intl-messageformat": "^9.3.1", "intl-messageformat": "^9.3.1",
@ -25,7 +23,9 @@
"power-di": "^2.2.4", "power-di": "^2.2.4",
"react": "^16", "react": "^16",
"react-dom": "^16.7.0", "react-dom": "^16.7.0",
"store": "^2.0.12" "store": "^2.0.12",
"mobx": "^6.3.0",
"mobx-react": "^7.2.0"
}, },
"devDependencies": { "devDependencies": {
"@alib/build-scripts": "^0.1.18", "@alib/build-scripts": "^0.1.18",

View File

@ -39,7 +39,7 @@ export class Editor extends EventEmitter implements IEditor {
/** /**
* Ioc Container * Ioc Container
*/ */
@obx.val private context = new Map<KeyType, any>(); @obx.shallow private context = new Map<KeyType, any>();
get locale() { get locale() {
return globalLocale.getLocale(); return globalLocale.getLocale();

View File

@ -97,7 +97,8 @@ export function createIntl(
getLocale(): string; getLocale(): string;
setLocale(locale: string): void; setLocale(locale: string): void;
} { } {
const data = computed(() => { // TODO: make reactive
const data = (() => {
const locale = globalLocale.getLocale(); const locale = globalLocale.getLocale();
if (typeof instance === 'string') { if (typeof instance === 'string') {
if ((window as any)[instance]) { if ((window as any)[instance]) {
@ -110,11 +111,11 @@ export function createIntl(
return (instance as any)[locale] || {}; return (instance as any)[locale] || {};
} }
return {}; return {};
}); })();
function intl(key: string, params?: object): string { function intl(key: string, params?: object): string {
// TODO: tries lost language // TODO: tries lost language
const str = data.value[key]; const str = data[key];
if (str == null) { if (str == null) {
return `##intl@${key}##`; return `##intl@${key}##`;

View File

@ -1,5 +1,24 @@
import { observer } from '@recore/obx-react'; import { observer } from 'mobx-react';
import { configure } from 'mobx';
export * from '@recore/obx'; configure({ enforceActions: 'never' });
// 常用的直接导出,其他的以 mobx 命名空间导出
export {
observable as obx,
observable,
observe,
autorun,
makeObservable,
makeAutoObservable,
reaction,
computed,
action,
runInAction,
untracked,
IReactionDisposer,
IReactionPublic,
IReactionOptions,
} from 'mobx';
export * as mobx from 'mobx';
export { observer }; export { observer };

View File

@ -1,4 +1,4 @@
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable } from '@ali/lowcode-editor-core';
import WidgetContainer from './widget/widget-container'; import WidgetContainer from './widget/widget-container';
import { Skeleton } from './skeleton'; import { Skeleton } from './skeleton';
import { IWidget } from './widget/widget'; import { IWidget } from './widget/widget';
@ -24,10 +24,11 @@ export default class Area<C extends IWidgetBaseConfig = any, T extends IWidget =
readonly container: WidgetContainer<T, C>; readonly container: WidgetContainer<T, C>;
constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) { constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) {
makeObservable(this);
this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent); this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent);
} }
@computed isEmpty(): boolean { isEmpty(): boolean {
return this.container.items.length < 1; return this.container.items.length < 1;
} }

View File

@ -1,6 +1,6 @@
import { Component, Fragment } from 'react'; import { Component, Fragment } from 'react';
import { Icon, Button, Message } from '@alifd/next'; import { Icon, Button, Message } from '@alifd/next';
import { Title } from '@ali/lowcode-editor-core'; import { Title, runInAction } from '@ali/lowcode-editor-core';
import { SetterType, FieldConfig, SetterConfig } from '@ali/lowcode-types'; import { SetterType, FieldConfig, SetterConfig } from '@ali/lowcode-types';
import { SettingField } from '@ali/lowcode-designer'; import { SettingField } from '@ali/lowcode-designer';
import { createSettingFieldView } from '../settings/settings-pane'; import { createSettingFieldView } from '../settings/settings-pane';
@ -60,11 +60,13 @@ export class ListSetter extends Component<ArraySetterProps, ArraySetterState> {
itemsMap, itemsMap,
}, () => { }, () => {
// setValue 会触发onItemChange需要在items被设值之后才能调用 // setValue 会触发onItemChange需要在items被设值之后才能调用
runInAction(() => {
value && value.map((item, index) => { value && value.map((item, index) => {
items[index].setValue(item); items[index].setValue(item);
return item; return item;
}); });
}); });
});
} }
delay(ms) { delay(ms) {

View File

@ -1,7 +1,6 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Node, Designer, Selection, SettingTopEntry } from '@ali/lowcode-designer'; import { Node, Designer, Selection, SettingTopEntry } from '@ali/lowcode-designer';
import { Editor, obx, computed } from '@ali/lowcode-editor-core'; import { Editor, obx, computed, makeObservable, action } from '@ali/lowcode-editor-core';
import { executePendingFn } from '@ali/lowcode-utils';
function generateSessionId(nodes: Node[]) { function generateSessionId(nodes: Node[]) {
return nodes return nodes
@ -34,6 +33,7 @@ export class SettingsMain {
private designer?: Designer; private designer?: Designer;
constructor(readonly editor: Editor) { constructor(readonly editor: Editor) {
makeObservable(this);
this.init(); this.init();
} }
@ -54,6 +54,7 @@ export class SettingsMain {
setupSelection(designer.currentSelection); setupSelection(designer.currentSelection);
} }
@action
private setup(nodes: Node[]) { private setup(nodes: Node[]) {
// check nodes change // check nodes change
const sessionId = generateSessionId(nodes); const sessionId = generateSessionId(nodes);

View File

@ -158,10 +158,6 @@ class SettingFieldView extends Component<{ field: SettingField }> {
class SettingGroupView extends Component<{ field: SettingField }> { class SettingGroupView extends Component<{ field: SettingField }> {
static contextType = SkeletonContext; static contextType = SkeletonContext;
shouldComponentUpdate() {
return false;
}
render() { render() {
const { field } = this.props; const { field } = this.props;
const { extraProps } = field; const { extraProps } = field;
@ -227,12 +223,7 @@ export type SettingsPaneProps = {
export class SettingsPane extends Component<SettingsPaneProps> { export class SettingsPane extends Component<SettingsPaneProps> {
static contextType = SkeletonContext; static contextType = SkeletonContext;
@obx @obx private currentStage?: Stage;
private currentStage?: Stage;
shouldComponentUpdate() {
return false;
}
private popupPipe = new PopupPipe(); private popupPipe = new PopupPipe();

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Tab, Breadcrumb } from '@alifd/next'; import { Tab, Breadcrumb } from '@alifd/next';
import { Title, observer, Editor, obx, globalContext, engineConfig } from '@ali/lowcode-editor-core'; import { Title, observer, Editor, obx, globalContext, engineConfig, makeObservable } from '@ali/lowcode-editor-core';
import { Node, isSettingField, SettingField, Designer } from '@ali/lowcode-designer'; import { Node, isSettingField, SettingField, Designer } from '@ali/lowcode-designer';
import { SettingsMain } from './main'; import { SettingsMain } from './main';
import { SettingsPane } from './settings-pane'; import { SettingsPane } from './settings-pane';
@ -16,8 +16,9 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any
@obx.ref private _activeKey?: any; @obx.ref private _activeKey?: any;
shouldComponentUpdate() { constructor(props) {
return false; super(props);
makeObservable(this);
} }
componentDidMount() { componentDidMount() {
@ -62,8 +63,8 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any
); );
} }
const editor = globalContext.get(Editor); const editor = globalContext.get('editor');
const designer = editor.get(Designer); const designer = editor.get('designer');
const current = designer?.currentSelection?.getNodes()?.[0]; const current = designer?.currentSelection?.getNodes()?.[0];
let node: Node | null = settings.first; let node: Node | null = settings.first;
const focusNode = node.document.focusNode; const focusNode = node.document.focusNode;
@ -229,6 +230,7 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any
return ( return (
<div className="lc-settings-main"> <div className="lc-settings-main">
{ this.renderBreadcrumb() }
<Tab <Tab
activeKey={activeKey} activeKey={activeKey}
onChange={(tabKey) => { onChange={(tabKey) => {
@ -238,7 +240,6 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any
animation={false} animation={false}
excessMode="dropdown" excessMode="dropdown"
contentClassName="lc-settings-tabs-content" contentClassName="lc-settings-tabs-content"
extra={this.renderBreadcrumb()}
> >
{tabs} {tabs}
</Tab> </Tab>

View File

@ -157,10 +157,6 @@ export class DraggableLineView extends Component<{ panel: Panel }> {
@observer @observer
export class TitledPanelView extends Component<{ panel: Panel; area?: string }> { export class TitledPanelView extends Component<{ panel: Panel; area?: string }> {
shouldComponentUpdate() {
return false;
}
componentDidMount() { componentDidMount() {
this.checkVisible(); this.checkVisible();
} }
@ -218,10 +214,6 @@ export class PanelView extends Component<{
hideOperationRow?: boolean; hideOperationRow?: boolean;
hideDragLine?: boolean; hideDragLine?: boolean;
}> { }> {
shouldComponentUpdate() {
return false;
}
componentDidMount() { componentDidMount() {
this.checkVisible(); this.checkVisible();
} }
@ -333,10 +325,6 @@ class PanelTitle extends Component<{ panel: Panel; className?: string }> {
@observer @observer
export class WidgetView extends Component<{ widget: IWidget }> { export class WidgetView extends Component<{ widget: IWidget }> {
shouldComponentUpdate() {
return false;
}
componentDidMount() { componentDidMount() {
this.checkVisible(); this.checkVisible();
this.checkDisabled(); this.checkDisabled();

View File

@ -1,11 +1,17 @@
import { Component, Fragment } from 'react'; import { Component, Fragment } from 'react';
import { Button, Icon } from '@alifd/next'; import { Button, Icon } from '@alifd/next';
import { action, makeObservable } from '@ali/lowcode-editor-core';
import { IconFix } from '../../icons/fix'; import { IconFix } from '../../icons/fix';
import { IconFloat } from '../../icons/float'; import { IconFloat } from '../../icons/float';
import Panel from '../../widget/panel'; import Panel from '../../widget/panel';
export default class PanelOperationRow extends Component<{ panel: Panel }> { export default class PanelOperationRow extends Component<{ panel: Panel }> {
constructor(props) {
super(props);
makeObservable(this);
}
// fix or float // fix or float
@action
setDisplay() { setDisplay() {
const { panel } = this.props; const { panel } = this.props;
const current = panel; const current = panel;

View File

@ -6,10 +6,6 @@ import Panel from '../widget/panel';
@observer @observer
export default class BottomArea extends Component<{ area: Area<any, Panel> }> { export default class BottomArea extends Component<{ area: Area<any, Panel> }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { area } = this.props; const { area } = this.props;
if (area.isEmpty()) { if (area.isEmpty()) {

View File

@ -25,7 +25,7 @@ class Contents extends Component<{ area: Area }> {
const { area } = this.props; const { area } = this.props;
const top: any[] = []; const top: any[] = [];
const bottom: any[] = []; const bottom: any[] = [];
area.container.items.sort((a, b) => { area.container.items.slice().sort((a, b) => {
const index1 = a.config?.index || 0; const index1 = a.config?.index || 0;
const index2 = b.config?.index || 0; const index2 = b.config?.index || 0;
return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);

View File

@ -4,17 +4,12 @@ import { observer } from '@ali/lowcode-editor-core';
import Area from '../area'; import Area from '../area';
import { PanelConfig } from '../types'; import { PanelConfig } from '../types';
import Panel from '../widget/panel'; import Panel from '../widget/panel';
import { Designer } from '@ali/lowcode-designer';
@observer @observer
export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> { export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> {
shouldComponentUpdate() {
return false;
}
componentDidUpdate() { componentDidUpdate() {
// FIXME: dirty fix, need deep think // FIXME: dirty fix, need deep think
this.props.area.skeleton.editor.get(Designer)?.touchOffsetObserver(); this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver();
} }
@ -42,10 +37,6 @@ export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, P
@observer @observer
class Contents extends Component<{ area: Area<PanelConfig, Panel> }> { class Contents extends Component<{ area: Area<PanelConfig, Panel> }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { area } = this.props; const { area } = this.props;
return <Fragment>{area.container.items.map((panel) => panel.content)}</Fragment>; return <Fragment>{area.container.items.map((panel) => panel.content)}</Fragment>;

View File

@ -6,11 +6,6 @@ import Panel from '../widget/panel';
@observer @observer
export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> { export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> {
shouldComponentUpdate() {
return false;
}
private dispose?: () => void; private dispose?: () => void;
private focusing?: Focusable; private focusing?: Focusable;
@ -118,10 +113,6 @@ export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }>
@observer @observer
class Contents extends Component<{ area: Area<any, Panel> }> { class Contents extends Component<{ area: Area<any, Panel> }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { area } = this.props; const { area } = this.props;
return ( return (

View File

@ -7,10 +7,6 @@ import Widget from '../widget/widget';
@observer @observer
export default class MainArea extends Component<{ area: Area<any, Panel | Widget> }> { export default class MainArea extends Component<{ area: Area<any, Panel | Widget> }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { area } = this.props; const { area } = this.props;
return ( return (

View File

@ -6,10 +6,6 @@ import Panel from '../widget/panel';
@observer @observer
export default class RightArea extends Component<{ area: Area<any, Panel> }> { export default class RightArea extends Component<{ area: Area<any, Panel> }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { area } = this.props; const { area } = this.props;
return ( return (

View File

@ -25,7 +25,7 @@ class Contents extends Component<{ area: Area, itemClassName?: string }> {
const left: any[] = []; const left: any[] = [];
const center: any[] = []; const center: any[] = [];
const right: any[] = []; const right: any[] = [];
area.container.items.sort((a, b) => { area.container.items.slice().sort((a, b) => {
const index1 = a.config?.index || 0; const index1 = a.config?.index || 0;
const index2 = b.config?.index || 0; const index2 = b.config?.index || 0;
return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);

View File

@ -22,10 +22,6 @@ export class Workbench extends Component<{ skeleton: Skeleton; config?: EditorCo
skeleton.buildFromConfig(config, components); skeleton.buildFromConfig(config, components);
} }
shouldComponentUpdate() {
return false;
}
// componentDidCatch(error: any) { // componentDidCatch(error: any) {
// globalContext.get(Editor).emit('editor.skeleton.workbench.error', error); // globalContext.get(Editor).emit('editor.skeleton.workbench.error', error);
// } // }

View File

@ -1,5 +1,5 @@
import { ReactNode, createElement } from 'react'; import { ReactNode, createElement } from 'react';
import { obx } from '@ali/lowcode-editor-core'; import { makeObservable, obx } from '@ali/lowcode-editor-core';
import { uniqueId, createContent } from '@ali/lowcode-utils'; import { uniqueId, createContent } from '@ali/lowcode-utils';
import { DockConfig } from '../types'; import { DockConfig } from '../types';
import { Skeleton } from '../skeleton'; import { Skeleton } from '../skeleton';
@ -59,6 +59,7 @@ export default class Dock implements IWidget {
} }
constructor(readonly skeleton: Skeleton, readonly config: DockConfig) { constructor(readonly skeleton: Skeleton, readonly config: DockConfig) {
makeObservable(this);
const { props = {}, name } = config; const { props = {}, name } = config;
this.name = name; this.name = name;
this.align = props.align; this.align = props.align;

View File

@ -1,4 +1,4 @@
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable } from '@ali/lowcode-editor-core';
import { uniqueId } from '@ali/lowcode-utils'; import { uniqueId } from '@ali/lowcode-utils';
import { createElement, ReactNode, ReactInstance } from 'react'; import { createElement, ReactNode, ReactInstance } from 'react';
import { Skeleton } from '../skeleton'; import { Skeleton } from '../skeleton';
@ -77,6 +77,7 @@ export default class PanelDock implements IWidget {
} }
constructor(readonly skeleton: Skeleton, readonly config: PanelDockConfig) { constructor(readonly skeleton: Skeleton, readonly config: PanelDockConfig) {
makeObservable(this);
const { content, contentProps, panelProps, name, props } = config; const { content, contentProps, panelProps, name, props } = config;
this.name = name; this.name = name;
this.id = uniqueId(`dock:${name}$`); this.id = uniqueId(`dock:${name}$`);

View File

@ -1,6 +1,6 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { createElement, ReactNode } from 'react'; import { createElement, ReactNode } from 'react';
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable } from '@ali/lowcode-editor-core';
import { uniqueId, createContent } from '@ali/lowcode-utils'; import { uniqueId, createContent } from '@ali/lowcode-utils';
import { TitleContent } from '@ali/lowcode-types'; import { TitleContent } from '@ali/lowcode-types';
import WidgetContainer from './widget-container'; import WidgetContainer from './widget-container';
@ -24,7 +24,7 @@ export default class Panel implements IWidget {
private emitter = new EventEmitter(); private emitter = new EventEmitter();
get actived(): boolean { @computed get actived(): boolean {
return this._actived; return this._actived;
} }
@ -81,6 +81,7 @@ export default class Panel implements IWidget {
private parent?: WidgetContainer; private parent?: WidgetContainer;
constructor(readonly skeleton: Skeleton, readonly config: PanelConfig) { constructor(readonly skeleton: Skeleton, readonly config: PanelConfig) {
makeObservable(this);
const { name, content, props = {} } = config; const { name, content, props = {} } = config;
const { hideTitleBar, title, icon, description, help } = props; const { hideTitleBar, title, icon, description, help } = props;
this.name = name; this.name = name;
@ -160,13 +161,13 @@ export default class Panel implements IWidget {
return; return;
} }
if (flag) { if (flag) {
this._actived = true;
this.parent?.active(this);
if (this.parent.name === 'leftFloatArea') { if (this.parent.name === 'leftFloatArea') {
this.skeleton.leftFixedArea.container.unactiveAll(); this.skeleton.leftFixedArea.container.unactiveAll();
} else if (this.parent.name === 'leftFixedArea') { } else if (this.parent.name === 'leftFixedArea') {
this.skeleton.leftFloatArea.container.unactiveAll(); this.skeleton.leftFloatArea.container.unactiveAll();
} }
this._actived = true;
this.parent?.active(this);
if (!this.inited) { if (!this.inited) {
this.inited = true; this.inited = true;
} }

View File

@ -1,6 +1,6 @@
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, makeObservable } from '@ali/lowcode-editor-core';
import { isPanel } from './panel';
import { hasOwnProperty } from '@ali/lowcode-utils'; import { hasOwnProperty } from '@ali/lowcode-utils';
import { isPanel } from './panel';
export interface WidgetItem { export interface WidgetItem {
name: string; name: string;
@ -15,7 +15,7 @@ function isActiveable(obj: any): obj is Activeable {
} }
export default class WidgetContainer<T extends WidgetItem = any, G extends WidgetItem = any> { export default class WidgetContainer<T extends WidgetItem = any, G extends WidgetItem = any> {
@obx.val items: T[] = []; @obx.shallow items: T[] = [];
private maps: { [name: string]: T } = {}; private maps: { [name: string]: T } = {};
@ -32,8 +32,9 @@ export default class WidgetContainer<T extends WidgetItem = any, G extends Widge
private exclusive: boolean = false, private exclusive: boolean = false,
private checkVisible: () => boolean = () => true, private checkVisible: () => boolean = () => true,
private defaultSetCurrent: boolean = false, private defaultSetCurrent: boolean = false,
// eslint-disable-next-line no-empty-function ) {
) {} makeObservable(this);
}
@computed get visible() { @computed get visible() {
return this.checkVisible(); return this.checkVisible();

View File

@ -1,5 +1,5 @@
import { ReactNode, createElement } from 'react'; import { ReactNode, createElement } from 'react';
import { obx } from '@ali/lowcode-editor-core'; import { makeObservable, obx } from '@ali/lowcode-editor-core';
import { createContent, uniqueId } from '@ali/lowcode-utils'; import { createContent, uniqueId } from '@ali/lowcode-utils';
import { WidgetConfig, IWidgetBaseConfig } from '../types'; import { WidgetConfig, IWidgetBaseConfig } from '../types';
import { Skeleton } from '../skeleton'; import { Skeleton } from '../skeleton';
@ -71,6 +71,7 @@ export default class Widget implements IWidget {
readonly title: TitleContent; readonly title: TitleContent;
constructor(readonly skeleton: Skeleton, readonly config: WidgetConfig) { constructor(readonly skeleton: Skeleton, readonly config: WidgetConfig) {
makeObservable(this);
const { props = {}, name } = config; const { props = {}, name } = config;
this.name = name; this.name = name;
this.align = props.align; this.align = props.align;

View File

@ -1,4 +1,4 @@
import { computed, obx } from '@ali/lowcode-editor-core'; import { computed, makeObservable, obx } from '@ali/lowcode-editor-core';
import { import {
Designer, Designer,
ISensor, ISensor,
@ -17,12 +17,12 @@ import {
contains, contains,
Node, Node,
} from '@ali/lowcode-designer'; } from '@ali/lowcode-designer';
import { uniqueId } from '@ali/lowcode-utils';
import { IEditor } from '@ali/lowcode-types';
import TreeNode from './tree-node'; import TreeNode from './tree-node';
import { IndentTrack } from './helper/indent-track'; import { IndentTrack } from './helper/indent-track';
import DwellTimer from './helper/dwell-timer'; import DwellTimer from './helper/dwell-timer';
import { uniqueId } from '@ali/lowcode-utils';
import { Backup } from './views/backup-pane'; import { Backup } from './views/backup-pane';
import { IEditor } from '@ali/lowcode-types';
import { ITreeBoard, TreeMaster, getTreeMaster } from './tree-master'; import { ITreeBoard, TreeMaster, getTreeMaster } from './tree-master';
export class OutlineMain implements ISensor, ITreeBoard, IScrollable { export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
@ -51,6 +51,7 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
readonly at: string | symbol; readonly at: string | symbol;
constructor(editor: IEditor, at: string | symbol) { constructor(editor: IEditor, at: string | symbol) {
makeObservable(this);
this.editor = editor; this.editor = editor;
this.at = at; this.at = at;
let inited = false; let inited = false;

View File

@ -1,4 +1,4 @@
import { computed, obx } from '@ali/lowcode-editor-core'; import { computed, makeObservable, obx } from '@ali/lowcode-editor-core';
import { Designer, isLocationChildrenDetail } from '@ali/lowcode-designer'; import { Designer, isLocationChildrenDetail } from '@ali/lowcode-designer';
import TreeNode from './tree-node'; import TreeNode from './tree-node';
import { Tree } from './tree'; import { Tree } from './tree';
@ -14,6 +14,7 @@ export class TreeMaster {
readonly designer: Designer; readonly designer: Designer;
constructor(designer: Designer) { constructor(designer: Designer) {
makeObservable(this);
this.designer = designer; this.designer = designer;
let startTime: any; let startTime: any;
designer.dragon.onDragstart(() => { designer.dragon.onDragstart(() => {
@ -71,7 +72,7 @@ export class TreeMaster {
} }
} }
@obx.val private boards = new Set<ITreeBoard>(); @obx.shallow private boards = new Set<ITreeBoard>();
addBoard(board: ITreeBoard) { addBoard(board: ITreeBoard) {
this.boards.add(board); this.boards.add(board);
@ -81,7 +82,7 @@ export class TreeMaster {
this.boards.delete(board); this.boards.delete(board);
} }
@computed hasVisibleTreeBoard() { hasVisibleTreeBoard() {
for (const item of this.boards) { for (const item of this.boards) {
if (item.visible && item.at !== Backup) { if (item.visible && item.at !== Backup) {
return true; return true;

View File

@ -1,5 +1,5 @@
import { TitleContent, isI18nData } from '@ali/lowcode-types'; import { TitleContent, isI18nData } from '@ali/lowcode-types';
import { computed, obx, intl } from '@ali/lowcode-editor-core'; import { computed, obx, intl, makeObservable } from '@ali/lowcode-editor-core';
import { Node, DocumentModel, isLocationChildrenDetail, LocationChildrenDetail, Designer } from '@ali/lowcode-designer'; import { Node, DocumentModel, isLocationChildrenDetail, LocationChildrenDetail, Designer } from '@ali/lowcode-designer';
import { Tree } from './tree'; import { Tree } from './tree';
@ -35,7 +35,7 @@ export default class TreeNode {
/** /**
* *
*/ */
@computed isResponseDropping(): boolean { isResponseDropping(): boolean {
const loc = this.node.document.dropLocation; const loc = this.node.document.dropLocation;
if (!loc) { if (!loc) {
return false; return false;
@ -43,7 +43,7 @@ export default class TreeNode {
return loc.target === this.node; return loc.target === this.node;
} }
@computed isFocusingNode(): boolean { isFocusingNode(): boolean {
const loc = this.node.document.dropLocation; const loc = this.node.document.dropLocation;
if (!loc) { if (!loc) {
return false; return false;
@ -218,6 +218,7 @@ export default class TreeNode {
readonly tree: Tree; readonly tree: Tree;
constructor(tree: Tree, node: Node) { constructor(tree: Tree, node: Node) {
makeObservable(this);
this.tree = tree; this.tree = tree;
this.document = node.document; this.document = node.document;
this.designer = this.document.designer; this.designer = this.document.designer;

View File

@ -1,5 +1,5 @@
import { DocumentModel, Node } from '@ali/lowcode-designer'; import { DocumentModel, Node } from '@ali/lowcode-designer';
import { computed } from '@ali/lowcode-editor-core'; import { computed, makeObservable } from '@ali/lowcode-editor-core';
import TreeNode from './tree-node'; import TreeNode from './tree-node';
export class Tree { export class Tree {
@ -15,6 +15,7 @@ export class Tree {
} }
constructor(readonly document: DocumentModel) { constructor(readonly document: DocumentModel) {
makeObservable(this);
this.id = document.id; this.id = document.id;
} }

View File

@ -10,10 +10,6 @@ import { IEditor } from '@ali/lowcode-types';
export class OutlinePane extends Component<{ config: any; editor: IEditor }> { export class OutlinePane extends Component<{ config: any; editor: IEditor }> {
private main = new OutlineMain(this.props.editor, this.props.config.name || this.props.config.pluginKey); private main = new OutlineMain(this.props.editor, this.props.config.name || this.props.config.pluginKey);
shouldComponentUpdate() {
return false;
}
componentWillUnmount() { componentWillUnmount() {
this.main.purge(); this.main.purge();
} }

View File

@ -18,10 +18,6 @@ class ModalTreeNodeView extends Component<{ treeNode: TreeNode }> {
this.modalNodesManager = props.treeNode.document.modalNodesManager; this.modalNodesManager = props.treeNode.document.modalNodesManager;
} }
shouldComponentUpdate() {
return false;
}
hideAllNodes() { hideAllNodes() {
this.modalNodesManager.hideModalNodes(); this.modalNodesManager.hideModalNodes();
} }
@ -57,10 +53,6 @@ class ModalTreeNodeView extends Component<{ treeNode: TreeNode }> {
@observer @observer
export default class RootTreeNodeView extends Component<{ treeNode: TreeNode }> { export default class RootTreeNodeView extends Component<{ treeNode: TreeNode }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { treeNode } = this.props; const { treeNode } = this.props;
const className = classNames('tree-node', { const className = classNames('tree-node', {

View File

@ -11,10 +11,6 @@ export default class TreeBranches extends Component<{
treeNode: TreeNode; treeNode: TreeNode;
isModal?: boolean; isModal?: boolean;
}> { }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { treeNode, isModal } = this.props; const { treeNode, isModal } = this.props;
const { expanded } = treeNode; const { expanded } = treeNode;
@ -39,10 +35,6 @@ class TreeNodeChildren extends Component<{
treeNode: TreeNode; treeNode: TreeNode;
isModal?: boolean; isModal?: boolean;
}> { }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { treeNode, isModal } = this.props; const { treeNode, isModal } = this.props;
const children: any = []; const children: any = [];
@ -112,10 +104,6 @@ class TreeNodeChildren extends Component<{
class TreeNodeSlots extends Component<{ class TreeNodeSlots extends Component<{
treeNode: TreeNode; treeNode: TreeNode;
}> { }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { treeNode } = this.props; const { treeNode } = this.props;
if (!treeNode.hasSlots()) { if (!treeNode.hasSlots()) {

View File

@ -10,10 +10,6 @@ export default class TreeNodeView extends Component<{
treeNode: TreeNode; treeNode: TreeNode;
isModal?: boolean; isModal?: boolean;
}> { }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { treeNode, isModal } = this.props; const { treeNode, isModal } = this.props;
const className = classNames('tree-node', { const className = classNames('tree-node', {

View File

@ -176,10 +176,6 @@ export default class TreeTitle extends Component<{
@observer @observer
class LockBtn extends Component<{ treeNode: TreeNode }> { class LockBtn extends Component<{ treeNode: TreeNode }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { treeNode } = this.props; const { treeNode } = this.props;
return ( return (
@ -199,10 +195,6 @@ class LockBtn extends Component<{ treeNode: TreeNode }> {
@observer @observer
class HideBtn extends Component<{ treeNode: TreeNode }> { class HideBtn extends Component<{ treeNode: TreeNode }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { treeNode } = this.props; const { treeNode } = this.props;
return ( return (
@ -224,10 +216,6 @@ class HideBtn extends Component<{ treeNode: TreeNode }> {
@observer @observer
class ExpandBtn extends Component<{ treeNode: TreeNode }> { class ExpandBtn extends Component<{ treeNode: TreeNode }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { treeNode } = this.props; const { treeNode } = this.props;
if (!treeNode.expandable) { if (!treeNode.expandable) {

View File

@ -17,7 +17,8 @@
"@ali/lowcode-utils": "1.0.66", "@ali/lowcode-utils": "1.0.66",
"@ali/recore-rax": "^1.2.4", "@ali/recore-rax": "^1.2.4",
"@ali/vu-css-style": "^1.0.2", "@ali/vu-css-style": "^1.0.2",
"@recore/obx": "^1.0.8", "mobx": "^6.3.0",
"mobx-react": "^7.2.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"driver-universal": "^3.1.3", "driver-universal": "^3.1.3",
"history": "^5.0.0", "history": "^5.0.0",
@ -30,7 +31,6 @@
"devDependencies": { "devDependencies": {
"@alib/build-scripts": "^0.1.18", "@alib/build-scripts": "^0.1.18",
"@babel/plugin-transform-react-jsx": "^7.10.4", "@babel/plugin-transform-react-jsx": "^7.10.4",
"@recore/obx": "^1.0.8",
"@types/classnames": "^2.2.7", "@types/classnames": "^2.2.7",
"@types/node": "^13.7.1", "@types/node": "^13.7.1",
"@types/rax": "^1.0.0", "@types/rax": "^1.0.0",

View File

@ -2,7 +2,7 @@ import { BuiltinSimulatorRenderer, Component, DocumentModel, Node, NodeInstance
import { ComponentSchema, NodeSchema, NpmInfo, RootSchema, TransformStage } from '@ali/lowcode-types'; import { ComponentSchema, NodeSchema, NpmInfo, RootSchema, TransformStage } from '@ali/lowcode-types';
import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isPlainObject, isReactComponent, setNativeSelection } from '@ali/lowcode-utils'; import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isPlainObject, isReactComponent, setNativeSelection } from '@ali/lowcode-utils';
import LowCodeRenderer from '@ali/lowcode-rax-renderer'; import LowCodeRenderer from '@ali/lowcode-rax-renderer';
import { computed, obx } from '@recore/obx'; import { computed, observable as obx, untracked, makeObservable, configure } from 'mobx';
import DriverUniversal from 'driver-universal'; import DriverUniversal from 'driver-universal';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { createMemoryHistory, MemoryHistory } from 'history'; import { createMemoryHistory, MemoryHistory } from 'history';
@ -17,6 +17,7 @@ import { getClientRects } from './utils/get-client-rects';
import loader from './utils/loader'; import loader from './utils/loader';
import { parseQuery, withQueryParams } from './utils/url'; import { parseQuery, withQueryParams } from './utils/url';
configure({ enforceActions: 'never' });
const { Instance } = shared; const { Instance } = shared;
export interface LibraryMap { export interface LibraryMap {
@ -110,6 +111,7 @@ export class DocumentInstance {
private dispose?: () => void; private dispose?: () => void;
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
makeObservable(this);
this.dispose = host.autorun(() => { this.dispose = host.autorun(() => {
// sync schema // sync schema
this._schema = document.export(TransformStage.Render); this._schema = document.export(TransformStage.Render);
@ -270,7 +272,8 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
}); });
const documentInstanceMap = new Map<string, DocumentInstance>(); const documentInstanceMap = new Map<string, DocumentInstance>();
let initialEntry = '/'; let initialEntry = '/';
host.autorun(({ firstRun }) => { let firstRun = true;
host.autorun(() => {
this._documentInstances = host.project.documents.map((doc) => { this._documentInstances = host.project.documents.map((doc) => {
let inst = documentInstanceMap.get(doc.id); let inst = documentInstanceMap.get(doc.id);
if (!inst) { if (!inst) {
@ -283,6 +286,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
const path = host.project.currentDocument ? documentInstanceMap.get(host.project.currentDocument.id)!.path : '/'; const path = host.project.currentDocument ? documentInstanceMap.get(host.project.currentDocument.id)!.path : '/';
if (firstRun) { if (firstRun) {
initialEntry = path; initialEntry = path;
firstRun = false;
} else { } else {
if (this.history.location.pathname !== path) { if (this.history.location.pathname !== path) {
this.history.replace(path); this.history.replace(path);

View File

@ -22,7 +22,9 @@
"@recore/obx-react": "^1.0.7", "@recore/obx-react": "^1.0.7",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"react": "^16", "react": "^16",
"react-dom": "^16.7.0" "react-dom": "^16.7.0",
"mobx": "^6.3.0",
"mobx-react": "^7.2.0"
}, },
"devDependencies": { "devDependencies": {
"@alib/build-scripts": "^0.1.18", "@alib/build-scripts": "^0.1.18",

View File

@ -1,3 +1,4 @@
import { runInAction } from 'mobx';
import renderer from './renderer'; import renderer from './renderer';
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
@ -5,10 +6,12 @@ if (typeof window !== 'undefined') {
} }
window.addEventListener('beforeunload', () => { window.addEventListener('beforeunload', () => {
runInAction(() => {
(window as any).LCSimulatorHost = null; (window as any).LCSimulatorHost = null;
renderer.dispose?.(); renderer.dispose?.();
(window as any).SimulatorRenderer = null; (window as any).SimulatorRenderer = null;
(window as any).ReactDOM.unmountComponentAtNode(document.getElementById('app')); (window as any).ReactDOM.unmountComponentAtNode(document.getElementById('app'));
});
}); });
export default renderer; export default renderer;

View File

@ -3,7 +3,7 @@ import { Router, Route, Switch } from 'react-router';
import cn from 'classnames'; import cn from 'classnames';
import { Node } from '@ali/lowcode-designer'; import { Node } from '@ali/lowcode-designer';
import LowCodeRenderer from '@ali/lowcode-react-renderer'; import LowCodeRenderer from '@ali/lowcode-react-renderer';
import { observer } from '@recore/obx-react'; import { observer } from 'mobx-react';
import { isFromVC, getClosestNode } from '@ali/lowcode-utils'; import { isFromVC, getClosestNode } from '@ali/lowcode-utils';
import { SimulatorRendererContainer, DocumentInstance } from './renderer'; import { SimulatorRendererContainer, DocumentInstance } from './renderer';
@ -99,10 +99,6 @@ function getDeviceView(view: any, device: string, mode: string) {
@observer @observer
class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> { class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { rendererContainer, children } = this.props; const { rendererContainer, children } = this.props;
const { layout } = rendererContainer; const { layout } = rendererContainer;
@ -133,10 +129,6 @@ class Renderer extends Component<{
rendererContainer: SimulatorRendererContainer, rendererContainer: SimulatorRendererContainer,
documentInstance: DocumentInstance, documentInstance: DocumentInstance,
}> { }> {
shouldComponentUpdate() {
return false;
}
render() { render() {
const { documentInstance, rendererContainer: renderer } = this.props; const { documentInstance, rendererContainer: renderer } = this.props;
const { container } = documentInstance; const { container } = documentInstance;

View File

@ -2,7 +2,7 @@ import React, { createElement, ReactInstance } from 'react';
import { render as reactRender } from 'react-dom'; import { render as reactRender } from 'react-dom';
import { host } from './host'; import { host } from './host';
import SimulatorRendererView from './renderer-view'; import SimulatorRendererView from './renderer-view';
import { computed, obx, untracked } from '@recore/obx'; import { computed, observable as obx, untracked, makeObservable, configure } from 'mobx';
import { getClientRects } from './utils/get-client-rects'; import { getClientRects } from './utils/get-client-rects';
import { reactFindDOMNodes, FIBER_KEY } from './utils/react-find-dom-nodes'; import { reactFindDOMNodes, FIBER_KEY } from './utils/react-find-dom-nodes';
import { import {
@ -28,7 +28,10 @@ import Leaf from './builtin-components/leaf';
import { withQueryParams, parseQuery } from './utils/url'; import { withQueryParams, parseQuery } from './utils/url';
import { supportsQuickPropSetting, getUppermostPropKey, setInstancesProp } from './utils/misc'; import { supportsQuickPropSetting, getUppermostPropKey, setInstancesProp } from './utils/misc';
const loader = new AssetLoader(); const loader = new AssetLoader();
const DELAY_THRESHOLD = 10;
const FULL_RENDER_THRESHOLD = 500; const FULL_RENDER_THRESHOLD = 500;
configure({ enforceActions: 'never' });
export class DocumentInstance { export class DocumentInstance {
public instancesMap = new Map<string, ReactInstance[]>(); public instancesMap = new Map<string, ReactInstance[]>();
@ -40,9 +43,18 @@ export class DocumentInstance {
private disposeFunctions: Array<() => void> = []; private disposeFunctions: Array<() => void> = [];
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
const documentExportDisposer = host.autorun(() => { makeObservable(this);
this._schema = document.export(TransformStage.Render); // 标识当前文档导出的状态,用来控制 reaction effect 是否执行
}); let asleep = false;
const setDocSchema = (value?: any) => {
this._schema = value || document.export(TransformStage.Render);
};
const documentExportDisposer = host.reaction(() => {
return document.export(TransformStage.Render);
}, (value) => {
if (asleep) return;
setDocSchema(value);
}, { delay: DELAY_THRESHOLD, fireImmediately: true });
this.disposeFunctions.push(documentExportDisposer); this.disposeFunctions.push(documentExportDisposer);
let tid: NodeJS.Timeout; let tid: NodeJS.Timeout;
this.disposeFunctions.push(host.onActivityEvent((data: ActivityData, ctx: any) => { this.disposeFunctions.push(host.onActivityEvent((data: ActivityData, ctx: any) => {
@ -53,7 +65,7 @@ export class DocumentInstance {
if (tid) clearTimeout(tid); if (tid) clearTimeout(tid);
// 临时关闭全量计算 schema 的逻辑,在增量计算结束后,来一次全量计算 // 临时关闭全量计算 schema 的逻辑,在增量计算结束后,来一次全量计算
documentExportDisposer.$obx.sleep(); asleep = true;
if (data.type === ActivityType.MODIFIED) { if (data.type === ActivityType.MODIFIED) {
// 对于修改场景,优先判断是否能走「快捷设置」逻辑 // 对于修改场景,优先判断是否能走「快捷设置」逻辑
if (supportsQuickPropSetting(data, this)) { if (supportsQuickPropSetting(data, this)) {
@ -69,7 +81,10 @@ export class DocumentInstance {
// FIXME: 待补充逻辑 // FIXME: 待补充逻辑
} }
tid = setTimeout(() => documentExportDisposer.$obx.wakeup(true), FULL_RENDER_THRESHOLD); tid = setTimeout(() => {
asleep = false;
setDocSchema();
}, FULL_RENDER_THRESHOLD);
// TODO: 调试增量模式,打开以下代码 // TODO: 调试增量模式,打开以下代码
// this._deltaData = data; // this._deltaData = data;
// this._deltaMode = true; // this._deltaMode = true;
@ -246,6 +261,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
} }
constructor() { constructor() {
makeObservable(this);
this.autoRender = host.autoRender; this.autoRender = host.autoRender;
this.disposeFunctions.push(host.connect(this, () => { this.disposeFunctions.push(host.connect(this, () => {
@ -272,7 +288,8 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
})); }));
const documentInstanceMap = new Map<string, DocumentInstance>(); const documentInstanceMap = new Map<string, DocumentInstance>();
let initialEntry = '/'; let initialEntry = '/';
this.disposeFunctions.push(host.autorun(({ firstRun }) => { let firstRun = true;
this.disposeFunctions.push(host.autorun(() => {
this._documentInstances = host.project.documents.map((doc) => { this._documentInstances = host.project.documents.map((doc) => {
let inst = documentInstanceMap.get(doc.id); let inst = documentInstanceMap.get(doc.id);
if (!inst) { if (!inst) {
@ -286,6 +303,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
: '/'; : '/';
if (firstRun) { if (firstRun) {
initialEntry = path; initialEntry = path;
firstRun = false;
} else if (this.history.location.pathname !== path) { } else if (this.history.location.pathname !== path) {
this.history.replace(path); this.history.replace(path);
} }

View File

@ -9,7 +9,7 @@ interface ILiteralObject {
} }
export class Env { export class Env {
@obx.val envs: ILiteralObject = {}; @obx.shallow envs: ILiteralObject = {};
private emitter: EventEmitter; private emitter: EventEmitter;

View File

@ -102,8 +102,8 @@ export class AccordionField extends VEField {
constructor(props: IVEFieldProps) { constructor(props: IVEFieldProps) {
super(props); super(props);
this._generateClassNames(props); this._generateClassNames(props);
if (this.props.onExpandChange) { if (props.onExpandChange) {
this.willDetach = this.props.onExpandChange(() => this.forceUpdate()); this.willDetach = props.onExpandChange(() => this.forceUpdate());
} }
} }

View File

@ -18,7 +18,7 @@ class DocItem {
constructor(parent, doc, unInitial) { constructor(parent, doc, unInitial) {
this.parent = parent; this.parent = parent;
const { use, ...strings } = doc; const { use, ...strings } = doc;
this.doc = obx.val({ this.doc = obx({
type: 'i18n', type: 'i18n',
...strings, ...strings,
}); });

View File

@ -6,3 +6,4 @@ export * from './remove-empty-prop-reducer';
export * from './style-reducer'; export * from './style-reducer';
export * from './upgrade-reducer'; export * from './upgrade-reducer';
export * from './node-top-fixed-reducer'; export * from './node-top-fixed-reducer';
export * from './reset-loop-default-value-reducer';

View File

@ -0,0 +1,10 @@
// 讲loop=[]的情况处理成loop=false
export function resetLoopDefaultValueReducer(props: any) {
if (props.loop && Array.isArray(props.loop) && props.loop.length === 0) {
return {
...props,
loop: undefined,
};
}
return props;
}

View File

@ -14,6 +14,7 @@ import {
initNodeReducer, initNodeReducer,
liveLifecycleReducer, liveLifecycleReducer,
nodeTopFixedReducer, nodeTopFixedReducer,
resetLoopDefaultValueReducer,
} from './props-reducers'; } from './props-reducers';
const { LiveEditing, TransformStage } = designerCabin; const { LiveEditing, TransformStage } = designerCabin;
@ -57,3 +58,6 @@ designer.addPropsReducer(removeEmptyPropsReducer, TransformStage.Save);
designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Render); designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Render);
designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Save); designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Save);
// loop的默认值处理
designer.addPropsReducer(resetLoopDefaultValueReducer, TransformStage.Save);

View File

@ -31,9 +31,9 @@
// skip type checking of declaration files // skip type checking of declaration files
"skipLibCheck": true, "skipLibCheck": true,
"baseUrl": "./packages", "baseUrl": "./packages",
"useDefineForClassFields": true,
"paths": { "paths": {
"@ali/lowcode-*": ["./*/src"], "@ali/lowcode-*": ["./*/src"]
"@ali/visualengine": ["./vision-preset/src"]
}, },
"outDir": "lib" "outDir": "lib"
}, },