Merge branch 'polyfill/vision' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into polyfill/vision

This commit is contained in:
mario.gk 2020-05-05 11:54:51 +08:00
commit a0ef20756a
17 changed files with 222 additions and 192 deletions

View File

@ -40,7 +40,8 @@
"@alife/theme-lowcode-dark": "^0.1.0",
"@alife/theme-lowcode-light": "^0.1.0",
"react": "^16.8.1",
"react-dom": "^16.8.1"
"react-dom": "^16.8.1",
"@ali/vu-function-parser": "^2.5.0-beta.0"
},
"devDependencies": {
"@ali/iceluna-cli": "^0.0.16",

View File

@ -1,7 +1,7 @@
/* eslint-disable */
import { createElement } from 'react';
import { Button } from '@alifd/next';
import Engine, { Panes } from '@ali/visualengine';
import Engine, { Panes, Prototype } from '@ali/visualengine';
import { ActionUtil as actionUtil } from '@ali/visualengine-utils';
import getTrunkPane from '@ali/ve-trunk-pane';
import DatapoolPane from '@ali/ve-datapool-pane';
@ -18,6 +18,9 @@ import { upgradeAssetsBundle } from './upgrade-assets';
import { isCSSUrl } from '@ali/lowcode-utils';
import { I18nSetter } from '@ali/visualengine-utils';
import VariableSetter from '@ali/vs-variable-setter';
import { isObject, isArray } from 'lodash';
import funcParser from '@ali/vu-function-parser';
const { editor, skeleton, context, HOOKS, Trunk } = Engine;
@ -324,6 +327,30 @@ function initActionPane() {
props,
});
}
function replaceFuncProp(props?: any){
const replaceProps = {};
for (const name in props) {
const prop = props[name];
if (!prop) {
continue;
}
if ((prop.compiled && prop.source) || prop.type === 'actionRef' || prop.type === 'js') {
replaceProps[name] = funcParser(prop);
} else if (isObject(prop)) {
replaceFuncProp(prop);
} else if (isArray(prop)) {
prop.map((propItem) => {
replaceFuncProp(propItem);
});
}
}
for (const name in replaceProps) {
props[name] = replaceProps[name];
}
return props;
};
// 操作历史与页面历史面板
function initHistoryPane() {
@ -388,6 +415,7 @@ async function init() {
subview: true,
i18nPane: true,
});
Prototype.addGlobalPropsReducer(replaceFuncProp);
await loadAssets();
await loadSchema();
await initTrunkPane();
@ -396,7 +424,6 @@ async function init() {
initActionPane();
initDemoPanes();
initHistoryPane();
Engine.init();
}
init();

View File

@ -9,3 +9,4 @@ declare module '@ali/ve-page-history';
declare module '@ali/ve-i18n-manage-pane';
declare module '@ali/ve-action-pane';
declare module '@ali/vu-legao-design-fetch-context';
declare module "@ali/vu-function-parser";

View File

@ -155,6 +155,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
private transformProps(props: any): any {
// FIXME! support PropsList
return this.document.designer.transformProps(props, this, TransformStage.Init);
// TODO: run transducers in metadata.experimental
}

View File

