fix variables

This commit is contained in:
kangwei 2020-05-03 02:12:24 +08:00
parent b18e3c14b3
commit 93a3c68f43
16 changed files with 179 additions and 56 deletions

View File

@ -25,9 +25,6 @@ Trunk.registerSetter('I18nSetter', {
'zh-CN': '国际化输入',
'en-US': 'International Input'
},
// TODO: below
// condition?: (field: any) => boolean;
// initialValue?: any | ((field: any) => any);
recommend: true,
});
context.use(HOOKS.VE_SETTING_FIELD_VARIABLE_SETTER, VariableSetter);
@ -112,7 +109,7 @@ function initDemoPanes() {
description: '帮助',
},
});
skeleton.add({
area: 'topArea',
type: 'Dock',
@ -289,6 +286,10 @@ function initActionPane() {
async function init() {
Engine.Env.setEnv('RE_VERSION', '7.2.0');
Engine.Env.setSupportFeatures({
subview: true,
i18nPane: true,
});
await loadAssets();
await loadSchema();
await initTrunkPane();

View File

@ -2,3 +2,7 @@ declare module "@ali/visualengine";
declare module "@ali/visualengine-utils";
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

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

View File

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

View File

@ -593,6 +593,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
return this.props;
}
onChildrenChange(fn: () => void) {
return this.children?.onChange(fn);
}
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
this.children?.mergeChildren(remover, adder, sorter);
}
@ -654,6 +658,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this._addons[key] = exportData;
}
getRect(): DOMRect | null {
return this.document.simulator?.computeRect(this) || null;
}
toString() {
return this.id;
}

View File

@ -39,9 +39,24 @@ export function registerSetter(
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 });
}
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 {
return settersMap.get(type) || null;
}

View File

@ -26,7 +26,7 @@ import { intlNode } from '../../locale';
import './style.less';
import { SettingField } from '@ali/lowcode-designer';
import { IconVariable } from 'editor-skeleton/src/icons/variable';
import { IconVariable } from '../../icons/variable';
export interface SetterItem {
name: string;
@ -120,14 +120,12 @@ export default class MixedSetter extends Component<{
const { field } = this.props;
let firstMatched: SetterItem | undefined;
for (const setter of this.setters) {
if (setter.name === this.used) {
return setter;
}
const matched = !setter.condition || setter.condition(field);
if (matched) {
if (setter.name === this.used) {
return setter;
}
if (!firstMatched) {
firstMatched = setter;
}
if (matched && !firstMatched) {
firstMatched = setter;
}
}
return firstMatched;
@ -234,6 +232,7 @@ export default class MixedSetter extends Component<{
);
} else {
// =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(),
@ -243,7 +242,7 @@ export default class MixedSetter extends Component<{
<Title
className={field.isUseVariable() ? 'variable-binded' : ''}
title={{
icon: IconVariable,
icon: <IconVariable size={24} />,
tip: tipContent,
}}
onClick={() => {
@ -314,7 +313,7 @@ export default class MixedSetter extends Component<{
actions: ReactNode,
} | undefined;
if (this.hasVariableSetter) {
// FIXME: polyfill vision variable setter logic
// polyfill vision variable setter logic
const setterComponent = getSetter('VariableSetter')?.component as any;
if (setterComponent && setterComponent.isPopup) {
contents = this.contentsFromPolyfill(setterComponent);

View File

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

View File

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

View File

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

View File

@ -181,7 +181,7 @@ export default function(metadata: TransformedComponentMetadata): TransformedComp
title: { type: 'i18n', 'zh-CN': '高级', 'en-US': 'Advance' },
items: [
{
name: '__condition',
name: '___condition',
title: { type: 'i18n', 'zh-CN': '条件显示', 'en-US': 'Condition' },
setter: 'ExpressionSetter',
},
@ -190,7 +190,7 @@ export default function(metadata: TransformedComponentMetadata): TransformedComp
title: { type: 'i18n', 'zh-CN': '循环', 'en-US': 'Loop' },
items: [
{
name: '__loop',
name: '___loop',
title: { type: 'i18n', 'zh-CN': '循环数据', 'en-US': 'Loop Data' },
setter: {
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' },
setter: {
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' },
setter: {
componentName: 'StringSetter',

View File

@ -6,6 +6,7 @@ import { PanelDockConfig } from '../types';
import Panel from './panel';
import { PanelDockView, WidgetView } from '../components/widget-views';
import { IWidget } from './widget';
import { composeTitle } from './utils';
export default class PanelDock implements IWidget {
readonly isWidget = true;
@ -63,7 +64,7 @@ export default class PanelDock implements IWidget {
name: this.panelName,
props: {
// FIXME! give default title for panel
// title: props ? composeTitle(props?.title, props?.icon, props?.description, true) : '',
title: props ? composeTitle(props?.title, props?.icon, props?.description, true) : '',
...panelProps,
},
contentProps,

View File

@ -74,6 +74,8 @@ export default class Panel implements IWidget {
);
content.forEach((item) => this.add(item));
}
// compatiable for vision, init at first
this.initBody();
// todo: process shortcut
}
@ -93,6 +95,7 @@ export default class Panel implements IWidget {
editor: this.skeleton.editor,
config: this.config,
panel: this,
pane: this,
});
}
}
@ -159,6 +162,18 @@ export default class Panel implements IWidget {
show() {
this.setActive(true);
}
getSupportedPositions() {
return ['default'];
}
getCurrentPosition() {
return 'default';
}
setPosition(position: string) {
}
}
export function isPanel(obj: any): obj is Panel {

View File

@ -5,6 +5,36 @@ import { SimulatorRenderer } from './renderer';
import { host } from './host';
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 }> {
render() {
const { renderer } = this.props;

View File

@ -284,6 +284,17 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
}
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) {
extraProps.getValue = (field: Field, fieldValue: any) => {
@ -294,17 +305,25 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
}
}
const setterInitial = getInitialFromSetter(setter);
addInitial({
name: slotName || name,
initial: (field: Field, currentValue: any) => {
// FIXME! read from prototype.defaultProps
const defaults = extraProps.defaultValue;
if (typeof initialFn === 'function') {
return initialFn.call(field, currentValue, defaults);
if (typeof initialFn !== 'function') {
initialFn = defaultInitial;
}
return currentValue == null ? defaults : currentValue;
const v = initialFn.call(field, currentValue, defaults);
if (setterInitial) {
return setterInitial.call(field, v, defaults);
}
return v;
},
});
@ -343,7 +362,6 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
];
if (allowTextInput !== false) {
setters.unshift('I18nSetter');
// FIXME: use I18nSetter
}
if (supportVariable) {
setters.push('VariableSetter');
@ -429,6 +447,18 @@ export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial)
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) {
const configure: any[] = [];
let ignoreSlotName: any = null;

View File

@ -25,7 +25,6 @@ export class VisualEngineContext {
component: plugin,
title: { type: 'i18n', 'zh-CN': '变量绑定', 'en-US': 'Variable Binding' },
// TODO: add logic below
// condition?: (field: any) => boolean;
// initialValue?: any | ((field: any) => any);
});
}