mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 01:21:58 +00:00
Merge branch 'components-panel' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into components-panel
This commit is contained in:
commit
4f042c6e6d
File diff suppressed because it is too large
Load Diff
@ -14,8 +14,8 @@
|
||||
</script>
|
||||
<script src="https://g.alicdn.com/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js,natty-storage/2.0.2/dist/natty-storage.min.js,natty-fetch/2.6.0/dist/natty-fetch.pc.min.js,tinymce/4.2.5/tinymce-full.js"></script>
|
||||
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
|
||||
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css" />
|
||||
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.alibaba-inc.com/@alifd/next@1.20.25/dist/next.min.css" />
|
||||
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.20.25/dist/next.min.js"></script>
|
||||
<link rel="stylesheet" href="/css/editor-preset-vision.css" />
|
||||
<script>
|
||||
window.pageConfig = {
|
||||
|
||||
@ -755,7 +755,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
// fix target : 浏览器事件响应目标
|
||||
if (!e.target || notMyEvent) {
|
||||
e.target = this.contentDocument!.elementFromPoint(e.canvasX!, e.canvasY!);
|
||||
e.target = this.contentDocument?.elementFromPoint(e.canvasX!, e.canvasY!);
|
||||
}
|
||||
|
||||
// documentModel : 目标文档
|
||||
|
||||
@ -1,19 +1,30 @@
|
||||
import { registerSetter } from '@ali/lowcode-editor-core';
|
||||
import { DatePicker, Input, Radio, Select, Switch, NumberPicker } from '@alifd/next';
|
||||
import { isJSExpression } from '@ali/lowcode-types';
|
||||
import { DatePicker, TimePicker, Input, Radio, Select, Switch, NumberPicker } from '@alifd/next';
|
||||
import ExpressionSetter from './expression-setter';
|
||||
import ColorSetter from './color-setter';
|
||||
import JsonSetter from './json-setter';
|
||||
import EventsSetter from './events-setter';
|
||||
import StyleSetter from './style-setter';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
export const StringSetter = {
|
||||
component: Input,
|
||||
defaultProps: { placeholder: '请输入' },
|
||||
defaultProps: { placeholder: '请输入', style: { maxWidth: 180 } },
|
||||
title: 'StringSetter',
|
||||
recommend: true,
|
||||
};
|
||||
export const NumberSetter = NumberPicker;
|
||||
export const BoolSetter = Switch;
|
||||
export class BoolSetter extends Component {
|
||||
|
||||
render() {
|
||||
const { onChange, value, defaultValue } = this.props;
|
||||
return <Switch checked={value || defaultValue} onChange={
|
||||
val => {
|
||||
onChange(val)
|
||||
}
|
||||
}/>;
|
||||
}
|
||||
}
|
||||
export const SelectSetter = Select;
|
||||
|
||||
// suggest: 做成 SelectSetter 一种变体
|
||||
@ -24,7 +35,12 @@ export const RadioGroupSetter = {
|
||||
},
|
||||
};
|
||||
// suggest: 做成 StringSetter 的一个参数,
|
||||
export const TextAreaSetter = Input.TextArea;
|
||||
export const TextAreaSetter = {
|
||||
component: Input.TextArea,
|
||||
defaultProps: { placeholder: '请输入', style: { maxWidth: 180 } },
|
||||
title: 'TextAreaSetter',
|
||||
recommend: true,
|
||||
};
|
||||
export const DateSetter = DatePicker;
|
||||
export const DateYearSetter = DatePicker.YearPicker;
|
||||
export const DateMonthSetter = DatePicker.MonthPicker;
|
||||
@ -32,6 +48,29 @@ export const DateRangeSetter = DatePicker.RangePicker;
|
||||
|
||||
export { ExpressionSetter, EventsSetter };
|
||||
|
||||
class StringDateSetter extends Component {
|
||||
|
||||
render() {
|
||||
const { onChange, editor } = this.props;
|
||||
return <DatePicker onChange={
|
||||
val => {
|
||||
onChange(val.format())
|
||||
}
|
||||
}/>;
|
||||
}
|
||||
}
|
||||
class StringTimePicker extends Component {
|
||||
|
||||
render() {
|
||||
const { onChange, editor } = this.props;
|
||||
return <TimePicker onChange={
|
||||
val => {
|
||||
onChange(val.format('HH:mm:ss'))
|
||||
}
|
||||
}/>;
|
||||
}
|
||||
}
|
||||
|
||||
const builtinSetters: any = {
|
||||
StringSetter,
|
||||
NumberSetter,
|
||||
@ -39,13 +78,18 @@ const builtinSetters: any = {
|
||||
SelectSetter,
|
||||
ExpressionSetter: {
|
||||
component: ExpressionSetter,
|
||||
condition: (field: any) => {
|
||||
const v = field.getValue();
|
||||
return v == null || isJSExpression(v);
|
||||
},
|
||||
defaultProps: { placeholder: '请输入表达式' },
|
||||
title: '表达式输入',
|
||||
recommend: true,
|
||||
},
|
||||
RadioGroupSetter,
|
||||
TextAreaSetter,
|
||||
DateSetter,
|
||||
DateSetter: StringDateSetter,
|
||||
TimePicker: StringTimePicker,
|
||||
DateYearSetter,
|
||||
DateMonthSetter,
|
||||
DateRangeSetter,
|
||||
|
||||
@ -72,11 +72,18 @@ export class ListSetter extends Component<ArraySetterProps, ArraySetterState> {
|
||||
|
||||
onSort(sortedIds: Array<string | number>) {
|
||||
const { itemsMap } = this.state;
|
||||
const { onChange } = this.props;
|
||||
const items = sortedIds.map((id, index) => {
|
||||
const item = itemsMap.get(id)!;
|
||||
item.setKey(index);
|
||||
// item.setKey(index);
|
||||
return item;
|
||||
});
|
||||
|
||||
const values = items.map((item) => {
|
||||
return item.getValue();
|
||||
});
|
||||
console.log('values',values);
|
||||
onChange(values);
|
||||
this.setState({
|
||||
items,
|
||||
});
|
||||
@ -253,6 +260,7 @@ export default class ArraySetter extends Component<{
|
||||
}
|
||||
|
||||
if (mode === 'popup' || forceInline) {
|
||||
|
||||
const title = (
|
||||
<Fragment>
|
||||
编辑:
|
||||
@ -270,6 +278,7 @@ export default class ArraySetter extends Component<{
|
||||
}
|
||||
this.pipe = (this.context as PopupPipe).create({ width });
|
||||
}
|
||||
|
||||
this.pipe.send(<TableSetter key={field.id} {...props} columns={columns} />, title);
|
||||
return (
|
||||
<Button
|
||||
|
||||
@ -8,7 +8,10 @@ import { SettingField, isSettingField, SettingTopEntry, SettingEntry } from '@al
|
||||
import { isSetterConfig, CustomView } from '@ali/lowcode-types';
|
||||
import { intl } from '../../locale';
|
||||
import { Skeleton } from 'editor-skeleton/src/skeleton';
|
||||
|
||||
function transformStringToFunction(str) {
|
||||
if (typeof str !== 'string') return str;
|
||||
return new Function(`"use strict"; return ${str}`)();
|
||||
}
|
||||
@observer
|
||||
class SettingFieldView extends Component<{ field: SettingField }> {
|
||||
render() {
|
||||
@ -60,7 +63,10 @@ class SettingFieldView extends Component<{ field: SettingField }> {
|
||||
}
|
||||
|
||||
// todo: error handling
|
||||
|
||||
let _onChange = extraProps?.onChange?.value;
|
||||
if (extraProps && extraProps.onChange && extraProps.onChange.type === 'JSFunction') {
|
||||
_onChange = transformStringToFunction(extraProps.onChange.value);
|
||||
}
|
||||
return createField(
|
||||
{
|
||||
meta: field?.componentMeta?.npm || field?.componentMeta?.componentName || '',
|
||||
@ -85,6 +91,7 @@ class SettingFieldView extends Component<{ field: SettingField }> {
|
||||
value,
|
||||
});
|
||||
field.setValue(value);
|
||||
if(_onChange) _onChange(value, field);
|
||||
},
|
||||
onInitial: () => {
|
||||
if (initialValue == null) {
|
||||
|
||||
@ -7,7 +7,7 @@ import { isPlainObject } from '@ali/lowcode-utils';
|
||||
import parseProps from './transducers/parse-props';
|
||||
import addonCombine from './transducers/addon-combine';
|
||||
import SlotSetter from './components/slot-setter';
|
||||
import { isJSSlot } from '@ali/lowcode-types';
|
||||
import { isJSSlot, isJSExpression } from '@ali/lowcode-types';
|
||||
|
||||
registerSetter('ArraySetter', {
|
||||
component: ArraySetter,
|
||||
@ -27,7 +27,7 @@ registerSetter('ObjectSetter', {
|
||||
title: 'ObjectSetter', // TODO
|
||||
condition: (field: any) => {
|
||||
const v = field.getValue();
|
||||
return v == null || isPlainObject(v);
|
||||
return v == null || (isPlainObject(v) && !isJSExpression(v) && !isJSSlot(v));
|
||||
},
|
||||
initialValue: {},
|
||||
recommend: true,
|
||||
|
||||
@ -90,20 +90,20 @@ function propTypeToSetter(propType: PropType): SetterType {
|
||||
initialValue: dataSource[0] ? dataSource[0].value : null,
|
||||
};
|
||||
|
||||
// case 'element':
|
||||
// case 'node': // TODO: use Mixin
|
||||
// return {
|
||||
// // slotSetter
|
||||
// componentName: 'NodeSetter',
|
||||
// props: {
|
||||
// mode: typeName,
|
||||
// },
|
||||
// isRequired,
|
||||
// initialValue: {
|
||||
// type: 'JSSlot',
|
||||
// value: '',
|
||||
// },
|
||||
// };
|
||||
case 'element':
|
||||
case 'node': // TODO: use Mixin
|
||||
return {
|
||||
// slotSetter
|
||||
componentName: 'SlotSetter',
|
||||
props: {
|
||||
mode: typeName,
|
||||
},
|
||||
isRequired,
|
||||
initialValue: {
|
||||
type: 'JSSlot',
|
||||
value: [],
|
||||
},
|
||||
};
|
||||
case 'shape':
|
||||
case 'exact':
|
||||
const items = ((propType as any).value || []).map((item: any) => propConfigToFieldConfig(item));
|
||||
@ -164,12 +164,11 @@ function propTypeToSetter(propType: PropType): SetterType {
|
||||
componentName: 'MixedSetter',
|
||||
props: {
|
||||
// TODO:
|
||||
// setters: (propType as OneOfType).value.map(item => propTypeToSetter(item)),
|
||||
setters: (propType as OneOfType).value.map(item => propTypeToSetter(item)),
|
||||
},
|
||||
isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
componentName: 'MixedSetter',
|
||||
isRequired,
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
.lowcode-plugin-sample-preview {
|
||||
padding: 10px 4px;
|
||||
}
|
||||
|
||||
.lowcode-plugin-sample-preview-content {
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
min-height: 300px;
|
||||
}
|
||||
@ -40,15 +40,10 @@ const SamplePreview = ({ editor }: PluginProps) => {
|
||||
<Button type="primary" onClick={handleClick}>
|
||||
预览
|
||||
</Button>
|
||||
<Dialog
|
||||
visible={visible}
|
||||
footer={false}
|
||||
onClose={handleClose}
|
||||
>
|
||||
{visible && <ReactRenderer
|
||||
schema={schema}
|
||||
components={components}
|
||||
/>}
|
||||
<Dialog visible={visible} footer={false} onClose={handleClose}>
|
||||
{visible &&
|
||||
<ReactRenderer className="lowcode-plugin-sample-preview-content" schema={schema} components={components} />
|
||||
}
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
|
||||
37
packages/react-renderer/demo/compose.md
Normal file
37
packages/react-renderer/demo/compose.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: 复杂组件
|
||||
order: 2
|
||||
---
|
||||
|
||||
````jsx
|
||||
import React, { PureComponent } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import ReactRenderer from '@ali/lowcode-react-renderer';
|
||||
import schema from './schemas/compose';
|
||||
import components from './config/components/index';
|
||||
import utils from './config/utils';
|
||||
import constants from './config/constants';
|
||||
|
||||
class Demo extends PureComponent {
|
||||
static displayName = 'renderer-demo';
|
||||
render() {
|
||||
return (
|
||||
<div className="demo">
|
||||
<ReactRenderer
|
||||
key={schema.fileName}
|
||||
schema={schema}
|
||||
components={components}
|
||||
appHelper={{
|
||||
utils,
|
||||
constants
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render((
|
||||
<Demo />
|
||||
), mountNode);
|
||||
````
|
||||
33
packages/react-renderer/demo/schemas/compose.js
vendored
Normal file
33
packages/react-renderer/demo/schemas/compose.js
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
componentName: 'Page',
|
||||
fileName: 'compose',
|
||||
props: {
|
||||
},
|
||||
children: [
|
||||
{
|
||||
"componentName": "Dropdown",
|
||||
"props": { "trigger": [{ "componentName": "Button", "props": { "type": "primary" }, "children": "确定" }], "triggerType": "click"},
|
||||
"children": [{ "componentName": "Menu", "props": { "style": { "width": 200 } }, "children": [{ "componentName": "MenuItem", "props": {}, "children": "Option 1" }, { "componentName": "MenuItem", "props": { "disabled": false }, "children": "option 2" }, { "componentName": "MenuItem", "props": { "disabled": false }, "children": "option 3" }]}]
|
||||
},
|
||||
{
|
||||
"componentName": "Menu",
|
||||
"props": {
|
||||
"style": {
|
||||
"width": 200
|
||||
}
|
||||
},
|
||||
"children": [{
|
||||
"componentName": "MenuItem",
|
||||
"props": {
|
||||
},
|
||||
"children": "Option 1"
|
||||
}, {
|
||||
"componentName": "MenuItem",
|
||||
"props": {
|
||||
},
|
||||
"children": "Option 2"
|
||||
}]
|
||||
}
|
||||
]
|
||||
};
|
||||
@ -27,7 +27,7 @@
|
||||
"@ali/b3-one": "^0.0.17",
|
||||
"@ali/bzb-request": "^2.6.0-beta.13",
|
||||
"@ali/lib-mtop": "^2.5.1",
|
||||
"@alifd/next": "^1.18.17",
|
||||
"@alifd/next": "^1.19.17",
|
||||
"debug": "^4.1.1",
|
||||
"events": "^3.0.0",
|
||||
"fetch-jsonp": "^1.1.3",
|
||||
|
||||
4
packages/react-renderer/src/index.js
vendored
4
packages/react-renderer/src/index.js
vendored
@ -37,7 +37,7 @@ class FaultComponent extends PureComponent {
|
||||
class NotFoundComponent extends PureComponent {
|
||||
render() {
|
||||
console.error('component not found', this.props);
|
||||
return <Div {...this.props} />;
|
||||
return <Div {...this.props} >{this.props.children || 'Component Not Found'}</Div>;
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ function isReactClass(obj) {
|
||||
return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component);
|
||||
}
|
||||
|
||||
export default class Renderer extends PureComponent {
|
||||
export default class Renderer extends Component {
|
||||
static dislayName = 'renderer';
|
||||
static propTypes = {
|
||||
appHelper: PropTypes.object,
|
||||
|
||||
@ -199,14 +199,13 @@ export default class BaseRender extends PureComponent {
|
||||
if (!schema || !schema.props) {
|
||||
return schema?.children;
|
||||
}
|
||||
let _children = schema.children;
|
||||
if (!_children) return schema.props.children;
|
||||
if (schema.props.children && schema.props.children.length) {
|
||||
if (Array.isArray(schema.props.children)) {
|
||||
_children = Array.isArray(_children) ? _children.concat(schema.props.children) : schema.props.children.unshift(_children);
|
||||
} else {
|
||||
Array.isArray(_children) && _children.push(schema.props.children) || (_children = [_children] && _children.push(schema.props.children));
|
||||
}
|
||||
if (!schema.children) return schema.props.children;
|
||||
if (!schema.props.children) return schema.children;
|
||||
var _children = [].concat(schema.children);
|
||||
if (Array.isArray(schema.props.children)) {
|
||||
_children = _children.concat(schema.props.children);
|
||||
} else {
|
||||
_children.push(schema.props.children);
|
||||
}
|
||||
return _children;
|
||||
};
|
||||
@ -233,9 +232,13 @@ export default class BaseRender extends PureComponent {
|
||||
if (!schema) return null;
|
||||
const { __appHelper: appHelper, __components: components = {} } =
|
||||
this.props || {};
|
||||
|
||||
if (isJSExpression(schema)) {
|
||||
return parseExpression(schema, self);
|
||||
}
|
||||
if (isJSSlot(schema)) {
|
||||
return this.__createVirtualDom(schema.value, self, parentInfo);
|
||||
}
|
||||
if (typeof schema === 'string') return schema;
|
||||
if (typeof schema === 'number' || typeof schema === 'boolean') {
|
||||
return schema.toString();
|
||||
@ -246,7 +249,7 @@ export default class BaseRender extends PureComponent {
|
||||
this.__createVirtualDom(item, self, parentInfo, item && item.__ctx && item.__ctx.lunaKey ? '' : idx),
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME
|
||||
const _children = this.getSchemaChildren(schema);
|
||||
//解析占位组件
|
||||
if (schema.componentName === 'Flagment' && _children) {
|
||||
@ -349,6 +352,9 @@ export default class BaseRender extends PureComponent {
|
||||
props.key = idx;
|
||||
}
|
||||
props.__id = schema.id;
|
||||
if (!props.key) {
|
||||
props.key = props.__id;
|
||||
}
|
||||
const renderComp = (props) => {
|
||||
return engine.createElement(
|
||||
Comp,
|
||||
|
||||
2
packages/react-renderer/src/utils/index.js
vendored
2
packages/react-renderer/src/utils/index.js
vendored
@ -64,7 +64,7 @@ const ENV = {
|
||||
export function isSchema(schema, ignoreArr) {
|
||||
if (isEmpty(schema)) return false;
|
||||
// Leaf 组件也返回 true
|
||||
if (schema.componentName === 'Leaf') return true;
|
||||
if (schema.componentName === 'Leaf' || schema.componentName === 'Slot') return true;
|
||||
if (!ignoreArr && Array.isArray(schema)) return schema.every((item) => isSchema(item));
|
||||
return !!(schema.componentName && schema.props && (typeof schema.props === 'object' || isJSExpression(schema.props)));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user