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

This commit is contained in:
mingjia.cmj 2020-05-01 17:14:21 +08:00
commit 7f794bd141
24 changed files with 500 additions and 230 deletions

View File

@ -28,6 +28,7 @@
"@ali/lowcode-runtime": "^0.8.13",
"@ali/lowcode-setters": "^0.8.11",
"@ali/lowcode-utils": "^0.8.2",
"@ali/vs-variable-setter": "^3.1.0",
"@ali/ve-action-pane": "^4.7.0-beta.0",
"@ali/ve-datapool-pane": "^6.4.3",
"@ali/ve-i18n-manage-pane": "^4.3.0",

View File

@ -12,8 +12,25 @@ import EventBindDialog from '@ali/lowcode-plugin-event-bind-dialog';
import loadUrls from './loader';
import { upgradeAssetsBundle } from './upgrade-assets';
import { isCSSUrl } from '@ali/lowcode-utils';
import { I18nSetter } from '@ali/visualengine-utils';
import VariableSetter from '@ali/vs-variable-setter';
const { editor, skeleton } = Engine;
const { editor, skeleton, context, HOOKS, Trunk } = Engine;
Trunk.registerSetter('I18nSetter', {
component: I18nSetter,
// todo: add icon
title: {
type: 'i18n',
'zh-CN': '国际化输入',
'en-US': 'International Input'
},
// TODO: below
// condition?: (field: any) => boolean;
// initialValue?: any | ((field: any) => any);
recommend: true,
});
context.use(HOOKS.VE_SETTING_FIELD_VARIABLE_SETTER, VariableSetter);
const externals = ['react', 'react-dom', 'prop-types', 'react-router', 'react-router-dom', '@ali/recore'];
@ -52,7 +69,7 @@ async function loadAssets() {
assets.packages.push({
library: '_prototypesStyle',
package: '_prototypes-style',
urls: prototypeStyles
urls: prototypeStyles,
});
}
await Promise.all(tasks);

View File

@ -1,3 +1,4 @@
declare module "@ali/visualengine";
declare module "@ali/visualengine-utils";
declare module "@ali/ve-trunk-pane"
declare module "@ali/ve-trunk-pane";
declare module "@ali/vs-variable-setter";

View File

