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

# Conflicts:
#	packages/editor-skeleton/src/widget/panel.ts
This commit is contained in:
mario.gk 2020-05-04 14:20:32 +08:00
commit c8ceb8443f
36 changed files with 732 additions and 293 deletions

View File

@ -76,6 +76,7 @@
<!-- lowcode engine globals --> <!-- lowcode engine globals -->
<script src="./vision-preset.js"></script> <script src="./vision-preset.js"></script>
<script src="https://dev.g.alicdn.com/vision/visualengine-utils/5.0.0/engine-utils.js"></script> <script src="https://dev.g.alicdn.com/vision/visualengine-utils/5.0.0/engine-utils.js"></script>
<link rel="stylesheet" type="text/css" href="//g.alicdn.com/??platform/common/s/1.1/global/global.css,uxcore/uxcore-kuma/2.2.1/orange.min.css">
<!-- lowcode engine app --> <!-- lowcode engine app -->
<script src="./lowcode-editor.js"></script> <script src="./lowcode-editor.js"></script>
</body> </body>

View File

@ -31,6 +31,7 @@
"@ali/ve-i18n-manage-pane": "^4.3.0", "@ali/ve-i18n-manage-pane": "^4.3.0",
"@ali/ve-i18n-pane": "^4.0.0-beta.0", "@ali/ve-i18n-pane": "^4.0.0-beta.0",
"@ali/ve-trunk-pane": "^5.1.0-beta.14", "@ali/ve-trunk-pane": "^5.1.0-beta.14",
"@ali/vs-variable-setter": "^3.1.0",
"@ali/vu-legao-design-fetch-context": "^1.0.3", "@ali/vu-legao-design-fetch-context": "^1.0.3",
"@alifd/next": "^1.19.12", "@alifd/next": "^1.19.12",
"@alife/theme-lowcode-dark": "^0.1.0", "@alife/theme-lowcode-dark": "^0.1.0",

View File

