mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 09:41:57 +00:00
fix variable setter
This commit is contained in:
parent
7082f637f4
commit
582da643be
@ -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",
|
||||
"@alifd/next": "^1.19.12",
|
||||
"@alife/theme-lowcode-dark": "^0.1.0",
|
||||
"@alife/theme-lowcode-light": "^0.1.0",
|
||||
|
||||
@ -6,8 +6,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);
|
||||
|
||||
// demo
|
||||
skeleton.add({
|
||||
@ -149,7 +166,7 @@ async function loadAssets() {
|
||||
assets.packages.push({
|
||||
library: '_prototypesStyle',
|
||||
package: '_prototypes-style',
|
||||
urls: prototypeStyles
|
||||
urls: prototypeStyles,
|
||||
});
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
|
||||
3
packages/demo/src/vision/module.d.ts
vendored
3
packages/demo/src/vision/module.d.ts
vendored
@ -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";
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,6 +465,9 @@ export class DocumentModel {
|
||||
getRoot() {
|
||||
return this.rootNode;
|
||||
}
|
||||
get root() {
|
||||
return this.rootNode;
|
||||
}
|
||||
}
|
||||
|
||||
export function isDocumentModel(obj: any): obj is DocumentModel {
|
||||
|
||||
@ -618,6 +618,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
}
|
||||
return { container: this.parent, ref: this };
|
||||
}
|
||||
getAddonData() {
|
||||
// TODO:
|
||||
return { online: [] };
|
||||
}
|
||||
toString() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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}##`;
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
11
packages/editor-skeleton/src/icons/variable.tsx
Normal file
11
packages/editor-skeleton/src/icons/variable.tsx
Normal 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';
|
||||
5
packages/editor-skeleton/src/locale/en-US.json
Normal file
5
packages/editor-skeleton/src/locale/en-US.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"Binded: {expr}": "Binded: {expr}",
|
||||
"Variable Binding": "Variable Binding",
|
||||
"Switch Setter": "Switch Setter"
|
||||
}
|
||||
10
packages/editor-skeleton/src/locale/index.ts
Normal file
10
packages/editor-skeleton/src/locale/index.ts
Normal 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 };
|
||||
5
packages/editor-skeleton/src/locale/zh-CN.json
Normal file
5
packages/editor-skeleton/src/locale/zh-CN.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"Binded: {expr}": "已绑定: {expr}",
|
||||
"Variable Binding": "变量绑定",
|
||||
"Switch Setter": "切换设置器"
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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',
|
||||
};
|
||||
@ -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();
|
||||
|
||||
@ -61,6 +61,7 @@ function upgradePropsReducer(props: any) {
|
||||
val = val.value;
|
||||
}
|
||||
}
|
||||
// todo: type: variable
|
||||
newProps[key] = val;
|
||||
});
|
||||
return newProps;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -49,4 +49,10 @@ const pages = Object.assign(project, {
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(pages, 'currentPage', {
|
||||
get() {
|
||||
return project.currentDocument;
|
||||
}
|
||||
})
|
||||
|
||||
export default pages;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user