Merge branch 'fix/jsslot-schema-format' into 'release/0.9.0'

Fix/jsslot schema format



See merge request !898101
This commit is contained in:
康为 2020-07-21 21:18:24 +08:00
commit 20fcfe6b29
19 changed files with 304 additions and 119 deletions

View File

@ -878,7 +878,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
event: e, event: e,
}; };
if (e.dragObject.type === 'node' && e.dragObject.nodes[0].getPrototype().isModal()) { if (e.dragObject.type === 'node' && e.dragObject.nodes[0]?.getPrototype()?.isModal()) {
return this.designer.createLocation({ return this.designer.createLocation({
target: this.document.rootNode, target: this.document.rootNode,
detail: { detail: {

View File

@ -386,6 +386,8 @@ export class Designer {
let meta = this._componentMetasMap.get(key); let meta = this._componentMetasMap.get(key);
if (meta) { if (meta) {
meta.setMetadata(data); meta.setMetadata(data);
this._componentMetasMap.set(key, meta);
} else { } else {
meta = this._lostComponentMetasMap.get(key); meta = this._lostComponentMetasMap.get(key);
@ -426,10 +428,11 @@ export class Designer {
@computed get componentsMap(): { [key: string]: NpmInfo | Component } { @computed get componentsMap(): { [key: string]: NpmInfo | Component } {
const maps: any = {}; const maps: any = {};
this._componentMetasMap.forEach((config, key) => { const designer = this;
designer._componentMetasMap.forEach((config, key) => {
const metaData = config.getMetadata(); const metaData = config.getMetadata();
if (metaData.devMode === 'lowcode') { if (metaData.devMode === 'lowcode') {
maps[key] = this.currentDocument?.simulator?.createComponent(metaData.schema!); maps[key] = metaData.schema;
} else { } else {
const view = metaData.experimental?.view; const view = metaData.experimental?.view;
if (view) { if (view) {

View File

@ -5,6 +5,18 @@ import { SettingEntry } from './setting-entry';
import { computed, obx } from '@ali/lowcode-editor-core'; import { computed, obx } from '@ali/lowcode-editor-core';
import { cloneDeep } from '@ali/lowcode-utils'; import { cloneDeep } from '@ali/lowcode-utils';
function getSettingFieldCollectorKey(parent: SettingEntry, config: FieldConfig) {
let top = parent;
const path = [config.name];
while (top !== parent.top) {
if (top instanceof SettingField && top.type !== 'group') {
path.unshift(top.name);
}
top = top.parent;
}
return path.join('.');
}
export class SettingField extends SettingPropEntry implements SettingEntry { export class SettingField extends SettingPropEntry implements SettingEntry {
readonly isSettingField = true; readonly isSettingField = true;
readonly isRequired: boolean; readonly isRequired: boolean;
@ -51,10 +63,11 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
this._expanded = extraProps?.defaultCollapsed ? false : true; this._expanded = extraProps?.defaultCollapsed ? false : true;
// initial items // initial items
if (this.type === 'group' && items) { if (items && items.length > 0) {
this.initItems(items, settingFieldCollector); this.initItems(items, settingFieldCollector);
} else if (settingFieldCollector && config.name) { }
settingFieldCollector(config.name, this); if (this.type !== 'group' && settingFieldCollector && config.name) {
settingFieldCollector(getSettingFieldCollectorKey(parent, config), this);
} }
// compatiable old config // compatiable old config

View File

@ -79,6 +79,10 @@ export class NodeChildren {
return this.size > 0; return this.size > 0;
} }
@computed length() {
return this.children.length;
}
/** /**
* *
*/ */
@ -94,6 +98,7 @@ export class NodeChildren {
deleted.purge(); deleted.purge();
} }
this.emitter.emit('change'); this.emitter.emit('change');
this.reportModified(node, this.owner, {type: 'remove', removeIndex: i, removeNode: node});
return false; return false;
} }
@ -290,4 +295,17 @@ export class NodeChildren {
// 保证向前兼容性 // 保证向前兼容性
return "Array"; return "Array";
} }
private reportModified(node: Node, owner: Node, options = {}) {
if (!node) { return; }
if (node.isRoot()) { return; }
const callbacks = owner.componentMeta.getMetadata().experimental?.callbacks;
if (callbacks?.onSubtreeModified) {
callbacks?.onSubtreeModified.call(node, owner, options);
}
if (owner.parent && !owner.parent.isRoot()) {
this.reportModified(node, owner.parent, options);
}
}
} }

View File

@ -634,6 +634,14 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this._slots.push(slotNode); this._slots.push(slotNode);
} }
/**
*
* @param node
*/
removeChild(node: Node) {
this.children?.delete(node);
}
private purged = false; private purged = false;
/** /**
* *

View File

@ -102,7 +102,7 @@ export class Project {
| string, | string,
): any {} ): any {}
open(doc?: string | DocumentModel | RootSchema): void { open(doc?: string | DocumentModel | RootSchema): DocumentModel {
if (!doc) { if (!doc) {
const got = this.documents.find((item) => item.isBlank()); const got = this.documents.find((item) => item.isBlank());
if (got) { if (got) {

View File

@ -220,6 +220,9 @@ class Prototype {
readonly isPrototype = true; readonly isPrototype = true;
readonly meta: ComponentMeta; readonly meta: ComponentMeta;
readonly options: OldPrototypeConfig | ComponentMetadata; readonly options: OldPrototypeConfig | ComponentMetadata;
get packageName() {
return this.meta.npm?.package;
}
constructor(input: OldPrototypeConfig | ComponentMetadata | ComponentMeta, lookup: boolean = false) { constructor(input: OldPrototypeConfig | ComponentMetadata | ComponentMeta, lookup: boolean = false) {
if (lookup) { if (lookup) {
@ -251,7 +254,7 @@ class Prototype {
} }
getPackageName() { getPackageName() {
return this.meta.npm?.package; return this.packageName;
} }
getContextInfo(name: string): any { getContextInfo(name: string): any {

View File

@ -332,6 +332,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
const setterInitial = getInitialFromSetter(setter); const setterInitial = getInitialFromSetter(setter);
if (type !== 'composite') {
collector.addInitial({ collector.addInitial({
// FIXME! name could be "xxx.xxx" // FIXME! name could be "xxx.xxx"
name: slotName || name, name: slotName || name,
@ -352,6 +353,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
return v; return v;
}, },
}); });
}
if (ignore != null || disabled != null) { if (ignore != null || disabled != null) {
collector.addFilter({ collector.addFilter({
@ -431,9 +433,11 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
autorun: item.autorun, autorun: item.autorun,
}); });
}, },
} },
) )
: []; : [];
newConfig.items = objItems;
const initial = (target: SettingTarget, value?: any) => { const initial = (target: SettingTarget, value?: any) => {
// TODO: // TODO:
const defaults = extraProps.defaultValue; const defaults = extraProps.defaultValue;
@ -749,10 +753,7 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
callbacks.onNodeRemove = didDropOut; callbacks.onNodeRemove = didDropOut;
} }
if (subtreeModified) { if (subtreeModified) {
callbacks.onSubtreeModified = (...args: any[]) => { callbacks.onSubtreeModified = subtreeModified;
// FIXME! args not correct
subtreeModified.apply(args[0], args as any);
};
} }
if (onResize) { if (onResize) {
callbacks.onResize = (e: any, currentNode: any) => { callbacks.onResize = (e: any, currentNode: any) => {

View File

@ -85,17 +85,35 @@ designer.addPropsReducer((props, node) => {
const newProps: any = { const newProps: any = {
...props, ...props,
}; };
const getRealValue = (propValue: any) => {
if (isVariable(propValue)) {
return propValue.value;
}
if (isJSExpression(propValue)) {
return propValue.mock;
}
return propValue;
};
initials.forEach((item) => { initials.forEach((item) => {
// FIXME! this implements SettingTarget // FIXME! this implements SettingTarget
try { try {
// FIXME! item.name could be 'xxx.xxx' // FIXME! item.name could be 'xxx.xxx'
const ov = props[item.name]; const ov = props[item.name];
const v = item.initial(node as any, isJSExpression(ov) ? ov.mock : ov); const v = item.initial(node as any, getRealValue(ov));
if (v !== undefined) { if (v !== undefined) {
newProps[item.name] = isJSExpression(ov) ? { if (isVariable(ov)) {
newProps[item.name] = {
...ov,
value: v,
};
} else if (isJSExpression(ov)) {
newProps[item.name] = {
...ov, ...ov,
mock: v, mock: v,
} : v; };
} else {
newProps[item.name] = v;
}
} }
} catch (e) { } catch (e) {
if (hasOwnProperty(props, item.name)) { if (hasOwnProperty(props, item.name)) {
@ -153,6 +171,14 @@ function compatiableReducer(props: any) {
}, },
} }
} }
// 为了能降级到老版本,建议在后期版本去掉以下代码
if (isJSExpression(val) && !val.events) {
val = {
type: 'variable',
value: val.mock,
variable: val.value,
}
}
newProps[key] = val; newProps[key] = val;
}); });
return newProps; return newProps;

View File

@ -34,6 +34,10 @@ export default class Area<C extends IWidgetBaseConfig = any, T extends IWidget =
return this.container.add(config); return this.container.add(config);
} }
remove(config: T | string): number {
return this.container.remove(config);
}
private lastCurrent: T | null = null; private lastCurrent: T | null = null;
setVisible(flag: boolean) { setVisible(flag: boolean) {
if (this.exclusive) { if (this.exclusive) {

View File

@ -0,0 +1,11 @@
import { SVGIcon, IconProps } from "@ali/lowcode-utils";
export function IconFix(props: IconProps) {
return (
<SVGIcon viewBox="0 0 1024 1024" {...props}>
<path d="M750.848 28.928l245.248 242.944a66.048 66.048 0 1 1-93.184 93.184l-25.6-19.456-249.6 353.792 78.336 78.336a66.048 66.048 0 0 1-93.184 92.672l-460.8-464.64a66.048 66.048 0 0 1 93.184-93.184l76.8 78.336 354.048-249.856-18.176-18.944a66.048 66.048 0 1 1 93.184-93.184zM380.672 732.416l-91.904-90.88c-74.24 89.6-191.488 219.904-212.736 247.04a419.84 419.84 0 0 0-70.656 128 419.84 419.84 0 0 0 128-70.144c27.136-21.248 157.44-138.496 246.528-214.016z"></path>
</SVGIcon>
);
}
IconFix.displayName = 'Fix';

View File

@ -0,0 +1,12 @@
import { SVGIcon, IconProps } from "@ali/lowcode-utils";
export function IconFloat(props: IconProps) {
return (
<SVGIcon viewBox="0 0 1024 1024" {...props}>
<path d="M160.256 816.64C116.224 872.448 102.4 921.6 102.4 921.6s49.152-13.824 104.96-57.856c22.016-17.408 128-112.64 200.704-174.08l-73.728-73.728c-61.44 72.704-157.184 178.688-174.08 200.704zM648.704 209.408L442.368 355.328l226.304 226.304 145.92-206.336 15.872 15.872c20.992 20.992 54.784 20.992 75.776 0s20.992-54.784 0-75.776l-197.12-197.12c-20.992-20.992-54.784-20.992-75.776 0-20.992 20.992-20.992 54.784 0 75.776l15.36 15.36zM247.808 334.848c-9.728 2.048-18.944 6.656-26.624 14.336-20.992 20.992-20.992 54.784 0 75.776l377.856 377.856c20.992 20.992 54.784 20.992 75.776 0 7.68-7.68 12.288-16.896 14.336-26.624L247.808 334.848z"></path>
<path d="M840.704 879.104c-9.728 0-19.456-3.584-27.136-11.264L155.648 210.432c-14.848-14.848-14.848-39.424 0-54.272 14.848-14.848 39.424-14.848 54.272 0L867.84 814.08c14.848 14.848 14.848 39.424 0 54.272-7.168 7.168-16.896 10.752-27.136 10.752z"></path>
</SVGIcon>
);
}
IconFloat.displayName = 'Float';

View File

@ -6,16 +6,31 @@ 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'; import { Designer } from '@ali/lowcode-designer';
import { IconFloat } from '../icons/float';
@observer @observer
export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> { export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> {
shouldComponentUpdate() { shouldComponentUpdate() {
return false; 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();
} }
// 取消固定
setFloat() {
const { area } = this.props;
const { current } = area;
if (!current) {
return;
}
area.skeleton.leftFixedArea.remove(current);
area.skeleton.leftFloatArea.add(current);
area.skeleton.leftFloatArea.container.active(current);
}
render() { render() {
const { area } = this.props; const { area } = this.props;
const hideTitleBar = area.current?.config.props?.hideTitleBar; const hideTitleBar = area.current?.config.props?.hideTitleBar;
@ -34,15 +49,24 @@ export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, P
style={style} style={style}
> >
{!hideTitleBar && ( {!hideTitleBar && (
<Fragment>
<Button <Button
text text
className="lc-pane-close" className="lc-pane-icon-float"
onClick={this.setFloat.bind(this)}
>
<IconFloat />
</Button>
<Button
text
className="lc-pane-icon-close"
onClick={() => { onClick={() => {
area.setVisible(false); area.setVisible(false);
}} }}
> >
<Icon type="close" /> <Icon type="close" />
</Button> </Button>
</Fragment>
)} )}
<Contents area={area} /> <Contents area={area} />
</div> </div>

View File

@ -2,6 +2,7 @@ import { Component, Fragment } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { observer, Focusable, focusTracker } from '@ali/lowcode-editor-core'; import { observer, Focusable, focusTracker } from '@ali/lowcode-editor-core';
import { Button, Icon } from '@alifd/next'; import { Button, Icon } from '@alifd/next';
import { IconFix } from '../icons/fix';
import Area from '../area'; import Area from '../area';
import Panel from '../widget/panel'; import Panel from '../widget/panel';
@ -76,6 +77,18 @@ export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }>
this.dispose?.(); this.dispose?.();
} }
// 固定
setFixed() {
const { area } = this.props;
const { current } = area;
if (!current) {
return;
}
area.skeleton.leftFloatArea.remove(current);
area.skeleton.leftFixedArea.add(current);
area.skeleton.leftFixedArea.container.active(current);
}
render() { render() {
const { area } = this.props; const { area } = this.props;
const width = area.current?.config.props?.width; const width = area.current?.config.props?.width;
@ -93,15 +106,24 @@ export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }>
> >
{ {
!hideTitleBar && ( !hideTitleBar && (
<Fragment>
<Button <Button
text text
className="lc-pane-close" className="lc-pane-icon-fix"
onClick={this.setFixed.bind(this)}
>
<IconFix />
</Button>
<Button
text
className="lc-pane-icon-close"
onClick={() => { onClick={() => {
area.setVisible(false); area.setVisible(false);
}} }}
> >
<Icon type="close" /> <Icon type="close" />
</Button> </Button>
</Fragment>
) )
} }
<Contents area={area} /> <Contents area={area} />

View File

@ -175,31 +175,7 @@ body {
display: flex; display: flex;
min-height: 0; min-height: 0;
position: relative; position: relative;
.lc-left-float-pane {
position: absolute;
top: 0;
bottom: 0;
width: var(--dock-pane-width);
min-width: var(--dock-fixed-pane-width);
left: calc(var(--left-area-width) + 1px);
background-color: var(--color-pane-background);
box-shadow: 4px 6px 6px 0 rgba(31,50,88,0.08);
z-index: 820;
display: none;
// padding-top: 36px;
&.lc-area-visible {
display: block;
}
.lc-pane-close{
position: absolute;
right: 16px;
top: 16px;
height: auto;
z-index: 2;
.next-icon{
line-height: 1;
}
}
.lc-tabs-title { .lc-tabs-title {
width: 100%; width: 100%;
height: 32px; height: 32px;
@ -225,6 +201,7 @@ body {
} }
} }
} }
.lc-tabs-content { .lc-tabs-content {
position: absolute; position: absolute;
top: 32px; top: 32px;
@ -232,6 +209,46 @@ body {
left: 0; left: 0;
right: 0; right: 0;
} }
.lc-pane-icon-close {
position: absolute;
right: 16px;
top: 14px;
height: auto;
z-index: 2;
.next-icon{
line-height: 1;
color: rgba(0,0,0,0.6);
}
}
.lc-pane-icon-fix, .lc-pane-icon-float{
position: absolute;
right: 38px;
top: 14px;
height: auto;
z-index: 2;
svg {
vertical-align: middle;
color: rgba(0,0,0,0.6);
}
}
.lc-left-float-pane {
position: absolute;
top: 0;
bottom: 0;
width: var(--dock-pane-width);
min-width: var(--dock-fixed-pane-width);
left: calc(var(--left-area-width) + 1px);
background-color: var(--color-pane-background);
box-shadow: 4px 6px 6px 0 rgba(31,50,88,0.08);
z-index: 820;
display: none;
// padding-top: 36px;
&.lc-area-visible {
display: block;
}
} }
.lc-left-area { .lc-left-area {
height: 100%; height: 100%;
@ -293,16 +310,6 @@ body {
&.lc-area-visible { &.lc-area-visible {
display: block; display: block;
} }
.lc-pane-close {
position: absolute;
right: 16px;
top: 16px;
height: auto;
z-index: 2;
.next-icon {
line-height: 1;
}
}
} }
.lc-left-area.lc-area-visible ~ .lc-left-fixed-pane { .lc-left-area.lc-area-visible ~ .lc-left-fixed-pane {
margin-left: 1px; margin-left: 1px;

View File

@ -71,7 +71,7 @@ class TreeNodeChildren extends Component<{
/> />
); );
treeNode.children?.forEach((child, index) => { treeNode.children?.forEach((child, index) => {
const childIsModal = child.node.getPrototype().isModal(); const childIsModal = child.node.getPrototype()?.isModal() || false;
if (isModal != childIsModal) { if (isModal != childIsModal) {
return; return;
} }

View File

@ -59,7 +59,7 @@ export default class BlockEngine extends BaseEngine {
} }
render() { render() {
const { __schema } = this.props; const { __schema, __components } = this.props;
if (!isSchema(__schema, true) || (__schema.componentName !== 'Block' && __schema.componentName !== 'Div')) { if (!isSchema(__schema, true) || (__schema.componentName !== 'Block' && __schema.componentName !== 'Div')) {
return '区块schema结构异常'; return '区块schema结构异常';
@ -69,7 +69,33 @@ export default class BlockEngine extends BaseEngine {
this.__generateCtx(); this.__generateCtx();
this.__render(); this.__render();
const { id, className, style, autoLoading, defaultHeight = 300, loading } = this.__parseData(__schema.props); const props = this.__parseData(__schema.props);
const { id, className, style, autoLoading, defaultHeight = 300, loading } = props;
const { Block } = __components;
if (Block) {
const { engine } = this.context || {};
return (
<AppContext.Provider
value={{
...this.context,
blockContext: this,
}}
>
{engine.createElement(
Block,
{
...props,
ref: this.__getRef,
className: classnames(getFileCssName(__schema.fileName), className, this.props.className),
__id: __schema.id,
},
this.__createDom(),
)}
</AppContext.Provider>
);
}
const renderContent = () => ( const renderContent = () => (
<AppContext.Provider <AppContext.Provider
value={{ value={{

View File

@ -74,7 +74,7 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
} }
private _libraryMap: { [key: string]: string } = {}; private _libraryMap: { [key: string]: string } = {};
private buildComponents() { private buildComponents() {
this._components = buildComponents(this._libraryMap, this._componentsMap); this._components = buildComponents(this._libraryMap, this._componentsMap, this.createComponent.bind(this));
} }
@obx.ref private _components: any = {}; @obx.ref private _components: any = {};
@computed get components(): object { @computed get components(): object {
@ -247,8 +247,10 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
} }
const _leaf = host.document.designer.currentDocument?.createNode(schema); const _leaf = host.document.designer.currentDocument?.createNode(schema);
const node = host.document.createNode(schema); const node = host.document.createNode(schema);
let props = processPropsSchema(schema.props, propsMap); let { props } = schema;
props = host.document.designer.transformProps(props, node, TransformStage.Init); props = host.document.designer.transformProps(props, node, TransformStage.Init);
props = host.document.designer.transformProps(props, node, TransformStage.Upgrade);
props = processPropsSchema(props, propsMap);
props = host.document.designer.transformProps(props, node, TransformStage.Render); props = host.document.designer.transformProps(props, node, TransformStage.Render);
return createElement(Com, { ...props, _leaf }, children); return createElement(Com, { ...props, _leaf }, children);
}; };
@ -386,16 +388,17 @@ const builtinComponents = {
Leaf, Leaf,
}; };
function buildComponents( function buildComponents(libraryMap: LibraryMap,
libraryMap: LibraryMap, componentsMap: { [componentName: string]: NpmInfo | ComponentType<any> | ComponentSchema },
componentsMap: { [componentName: string]: NpmInfo | ComponentType<any> }, createComponent: (schema: ComponentSchema) => Component | null) {
) {
const components: any = { const components: any = {
...builtinComponents, ...builtinComponents,
}; };
Object.keys(componentsMap).forEach((componentName) => { Object.keys(componentsMap).forEach((componentName) => {
let component = componentsMap[componentName]; let component = componentsMap[componentName];
if (isReactComponent(component)) { if (component && (component as ComponentSchema).componentName === 'Component') {
components[componentName] = createComponent(component as ComponentSchema);
} else if (isReactComponent(component)) {
components[componentName] = component; components[componentName] = component;
} else { } else {
component = findComponent(libraryMap, componentName, component); component = findComponent(libraryMap, componentName, component);

View File

@ -11,6 +11,10 @@ export interface JSExpression {
* *
*/ */
mock?: any; mock?: any;
/**
* extTypeevents
*/
[key: string]: any;
} }
export interface JSSlot { export interface JSSlot {