@ -13,8 +13,22 @@ import EventBindDialog from '@ali/lowcode-plugin-event-bind-dialog';
import loadUrls from './loader'; import loadUrls from './loader';
import { upgradeAssetsBundle } from './upgrade-assets'; import { upgradeAssetsBundle } from './upgrade-assets';
import { isCSSUrl } from '@ali/lowcode-utils'; 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'
},
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']; const externals = ['react', 'react-dom', 'prop-types', 'react-router', 'react-router-dom', '@ali/recore'];
@ -53,7 +67,7 @@ async function loadAssets() {
assets.packages.push({ assets.packages.push({
library: '_prototypesStyle', library: '_prototypesStyle',
package: '_prototypes-style', package: '_prototypes-style',
urls: prototypeStyles urls: prototypeStyles,
}); });
} }
await Promise.all(tasks); await Promise.all(tasks);
@ -310,6 +324,10 @@ function initActionPane() {
async function init() { async function init() {
Engine.Env.setEnv('RE_VERSION', '7.2.0'); Engine.Env.setEnv('RE_VERSION', '7.2.0');
Engine.Env.setSupportFeatures({
subview: true,
i18nPane: true,
});
await loadAssets(); await loadAssets();
await loadSchema(); await loadSchema();
await initTrunkPane(); await initTrunkPane();

View File

@ -1,3 +1,8 @@
declare module "@ali/visualengine"; declare module "@ali/visualengine";
declare module "@ali/visualengine-utils"; declare module "@ali/visualengine-utils";
declare module "@ali/ve-trunk-pane" declare module "@ali/ve-trunk-pane";
declare module "@ali/vs-variable-setter";
declare module "@ali/ve-datapool-pane";
declare module "@ali/ve-i18n-manage-pane";
declare module "@ali/ve-action-pane";
declare module "@ali/vu-legao-design-fetch-context";

View File

@ -72,8 +72,12 @@ export class Designer {
const { dragObject } = e; const { dragObject } = e;
if (isDragNodeObject(dragObject)) { if (isDragNodeObject(dragObject)) {
if (dragObject.nodes.length === 1) { if (dragObject.nodes.length === 1) {
if (dragObject.nodes[0].parent) {
// ensure current selecting // ensure current selecting
dragObject.nodes[0].select(); dragObject.nodes[0].select();
} else {
this.currentSelection?.clear();
}
} }
} else { } else {
this.currentSelection?.clear(); this.currentSelection?.clear();

View File

@ -1,10 +1,11 @@
import { obx, computed } from '@ali/lowcode-editor-core'; import { obx, computed, autorun } 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 { uniqueId } from '@ali/lowcode-utils';
import { SettingEntry } from './setting-entry'; import { SettingEntry } from './setting-entry';
import { Node } from '../../document'; import { Node } from '../../document';
import { ComponentMeta } from '../../component-meta'; import { ComponentMeta } from '../../component-meta';
import { Designer } from '../designer'; import { Designer } from '../designer';
import { EventEmitter } from 'events';
export class SettingPropEntry implements SettingEntry { export class SettingPropEntry implements SettingEntry {
// === static properties === // === static properties ===
@ -20,6 +21,8 @@ export class SettingPropEntry implements SettingEntry {
readonly type: 'field' | 'group'; readonly type: 'field' | 'group';
readonly id = uniqueId('entry'); readonly id = uniqueId('entry');
readonly emitter = new EventEmitter();
// ==== dynamic properties ==== // ==== dynamic properties ====
@obx.ref private _name: string | number; @obx.ref private _name: string | number;
get name() { get name() {
@ -59,6 +62,14 @@ export class SettingPropEntry implements SettingEntry {
this.isSingle = parent.isSingle; this.isSingle = parent.isSingle;
this.designer = parent.designer; this.designer = parent.designer;
this.top = parent.top; this.top = parent.top;
autorun(({ firstRun }) => {
const value = this.getValue();
if (firstRun) {
return;
}
this.emitter.emit('valuechange', value);
});
} }
getId() { getId() {
@ -88,7 +99,7 @@ export class SettingPropEntry implements SettingEntry {
const propName = this.path.join('.'); const propName = this.path.join('.');
let l = this.nodes.length; let l = this.nodes.length;
while (l-- > 1) { while (l-- > 1) {
this.nodes[l].getProp(propName)?.remove() this.nodes[l].getProp(propName)?.remove();
} }
} }
@ -117,7 +128,6 @@ export class SettingPropEntry implements SettingEntry {
if (setValue) { if (setValue) {
setValue(this, val); setValue(this, val);
} }
// TODO: emit value change
} }
/** /**
@ -170,9 +180,21 @@ export class SettingPropEntry implements SettingEntry {
return this.top; return this.top;
} }
onValueChange() { onValueChange(func: () => any) {
// TODO: this.emitter.on('valuechange', func);
return () => {};
return () => {
this.emitter.removeListener('valuechange', func);
};
}
/**
* @deprecated
*/
valueChange() {
console.warn('valueChange deprecated');
this.emitter.emit('valuechange');
} }
getDefaultValue() { getDefaultValue() {
@ -191,4 +213,44 @@ export class SettingPropEntry implements SettingEntry {
return this.config; 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() { getRoot() {
return this.rootNode; return this.rootNode;
} }
get root() {
return this.rootNode;
}
} }
export function isDocumentModel(obj: any): obj is DocumentModel { export function isDocumentModel(obj: any): obj is DocumentModel {

View File

@ -2,9 +2,13 @@ import { obx, computed } from '@ali/lowcode-editor-core';
import { Node, ParentalNode } from './node'; import { Node, ParentalNode } from './node';
import { TransformStage } from './transform-stage'; import { TransformStage } from './transform-stage';
import { NodeData, isNodeSchema } from '@ali/lowcode-types'; import { NodeData, isNodeSchema } from '@ali/lowcode-types';
import { shallowEqual } from '@ali/lowcode-utils';
import { EventEmitter } from 'events';
export class NodeChildren { export class NodeChildren {
@obx.val private children: Node[]; @obx.val private children: Node[];
private emitter = new EventEmitter();
constructor(readonly owner: ParentalNode, data: NodeData | NodeData[]) { constructor(readonly owner: ParentalNode, data: NodeData | NodeData[]) {
this.children = (Array.isArray(data) ? data : [data]).map(child => { this.children = (Array.isArray(data) ? data : [data]).map(child => {
return this.owner.document.createNode(child); return this.owner.document.createNode(child);
@ -52,6 +56,9 @@ export class NodeChildren {
this.children = children; this.children = children;
this.interalInitParent(); this.interalInitParent();
if (!shallowEqual(children, originChildren)) {
this.emitter.emit('change');
}
} }
/** /**
@ -86,6 +93,7 @@ export class NodeChildren {
deleted.internalSetParent(null); deleted.internalSetParent(null);
deleted.purge(); deleted.purge();
} }
this.emitter.emit('change');
return false; return false;
} }
@ -118,6 +126,8 @@ export class NodeChildren {
children.splice(index, 0, node); children.splice(index, 0, node);
} }
this.emitter.emit('change');
// check condition group // check condition group
if (node.conditionGroup) { if (node.conditionGroup) {
if ( if (
@ -208,14 +218,7 @@ export class NodeChildren {
} }
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) { mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
/* let changed = false;
const children = this.children.slice();
children.forEach(child => child.internalSetParent(null));
this.children = children;
this.interalInitParent();
*/
if (remover) { if (remover) {
const willRemove = this.children.filter(remover); const willRemove = this.children.filter(remover);
if (willRemove.length > 0) { if (willRemove.length > 0) {
@ -226,6 +229,7 @@ export class NodeChildren {
node.remove(); node.remove();
} }
}); });
changed = true;
} }
} }
if (adder) { if (adder) {
@ -236,11 +240,23 @@ export class NodeChildren {
this.children.push(node); this.children.push(node);
node.internalSetParent(this.owner); node.internalSetParent(this.owner);
}); });
changed = true;
} }
} }
if (sorter) { if (sorter) {
this.children = this.children.sort(sorter); this.children = this.children.sort(sorter);
changed = true;
} }
if (changed) {
this.emitter.emit('change');
}
}
onChange(fn: () => void) {
this.emitter.on('change', fn);
return () => {
this.emitter.removeListener('change', fn);
};
} }
private purged = false; private purged = false;

View File

@ -10,6 +10,7 @@ import {
SlotSchema, SlotSchema,
PageSchema, PageSchema,
ComponentSchema, ComponentSchema,
NodeStatus,
} from '@ali/lowcode-types'; } from '@ali/lowcode-types';
import { Props, EXTRA_KEY_PREFIX } from './props/props'; import { Props, EXTRA_KEY_PREFIX } from './props/props';
import { DocumentModel } from '../document-model'; import { DocumentModel } from '../document-model';
@ -483,7 +484,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
} }
const { props = {}, extras } = this.props.export(stage) || {}; const { props = {}, extras } = this.props.export(stage) || {};
const _extras_: {[key: string]: any} = { const _extras_: { [key: string]: any } = {
...extras, ...extras,
}; };
if (_extras_) { if (_extras_) {
@ -593,20 +594,42 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
return this.props; return this.props;
} }
onChildrenChange(fn: () => void) {
return this.children?.onChange(fn);
}
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) { mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
this.children?.mergeChildren(remover, adder, sorter); this.children?.mergeChildren(remover, adder, sorter);
} }
@obx.val status: NodeStatus = {
inPlaceEditing: false,
locking: false,
pseudo: false,
};
/** /**
* @deprecated * @deprecated
*/ */
getStatus() { getStatus(field?: keyof NodeStatus) {
return 'default'; if (field && this.status[field] != null) {
return this.status[field];
}
return this.status;
} }
/** /**
* @deprecated * @deprecated
*/ */
setStatus() {} setStatus(field: keyof NodeStatus, flag: boolean) {
if (!this.status.hasOwnProperty(field)) {
return;
}
if (flag !== this.status[field]) {
this.status[field] = flag;
}
}
/** /**
* @deprecated * @deprecated
*/ */
@ -654,6 +677,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this._addons[key] = exportData; this._addons[key] = exportData;
} }
getRect(): DOMRect | null {
return this.document.simulator?.computeRect(this) || null;
}
toString() { toString() {
return this.id; return this.id;
} }
@ -666,9 +693,9 @@ export interface LeafNode extends Node {
readonly children: null; readonly children: null;
} }
export interface SlotNode extends ParentalNode<SlotSchema> {} export type SlotNode = ParentalNode<SlotSchema>;
export interface PageNode extends ParentalNode<PageSchema> {} export type PageNode = ParentalNode<PageSchema>;
export interface ComponentNode extends ParentalNode<ComponentSchema> {} export type ComponentNode = ParentalNode<ComponentSchema>;
export type RootNode = PageNode | ComponentNode; export type RootNode = PageNode | ComponentNode;
export function isNode(node: any): node is Node { export function isNode(node: any): node is Node {

View File

@ -39,9 +39,24 @@ export function registerSetter(
title: (setter as any).displayName || (setter as any).name || 'CustomSetter', title: (setter as any).displayName || (setter as any).name || 'CustomSetter',
}; };
} }
if (!setter.initialValue) {
const initial = getInitialFromSetter(setter.component);
if (initial) {
setter.initialValue = (field: any) => {
return initial.call(field, field.getValue());
};
}
}
settersMap.set(typeOrMaps, { type: typeOrMaps, ...setter }); settersMap.set(typeOrMaps, { type: typeOrMaps, ...setter });
} }
function getInitialFromSetter(setter: any) {
return setter && (
setter.initial || setter.Initial
|| (setter.type && (setter.type.initial || setter.type.Initial))
) || null; // eslint-disable-line
}
export function getSetter(type: string): RegisteredSetter | null { export function getSetter(type: string): RegisteredSetter | null {
return settersMap.get(type) || null; return settersMap.get(type) || null;
} }