@ -52,17 +52,17 @@ export class Prop implements IPropParent {
if (type === 'slot') {
const schema = this._slotNode!.export(stage);
if (stage === TransformStage.Save) {
if (stage === TransformStage.Render) {
return {
type: 'JSSlot',
params: schema.params,
value: schema.children,
value: schema,
};
}
return {
type: 'JSSlot',
params: schema.params,
value: schema,
value: schema.children,
};
}

View File

@ -121,16 +121,22 @@ export default class MixedSetter extends Component<{
@computed private getCurrentSetter() {
const { field } = this.props;
let firstMatched: SetterItem | undefined;
let firstDefault: SetterItem | undefined;
for (const setter of this.setters) {
if (setter.name === this.used) {
return setter;
}
const matched = !setter.condition || setter.condition(field);
if (matched && !firstMatched) {
if (!setter.condition) {
if (!firstDefault) {
firstDefault = setter;
}
continue;
}
if (!firstMatched && setter.condition(field)) {
firstMatched = setter;
}
}
return firstMatched;
return firstMatched || firstDefault || this.setters[0];
}
// dirty fix vision variable setter logic
@ -151,14 +157,19 @@ export default class MixedSetter extends Component<{
const setter = this.setters.find((item) => item.name === name);
this.used = name;
if (setter) {
let newValue: any = setter.initialValue;
if (newValue && typeof newValue === 'function') {
newValue = newValue(field);
}
onChange && onChange(newValue);
this.handleInitial(setter);
}
};
private handleInitial({ initialValue }: SetterItem) {
const { field, onChange } = this.props;
let newValue: any = initialValue;
if (newValue && typeof newValue === 'function') {
newValue = newValue(field);
}
onChange && onChange(newValue);
}
private shell: HTMLDivElement | null = null;
private checkIsBlockField() {
if (this.shell) {
@ -207,6 +218,9 @@ export default class MixedSetter extends Component<{
field,
...restProps,
...extraProps,
onInitial: () => {
this.handleInitial(currentSetter);
}
});
}

View File

@ -25,7 +25,7 @@
border-radius: 3px;
}
}
.next-input,.next-date-picker {
.next-input,.next-date-picker,.next-month-picker {
width: 100%;
}
&.lc-block-setter {

View File

@ -20,6 +20,7 @@ class SettingFieldView extends Component<{ field: SettingField }> {
let setterProps: any = {};
let setterType: any;
let initialValue: any = null;
if (Array.isArray(setter)) {
setterType = 'MixedSetter';
setterProps = {
@ -33,6 +34,9 @@ class SettingFieldView extends Component<{ field: SettingField }> {
setterProps = setterProps(field);
}
}
if (setter.initialValue != null) {
initialValue = setter.initialValue;
}
} else if (setter) {
setterType = setter;
}
@ -40,6 +44,9 @@ class SettingFieldView extends Component<{ field: SettingField }> {
if (field.type === 'field') {
if (defaultValue != null && !('defaultValue' in setterProps)) {
setterProps.defaultValue = defaultValue;
if (initialValue == null) {
initialValue = defaultValue;
}
}
if (field.valueState > 0) {
value = field.getValue();
@ -79,6 +86,16 @@ class SettingFieldView extends Component<{ field: SettingField }> {
});
field.setValue(value);
},
onInitial: () => {
if (initialValue == null) {
return;
}
const value = typeof initialValue === 'function' ? initialValue(field) : initialValue;
this.setState({
value,
});
field.setValue(value);
}
}),
extraProps.forceInline ? 'plain' : extraProps.display,
);

View File

@ -0,0 +1,7 @@
.lc-setter-slot {
display: flex;
align-items: center;
.lc-slot-params {
margin-left: 5px;
}
}

View File

@ -0,0 +1,97 @@
import { Component } from 'react';
import { isJSSlot } from '@ali/lowcode-types';
import { Button, Input, Icon } from '@alifd/next';
import './index.less';
export default class SlotSetter extends Component<{
value: any;
onChange?: (value: any) => void;
onInitial?: () => void;
// 是否支持设置入参
supportParams?: boolean;
}> {
private handleInitial = () => {
const { value, onChange, onInitial } = this.props;
if (onInitial) {
onInitial();
return;
}
if (!onChange) {
return;
}
onChange({
type: 'JSSlot',
value: null,
});
};
render() {
const { value, onChange, supportParams } = this.props;
if (!isJSSlot(value)) {
return (
<Button type="primary" onClick={this.handleInitial}>
</Button>
);
}
const hasParams = value.params && Array.isArray(value.params);
return (
<div className="lc-setter-slot">
<Button
onClick={() => {
// TODO: use slot first child literal value pad
onChange && onChange(null);
}}
type="secondary"
>
</Button>
{hasParams ? (
<Input
className="lc-slot-params"
addonTextBefore="入参"
placeholder="插槽入参,以逗号风格"
value={value.params!.join(',')}
autoFocus
onChange={(val) => {
val = val.trim();
const params = val ? val.split(/ *, */) : [];
onChange &&
onChange({
...value,
params,
});
}}
addonAfter={
<Button
type="secondary"
onClick={() => {
onChange &&
onChange({
type: 'JSSlot',
value: value.value,
});
}}
>
<Icon type="close" />
</Button>
}
/>
) : supportParams ? (
<Button
className="lc-slot-params"
type="primary"
onClick={() => {
onChange &&
onChange({
...value,
params: [],
});
}}
>
</Button>
) : null}
</div>
);
}
}

View File

@ -6,6 +6,8 @@ import MixedSetter from './components/mixed-setter';
import { isPlainObject } from '@ali/lowcode-utils';
import parseProps from './transducers/parse-props';
import addonCombine from './transducers/addon-combine';
import SlotSetter from './components/slot-setter';
import { isJSSlot } from '@ali/lowcode-types';
registerSetter('ArraySetter', {
component: ArraySetter,
@ -30,6 +32,27 @@ registerSetter('ObjectSetter', {
initialValue: {},
recommend: true,
});
registerSetter('SlotSetter', {
component: SlotSetter,
title: {
type: 'i18n',
'zh-CN': '插槽输入',
'en-US': 'Slot Setter'
},
condition: (field: any) => {
return isJSSlot(field.getValue());
},
initialValue: (field: any, value: any) => {
if (isJSSlot(value)) {
return value;
}
return {
type: 'JSSlot',
value: value
};
},
recommend: true,
});
registerSetter('MixedSetter', MixedSetter);
// parseProps

View File

@ -334,7 +334,7 @@ class Calendar extends Component {
[CALENDAR_MODE_MONTH]: <MonthPanelHeader {...headerProps} />,
[CALENDAR_MODE_YEAR]: <YearPanelHeader {...headerProps} />,
};
return (
<div
{...obj.pickOthers(Calendar.propTypes, others)}

View File

@ -1,169 +0,0 @@
import * as utils from '@ali/ve-utils';
import popups from '@ali/ve-popups';
import Icons from '@ali/ve-icons';
import { VE_EVENTS, VE_HOOKS } from '../const';
import Bus from '../bus';
import Symbols from '../symbols';
import Skeleton from '@ali/lowcode-editor-skeleton';
import editor from '../editor';
const VEOldAPIs = {
/**
* VE.Popup
*/
Popup: popups,
/**
* VE.ui.xxx
*
* Core UI Components
*/
ui: {
// FIELD_TYPE_MAP
Field: {
// SettingField,
// Stage,
// CaptionField,
// PopupField,
// EntryField,
// AccordionField,
// BlockField,
// InlineField,
// PlainField
AccordionField,
InlineField,
BlockField,
CaptionField, // 不支持 variableSwitcher 版的 BlockField
PlainField, // 不渲染 title 的 InlineField
EntryField,
PopupField,
},
Icon: Icons,
Icons,
Popup: popups,
/*
// for rax visualpage, will not support any
FaultComponent,
HiddenComponent,
UnknownComponent,
InsertionGhost,
*/
},
/**
* VE.context DI
*
* init
*/
context: new VisualEngineContext(),
/**
* VE.init
*
* Initialized the whole VisualEngine UI
*/
init: (container?: Element, contextConfigs?: any) => {
if (!container) {
container = document.createElement('div');
document.body.appendChild(container);
}
container.id = 'engine';
ReactDOM.render(<Skeleton editor={editor} />, container);
},
/**
* VE.modules.xxx
*
* VE BuildIn Modules
*/
modules: {
// SchemaManager, 没看到使用的地方
// VisualDesigner, 没看到使用的地方
VisualManager // legao-designer 有用
// VisualRender, 没看到使用的地方
I18nUtil, // vs-list vs-rhino-widget-mapping
Prop, // vs-list vs-rhino-widget-mapping
/* 使
Node,
Props,
Scroller,
Insertion,
*/
},
/**
* VE Utils
*/
utils,
/* 包抽象 */
Bundle,
/* pub/sub 集线器 */
// ve-quick-search-pane, ve-section-pane vp-in-place-editing ve-action-save
// ve-page-history vs-q-chart-data ve-action-pane ve-page-lock-pane
// ve-datapool-pane ve-youshu-card-param-pane
Bus,
/* 拖拽引擎 */
DragEngine, // 在 ve-metadata-pane, ve-section-pane ve-trunk-pane-simple ve-trunk-pane 中有用
/* 环境变量 */
// vu-oneapi-parser vu-events-property ve-section-pane vs-formula vu-link-property
// ve-datapool-pane vs-form-validator vs-style vs-link vs-micro-link vs-link-options vu-field-property
Env,
/* 状态交换 */
//
Exchange,
/* 状态 Flags */
// legao-design tree-pane
Flags,
/* 快捷键 */
// legao-design
Hotkey,
/* 多语言文案 */
I18nUtil,
/* 页面管理 */
Pages,
/* 面板管理 */
Panes,
/* 应用管理 */
Project,
/* 包原型 */
Prototype,
/* 组件仓库 */
Trunk,
/* 事件 */
EVENTS: VE_EVENTS, // legao-design
/* 修饰方法 */
HOOKS: VE_HOOKS, // legao-design vu-visualpage-rax
/* 视图管理 */
Viewport,
/* Symbol 管理类 */
Symbols, // legao-design vu-action-util
/**
* VisualEngine Logger Tool
*/
// lg: logger, 没看到使用的地方
// logger,
/* 版本号 */
// Version: VERSION,
// Location,
// Node,
// VirtualRenderingNode
}

View File

@ -5,6 +5,7 @@ import {
addBuiltinComponentAction,
isComponentMeta,
registerMetadataTransducer,
TransformStage,
} from '@ali/lowcode-designer';
import {
OldPropConfig,
@ -112,9 +113,10 @@ function addGlobalExtraActions(action: () => ReactElement) {
upgradeActions(action)?.forEach(addBuiltinComponentAction);
}
const GlobalPropsReducers: any[] = [];
// const GlobalPropsReducers: any[] = [];
function addGlobalPropsReducer(reducer: () => any) {
GlobalPropsReducers.push(reducer);
// GlobalPropsReducers.push(reducer);
designer.addPropsReducer(reducer, TransformStage.Render);
}
export interface OldGlobalPropConfig extends OldPropConfig {

View File

@ -1,6 +1,6 @@
import { isJSBlock } from '@ali/lowcode-types';
import { isJSBlock, isJSSlot } from '@ali/lowcode-types';
import { isPlainObject } from '@ali/lowcode-utils';
import { globalContext, Editor } from '@ali/lowcode-editor-core';
import { globalContext, Editor, registerSetter } from '@ali/lowcode-editor-core';
import { Designer, TransformStage } from '@ali/lowcode-designer';
// import { registerSetters } from '@ali/lowcode-setters';
import Outline from '@ali/lowcode-plugin-outline-pane';
@ -11,8 +11,6 @@ import Preview from '@ali/lowcode-plugin-sample-preview';
// import SourceEditor from '@ali/lowcode-plugin-source-editor';
import { i18nReducer } from './i18n-reducer';
// registerSetters();
export const editor = new Editor();
globalContext.register(editor, Editor);

View File

@ -9,7 +9,6 @@ interface I18nObject {
}
export function i18nReducer(obj?: any): any {
console.info(obj);
if (!obj) { return obj; }
if (Array.isArray(obj)) {
return obj.map((item) => i18nReducer(item));

View File

@ -85,6 +85,18 @@ html.engine-blur #engine {
white-space: nowrap;
}
// dirty fix override vision reset
.engine-design-mode {
.next-input-group,
.next-checkbox-group,.next-date-picker,.next-input,.next-month-picker,
.next-number-picker,.next-radio-group,.next-range,.next-range-picker,
.next-rating,.next-select,.next-switch,.next-time-picker,.next-upload,
.next-year-picker {
pointer-events: auto !important;
}
}
.lc-left-float-pane {
font-size: 14px;
}