@ -71,7 +71,7 @@ export class Designer {
this.hovering.enable = false;
const { dragObject } = e;
if (isDragNodeObject(dragObject)) {
if (dragObject.nodes.length === 1) {
if (dragObject.nodes.length === 1 && dragObject.nodes[0].parent) {
// ensure current selecting
dragObject.nodes[0].select();
}

View File

@ -1,5 +1,5 @@
import { obx, computed } from '@ali/lowcode-editor-core';
import { IEditor } from '@ali/lowcode-types';
import { IEditor, isJSExpression } from '@ali/lowcode-types';
import { uniqueId } from '@ali/lowcode-utils';
import { SettingEntry } from './setting-entry';
import { Node } from '../../document';
@ -191,4 +191,44 @@ export class SettingPropEntry implements SettingEntry {
return this.config;
}
*/
getVariableValue() {
const v = this.getValue();
if (isJSExpression(v)) {
return v.value;
}
return '';
}
setVariableValue(value: string) {
const v = this.getValue();
this.setValue({
type: 'JSExpression',
value,
mock: isJSExpression(v) ? v.mock : v,
});
}
setUseVariable(flag: boolean) {
if (this.isUseVariable() === flag) {
return;
}
const v = this.getValue();
if (isJSExpression(v)) {
this.setValue(v.mock);
} else {
this.setValue({
type: 'JSExpression',
value: '',
mock: v,
});
}
}
isUseVariable() {
return isJSExpression(this.getValue());
}
getMockOrValue() {
const v = this.getValue();
if (isJSExpression(v)) {
return v.mock;
}
return v;
}
}

View File

@ -465,6 +465,9 @@ export class DocumentModel {
getRoot() {
return this.rootNode;
}
get root() {
return this.rootNode;
}
}
export function isDocumentModel(obj: any): obj is DocumentModel {

View File

@ -653,7 +653,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this._addons[key] = exportData;
}
toString() {
return this.id;
}

View File

@ -1,5 +1,5 @@
import { EventEmitter } from 'events';
import { obx } from '../utils/obx';
import { obx, computed } from '../utils/obx';
const languageMap: { [key: string]: string } = {
en: 'en-US',
zh: 'zh-CN',
@ -29,8 +29,50 @@ const languageMap: { [key: string]: string } = {
const LowcodeConfigKey = 'ali-lowcode-config';
class AliGlobalLocale {
@obx.ref private locale: string = '';
private emitter = new EventEmitter();
@obx.ref private _locale?: string;
@computed get locale() {
if (this._locale != null) {
return this._locale;
}
const { g_config, navigator } = window as any;
if (hasLocalStorage(window)) {
const store = window.localStorage;
let config: any;
try {
config = JSON.parse(store.getItem(LowcodeConfigKey) || '');
} catch (e) {
// ignore;
}
if (config?.locale) {
return (config.locale || '').replace('_', '-');
}
} else if (g_config) {
if (g_config.locale) {
return languageMap[g_config.locale] || (g_config.locale || '').replace('_', '-');
}
}
let locale: string = '';
if (navigator.language) {
locale = (navigator.language as string).replace('_', '-');
}
// IE10 及更低版本使用 browserLanguage
if (navigator.browserLanguage) {
const it = navigator.browserLanguage.split('-');
locale = it[0];
if (it[1]) {
locale += '-' + it[1].toUpperCase();
}
}
if (!locale) {
locale = 'zh-CN';
}
return locale;
}
constructor() {
this.emitter.setMaxListeners(0);
@ -40,7 +82,7 @@ class AliGlobalLocale {
if (locale === this.locale) {
return;
}
this.locale = locale;
this._locale = locale;
if (hasLocalStorage(window)) {
const store = window.localStorage;
let config: any;
@ -62,47 +104,6 @@ class AliGlobalLocale {
}
getLocale() {
if (this.locale) {
return this.locale;
}
const { g_config, navigator } = window as any;
if (hasLocalStorage(window)) {
const store = window.localStorage;
let config: any;
try {
config = JSON.parse(store.getItem(LowcodeConfigKey) || '');
} catch (e) {
// ignore;
}
if (config?.locale) {
this.locale = (config.locale || '').replace('_', '-');
return this.locale;
}
} else if (g_config) {
if (g_config.locale) {
this.locale = languageMap[g_config.locale] || (g_config.locale || '').replace('_', '-');
return this.locale;
}
}
if (navigator.language) {
this.locale = (navigator.language as string).replace('_', '-');
}
// IE10 及更低版本使用 browserLanguage
if (navigator.browserLanguage) {
const it = navigator.browserLanguage.split('-');
this.locale = it[0];
if (it[1]) {
this.locale += '-' + it[1].toUpperCase();
}
}
if (!this.locale) {
this.locale = 'zh-CN';
}
return this.locale;
}

View File

@ -98,19 +98,20 @@ export function createIntl(
const locale = globalLocale.getLocale();
if (typeof instance === 'string') {
if ((window as any)[instance]) {
data.messages = (window as any)[instance][locale] || {};
} else {
const key = `${instance}_${locale.toLocaleLowerCase()}`;
data.messages = (window as any)[key] || {};
return (window as any)[instance][locale] || {};
}
} else if (instance && typeof instance === 'object') {
data.messages = (instance as any)[locale] || {};
const key = `${instance}_${locale.toLocaleLowerCase()}`;
return (window as any)[key] || {};
}
if (instance && typeof instance === 'object') {
return (instance as any)[locale] || {};
}
return {};
});
function intl(key: string, params?: object): string {
// TODO: tries lost language
const str = data[key];
const str = data.value[key];
if (str == null) {
return `##intl@${key}##`;

View File

@ -157,17 +157,12 @@ export class EntryField extends Component<EntryFieldProps> {
fieldProps['data-stage-target'] = stageName;
}
const innerElements = [
<span className="engine-field-title" key="field-title">
{title}
</span>,
// renderTip(tip, { propName }),
// <Icons name="arrow" className="engine-field-arrow" size="12px" key="engine-field-arrow-icon" />,
];
return (
<div className={classNameList} {...fieldProps}>
{innerElements}
<div className="lc-field-title">
<Title title={title || ''} />
</div>
<Icon className="lc-field-icon" type="arrow-left" size="xs" />
</div>
);
}

View File

@ -1,4 +1,4 @@
import React, { Component, isValidElement } from 'react';
import React, { Component, ComponentClass, ReactNode } from 'react';
import classNames from 'classnames';
import { Dropdown, Menu } from '@alifd/next';
import {
@ -9,7 +9,6 @@ import {
TitleContent,
isSetterConfig,
isDynamicSetter,
isI18nData,
} from '@ali/lowcode-types';
import {
getSetter,
@ -20,13 +19,14 @@ import {
createSetterContent,
observer,
shallowIntl,
Tip,
} from '@ali/lowcode-editor-core';
import { IconConvert } from '../../icons/convert';
import { intlNode } from '../../locale';
import './style.less';
import { SettingField } from '@ali/lowcode-designer';
import { IconVariable } from 'editor-skeleton/src/icons/variable';
export interface SetterItem {
name: string;
@ -101,6 +101,10 @@ function nomalizeSetters(setters?: Array<string | SetterConfig | CustomView | Dy
});
}
interface VariableSetter extends ComponentClass {
show(params: object): void;
}
@observer
export default class MixedSetter extends Component<{
field: SettingField;
@ -129,11 +133,21 @@ export default class MixedSetter extends Component<{
return firstMatched;
}
// dirty fix vision variable setter logic
private hasVariableSetter = this.setters.some((item) => item.name === 'VariableSetter');
private useSetter = (name: string) => {
const { field, onChange } = this.props;
if (name === 'VariableSetter') {
const setterComponent = getSetter('VariableSetter')?.component as any;
if (setterComponent && setterComponent.isPopup) {
setterComponent.show({ prop: field });
return;
}
}
if (name === this.used) {
return;
}
const { field, onChange } = this.props;
const setter = this.setters.find((item) => item.name === name);
this.used = name;
if (setter) {
@ -163,99 +177,161 @@ export default class MixedSetter extends Component<{
this.checkIsBlockField();
}
render() {
private renderCurrentSetter(currentSetter?: SetterItem, extraProps?: object) {
const { className, field, setters, onSetterChange, ...restProps } = this.props;
const currentSetter = this.getCurrentSetter();
const isTwoType = this.setters.length < 3;
let setterContent: any;
const triggerTitle: any = {
tip: {
type: 'i18n',
'zh-CN': '切换格式',
'en-US': 'Switch Format',
},
icon: <IconConvert size={24} />,
};
if (currentSetter) {
const { setter, title, props } = currentSetter;
let setterProps: any = {};
let setterType: any;
if (isDynamicSetter(setter)) {
setterType = setter.call(field, field);
} else {
setterType = setter;
}
if (props) {
setterProps = props;
if (typeof setterProps === 'function') {
setterProps = setterProps(field);
}
}
setterContent = createSetterContent(setterType, {
...shallowIntl(setterProps),
field,
...restProps,
});
if (title) {
if (typeof title !== 'object' || isI18nData(title) || isValidElement(title)) {
triggerTitle.tip = title;
} else {
triggerTitle.tip = title.tip || title.label;
}
}
} else {
// 未匹配的 null 值,显示 NullValue 空值
// 未匹配的 其它 值,显示 InvalidValue 非法值
if (!currentSetter) {
// TODO: use intl
if (restProps.value == null) {
setterContent = <span>NullValue</span>;
return <span>NullValue</span>;
} else {
setterContent = <span>InvalidValue</span>;
return <span>InvalidValue</span>;
}
}
const { setter, props } = currentSetter;
let setterProps: any = {};
let setterType: any;
if (isDynamicSetter(setter)) {
setterType = setter.call(field, field);
} else {
setterType = setter;
}
if (props) {
setterProps = props;
if (typeof setterProps === 'function') {
setterProps = setterProps(field);
}
}
return createSetterContent(setterType, {
...shallowIntl(setterProps),
field,
...restProps,
...extraProps,
});
}
private contentsFromPolyfill(setterComponent: VariableSetter) {
const { field } = this.props;
const n = this.setters.length;
let setterContent: any;
let actions: any;
if (n < 3) {
const tipContent = field.isUseVariable()
? intlNode('Binded: {expr}', { expr: field.getVariableValue() })
: intlNode('Variable Binding');
if (n === 1) {
// =1: 原地展示<当前绑定的值,点击调用 VariableSetter.show>icon 高亮是否->isUseVaiable点击 VariableSetter.show
setterContent = (
<a
onClick={() => {
setterComponent.show({ prop: field });
}}
>
{tipContent}
</a>
);
} else {
// =2: 另外一个 Setter 原地展示icon 高亮,点击弹出调用 VariableSetter.show
const otherSetter = this.setters.find((item) => item.name !== 'VariableSetter')!;
setterContent = this.renderCurrentSetter(otherSetter, {
value: field.getMockOrValue(),
});
}
actions = (
<Title
className={field.isUseVariable() ? 'variable-binded' : ''}
title={{
icon: IconVariable,
tip: tipContent,
}}
onClick={() => {
setterComponent.show({ prop: field });
}}
/>
);
} else {
// >=3: 原地展示当前 setter<当前绑定的值,点击调用 VariableSetter.show>icon tip 提示绑定的值,点击展示切换 Setter点击其它 setter 直接切换,点击 Variable Setter-> VariableSetter.show
const currentSetter = field.isUseVariable()
? this.setters.find((item) => item.name === 'VariableSetter')
: this.getCurrentSetter();
if (currentSetter?.name === 'VariableSetter') {
setterContent = (
<a
onClick={() => {
setterComponent.show({ prop: field });
}}
>
{intlNode('Binded: {expr}', { expr: field.getVariableValue() })}
</a>
);
} else {
setterContent = this.renderCurrentSetter(currentSetter);
}
actions = this.renderSwitchAction(currentSetter);
}
return {
setterContent,
actions,
};
}
private renderSwitchAction(currentSetter?: SetterItem) {
const usedName = currentSetter?.name || this.used;
let moreBtnNode = (
const triggerNode = (
<Title
title={triggerTitle}
title={{
tip: intlNode('Switch Setter'),
// FIXME: got a beautiful icon
icon: <IconConvert size={24} />,
}}
className="lc-switch-trigger"
onClick={
isTwoType
? () => {
if (this.setters[0]?.name === usedName) {
this.useSetter(this.setters[1]?.name);
} else {
this.useSetter(this.setters[0]?.name);
}
}
: undefined
}
/>
);
if (!isTwoType) {
moreBtnNode = (
<Dropdown trigger={moreBtnNode} triggerType="click" align="tr br">
<Menu selectMode="single" hasSelectedIcon={true} selectedKeys={usedName} onItemClick={this.useSetter}>
{this.setters
.filter((setter) => setter.list || setter.name === usedName)
.map((setter) => {
return (
<Menu.Item key={setter.name}>
<Title title={setter.title} />
</Menu.Item>
);
})}
</Menu>
</Dropdown>
);
return (
<Dropdown trigger={triggerNode} triggerType="click" align="tr br">
<Menu selectMode="single" hasSelectedIcon={true} selectedKeys={usedName} onItemClick={this.useSetter}>
{this.setters
.filter((setter) => setter.list || setter.name === usedName)
.map((setter) => {
return (
<Menu.Item key={setter.name}>
<Title title={setter.title} />
</Menu.Item>
);
})}
</Menu>
</Dropdown>
);
}
render() {
const { className } = this.props;
let contents: {
setterContent: ReactNode,
actions: ReactNode,
} | undefined;
if (this.hasVariableSetter) {
// FIXME: polyfill vision variable setter logic
const setterComponent = getSetter('VariableSetter')?.component as any;
if (setterComponent && setterComponent.isPopup) {
contents = this.contentsFromPolyfill(setterComponent);
}
}
if (!contents) {
const currentSetter = this.getCurrentSetter();
contents = {
setterContent: this.renderCurrentSetter(currentSetter),
actions: this.renderSwitchAction(currentSetter),
};
}
return (
<div ref={(shell) => (this.shell = shell)} className={classNames('lc-setter-mixed', className)}>
{setterContent}
<div className="lc-setter-actions">{moreBtnNode}</div>
{contents.setterContent}
<div className="lc-setter-actions">{contents.actions}</div>
</div>
);
}

View File

@ -0,0 +1,11 @@
import { SVGIcon, IconProps } from "@ali/lowcode-utils";
export function IconVariable(props: IconProps) {
return (
<SVGIcon viewBox="0 0 1024 1024" {...props}>
<path d="M596.32 263.392c18.048 6.56 27.328 26.496 20.8 44.512l-151.04 414.912a34.72 34.72 0 1 1-65.28-23.744l151.04-414.912a34.72 34.72 0 0 1 44.48-20.768zM220.64 192H273.6v55.488H233.024c-26.112 0-38.464 14.4-38.464 44.544v134.304c0 42.496-19.936 71.264-59.104 85.664 39.168 16.448 59.104 44.544 59.104 85.664v134.976c0 28.8 12.352 43.84 38.464 43.84H273.6V832H220.672c-30.24 0-53.6-10.272-70.08-29.44-15.136-17.856-22.72-42.496-22.72-72.64v-128.832c0-19.872-4.096-34.24-12.352-43.2-9.6-10.944-26.784-16.416-51.52-17.792v-56.192c24.736-1.376 41.92-7.52 51.52-17.824 8.256-9.6 12.384-24 12.384-43.168V294.784c0-30.848 7.552-55.488 22.688-73.312C167.04 201.6 190.4 192 220.672 192z m529.792 0h52.896c30.24 0 53.6 9.6 70.08 29.44 15.136 17.856 22.72 42.496 22.72 73.344v128.128c0 19.2 4.096 34.24 13.024 43.84 8.96 9.6 26.112 15.776 50.848 17.152v56.192c-24.736 1.376-41.92 6.848-51.52 17.824-8.256 8.896-12.384 23.296-12.384 43.168v128.8c0 30.176-7.552 54.816-22.688 72.64-16.48 19.2-39.84 29.472-70.08 29.472h-52.896v-55.488h40.544c25.408 0 38.464-15.104 38.464-43.84v-135.04c0-41.088 19.232-69.184 59.104-85.632-39.872-14.4-59.104-43.168-59.104-85.664V292.032c0-30.144-13.056-44.544-38.464-44.544H750.4V192z" />
</SVGIcon>
);
}
IconVariable.displayName = 'Variable';

View File

@ -0,0 +1,5 @@
{
"Binded: {expr}": "Binded: {expr}",
"Variable Binding": "Variable Binding",
"Switch Setter": "Switch Setter"
}

View File

@ -0,0 +1,10 @@
import { createIntl } from '@ali/lowcode-editor-core';
import en_US from './en-US.json';
import zh_CN from './zh-CN.json';
const { intl, intlNode, getLocale, setLocale } = createIntl({
'en-US': en_US,
'zh-CN': zh_CN,
});
export { intl, intlNode, getLocale, setLocale };

View File

@ -0,0 +1,5 @@
{
"Binded: {expr}": "已绑定: {expr}",
"Variable Binding": "变量绑定",
"Switch Setter": "切换设置器"
}

View File

@ -1,7 +1,8 @@
import { ReactElement, ComponentType } from 'react';
import { EventEmitter } from 'events';
import { registerSetter } from '@ali/lowcode-editor-core';
import { registerSetter, RegisteredSetter } from '@ali/lowcode-editor-core';
import Bundle from './bundle';
import { CustomView } from '@ali/lowcode-types';
export class Trunk {
private trunk: any[] = [];
@ -51,7 +52,7 @@ export class Trunk {
};
}
registerSetter(type: string, setter: ReactElement | ComponentType<any>) {
registerSetter(type: string, setter: CustomView | RegisteredSetter) {
console.warn('Trunk.registerSetter is deprecated');
registerSetter(type, setter);
}

View File

@ -342,11 +342,11 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
},
];
if (allowTextInput !== false) {
setters.unshift('StringSetter');
setters.unshift('I18nSetter');
// FIXME: use I18nSetter
}
if (supportVariable) {
setters.push('ExpressionSetter');
setters.push('VariableSetter');
}
newConfig.setter = setters.length > 1 ? setters : setters[0];
@ -403,25 +403,24 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
primarySetter = setter;
}
}
if (!primarySetter) {
primarySetter = 'I18nSetter';
}
if (supportVariable) {
if (primarySetter) {
const setters = Array.isArray(primarySetter)
? primarySetter.concat('ExpressionSetter')
: [primarySetter, 'ExpressionSetter'];
primarySetter = {
componentName: 'MixedSetter',
props: {
setters,
onSetterChange: (field: Field, name: string) => {
if (useVariableChange) {
useVariableChange.call(field, { isUseVariable: name === 'ExpressionSetter' });
}
},
const setters = Array.isArray(primarySetter)
? primarySetter.concat('VariableSetter')
: [primarySetter, 'VariableSetter'];
primarySetter = {
componentName: 'MixedSetter',
props: {
setters,
onSetterChange: (field: Field, name: string) => {
if (useVariableChange) {
useVariableChange.call(field, { isUseVariable: name === 'VariableSetter' });
}
},
};
} else {
primarySetter = 'ExpressionSetter';
}
},
};
}
newConfig.setter = primarySetter;

View File

@ -1,44 +0,0 @@
/**
* Storage the const variables
*/
/**
* Global
*/
export const VERSION = '5.3.0';
/**
* schema version defined in alibaba
*/
export const ALI_SCHEMA_VERSION = '1.0.0';
export const VE_EVENTS = {
/**
* node props to be dynamically replaced
* @event props the new props object been replaced
*/
VE_NODE_CREATED: 've.node.created',
VE_NODE_DESTROY: 've.node.destroyed',
VE_NODE_PROPS_REPLACE: 've.node.props.replaced',
// copy / clone node
VE_OVERLAY_ACTION_CLONE_NODE: 've.overlay.cloneElement',
// remove / delete node
VE_OVERLAY_ACTION_REMOVE_NODE: 've.overlay.removeElement',
// one page successfully mount on the DOM
VE_PAGE_PAGE_READY: 've.page.pageReady',
};
export const VE_HOOKS = {
// a decorator function
VE_NODE_PROPS_DECORATOR: 've.leaf.props.decorator',
// a remove callback function
VE_NODE_REMOVE_HELPER: 've.outline.actions.removeHelper',
/**
* provide customization field
*/
VE_SETTING_FIELD_PROVIDER: 've.settingField.provider',
/**
* VariableSetter for variable mode of a specified prop
*/
VE_SETTING_FIELD_VARIABLE_SETTER: 've.settingField.variableSetter',
};

View File

@ -3,30 +3,32 @@ import { assign } from 'lodash';
import { Component, ReactElement } from 'react';
import VisualManager from './base/visualManager';
import Prototype from './bundle/prototype';
import { VE_HOOKS } from './base/const';
import { registerSetter } from '@ali/lowcode-editor-core';
// TODO: Env 本地引入后需要兼容方法 getDesignerLocale
// import Env from './env';
let contextInstance: VisualEngineContext;
// prop is Prop object in Designer
export type SetterProvider = (prop: any, componentPrototype: Prototype) => Component | ReactElement<any>;
export default class VisualEngineContext {
export class VisualEngineContext {
private managerMap: { [name: string]: VisualManager } = {};
private moduleMap: { [name: string]: any } = {};
private pluginsMap: { [name: string]: any } = {};
constructor() {
if (!contextInstance) {
contextInstance = this;
} else {
return contextInstance;
}
}
use(pluginName: string, plugin: any) {
this.pluginsMap[pluginName || 'unknown'] = plugin;
if (pluginName === VE_HOOKS.VE_SETTING_FIELD_VARIABLE_SETTER) {
registerSetter('VariableSetter', {
component: plugin,
title: { type: 'i18n', 'zh-CN': '变量绑定', 'en-US': 'Variable Binding' },
// TODO: add logic below
// condition?: (field: any) => boolean;
// initialValue?: any | ((field: any) => any);
});
}
}
getPlugin(name: string) {
@ -102,3 +104,5 @@ export default class VisualEngineContext {
}
}
}
export default new VisualEngineContext();

View File

@ -61,6 +61,7 @@ function upgradePropsReducer(props: any) {
val = val.value;
}
}
// todo: type: variable
newProps[key] = val;
});
return newProps;

View File

@ -1,7 +1,145 @@
import { Component } from "react";
import { Component, ReactNode } from 'react';
import {
PopupField,
Field as NormalField,
EntryField,
PlainField,
createSettingFieldView,
SettingsPane,
createField,
} from '@ali/lowcode-editor-skeleton';
import { createSetterContent } from '@ali/lowcode-editor-core';
import { isPlainObject } from '@ali/lowcode-utils';
import { isSetterConfig } from '@ali/lowcode-types';
import context from './context';
import { VE_HOOKS } from './base/const';
export class Placeholder extends Component {
render() {
console.info(this.props);
return 'rending placeholder here';
}
}
export class SettingField extends Component<{
prop: any;
selected?: boolean;
forceDisplay?: string;
className?: string;
children?: ReactNode;
compact?: boolean;
key?: string;
addonProps?: object;
}> {
constructor(props: any) {
super(props);
console.info(props);
}
render() {
const { prop, selected, addonProps } = this.props;
const display = this.props.forceDisplay || prop.getDisplay();
if (display === 'none') {
return null;
}
// 标准的属性,即每一个 Field 在 VE 下都拥有的属性
const standardProps = {
className: this.props.className,
compact: this.props.compact,
isSupportMultiSetter: this.supportMultiSetter(),
isSupportVariable: prop.isSupportVariable(),
isUseVariable: prop.isUseVariable(),
prop,
setUseVariable: () => prop.setUseVariable(!prop.isUseVariable()),
tip: prop.getTip(),
title: prop.getTitle(),
};
// 部分 Field 所需要的额外 fieldProps
const extraProps = {};
const ctx = context;
const plugin = ctx.getPlugin(VE_HOOKS.VE_SETTING_FIELD_PROVIDER);
let Field;
if (typeof plugin === 'function') {
Field = plugin(display, FIELD_TYPE_MAP, prop);
}
if (!Field) {
Field = FIELD_TYPE_MAP[display] || PlainField;
}
createField()
this._prepareProps(display, extraProps);
if (display === 'entry') {
return <Field {...{ ...standardProps, ...extraProps }} />;
}
let setter;
const props: any = {
prop,
selected,
};
const fieldProps = { ...standardProps, ...extraProps };
if (prop.isUseVariable() && !this.variableSetter.isPopup) {
props.placeholder = '请输入表达式: ${var}';
props.key = `${prop.getId()}-variable`;
setter = React.createElement(this.variableSetter, props);
return <Field {...fieldProps}>{setter}</Field>;
}
// for composited prop
if (prop.getVisibleItems) {
setter = prop
.getVisibleItems()
.map((item: any) => <SettingField {...{ key: item.getId(), prop: item, selected }} />);
return <Field {...fieldProps}>{setter}</Field>;
}
setter = createSetterContent(prop.getSetter(), {
...addonProps,
...props,
});
return <Field {...fieldProps}>{setter}</Field>;
}
private supportMultiSetter() {
const { prop } = this.props;
const setter = prop && prop.getConfig && prop.getConfig('setter');
return prop.isSupportVariable() || Array.isArray(setter);
}
private _prepareProps(displayType: string, extraProps: IExtraProps): void {
const { prop } = this.props;
extraProps.propName = prop.isGroup() ? '组合属性,无属性名称' : prop.getName();
switch (displayType) {
case 'title':
break;
case 'block':
assign(extraProps, { isGroup: prop.isGroup() });
break;
case 'accordion':
assign(extraProps, {
headDIY: true,
isExpand: prop.isExpand(),
isGroup: prop.isGroup(),
onExpandChange: () => prop.onExpandChange(() => this.forceUpdate()),
toggleExpand: () => {
prop.toggleExpand();
},
});
break;
case 'entry':
assign(extraProps, { stageName: prop.getName() });
break;
default:
break;
}
}
}
const Field = {
@ -11,7 +149,7 @@ const Field = {
EntryField: Placeholder,
AccordionField: Placeholder,
BlockField: Placeholder,
InlineField: Placeholder
InlineField: Placeholder,
};
export default Field;

View File

@ -9,6 +9,7 @@ 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

@ -5,13 +5,13 @@ import { render } from 'react-dom';
import I18nUtil from '@ali/ve-i18n-util';
import { hotkey as Hotkey } from '@ali/lowcode-editor-core';
import { createElement } from 'react';
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS } from './const';
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS } from './base/const';
import Bus from './bus';
import { skeleton } from './editor';
import { Workbench } from '@ali/lowcode-editor-skeleton';
import Panes from './panes';
import Exchange from './exchange';
import VisualEngineContext from './context';
import context from './context';
import VisualManager from './base/visualManager';
import Trunk from './bundle/trunk';
import Prototype from './bundle/prototype';
@ -58,8 +58,6 @@ const modules = {
Prop,
};
const context = new VisualEngineContext();
const VisualEngine = {
designer,
editor,

View File

@ -49,4 +49,10 @@ const pages = Object.assign(project, {
}
});
Object.defineProperty(pages, 'currentPage', {
get() {
return project.currentDocument;
}
})
export default pages;