View File

@ -1,5 +1,5 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { obx } from '../utils/obx'; import { obx, computed } from '../utils/obx';
const languageMap: { [key: string]: string } = { const languageMap: { [key: string]: string } = {
en: 'en-US', en: 'en-US',
zh: 'zh-CN', zh: 'zh-CN',
@ -29,8 +29,50 @@ const languageMap: { [key: string]: string } = {
const LowcodeConfigKey = 'ali-lowcode-config'; const LowcodeConfigKey = 'ali-lowcode-config';
class AliGlobalLocale { class AliGlobalLocale {
@obx.ref private locale: string = '';
private emitter = new EventEmitter(); 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() { constructor() {
this.emitter.setMaxListeners(0); this.emitter.setMaxListeners(0);
@ -40,7 +82,7 @@ class AliGlobalLocale {
if (locale === this.locale) { if (locale === this.locale) {
return; return;
} }
this.locale = locale; this._locale = locale;
if (hasLocalStorage(window)) { if (hasLocalStorage(window)) {
const store = window.localStorage; const store = window.localStorage;
let config: any; let config: any;
@ -62,47 +104,6 @@ class AliGlobalLocale {
} }
getLocale() { 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; return this.locale;
} }

View File

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

View File

@ -157,17 +157,12 @@ export class EntryField extends Component<EntryFieldProps> {
fieldProps['data-stage-target'] = stageName; 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 ( return (
<div className={classNameList} {...fieldProps}> <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> </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 classNames from 'classnames';
import { Dropdown, Menu } from '@alifd/next'; import { Dropdown, Menu } from '@alifd/next';
import { import {
@ -9,7 +9,6 @@ import {
TitleContent, TitleContent,
isSetterConfig, isSetterConfig,
isDynamicSetter, isDynamicSetter,
isI18nData,
} from '@ali/lowcode-types'; } from '@ali/lowcode-types';
import { import {
getSetter, getSetter,
@ -20,13 +19,14 @@ import {
createSetterContent, createSetterContent,
observer, observer,
shallowIntl, shallowIntl,
Tip,
} from '@ali/lowcode-editor-core'; } from '@ali/lowcode-editor-core';
import { IconConvert } from '../../icons/convert'; import { IconConvert } from '../../icons/convert';
import { intlNode } from '../../locale';
import './style.less'; import './style.less';
import { SettingField } from '@ali/lowcode-designer'; import { SettingField } from '@ali/lowcode-designer';
import { IconVariable } from '../../icons/variable';
export interface SetterItem { export interface SetterItem {
name: string; name: string;
@ -101,6 +101,10 @@ function nomalizeSetters(setters?: Array<string | SetterConfig | CustomView | Dy
}); });
} }
interface VariableSetter extends ComponentClass {
show(params: object): void;
}
@observer @observer
export default class MixedSetter extends Component<{ export default class MixedSetter extends Component<{
field: SettingField; field: SettingField;
@ -116,24 +120,32 @@ export default class MixedSetter extends Component<{
const { field } = this.props; const { field } = this.props;
let firstMatched: SetterItem | undefined; let firstMatched: SetterItem | undefined;
for (const setter of this.setters) { for (const setter of this.setters) {
const matched = !setter.condition || setter.condition(field);
if (matched) {
if (setter.name === this.used) { if (setter.name === this.used) {
return setter; return setter;
} }
if (!firstMatched) { const matched = !setter.condition || setter.condition(field);
if (matched && !firstMatched) {
firstMatched = setter; firstMatched = setter;
} }
} }
}
return firstMatched; return firstMatched;
} }
// dirty fix vision variable setter logic
private hasVariableSetter = this.setters.some((item) => item.name === 'VariableSetter');
private useSetter = (name: string) => { 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) { if (name === this.used) {
return; return;
} }
const { field, onChange } = this.props;
const setter = this.setters.find((item) => item.name === name); const setter = this.setters.find((item) => item.name === name);
this.used = name; this.used = name;
if (setter) { if (setter) {
@ -163,23 +175,17 @@ export default class MixedSetter extends Component<{
this.checkIsBlockField(); this.checkIsBlockField();
} }
render() { private renderCurrentSetter(currentSetter?: SetterItem, extraProps?: object) {
const { className, field, setters, onSetterChange, ...restProps } = this.props; const { className, field, setters, onSetterChange, ...restProps } = this.props;
if (!currentSetter) {
const currentSetter = this.getCurrentSetter(); // TODO: use intl
const isTwoType = this.setters.length < 3; if (restProps.value == null) {
return <span>NullValue</span>;
let setterContent: any; } else {
const triggerTitle: any = { return <span>InvalidValue</span>;
tip: { }
type: 'i18n', }
'zh-CN': '切换格式', const { setter, props } = currentSetter;
'en-US': 'Switch Format',
},
icon: <IconConvert size={24} />,
};
if (currentSetter) {
const { setter, title, props } = currentSetter;
let setterProps: any = {}; let setterProps: any = {};
let setterType: any; let setterType: any;
if (isDynamicSetter(setter)) { if (isDynamicSetter(setter)) {
@ -194,48 +200,97 @@ export default class MixedSetter extends Component<{
} }
} }
setterContent = createSetterContent(setterType, { return createSetterContent(setterType, {
...shallowIntl(setterProps), ...shallowIntl(setterProps),
field, field,
...restProps, ...restProps,
...extraProps,
}); });
if (title) { }
if (typeof title !== 'object' || isI18nData(title) || isValidElement(title)) {
triggerTitle.tip = title; 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 { } else {
triggerTitle.tip = title.tip || title.label; // =2: 另外一个 Setter 原地展示icon 高亮,点击弹出调用 VariableSetter.show
// FIXME! use variable placeholder setter
const otherSetter = this.setters.find((item) => item.name !== 'VariableSetter')!;
setterContent = this.renderCurrentSetter(otherSetter, {
value: field.getMockOrValue(),
});
} }
} actions = (
} else {
// 未匹配的 null 值,显示 NullValue 空值
// 未匹配的 其它 值,显示 InvalidValue 非法值
if (restProps.value == null) {
setterContent = <span>NullValue</span>;
} else {
setterContent = <span>InvalidValue</span>;
}
}
const usedName = currentSetter?.name || this.used;
let moreBtnNode = (
<Title <Title
title={triggerTitle} className={field.isUseVariable() ? 'variable-binded' : ''}
className="lc-switch-trigger" title={{
onClick={ icon: <IconVariable size={24} />,
isTwoType tip: tipContent,
? () => { }}
if (this.setters[0]?.name === usedName) { onClick={() => {
this.useSetter(this.setters[1]?.name); setterComponent.show({ prop: field });
} else { }}
this.useSetter(this.setters[0]?.name);
}
}
: undefined
}
/> />
); );
if (!isTwoType) { } else {
moreBtnNode = ( // >=3: 原地展示当前 setter<当前绑定的值,点击调用 VariableSetter.show>icon tip 提示绑定的值,点击展示切换 Setter点击其它 setter 直接切换,点击 Variable Setter-> VariableSetter.show
<Dropdown trigger={moreBtnNode} triggerType="click" align="tr br"> 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;
const triggerNode = (
<Title
title={{
tip: intlNode('Switch Setter'),
// FIXME: got a beautiful icon
icon: <IconConvert size={24} />,
}}
className="lc-switch-trigger"
/>
);
return (
<Dropdown trigger={triggerNode} triggerType="click" align="tr br">
<Menu selectMode="single" hasSelectedIcon={true} selectedKeys={usedName} onItemClick={this.useSetter}> <Menu selectMode="single" hasSelectedIcon={true} selectedKeys={usedName} onItemClick={this.useSetter}>
{this.setters {this.setters
.filter((setter) => setter.list || setter.name === usedName) .filter((setter) => setter.list || setter.name === usedName)
@ -251,11 +306,31 @@ export default class MixedSetter extends Component<{
); );
} }
render() {
const { className } = this.props;
let contents: {
setterContent: ReactNode,
actions: ReactNode,
} | undefined;
if (this.hasVariableSetter) {
// 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 ( return (
<div ref={(shell) => (this.shell = shell)} className={classNames('lc-setter-mixed', className)}> <div ref={(shell) => (this.shell = shell)} className={classNames('lc-setter-mixed', className)}>
{setterContent} {contents.setterContent}
<div className="lc-setter-actions">{contents.actions}</div>
<div className="lc-setter-actions">{moreBtnNode}</div>
</div> </div>
); );
} }

View File

@ -16,6 +16,14 @@
opacity: 1; opacity: 1;
} }
} }
.lc-title {
cursor: pointer;
}
.variable-binded {
background: var(--color-brand, #006cff);
color: #fff!important;
border-radius: 3px;
}
} }
.next-input,.next-date-picker { .next-input,.next-date-picker {
width: 100%; width: 100%;

View File

@ -95,7 +95,7 @@ export class TitledPanelView extends Component<{ panel: Panel }> {
hidden: !panel.visible, hidden: !panel.visible,
})}> })}>
<PanelTitle panel={panel} /> <PanelTitle panel={panel} />
<div className="lc-pane-body">{panel.body}</div> <div className="lc-panel-body">{panel.body}</div>
</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

@ -50,24 +50,28 @@ body {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: relative;
.pane-title { &.hidden {
// height: var(--pane-title-height); display: none;
}
.lc-panel-title {
height: 32px;
background-color: var(--pane-title-bg-color); background-color: var(--pane-title-bg-color);
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 15px; padding: 0 15px;
.my-help-tip { .lc-help-tip {
margin-left: 4px; margin-left: 4px;
} }
} }
.pane-body { .lc-panel-body {
position: absolute; position: absolute;
top: 0; top: 32px;
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
overflow: auto; overflow: auto;
/*
.my-tabs { .my-tabs {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -99,10 +103,7 @@ body {
overflow: hidden; overflow: hidden;
} }
} }
} */
&.titled > .pane-body {
top: var(--pane-title-height);
} }
} }
.lc-panel { .lc-panel {
@ -112,16 +113,7 @@ body {
&.hidden { &.hidden {
display: none; display: none;
} }
.pane-title { /*
height: var(--pane-title-height);
background-color: var(--pane-title-bg-color);
display: flex;
align-items: center;
padding: 0 15px;
.my-help-tip {
margin-left: 4px;
}
}
.my-tabs { .my-tabs {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -154,6 +146,7 @@ body {
overflow: hidden; overflow: hidden;
} }
} }
*/
} }
.my-dock { .my-dock {

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

@ -181,7 +181,7 @@ export default function(metadata: TransformedComponentMetadata): TransformedComp
title: { type: 'i18n', 'zh-CN': '高级', 'en-US': 'Advance' }, title: { type: 'i18n', 'zh-CN': '高级', 'en-US': 'Advance' },
items: [ items: [
{ {
name: '__condition', name: '___condition',
title: { type: 'i18n', 'zh-CN': '条件显示', 'en-US': 'Condition' }, title: { type: 'i18n', 'zh-CN': '条件显示', 'en-US': 'Condition' },
setter: 'ExpressionSetter', setter: 'ExpressionSetter',
}, },
@ -190,7 +190,7 @@ export default function(metadata: TransformedComponentMetadata): TransformedComp
title: { type: 'i18n', 'zh-CN': '循环', 'en-US': 'Loop' }, title: { type: 'i18n', 'zh-CN': '循环', 'en-US': 'Loop' },
items: [ items: [
{ {
name: '__loop', name: '___loop',
title: { type: 'i18n', 'zh-CN': '循环数据', 'en-US': 'Loop Data' }, title: { type: 'i18n', 'zh-CN': '循环数据', 'en-US': 'Loop Data' },
setter: { setter: {
componentName: 'MixinSetter', componentName: 'MixinSetter',
@ -215,7 +215,7 @@ export default function(metadata: TransformedComponentMetadata): TransformedComp
}, },
}, },
{ {
name: '__loopArgs.0', name: '___loopArgs.0',
title: { type: 'i18n', 'zh-CN': '迭代变量名', 'en-US': 'Loop Item' }, title: { type: 'i18n', 'zh-CN': '迭代变量名', 'en-US': 'Loop Item' },
setter: { setter: {
componentName: 'StringSetter', componentName: 'StringSetter',
@ -225,7 +225,7 @@ export default function(metadata: TransformedComponentMetadata): TransformedComp
}, },
}, },
{ {
name: '__loopArgs.1', name: '___loopArgs.1',
title: { type: 'i18n', 'zh-CN': '索引变量名', 'en-US': 'Loop Index' }, title: { type: 'i18n', 'zh-CN': '索引变量名', 'en-US': 'Loop Index' },
setter: { setter: {
componentName: 'StringSetter', componentName: 'StringSetter',

View File

@ -6,6 +6,7 @@ import { PanelDockConfig } from '../types';
import Panel from './panel'; import Panel from './panel';
import { PanelDockView, WidgetView } from '../components/widget-views'; import { PanelDockView, WidgetView } from '../components/widget-views';
import { IWidget } from './widget'; import { IWidget } from './widget';
import { composeTitle } from './utils';
export default class PanelDock implements IWidget { export default class PanelDock implements IWidget {
readonly isWidget = true; readonly isWidget = true;

View File

@ -74,6 +74,8 @@ export default class Panel implements IWidget {
); );
content.forEach((item) => this.add(item)); content.forEach((item) => this.add(item));
} }
// compatiable for vision, init at first
this.initBody();
// todo: process shortcut // todo: process shortcut
} }
@ -164,15 +166,21 @@ export default class Panel implements IWidget {
/** /**
* @deprecated * @deprecated
*/ */
getCurrentPosition() { getSupportedPositions() {
return 'left'; return ['default'];
} }
/** /**
* @deprecated * @deprecated
*/ */
getSupportedPositions() { getCurrentPosition() {
return ['left']; return 'default';
}
/**
* @deprecated
*/
setPosition(position: string) {
} }
} }

View File

@ -5,6 +5,36 @@ import { SimulatorRenderer } from './renderer';
import { host } from './host'; import { host } from './host';
import './renderer.less'; import './renderer.less';
// patch cloneElement avoid lost keyProps
const originCloneElement = window.React.cloneElement;
(window as any).React.cloneElement = (child: any, { _leaf, ...props}: any = {}) => {
if (child.ref && props.ref) {
const dRef = props.ref;
const cRef = child.ref;
props.ref = (x: any) => {
if (cRef) {
if (typeof cRef === 'function') {
cRef(x);
} else {
try {
cRef.current = x;
} catch (e) { }
}
}
if (dRef) {
if (typeof dRef === 'function') {
dRef(x);
} else {
try {
dRef.current = x;
} catch (e) { }
}
}
}
};
return originCloneElement(child, props);
}
export default class SimulatorRendererView extends Component<{ renderer: SimulatorRenderer }> { export default class SimulatorRendererView extends Component<{ renderer: SimulatorRenderer }> {
render() { render() {
const { renderer } = this.props; const { renderer } = this.props;

View File

@ -13,3 +13,4 @@ export * from './utils';
export * from './value-type'; export * from './value-type';
export * from './setter-config'; export * from './setter-config';
export * from './setting-target'; export * from './setting-target';
export * from './node';

View File

@ -0,0 +1,5 @@
export interface NodeStatus {
locking: boolean;
pseudo: boolean;
inPlaceEditing: boolean;
}

View File

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

View File

@ -284,6 +284,17 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
} }
let initialFn = (slotName ? null : initial) || initialValue; let initialFn = (slotName ? null : initial) || initialValue;
if (slotName && initialValue === true) {
initialFn = (field: any, value: any) => {
if (isJSSlot(value)) {
return value;
}
return {
type: 'JSSlot',
value: initialChildren,
};
};
}
if (accessor && !slotName) { if (accessor && !slotName) {
extraProps.getValue = (field: Field, fieldValue: any) => { extraProps.getValue = (field: Field, fieldValue: any) => {
@ -294,17 +305,25 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
} }
} }
const setterInitial = getInitialFromSetter(setter);
addInitial({ addInitial({
name: slotName || name, name: slotName || name,
initial: (field: Field, currentValue: any) => { initial: (field: Field, currentValue: any) => {
// FIXME! read from prototype.defaultProps // FIXME! read from prototype.defaultProps
const defaults = extraProps.defaultValue; const defaults = extraProps.defaultValue;
if (typeof initialFn === 'function') { if (typeof initialFn !== 'function') {
return initialFn.call(field, currentValue, defaults); initialFn = defaultInitial;
} }
return currentValue == null ? defaults : currentValue; const v = initialFn.call(field, currentValue, defaults);
if (setterInitial) {
return setterInitial.call(field, v, defaults);
}
return v;
}, },
}); });
@ -342,11 +361,10 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
}, },
]; ];
if (allowTextInput !== false) { if (allowTextInput !== false) {
setters.unshift('StringSetter'); setters.unshift('I18nSetter');
// FIXME: use I18nSetter
} }
if (supportVariable) { if (supportVariable) {
setters.push('ExpressionSetter'); setters.push('VariableSetter');
} }
newConfig.setter = setters.length > 1 ? setters : setters[0]; newConfig.setter = setters.length > 1 ? setters : setters[0];
@ -403,25 +421,24 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
primarySetter = setter; primarySetter = setter;
} }
} }
if (!primarySetter) {
primarySetter = 'I18nSetter';
}
if (supportVariable) { if (supportVariable) {
if (primarySetter) {
const setters = Array.isArray(primarySetter) const setters = Array.isArray(primarySetter)
? primarySetter.concat('ExpressionSetter') ? primarySetter.concat('VariableSetter')
: [primarySetter, 'ExpressionSetter']; : [primarySetter, 'VariableSetter'];
primarySetter = { primarySetter = {
componentName: 'MixedSetter', componentName: 'MixedSetter',
props: { props: {
setters, setters,
onSetterChange: (field: Field, name: string) => { onSetterChange: (field: Field, name: string) => {
if (useVariableChange) { if (useVariableChange) {
useVariableChange.call(field, { isUseVariable: name === 'ExpressionSetter' }); useVariableChange.call(field, { isUseVariable: name === 'VariableSetter' });
} }
}, },
}, },
}; };
} else {
primarySetter = 'ExpressionSetter';
}
} }
newConfig.setter = primarySetter; newConfig.setter = primarySetter;
@ -430,6 +447,18 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
type AddIntial = (initialItem: InitialItem) => void; type AddIntial = (initialItem: InitialItem) => void;
function getInitialFromSetter(setter: any) {
return setter && (
setter.initial || setter.Initial
|| (setter.type && (setter.type.initial || setter.type.Initial))
) || null; // eslint-disable-line
}
function defaultInitial(value: any, defaultValue: any) {
return value == null ? defaultValue : value;
}
export function upgradeConfigure(items: OldPropConfig[], addInitial: AddIntial) { export function upgradeConfigure(items: OldPropConfig[], addInitial: AddIntial) {
const configure: any[] = []; const configure: any[] = [];
let ignoreSlotName: any = null; let ignoreSlotName: any = null;

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,31 @@ import { assign } from 'lodash';
import { Component, ReactElement } from 'react'; import { Component, ReactElement } from 'react';
import VisualManager from './base/visualManager'; import VisualManager from './base/visualManager';
import Prototype from './bundle/prototype'; import Prototype from './bundle/prototype';
import { VE_HOOKS } from './base/const';
import { registerSetter } from '@ali/lowcode-editor-core';
// TODO: Env 本地引入后需要兼容方法 getDesignerLocale // TODO: Env 本地引入后需要兼容方法 getDesignerLocale
// import Env from './env'; // import Env from './env';
let contextInstance: VisualEngineContext;
// prop is Prop object in Designer // prop is Prop object in Designer
export type SetterProvider = (prop: any, componentPrototype: Prototype) => Component | ReactElement<any>; export type SetterProvider = (prop: any, componentPrototype: Prototype) => Component | ReactElement<any>;
export default class VisualEngineContext { export class VisualEngineContext {
private managerMap: { [name: string]: VisualManager } = {}; private managerMap: { [name: string]: VisualManager } = {};
private moduleMap: { [name: string]: any } = {}; private moduleMap: { [name: string]: any } = {};
private pluginsMap: { [name: string]: any } = {}; private pluginsMap: { [name: string]: any } = {};
constructor() {
if (!contextInstance) {
contextInstance = this;
} else {
return contextInstance;
}
}
use(pluginName: string, plugin: any) { use(pluginName: string, plugin: any) {
this.pluginsMap[pluginName || 'unknown'] = plugin; 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
// initialValue?: any | ((field: any) => any);
});
}
} }
getPlugin(name: string) { getPlugin(name: string) {
@ -102,3 +103,5 @@ export default class VisualEngineContext {
} }
} }
} }
export default new VisualEngineContext();

View File

@ -61,6 +61,7 @@ function upgradePropsReducer(props: any) {
val = val.value; val = val.value;
} }
} }
// todo: type: variable
newProps[key] = val; newProps[key] = val;
}); });
return newProps; 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 { 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 = { const Field = {
@ -11,7 +149,7 @@ const Field = {
EntryField: Placeholder, EntryField: Placeholder,
AccordionField: Placeholder, AccordionField: Placeholder,
BlockField: Placeholder, BlockField: Placeholder,
InlineField: Placeholder InlineField: Placeholder,
}; };
export default Field; export default Field;

View File

@ -9,6 +9,7 @@ interface I18nObject {
} }
export function i18nReducer(obj?: any): any { export function i18nReducer(obj?: any): any {
console.info(obj);
if (!obj) { return obj; } if (!obj) { return obj; }
if (Array.isArray(obj)) { if (Array.isArray(obj)) {
return obj.map((item) => i18nReducer(item)); 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 I18nUtil from '@ali/ve-i18n-util';
import { hotkey as Hotkey } from '@ali/lowcode-editor-core'; import { hotkey as Hotkey } from '@ali/lowcode-editor-core';
import { createElement } from 'react'; 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 Bus from './bus';
import { skeleton } from './editor'; import { skeleton } from './editor';
import { Workbench } from '@ali/lowcode-editor-skeleton'; import { Workbench } from '@ali/lowcode-editor-skeleton';
import Panes from './panes'; import Panes from './panes';
import Exchange from './exchange'; import Exchange from './exchange';
import VisualEngineContext from './context'; import context from './context';
import VisualManager from './base/visualManager'; import VisualManager from './base/visualManager';
import Trunk from './bundle/trunk'; import Trunk from './bundle/trunk';
import Prototype from './bundle/prototype'; import Prototype from './bundle/prototype';
@ -26,6 +26,11 @@ import { designer, editor } from './editor';
import './vision.less'; import './vision.less';
function init(container?: Element) { function init(container?: Element) {
//TODO: dirty fix
// 之前的组件库依赖了这个样式临时fix一下。
// 取决于预览模式是否保留。
document.documentElement.classList.add('engine-design-mode');
if (!container) { if (!container) {
container = document.createElement('div'); container = document.createElement('div');
document.body.appendChild(container); document.body.appendChild(container);
@ -59,8 +64,6 @@ const modules = {
Prop, Prop,
}; };
const context = new VisualEngineContext();
const VisualEngine = { const VisualEngine = {
designer, designer,
editor, editor,

View File

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