mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 09:41:57 +00:00
Merge branch 'preset-vision/0.9.0' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into preset-vision/0.9.0
This commit is contained in:
commit
66d0bb06e9
@ -1,5 +1,6 @@
|
||||
{
|
||||
"entry": {
|
||||
"index": "src/index",
|
||||
"editor-preset-vision": "../editor-preset-vision/src/index.ts",
|
||||
"react-simulator-renderer": "../react-simulator-renderer/src/index.ts"
|
||||
},
|
||||
|
||||
@ -4,7 +4,7 @@ import Viewport from './viewport';
|
||||
import { createSimulator } from './create-simulator';
|
||||
import { Node, ParentalNode, DocumentModel, isNode, contains, isRootNode } from '../document';
|
||||
import ResourceConsumer from './resource-consumer';
|
||||
import { AssetLevel, Asset, AssetList, assetBundle, assetItem, AssetType, isElement } from '@ali/lowcode-utils';
|
||||
import { AssetLevel, Asset, AssetList, assetBundle, assetItem, AssetType, isElement, isFormEvent } from '@ali/lowcode-utils';
|
||||
import {
|
||||
DragObjectType,
|
||||
isShaken,
|
||||
@ -240,6 +240,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
doc.addEventListener(
|
||||
'mousedown',
|
||||
(downEvent: MouseEvent) => {
|
||||
// fix for popups close logic
|
||||
document.dispatchEvent(new Event('mousedown'));
|
||||
if (this.liveEditing.editing) {
|
||||
return;
|
||||
}
|
||||
@ -306,9 +308,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
doc.addEventListener(
|
||||
'click',
|
||||
(e) => {
|
||||
// fix for popups close logic
|
||||
document.dispatchEvent(new Event('click'));
|
||||
const target = e.target as HTMLElement;
|
||||
if (isFormEvent(e) || target?.closest('.next-input-group,.next-checkbox-group,.next-date-picker,.next-input,.next-month-picker,.next-number-picker,.next-radio-group,.next-range,.next-range-picker,.next-rating,.next-select,.next-switch,.next-time-picker,.next-upload,.next-year-picker,.next-breadcrumb-item,.next-calendar-header,.next-calendar-table')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
// stop response document click event
|
||||
// e.preventDefault();
|
||||
// e.stopPropagation();
|
||||
// todo: catch link redirect
|
||||
},
|
||||
true,
|
||||
|
||||
@ -140,9 +140,7 @@ export class LiveEditing {
|
||||
|
||||
// TODO: upward testing for b/i/a html elements
|
||||
|
||||
// 非文本编辑
|
||||
// 国际化数据,改变当前
|
||||
// JSExpression, 改变 mock 或 弹出绑定变量
|
||||
|
||||
}
|
||||
|
||||
get editing() {
|
||||
|
||||
@ -249,6 +249,9 @@ export class ComponentMeta {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// compatiable vision
|
||||
prototype?: any;
|
||||
}
|
||||
|
||||
export function isComponentMeta(obj: any): obj is ComponentMeta {
|
||||
|
||||
@ -394,7 +394,7 @@ export class Designer {
|
||||
this._componentMetasMap.forEach((config, key) => {
|
||||
const metaData = config.getMetadata();
|
||||
if (metaData.devMode === 'lowcode') {
|
||||
maps[key] = this.currentDocument?.simulator?.createComponent(metaData.schema);
|
||||
maps[key] = this.currentDocument?.simulator?.createComponent(metaData.schema!);
|
||||
} else {
|
||||
const view = metaData.experimental?.view;
|
||||
if (view) {
|
||||
|
||||
@ -294,6 +294,9 @@ export class SettingPropEntry implements SettingEntry {
|
||||
isUseVariable() {
|
||||
return isJSExpression(this.getValue());
|
||||
}
|
||||
get useVariable() {
|
||||
return this.isUseVariable();
|
||||
}
|
||||
getMockOrValue() {
|
||||
const v = this.getValue();
|
||||
if (isJSExpression(v)) {
|
||||
|
||||
@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
|
||||
import { CustomView, isCustomView, IEditor } from '@ali/lowcode-types';
|
||||
import { computed } from '@ali/lowcode-editor-core';
|
||||
import { SettingEntry } from './setting-entry';
|
||||
import { SettingField } from './setting-field';
|
||||
import { SettingField, isSettingField } from './setting-field';
|
||||
import { SettingPropEntry } from './setting-prop-entry';
|
||||
import { Node } from '../../document';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
@ -124,7 +124,14 @@ export class SettingTopEntry implements SettingEntry {
|
||||
* 获取子项
|
||||
*/
|
||||
get(propName: string | number): SettingPropEntry {
|
||||
return new SettingPropEntry(this, propName);
|
||||
const matched = this.items.find(item => {
|
||||
if (isSettingField(item)) {
|
||||
// TODO: thinkof use name or path?
|
||||
return item.name === propName;
|
||||
}
|
||||
return false;
|
||||
}) as SettingPropEntry;
|
||||
return matched || (new SettingPropEntry(this, propName));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { obx, computed } from '@ali/lowcode-editor-core';
|
||||
import { obx, computed, autorun } from '@ali/lowcode-editor-core';
|
||||
import {
|
||||
isDOMText,
|
||||
isJSExpression,
|
||||
@ -155,17 +155,29 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
this._children = new NodeChildren(this as ParentalNode, this.initialChildren(children));
|
||||
this._children.interalInitParent();
|
||||
this.props.import(this.transformProps(props || {}), extras);
|
||||
this.setupAutoruns();
|
||||
}
|
||||
}
|
||||
|
||||
private transformProps(props: any): any {
|
||||
// FIXME! support PropsList
|
||||
const x = this.document.designer.transformProps(props, this, TransformStage.Init);
|
||||
|
||||
return x;
|
||||
return this.document.designer.transformProps(props, this, TransformStage.Init);
|
||||
// TODO: run transducers in metadata.experimental
|
||||
}
|
||||
|
||||
private autoruns?: Array<() => void>;
|
||||
private setupAutoruns() {
|
||||
const autoruns = this.componentMeta.getMetadata().experimental?.autoruns;
|
||||
if (!autoruns || autoruns.length < 1) {
|
||||
return;
|
||||
}
|
||||
this.autoruns = autoruns.map(item => {
|
||||
return autorun(() => {
|
||||
item.autorun(this.props.get(item.name, true) as any)
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
private initialChildren(children: any): NodeData[] {
|
||||
// FIXME! this is dirty code
|
||||
if (children == null) {
|
||||
@ -591,6 +603,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
if (this.isParental()) {
|
||||
this.children.purge();
|
||||
}
|
||||
this.autoruns?.forEach(dispose => dispose());
|
||||
this.props.purge();
|
||||
this.document.internalRemoveAndPurgeNode(this);
|
||||
}
|
||||
@ -608,7 +621,16 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
insertBefore(node: Node, ref?: Node) {
|
||||
this.children?.insert(node, ref ? ref.index : null);
|
||||
}
|
||||
insertAfter(node: Node, ref?: Node) {
|
||||
insertAfter(node: any, ref?: Node) {
|
||||
if (!isNode(node)) {
|
||||
if (node.getComponentName) {
|
||||
node = this.document.createNode({
|
||||
componentName: node.getComponentName(),
|
||||
});
|
||||
} else {
|
||||
node = this.document.createNode(node);
|
||||
}
|
||||
}
|
||||
this.children?.insert(node, ref ? ref.index + 1 : null);
|
||||
}
|
||||
getParent() {
|
||||
@ -687,6 +709,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
* @deprecated
|
||||
*/
|
||||
getSuitablePlace(node: Node, ref: any): any {
|
||||
// TODO:
|
||||
if (this.isRoot()) {
|
||||
return { container: this, ref };
|
||||
}
|
||||
@ -721,7 +744,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
}
|
||||
|
||||
getPrototype() {
|
||||
return this;
|
||||
return this.componentMeta.prototype;
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { obx, autorun, untracked, computed } from '@ali/lowcode-editor-core';
|
||||
import { Prop, IPropParent, UNSET } from './prop';
|
||||
import { Props } from './props';
|
||||
import { Node } from '../node';
|
||||
|
||||
export type PendingItem = Prop[];
|
||||
export class PropStash implements IPropParent {
|
||||
@ -15,8 +16,10 @@ export class PropStash implements IPropParent {
|
||||
return maps;
|
||||
}
|
||||
private willPurge: () => void;
|
||||
readonly owner: Node;
|
||||
|
||||
constructor(readonly props: Props, write: (item: Prop) => void) {
|
||||
this.owner = props.owner;
|
||||
this.willPurge = autorun(() => {
|
||||
if (this.space.size < 1) {
|
||||
return;
|
||||
|
||||
@ -4,7 +4,7 @@ import { uniqueId, isPlainObject, hasOwnProperty } from '@ali/lowcode-utils';
|
||||
import { PropStash } from './prop-stash';
|
||||
import { valueToSource } from './value-to-source';
|
||||
import { Props } from './props';
|
||||
import { SlotNode } from '../node';
|
||||
import { SlotNode, Node } from '../node';
|
||||
import { TransformStage } from '../transform-stage';
|
||||
|
||||
export const UNSET = Symbol.for('unset');
|
||||
@ -13,12 +13,14 @@ export type UNSET = typeof UNSET;
|
||||
export interface IPropParent {
|
||||
delete(prop: Prop): void;
|
||||
readonly props: Props;
|
||||
readonly owner: Node;
|
||||
}
|
||||
|
||||
export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot';
|
||||
|
||||
export class Prop implements IPropParent {
|
||||
readonly isProp = true;
|
||||
readonly owner: Node;
|
||||
|
||||
/**
|
||||
* @see SettingTarget
|
||||
@ -350,6 +352,7 @@ export class Prop implements IPropParent {
|
||||
key?: string | number,
|
||||
spread = false,
|
||||
) {
|
||||
this.owner = parent.owner;
|
||||
this.props = parent.props;
|
||||
if (value !== UNSET) {
|
||||
this.setValue(value);
|
||||
@ -613,6 +616,10 @@ export class Prop implements IPropParent {
|
||||
getProps() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
getNode() {
|
||||
return this.owner;
|
||||
}
|
||||
}
|
||||
|
||||
export function isProp(obj: any): obj is Prop {
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
"@ali/lowcode-editor-skeleton": "^0.8.24",
|
||||
"@ali/lowcode-plugin-designer": "^0.9.18",
|
||||
"@ali/lowcode-plugin-outline-pane": "^0.8.24",
|
||||
"@ali/ve-i18n-util": "^2.0.2",
|
||||
"@ali/ve-icons": "^4.1.9",
|
||||
"@ali/ve-less-variables": "2.0.3",
|
||||
"@ali/ve-popups": "^4.2.5",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ComponentType, ReactElement } from 'react';
|
||||
import { ComponentMetadata, FieldConfig, InitialItem, FilterItem } from '@ali/lowcode-types';
|
||||
import { ComponentMetadata, FieldConfig, InitialItem, FilterItem, AutorunItem } from '@ali/lowcode-types';
|
||||
import {
|
||||
ComponentMeta,
|
||||
addBuiltinComponentAction,
|
||||
@ -22,12 +22,14 @@ const GlobalPropsConfigure: Array<{
|
||||
position: string;
|
||||
initials?: InitialItem[];
|
||||
filters?: FilterItem[];
|
||||
autoruns?: AutorunItem[];
|
||||
config: FieldConfig
|
||||
}> = [];
|
||||
const Overrides: {
|
||||
[componentName: string]: {
|
||||
initials?: InitialItem[];
|
||||
filters?: FilterItem[];
|
||||
autoruns?: AutorunItem[];
|
||||
override: any;
|
||||
};
|
||||
} = {};
|
||||
@ -35,10 +37,12 @@ const Overrides: {
|
||||
function addGlobalPropsConfigure(config: OldGlobalPropConfig) {
|
||||
const initials: InitialItem[] = [];
|
||||
const filters: FilterItem[] = [];
|
||||
const autoruns: AutorunItem[] = [];
|
||||
GlobalPropsConfigure.push({
|
||||
position: config.position || 'bottom',
|
||||
initials,
|
||||
filters,
|
||||
autoruns,
|
||||
config: upgradePropConfig(config, {
|
||||
addInitial: (item) => {
|
||||
initials.push(item);
|
||||
@ -46,6 +50,9 @@ function addGlobalPropsConfigure(config: OldGlobalPropConfig) {
|
||||
addFilter: (item) => {
|
||||
filters.push(item);
|
||||
},
|
||||
addAutorun: (item) => {
|
||||
autoruns.push(item);
|
||||
},
|
||||
})
|
||||
});
|
||||
}
|
||||
@ -60,24 +67,29 @@ function removeGlobalPropsConfigure(name: string) {
|
||||
function overridePropsConfigure(componentName: string, config: { [name: string]: OldPropConfig } | OldPropConfig[]) {
|
||||
const initials: InitialItem[] = [];
|
||||
const filters: FilterItem[] = [];
|
||||
const autoruns: AutorunItem[] = [];
|
||||
const addInitial = (item: InitialItem) => {
|
||||
initials.push(item);
|
||||
};
|
||||
const addFilter = (item: FilterItem) => {
|
||||
filters.push(item);
|
||||
};
|
||||
const addAutorun = (item: AutorunItem) => {
|
||||
autoruns.push(item);
|
||||
};
|
||||
let override: any;
|
||||
if (Array.isArray(config)) {
|
||||
override = upgradeConfigure(config, { addInitial, addFilter });
|
||||
override = upgradeConfigure(config, { addInitial, addFilter, addAutorun });
|
||||
} else {
|
||||
override = {};
|
||||
Object.keys(config).forEach(key => {
|
||||
override[key] = upgradePropConfig(config[key], { addInitial, addFilter });
|
||||
override[key] = upgradePropConfig(config[key], { addInitial, addFilter, addAutorun });
|
||||
});
|
||||
}
|
||||
Overrides[componentName] = {
|
||||
initials,
|
||||
filters,
|
||||
autoruns,
|
||||
override,
|
||||
};
|
||||
}
|
||||
@ -107,6 +119,7 @@ registerMetadataTransducer(
|
||||
} else if (position === 'bottom') {
|
||||
bottom.push(item.config);
|
||||
}
|
||||
// TODO: replace autoruns,initials,filters
|
||||
});
|
||||
|
||||
const override = Overrides[componentName]?.override;
|
||||
@ -127,6 +140,7 @@ registerMetadataTransducer(
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: replace autoruns,initials,filters
|
||||
}
|
||||
|
||||
return metadata;
|
||||
@ -202,7 +216,7 @@ class Prototype {
|
||||
return new Prototype(config);
|
||||
}
|
||||
|
||||
private id: string;
|
||||
readonly isPrototype = true;
|
||||
private meta: ComponentMeta;
|
||||
readonly options: OldPrototypeConfig | ComponentMetadata;
|
||||
|
||||
@ -215,11 +229,11 @@ class Prototype {
|
||||
const metadata = isNewSpec(input) ? input : upgradeMetadata(input);
|
||||
this.meta = designer.createComponentMeta(metadata);
|
||||
}
|
||||
this.id = uniqueId('prototype');
|
||||
(this.meta as any).prototype = this;
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id;
|
||||
return this.getComponentName();
|
||||
}
|
||||
|
||||
getConfig(configName?: keyof (OldPrototypeConfig | ComponentMetadata)) {
|
||||
@ -316,4 +330,8 @@ class Prototype {
|
||||
}
|
||||
}
|
||||
|
||||
export function isPrototype(obj: any): obj is Prototype {
|
||||
return obj && obj.isPrototype;
|
||||
}
|
||||
|
||||
export default Prototype;
|
||||
|
||||
@ -41,6 +41,10 @@ export class Trunk {
|
||||
return this.metaBundle.getFromMeta(name);
|
||||
}
|
||||
|
||||
getPrototypeById(id: string) {
|
||||
return this.getPrototype(id);
|
||||
}
|
||||
|
||||
listByCategory() {
|
||||
const categories: any[] = [];
|
||||
const categoryMap: any = {};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { ComponentType, ReactElement, isValidElement, ComponentClass } from 'react';
|
||||
import { isPlainObject } from '@ali/lowcode-utils';
|
||||
import { isI18nData, SettingTarget, InitialItem, FilterItem, isJSSlot, ProjectSchema } from '@ali/lowcode-types';
|
||||
import { isI18nData, SettingTarget, InitialItem, FilterItem, isJSSlot, ProjectSchema, AutorunItem } from '@ali/lowcode-types';
|
||||
import { untracked } from '@ali/lowcode-editor-core';
|
||||
|
||||
type Field = SettingTarget;
|
||||
|
||||
@ -292,19 +293,44 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
|
||||
};
|
||||
}
|
||||
|
||||
if (accessor && !slotName) {
|
||||
extraProps.getValue = (field: Field, fieldValue: any) => {
|
||||
return accessor.call(field, fieldValue);
|
||||
};
|
||||
if (!initialFn) {
|
||||
initialFn = accessor;
|
||||
if (!slotName) {
|
||||
if (accessor) {
|
||||
extraProps.getValue = (field: Field, fieldValue: any) => {
|
||||
return accessor.call(field, fieldValue);
|
||||
};
|
||||
}
|
||||
|
||||
if (sync || accessor) {
|
||||
collector.addAutorun({
|
||||
name,
|
||||
autorun: (field: Field) => {
|
||||
let fieldValue = untracked(() => field.getValue());
|
||||
if (accessor) {
|
||||
fieldValue = accessor.call(field, fieldValue)
|
||||
}
|
||||
if (sync) {
|
||||
fieldValue = sync.call(field, fieldValue);
|
||||
if (fieldValue !== undefined) {
|
||||
field.setValue(fieldValue);
|
||||
}
|
||||
} else {
|
||||
field.setValue(fieldValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (mutator) {
|
||||
extraProps.setValue = (field: Field, value: any) => {
|
||||
mutator.call(field, value, value);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const setterInitial = getInitialFromSetter(setter);
|
||||
|
||||
collector.addInitial({
|
||||
// FIXME! name should be "xxx.xxx"
|
||||
// FIXME! name could be "xxx.xxx"
|
||||
name: slotName || name,
|
||||
initial: (field: Field, currentValue: any) => {
|
||||
// FIXME! read from prototype.defaultProps
|
||||
@ -347,20 +373,6 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
|
||||
});
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
extraProps.autorun = (field: Field) => {
|
||||
const value = sync.call(field, field.getValue());
|
||||
if (value !== undefined) {
|
||||
field.setValue(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
if (mutator && !slotName) {
|
||||
extraProps.setValue = (field: Field, value: any) => {
|
||||
mutator.call(field, value, value);
|
||||
};
|
||||
}
|
||||
|
||||
if (slotName) {
|
||||
newConfig.name = slotName;
|
||||
if (!newConfig.title && slotTitle) {
|
||||
@ -398,7 +410,6 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
|
||||
let primarySetter: any;
|
||||
if (type === 'composite') {
|
||||
const initials: InitialItem[] = [];
|
||||
const filters: FilterItem[] = [];
|
||||
const objItems = items
|
||||
? upgradeConfigure(items,
|
||||
{
|
||||
@ -406,8 +417,17 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
|
||||
initials.push(item);
|
||||
},
|
||||
addFilter: (item) => {
|
||||
filters.push(item);
|
||||
}
|
||||
collector.addFilter({
|
||||
name: `${name}.${item.name}`,
|
||||
filter: item.filter,
|
||||
});
|
||||
},
|
||||
addAutorun: (item) => {
|
||||
collector.addAutorun({
|
||||
name: `${name}.${item.name}`,
|
||||
autorun: item.autorun,
|
||||
});
|
||||
},
|
||||
}
|
||||
)
|
||||
: [];
|
||||
@ -483,10 +503,12 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
|
||||
|
||||
type AddInitial = (initialItem: InitialItem) => void;
|
||||
type AddFilter = (filterItem: FilterItem) => void;
|
||||
type AddAutorun = (autorunItem: AutorunItem) => void;
|
||||
|
||||
type ConfigCollector = {
|
||||
addInitial: AddInitial,
|
||||
addFilter: AddFilter,
|
||||
addInitial: AddInitial;
|
||||
addFilter: AddFilter;
|
||||
addAutorun: AddAutorun;
|
||||
}
|
||||
|
||||
function getInitialFromSetter(setter: any) {
|
||||
@ -755,6 +777,7 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
||||
|
||||
const initials: InitialItem[] = [];
|
||||
const filters: FilterItem[] = [];
|
||||
const autoruns: AutorunItem[] = [];
|
||||
const props = upgradeConfigure(configure || [],
|
||||
{
|
||||
addInitial: (item) => {
|
||||
@ -763,10 +786,14 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
||||
addFilter: (item) => {
|
||||
filters.push(item);
|
||||
},
|
||||
addAutorun: (item) => {
|
||||
autoruns.push(item);
|
||||
}
|
||||
}
|
||||
);
|
||||
experimental.initials = initials;
|
||||
experimental.filters = filters;
|
||||
experimental.autoruns = autoruns;
|
||||
|
||||
const supports: any = {};
|
||||
if (canUseCondition != null) {
|
||||
|
||||
@ -1,21 +1,18 @@
|
||||
import Env from './env';
|
||||
import { isJSSlot, isI18nData, isJSExpression } from '@ali/lowcode-types';
|
||||
import { isPlainObject } from '@ali/lowcode-utils';
|
||||
const I18nUtil = require('@ali/ve-i18n-util');
|
||||
import i18nUtil from './i18n-util';
|
||||
|
||||
interface I18nObject {
|
||||
type?: string;
|
||||
use?: string;
|
||||
key?: string;
|
||||
[lang: string]: string | undefined;
|
||||
}
|
||||
|
||||
export function i18nReducer(obj?: any): any {
|
||||
// FIXME: 表达式使用 mock 值,未来live 模式直接使用原始值
|
||||
export function deepValueParser(obj?: any): any {
|
||||
if (isJSExpression(obj)) {
|
||||
obj = obj.mock;
|
||||
}
|
||||
if (!obj) {
|
||||
return obj;
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => i18nReducer(item));
|
||||
return obj.map((item) => deepValueParser(item));
|
||||
}
|
||||
if (isPlainObject(obj)) {
|
||||
if (isI18nData(obj)) {
|
||||
@ -23,19 +20,20 @@ export function i18nReducer(obj?: any): any {
|
||||
let locale = Env.getLocale();
|
||||
if (obj.key) {
|
||||
// FIXME: 此处需要升级I18nUtil,改成响应式
|
||||
return I18nUtil.get(obj.key, locale);
|
||||
return i18nUtil.get(obj.key, locale);
|
||||
}
|
||||
if (locale !== 'zh_CN' && locale !== 'zh_TW' && !obj[locale]) {
|
||||
locale = 'en_US';
|
||||
}
|
||||
return obj[obj.use || locale] || obj.zh_CN;
|
||||
}
|
||||
if (isJSSlot(obj) || isJSExpression(obj)) {
|
||||
|
||||
if (isJSSlot(obj)) {
|
||||
return obj;
|
||||
}
|
||||
const out: I18nObject = {};
|
||||
const out: any = {};
|
||||
Object.keys(obj).forEach((key) => {
|
||||
out[key] = i18nReducer(obj[key]);
|
||||
out[key] = deepValueParser(obj[key]);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import { designer } from './editor';
|
||||
import { DragObjectType, isNode, isDragNodeDataObject } from '@ali/lowcode-designer';
|
||||
import { isPrototype } from './bundle/prototype';
|
||||
|
||||
const dragon = designer.dragon;
|
||||
const DragEngine = {
|
||||
@ -9,7 +10,14 @@ const DragEngine = {
|
||||
if (!r) {
|
||||
return null;
|
||||
}
|
||||
if (isNode(r)) {
|
||||
if (isPrototype(r)) {
|
||||
return {
|
||||
type: DragObjectType.NodeData,
|
||||
data: {
|
||||
componentName: r.getComponentName(),
|
||||
},
|
||||
};
|
||||
} else if (isNode(r)) {
|
||||
return {
|
||||
type: DragObjectType.Node,
|
||||
nodes: [r],
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { isJSBlock, isJSExpression, isJSSlot, isI18nData } from '@ali/lowcode-types';
|
||||
import { isPlainObject, hasOwnProperty } from '@ali/lowcode-utils';
|
||||
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||
import { Designer, LiveEditing, TransformStage, addBuiltinComponentAction, Node } from '@ali/lowcode-designer';
|
||||
import { Designer, LiveEditing, TransformStage, Node } from '@ali/lowcode-designer';
|
||||
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
||||
import { toCss } from '@ali/vu-css-style';
|
||||
import logger from '@ali/vu-logger';
|
||||
@ -9,9 +9,8 @@ import logger from '@ali/vu-logger';
|
||||
import DesignerPlugin from '@ali/lowcode-plugin-designer';
|
||||
import { Skeleton, SettingsPrimaryPane } from '@ali/lowcode-editor-skeleton';
|
||||
|
||||
import { i18nReducer } from './i18n-reducer';
|
||||
import { InstanceNodeSelector } from './components';
|
||||
import { liveEditingRule } from './vc-live-editing';
|
||||
import { deepValueParser } from './deep-value-parser';
|
||||
import { liveEditingRule, liveEditingSaveHander } from './vc-live-editing';
|
||||
|
||||
export const editor = new Editor();
|
||||
globalContext.register(editor, Editor);
|
||||
@ -49,8 +48,6 @@ designer.addPropsReducer((props, node) => {
|
||||
return props;
|
||||
}, TransformStage.Init);
|
||||
|
||||
// 国际化渲染时处理
|
||||
designer.addPropsReducer(i18nReducer, TransformStage.Render);
|
||||
|
||||
function filterReducer(props: any, node: Node): any {
|
||||
const filters = node.componentMeta.getMetadata().experimental?.filters;
|
||||
@ -152,31 +149,8 @@ function appendStyleNode(props: any, styleProp: any, cssClass: string, cssId: st
|
||||
}
|
||||
designer.addPropsReducer(stylePropsReducer, TransformStage.Render);
|
||||
|
||||
// FIXME: 表达式使用 mock 值,未来live 模式直接使用原始值
|
||||
function expressionReducer(obj?: any): any {
|
||||
// TODO: merge with i18nReducer for optimize
|
||||
if (!obj) {
|
||||
return obj;
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => expressionReducer(item));
|
||||
}
|
||||
if (isPlainObject(obj)) {
|
||||
if (isJSExpression(obj)) {
|
||||
return obj.mock;
|
||||
}
|
||||
if (isJSSlot(obj) || isI18nData(obj)) {
|
||||
return obj;
|
||||
}
|
||||
const out: any = {};
|
||||
Object.keys(obj).forEach((key) => {
|
||||
out[key] = expressionReducer(obj[key]);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
designer.addPropsReducer(expressionReducer, TransformStage.Render);
|
||||
// 国际化 & Expression 渲染时处理
|
||||
designer.addPropsReducer(deepValueParser, TransformStage.Render);
|
||||
|
||||
skeleton.add({
|
||||
area: 'mainArea',
|
||||
@ -212,11 +186,4 @@ skeleton.add({
|
||||
});
|
||||
|
||||
LiveEditing.addLiveEditingSpecificRule(liveEditingRule);
|
||||
|
||||
// 实例节点选择器,线框高亮
|
||||
// addBuiltinComponentAction({
|
||||
// name: 'instance-node-selector',
|
||||
// content: InstanceNodeSelector,
|
||||
// important: true,
|
||||
// condition: 'always'
|
||||
// });
|
||||
LiveEditing.addLiveEditingSaveHandler(liveEditingSaveHander);
|
||||
|
||||
79
packages/editor-preset-vision/src/i18n-util/index.d.ts
vendored
Normal file
79
packages/editor-preset-vision/src/i18n-util/index.d.ts
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
declare enum LANGUAGES {
|
||||
zh_CN = 'zh_CN',
|
||||
en_US = 'en_US'
|
||||
}
|
||||
|
||||
export interface I18nRecord {
|
||||
type?: 'i18n';
|
||||
[key: string]: string;
|
||||
/**
|
||||
* i18n unique key
|
||||
*/
|
||||
key?: string;
|
||||
}
|
||||
|
||||
export interface I18nRecordData {
|
||||
gmtCreate: Date;
|
||||
gmtModified: Date;
|
||||
i18nKey: string;
|
||||
i18nText: I18nRecord;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface II18nUtilConfigs {
|
||||
items?: {};
|
||||
/**
|
||||
* 是否禁用初始化加载
|
||||
*/
|
||||
disableInstantLoad?: boolean;
|
||||
/**
|
||||
* 初始化的时候是否全量加载
|
||||
*/
|
||||
disableFullLoad?: boolean;
|
||||
loader?: (configs: ILoaderConfigs) => Promise<I18nRecordData[]>;
|
||||
remover?: (key: string, dic: I18nRecord) => Promise<void>;
|
||||
saver?: (key: string, dic: I18nRecord) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface ILoaderConfigs {
|
||||
/**
|
||||
* search keywords
|
||||
*/
|
||||
keyword?: string;
|
||||
/**
|
||||
* should load all i18n items
|
||||
*/
|
||||
isFull?: boolean;
|
||||
/**
|
||||
* search i18n item based on uniqueKey
|
||||
*/
|
||||
key?: string;
|
||||
}
|
||||
|
||||
export interface II18nUtil {
|
||||
init(config: II18nUtilConfigs): void;
|
||||
isInitialized(): boolean;
|
||||
isReady(): boolean;
|
||||
attach(prop: object, value: I18nRecord, updator: () => any);
|
||||
search(keyword: string, silent?: boolean);
|
||||
load(configs: ILoaderConfigs): Promise<I18nRecord[]>;
|
||||
/**
|
||||
* Get local i18n Record
|
||||
* @param key
|
||||
* @param lang
|
||||
*/
|
||||
get(key: string, lang: string): string | I18nRecord;
|
||||
getFromRemote(key: string): Promise<I18nRecord>;
|
||||
getItem(key: string, forceData?: boolean): any;
|
||||
getItems(): I18nRecord[];
|
||||
update(key: string, doc: I18nRecord, lang: LANGUAGES);
|
||||
create(doc: I18nRecord, lang: LANGUAGES): string;
|
||||
remove(key: string): Promise<void>;
|
||||
|
||||
onReady(func: () => any);
|
||||
onRowsChange(func: () => any);
|
||||
onChange(func: (dic: I18nRecord) => any);
|
||||
}
|
||||
|
||||
declare const i18nUtil: II18nUtil;
|
||||
export default i18nUtil;
|
||||
310
packages/editor-preset-vision/src/i18n-util/index.js
Normal file
310
packages/editor-preset-vision/src/i18n-util/index.js
Normal file
@ -0,0 +1,310 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { obx } from '@ali/lowcode-editor-core';
|
||||
|
||||
|
||||
let keybase = Date.now();
|
||||
function keygen(maps) {
|
||||
let key;
|
||||
do {
|
||||
key = `i18n-${(keybase).toString(36)}`;
|
||||
keybase += 1;
|
||||
} while (key in maps);
|
||||
return key;
|
||||
}
|
||||
|
||||
class DocItem {
|
||||
constructor(parent, doc, unInitial) {
|
||||
this.parent = parent;
|
||||
const { use, ...strings } = doc;
|
||||
this.doc = obx.val({
|
||||
type: 'i18n',
|
||||
...strings,
|
||||
});
|
||||
this.emitter = new EventEmitter;
|
||||
this.inited = unInitial !== true;
|
||||
}
|
||||
|
||||
getKey() {
|
||||
return this.doc.key;
|
||||
}
|
||||
|
||||
getDoc(lang) {
|
||||
if (lang) {
|
||||
return this.doc[lang];
|
||||
}
|
||||
return this.doc;
|
||||
}
|
||||
|
||||
setDoc(doc, lang, initial) {
|
||||
if (lang) {
|
||||
this.doc[lang] = doc;
|
||||
} else {
|
||||
const { use, strings } = doc || {};
|
||||
Object.assign(this.doc, strings);
|
||||
}
|
||||
this.emitter.emit('change', this.doc);
|
||||
|
||||
if (initial) {
|
||||
this.inited = true;
|
||||
} else if (this.inited) {
|
||||
this.parent._saveChange(this.doc.key, this.doc);
|
||||
}
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (!this.inited) return Promise.reject('not initialized');
|
||||
|
||||
const { key, ...doc } = this.doc; // eslint-disable-line
|
||||
this.emitter.emit('change', doc);
|
||||
return this.parent.remove(this.getKey());
|
||||
}
|
||||
|
||||
onChange(func) {
|
||||
this.emitter.on('change', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('change', func);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class I18nUtil {
|
||||
constructor() {
|
||||
this.emitter = new EventEmitter;
|
||||
// original data source from remote
|
||||
this.i18nData = {};
|
||||
// current i18n records on the left pane
|
||||
this.items = [];
|
||||
this.maps = {};
|
||||
// full list of i18n records for synchronized call
|
||||
this.fullList = [];
|
||||
this.fullMap = {};
|
||||
|
||||
this.config = {};
|
||||
this.ready = false;
|
||||
this.isInited = false;
|
||||
}
|
||||
|
||||
_prepareItems(items, isFull = false, isSilent = false) {
|
||||
this[isFull ? 'fullList' : 'items'] = items.map((dict) => {
|
||||
let item = this[isFull ? 'fullMap' : 'maps'][dict.key];
|
||||
if (item) {
|
||||
item.setDoc(dict, null, true);
|
||||
} else {
|
||||
item = new DocItem(this, dict);
|
||||
this[isFull ? 'fullMap' : 'maps'][dict.key] = item;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
if (this.ready && !isSilent) {
|
||||
this.emitter.emit('rowschange');
|
||||
this.emitter.emit('change');
|
||||
} else {
|
||||
this.ready = true;
|
||||
this.emitter.emit('ready');
|
||||
}
|
||||
}
|
||||
|
||||
_load(configs = {}, silent) {
|
||||
if (!this.config.loader) {
|
||||
console.error(new Error('Please load loader while init I18nUtil.'));
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return this.config.loader(configs).then((data) => {
|
||||
if (configs.i18nKey) {
|
||||
return Promise.resolve(data.i18nText);
|
||||
}
|
||||
this._prepareItems(data.data, configs.isFull, silent);
|
||||
// set pagination data to i18nData
|
||||
this.i18nData = data;
|
||||
if (!silent) {
|
||||
this.emitter.emit('rowschange');
|
||||
this.emitter.emit('change');
|
||||
}
|
||||
return Promise.resolve(this.items.map(i => i.getDoc()));
|
||||
});
|
||||
}
|
||||
|
||||
_saveToItems(key, dict) {
|
||||
let item = null;
|
||||
item = this.items.find(doc => doc.getKey() === key);
|
||||
if (!item) {
|
||||
item = this.fullList.find(doc => doc.getKey() === key);
|
||||
}
|
||||
|
||||
if (item) {
|
||||
item.setDoc(dict);
|
||||
} else {
|
||||
item = new DocItem(this, {
|
||||
key,
|
||||
...dict,
|
||||
});
|
||||
this.items.unshift(item);
|
||||
this.fullList.unshift(item);
|
||||
this.maps[key] = item;
|
||||
this.fullMap[key] = item;
|
||||
this._saveChange(key, dict, true);
|
||||
}
|
||||
}
|
||||
|
||||
_saveChange(key, dict, rowschange) {
|
||||
if (rowschange) {
|
||||
this.emitter.emit('rowschange');
|
||||
}
|
||||
this.emitter.emit('change');
|
||||
if (dict === null) {
|
||||
delete this.maps[key];
|
||||
delete this.fullMap[key];
|
||||
}
|
||||
return this._save(key, dict);
|
||||
}
|
||||
|
||||
_save(key, dict) {
|
||||
const saver = dict === null ? this.config.remover : this.config.saver;
|
||||
if (!saver) return Promise.reject('Saver function is not set');
|
||||
return saver(key, dict);
|
||||
}
|
||||
|
||||
init(config) {
|
||||
if (this.isInited) return;
|
||||
this.config = config || {};
|
||||
if (this.config.items) {
|
||||
// inject to current page
|
||||
this._prepareItems(this.config.items);
|
||||
}
|
||||
if (!this.config.disableInstantLoad) {
|
||||
this._load({ isFull: !this.config.disableFullLoad });
|
||||
}
|
||||
this.isInited = true;
|
||||
}
|
||||
|
||||
isInitialized() {
|
||||
return this.isInited;
|
||||
}
|
||||
|
||||
isReady() {
|
||||
return this.ready;
|
||||
}
|
||||
|
||||
// add events updater when i18n record change
|
||||
// we should notify engine's view to change
|
||||
attach(prop, value, updator) {
|
||||
const isI18nValue = value && value.type === 'i18n' && value.key;
|
||||
const key = isI18nValue ? value.key : null;
|
||||
if (prop.i18nLink) {
|
||||
if (isI18nValue && (key === prop.i18nLink.key)) {
|
||||
return prop.i18nLink;
|
||||
}
|
||||
prop.i18nLink.detach();
|
||||
}
|
||||
|
||||
if (isI18nValue) {
|
||||
return {
|
||||
key,
|
||||
detach: this.getItem(key, value).onChange(updator),
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索 i18n 词条
|
||||
*
|
||||
* @param {any} keyword 搜索关键字
|
||||
* @param {boolean} [silent=false] 是否刷新左侧的 i18n 数据
|
||||
* @returns
|
||||
*
|
||||
* @memberof I18nUtil
|
||||
*/
|
||||
search(keyword, silent = false) {
|
||||
return this._load({ keyword }, silent);
|
||||
}
|
||||
|
||||
load(configs = {}) {
|
||||
return this._load(configs);
|
||||
}
|
||||
|
||||
get(key, lang) {
|
||||
const item = this.getItem(key);
|
||||
if (item) {
|
||||
return item.getDoc(lang);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getFromRemote(key) {
|
||||
return this._load({ i18nKey: key });
|
||||
}
|
||||
|
||||
getItem(key, forceData) {
|
||||
if (forceData && !this.maps[key] && !this.fullList[key]) {
|
||||
const item = new DocItem(this, {
|
||||
key,
|
||||
...forceData,
|
||||
}, true);
|
||||
this.maps[key] = item;
|
||||
this.fullMap[key] = item;
|
||||
this.fullList.push(item);
|
||||
this.items.push(item);
|
||||
}
|
||||
return this.maps[key] || this.fullMap[key];
|
||||
}
|
||||
|
||||
getItems() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
update(key, doc, lang) {
|
||||
let dict = this.get(key) || {};
|
||||
if (!lang) {
|
||||
dict = doc;
|
||||
} else {
|
||||
dict[lang] = doc;
|
||||
}
|
||||
this._saveToItems(key, dict);
|
||||
}
|
||||
|
||||
create(doc, lang) {
|
||||
const dict = lang ? { [lang]: doc } : doc;
|
||||
const key = keygen(this.fullMap);
|
||||
this._saveToItems(key, dict);
|
||||
return key;
|
||||
}
|
||||
|
||||
remove(key) {
|
||||
const index = this.items.findIndex(item => item.getKey() === key);
|
||||
const indexG = this.fullList.findIndex(item => item.getKey() === key);
|
||||
if (index > -1) {
|
||||
this.items.splice(index, 1);
|
||||
}
|
||||
if (indexG > -1) {
|
||||
this.fullList.splice(index, 1);
|
||||
}
|
||||
return this._saveChange(key, null, true);
|
||||
}
|
||||
|
||||
onReady(func) {
|
||||
this.emitter.on('ready', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('ready', func);
|
||||
};
|
||||
}
|
||||
|
||||
onRowsChange(func) {
|
||||
this.emitter.on('rowschange', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('rowschange', func);
|
||||
};
|
||||
}
|
||||
|
||||
onChange(func) {
|
||||
this.emitter.on('change', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('change', func);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default new I18nUtil();
|
||||
@ -3,7 +3,7 @@ import Popup from '@ali/ve-popups';
|
||||
import Icons from '@ali/ve-icons';
|
||||
import logger from '@ali/vu-logger';
|
||||
import { render } from 'react-dom';
|
||||
import I18nUtil from '@ali/ve-i18n-util';
|
||||
import I18nUtil from './i18n-util';
|
||||
import { hotkey as Hotkey } from '@ali/lowcode-editor-core';
|
||||
import { createElement } from 'react';
|
||||
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS, VERSION as Version } from './base/const';
|
||||
@ -164,7 +164,7 @@ export {
|
||||
const version = '6.0.0(LowcodeEngine 0.9.0-beta)';
|
||||
|
||||
console.log(
|
||||
`%cVisionEngine %cv${version}`,
|
||||
"color:#000;font-weight:bold;",
|
||||
"color:green;font-weight:bold;"
|
||||
`%c VisionEngine %c v${version} `,
|
||||
"padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060;font-weight:bold;",
|
||||
"padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e;font-weight:bold;"
|
||||
);
|
||||
|
||||
@ -4,34 +4,60 @@ import { DocumentModel } from '@ali/lowcode-designer';
|
||||
|
||||
const { project } = designer;
|
||||
|
||||
export interface OldPageData {
|
||||
export interface PageDataV1 {
|
||||
id: string;
|
||||
componentsTree: RootSchema[];
|
||||
layout: RootSchema;
|
||||
[dataAddon: string]: any;
|
||||
}
|
||||
|
||||
export interface PageDataV2 {
|
||||
id: string;
|
||||
componentsTree: RootSchema[];
|
||||
[dataAddon: string]: any;
|
||||
}
|
||||
|
||||
function isPageDataV1(obj: any): obj is PageDataV1 {
|
||||
return obj && obj.layout;
|
||||
}
|
||||
function isPageDataV2(obj: any): obj is PageDataV2 {
|
||||
return obj && obj.componentsTree && Array.isArray(obj.componentsTree);
|
||||
}
|
||||
|
||||
type OldPageData = PageDataV1 | PageDataV2;
|
||||
|
||||
const pages = Object.assign(project, {
|
||||
setPages(pages: OldPageData[]) {
|
||||
if (!pages || !Array.isArray(pages) || pages.length === 0) {
|
||||
throw new Error('pages schema 不合法');
|
||||
}
|
||||
|
||||
if (pages[0].componentsTree[0]) {
|
||||
pages[0].componentsTree[0].componentName = 'Page';
|
||||
// FIXME
|
||||
pages[0].componentsTree[0].lifeCycles = {};
|
||||
pages[0].componentsTree[0].methods = {};
|
||||
let componentsTree: any;
|
||||
if (isPageDataV1(pages[0])) {
|
||||
componentsTree = [pages[0].layout];
|
||||
} else {
|
||||
componentsTree = pages[0].componentsTree;
|
||||
if (componentsTree[0]) {
|
||||
componentsTree[0].componentName = 'Page';
|
||||
// FIXME
|
||||
componentsTree[0].lifeCycles = {};
|
||||
componentsTree[0].methods = {};
|
||||
}
|
||||
}
|
||||
|
||||
project.load({
|
||||
version: '1.0.0',
|
||||
componentsMap: [],
|
||||
componentsTree: pages[0].componentsTree,
|
||||
componentsTree,
|
||||
}, true);
|
||||
},
|
||||
// FIXME:
|
||||
addPage(data: OldPageData) {
|
||||
return project.open(data.layout);
|
||||
addPage(data: OldPageData | RootSchema) {
|
||||
if (isPageDataV1(data)) {
|
||||
data = data.layout;
|
||||
} else if (isPageDataV2(data)) {
|
||||
data = data.componentsTree[0];
|
||||
}
|
||||
return project.open(data);
|
||||
},
|
||||
getPage(fnOrIndex: ((page: DocumentModel) => boolean) | number) {
|
||||
if (typeof fnOrIndex === 'number') {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { EditingTarget, Node as DocNode } from '@ali/lowcode-designer';
|
||||
import { EditingTarget, Node as DocNode, SaveHandler } from '@ali/lowcode-designer';
|
||||
import Env from './env';
|
||||
import { isJSExpression } from '@ali/lowcode-types';
|
||||
const I18nUtil = require('@ali/ve-i18n-util');
|
||||
import { isJSExpression, isI18nData } from '@ali/lowcode-types';
|
||||
import i18nUtil from './i18n-util';
|
||||
|
||||
interface I18nObject {
|
||||
type?: string;
|
||||
@ -13,7 +13,7 @@ interface I18nObject {
|
||||
function getI18nText(obj: I18nObject) {
|
||||
let locale = Env.getLocale();
|
||||
if (obj.key) {
|
||||
return I18nUtil.get(obj.key, locale);
|
||||
return i18nUtil.get(obj.key, locale);
|
||||
}
|
||||
if (locale !== 'zh_CN' && locale !== 'zh_TW' && !obj[locale]) {
|
||||
locale = 'en_US';
|
||||
@ -26,7 +26,10 @@ function getText(node: DocNode, prop: string) {
|
||||
if (!p || p.isUnset()) {
|
||||
return null;
|
||||
}
|
||||
const v = p.getValue();
|
||||
let v = p.getValue();
|
||||
if (isJSExpression(v)) {
|
||||
v = v.mock;
|
||||
}
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
@ -36,9 +39,7 @@ function getText(node: DocNode, prop: string) {
|
||||
if ((v as any).type === 'i18n') {
|
||||
return getI18nText(v as any);
|
||||
}
|
||||
if (isJSExpression(v)) {
|
||||
return v.mock;
|
||||
}
|
||||
return Symbol.for('not-literal');
|
||||
}
|
||||
|
||||
export function liveEditingRule(target: EditingTarget) {
|
||||
@ -73,7 +74,43 @@ function equalText(v: any, innerText: string) {
|
||||
return v.trim() === innerText
|
||||
}
|
||||
|
||||
// TODO:
|
||||
export function liveEditingSaveHander() {
|
||||
|
||||
export const liveEditingSaveHander: SaveHandler = {
|
||||
condition: (prop) => {
|
||||
const v = prop.getValue();
|
||||
return prop.type === 'expression' || isI18nData(v);
|
||||
},
|
||||
onSaveContent: (content, prop) => {
|
||||
const v = prop.getValue();
|
||||
const locale = Env.getLocale();
|
||||
let data = v;
|
||||
if (isJSExpression(v)) {
|
||||
data = v.mock;
|
||||
}
|
||||
if (isI18nData(data)) {
|
||||
const i18n = data.key ? i18nUtil.getItem(data.key) : null;
|
||||
if (i18n) {
|
||||
i18n.setDoc(content, locale);
|
||||
return;
|
||||
}
|
||||
data = {
|
||||
...(data as any),
|
||||
[locale]: content,
|
||||
};
|
||||
} else {
|
||||
data = content;
|
||||
}
|
||||
if (isJSExpression(v)) {
|
||||
prop.setValue({
|
||||
type: 'JSExpression',
|
||||
value: v.value,
|
||||
mock: data,
|
||||
});
|
||||
} else {
|
||||
prop.setValue(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO:
|
||||
// 非文本编辑
|
||||
// 国际化数据,改变当前
|
||||
// JSExpression, 改变 mock 或 弹出绑定变量
|
||||
|
||||
@ -43,7 +43,7 @@ html {
|
||||
}
|
||||
|
||||
html.engine-blur #engine {
|
||||
-webkit-filter: blur(4px);
|
||||
filter: blur(4px);
|
||||
}
|
||||
|
||||
.engine-main {
|
||||
@ -98,6 +98,11 @@ html.engine-blur #engine {
|
||||
}
|
||||
}
|
||||
|
||||
.vs-icon .vs-icon-del, .vs-icon .vs-icon-entry {
|
||||
width: 16px!important;
|
||||
height: 16px!important;
|
||||
}
|
||||
|
||||
.lc-left-float-pane {
|
||||
font-size: 14px;
|
||||
}
|
||||
@ -107,3 +112,13 @@ html.engine-preview-mode {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ve-popups .ve-message {
|
||||
right: 290px;
|
||||
|
||||
.ve-message-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
@ -36,8 +36,8 @@ export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }>
|
||||
.contentWindow.document.documentElement.contains(target)) {
|
||||
return false;
|
||||
}
|
||||
// 防止点击 popup / dialog 等触发失焦
|
||||
if (!document.querySelector('.lc-workbench-center')?.contains(target)) {
|
||||
// 点击非编辑区域的 popup / dialog 等,不触发失焦
|
||||
if (!document.querySelector('.lc-workbench')?.contains(target)) {
|
||||
return true;
|
||||
}
|
||||
const docks = area.current?.getAssocDocks();
|
||||
|
||||
@ -294,7 +294,7 @@ export class Skeleton {
|
||||
let { area } = parsedConfig;
|
||||
if (!area) {
|
||||
if (parsedConfig.type === 'Panel') {
|
||||
area = 'leftFloatArea'
|
||||
area = 'leftFloatArea';
|
||||
} else if (parsedConfig.type === 'Widget') {
|
||||
area = 'mainArea';
|
||||
} else {
|
||||
|
||||
@ -105,12 +105,13 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> {
|
||||
customCreateElement={(Component: any, props: any, children: any) => {
|
||||
const { __id, __desingMode, ...viewProps } = props;
|
||||
viewProps.componentId = __id;
|
||||
viewProps._leaf = host.document.getNode(__id);
|
||||
const leaf = host.document.getNode(__id);
|
||||
viewProps._leaf = leaf;
|
||||
|
||||
return createElement(
|
||||
getDeviceView(Component, device, designMode),
|
||||
viewProps,
|
||||
children == null ? [] : Array.isArray(children) ? children : [children],
|
||||
leaf?.isContainer() ? (children == null ? [] : Array.isArray(children) ? children : [children]) : null,
|
||||
);
|
||||
}}
|
||||
onCompGetRef={(schema: any, ref: ReactInstance | null) => {
|
||||
|
||||
@ -49,6 +49,11 @@ export interface FilterItem {
|
||||
name: string;
|
||||
filter: (target: SettingTarget, currentValue: any) => any;
|
||||
}
|
||||
export interface AutorunItem {
|
||||
name: string;
|
||||
autorun: (target: SettingTarget) => any;
|
||||
}
|
||||
|
||||
|
||||
export interface Experimental {
|
||||
context?: { [contextInfoName: string]: any };
|
||||
@ -57,8 +62,8 @@ export interface Experimental {
|
||||
transducers?: any; // ? should support
|
||||
initials?: InitialItem[];
|
||||
filters?: FilterItem[];
|
||||
autoruns?: AutorunItem[];
|
||||
callbacks?: Callbacks;
|
||||
// TODO: thinkof function
|
||||
initialChildren?: NodeData[] | ((target: SettingTarget) => NodeData[]);
|
||||
|
||||
// 样式 及 位置,handle上必须有明确的标识以便事件路由判断,或者主动设置事件独占模式
|
||||
@ -85,7 +90,7 @@ export interface Experimental {
|
||||
liveTextEditing?: LiveTextEditingConfig[];
|
||||
}
|
||||
|
||||
// thinkof Array
|
||||
// thinkof Array
|
||||
export interface LiveTextEditingConfig {
|
||||
propTarget: string;
|
||||
selector?: string;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user