mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-17 11:13:50 +00:00
Merge branch 'release/0.9.0' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into feat/monitor
This commit is contained in:
commit
35f255a229
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#### 创建新包:
|
#### 创建新包:
|
||||||
|
|
||||||
- `./create.sh <package-name>`
|
- `./scripts/create.sh <package-name>`
|
||||||
|
|
||||||
#### 跑起来:
|
#### 跑起来:
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,7 @@ const demoData: IProjectSchema = {
|
|||||||
componentsTree: [
|
componentsTree: [
|
||||||
{
|
{
|
||||||
componentName: 'Page',
|
componentName: 'Page',
|
||||||
id: 'node$1',
|
id: 'node_1',
|
||||||
meta: {
|
meta: {
|
||||||
title: '测试',
|
title: '测试',
|
||||||
router: '/',
|
router: '/',
|
||||||
@ -74,7 +74,7 @@ const demoData: IProjectSchema = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
componentName: 'Form',
|
componentName: 'Form',
|
||||||
id: 'node$2',
|
id: 'node_2',
|
||||||
props: {
|
props: {
|
||||||
labelCol: 4,
|
labelCol: 4,
|
||||||
style: {},
|
style: {},
|
||||||
@ -83,7 +83,7 @@ const demoData: IProjectSchema = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
componentName: 'Form.Item',
|
componentName: 'Form.Item',
|
||||||
id: 'node$3',
|
id: 'node_3',
|
||||||
props: {
|
props: {
|
||||||
label: '姓名:',
|
label: '姓名:',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
@ -92,7 +92,7 @@ const demoData: IProjectSchema = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
componentName: 'Input',
|
componentName: 'Input',
|
||||||
id: 'node$4',
|
id: 'node_4',
|
||||||
props: {
|
props: {
|
||||||
placeholder: '请输入',
|
placeholder: '请输入',
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
@ -105,7 +105,7 @@ const demoData: IProjectSchema = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
componentName: 'Form.Item',
|
componentName: 'Form.Item',
|
||||||
id: 'node$5',
|
id: 'node_5',
|
||||||
props: {
|
props: {
|
||||||
label: '年龄:',
|
label: '年龄:',
|
||||||
name: 'age',
|
name: 'age',
|
||||||
@ -114,7 +114,7 @@ const demoData: IProjectSchema = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
componentName: 'NumberPicker',
|
componentName: 'NumberPicker',
|
||||||
id: 'node$6',
|
id: 'node_6',
|
||||||
props: {
|
props: {
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
type: 'normal',
|
type: 'normal',
|
||||||
@ -124,7 +124,7 @@ const demoData: IProjectSchema = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
componentName: 'Form.Item',
|
componentName: 'Form.Item',
|
||||||
id: 'node$7',
|
id: 'node_7',
|
||||||
props: {
|
props: {
|
||||||
label: '职业:',
|
label: '职业:',
|
||||||
name: 'profession',
|
name: 'profession',
|
||||||
@ -132,7 +132,7 @@ const demoData: IProjectSchema = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
componentName: 'Select',
|
componentName: 'Select',
|
||||||
id: 'node$8',
|
id: 'node_8',
|
||||||
props: {
|
props: {
|
||||||
dataSource: [
|
dataSource: [
|
||||||
{
|
{
|
||||||
@ -154,7 +154,7 @@ const demoData: IProjectSchema = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
componentName: 'Div',
|
componentName: 'Div',
|
||||||
id: 'node$9',
|
id: 'node_9',
|
||||||
props: {
|
props: {
|
||||||
style: {
|
style: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
@ -163,12 +163,12 @@ const demoData: IProjectSchema = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
componentName: 'Button.Group',
|
componentName: 'Button.Group',
|
||||||
id: 'node$a',
|
id: 'node_a',
|
||||||
props: {},
|
props: {},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
componentName: 'Button',
|
componentName: 'Button',
|
||||||
id: 'node$b',
|
id: 'node_b',
|
||||||
props: {
|
props: {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
style: {
|
style: {
|
||||||
@ -180,7 +180,7 @@ const demoData: IProjectSchema = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
componentName: 'Button',
|
componentName: 'Button',
|
||||||
id: 'node$d',
|
id: 'node_d',
|
||||||
props: {
|
props: {
|
||||||
type: 'normal',
|
type: 'normal',
|
||||||
style: {
|
style: {
|
||||||
|
|||||||
@ -40,7 +40,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Div",
|
"componentName": "Card",
|
||||||
|
"npm": {
|
||||||
|
"package": "@alifd/next",
|
||||||
|
"version": "1.19.18",
|
||||||
|
"destructuring": true,
|
||||||
|
"exportName": "Card"
|
||||||
|
},
|
||||||
"title": "容器",
|
"title": "容器",
|
||||||
"configure": {
|
"configure": {
|
||||||
"component": {
|
"component": {
|
||||||
@ -197,6 +203,10 @@
|
|||||||
"exportName": "Input"
|
"exportName": "Input"
|
||||||
},
|
},
|
||||||
"props": [{
|
"props": [{
|
||||||
|
"name": "value",
|
||||||
|
"propType": "string",
|
||||||
|
"description": ""
|
||||||
|
},{
|
||||||
"name": "label",
|
"name": "label",
|
||||||
"propType": "node",
|
"propType": "node",
|
||||||
"description": "label"
|
"description": "label"
|
||||||
@ -1503,7 +1513,7 @@
|
|||||||
"children": [{
|
"children": [{
|
||||||
"componentName": "Button",
|
"componentName": "Button",
|
||||||
"title": "按钮",
|
"title": "按钮",
|
||||||
"icon": "",
|
"icon": "add",
|
||||||
"package": "@alife/next",
|
"package": "@alife/next",
|
||||||
"library": "Next",
|
"library": "Next",
|
||||||
"snippets": [{
|
"snippets": [{
|
||||||
@ -1532,7 +1542,8 @@
|
|||||||
"schema": {
|
"schema": {
|
||||||
"componentName": "Button",
|
"componentName": "Button",
|
||||||
"props": {
|
"props": {
|
||||||
"type": "normal"
|
"type": "normal",
|
||||||
|
"value": "normal"
|
||||||
},
|
},
|
||||||
"children": "normal"
|
"children": "normal"
|
||||||
}
|
}
|
||||||
@ -1588,7 +1599,7 @@
|
|||||||
"title": "其他",
|
"title": "其他",
|
||||||
"icon": "",
|
"icon": "",
|
||||||
"children": [{
|
"children": [{
|
||||||
"componentName": "Div",
|
"componentName": "Card",
|
||||||
"library": "Next",
|
"library": "Next",
|
||||||
"title": "容器",
|
"title": "容器",
|
||||||
"icon": "",
|
"icon": "",
|
||||||
@ -1596,7 +1607,7 @@
|
|||||||
"title": "默认",
|
"title": "默认",
|
||||||
"screenshot": "",
|
"screenshot": "",
|
||||||
"schema": {
|
"schema": {
|
||||||
"componentName": "Div",
|
"componentName": "Card",
|
||||||
"props": {}
|
"props": {}
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"componentName": "Page",
|
"componentName": "Page",
|
||||||
"id": "node$1",
|
"id": "node_1",
|
||||||
"props": {
|
"props": {
|
||||||
"ref": "outterView",
|
"ref": "outterView",
|
||||||
"autoLoading": true,
|
"autoLoading": true,
|
||||||
@ -23,7 +23,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "Steps",
|
"componentName": "Steps",
|
||||||
"id": "node$1i",
|
"id": "node_1i",
|
||||||
"props": {
|
"props": {
|
||||||
"dataSource": [
|
"dataSource": [
|
||||||
{
|
{
|
||||||
@ -87,7 +87,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Title",
|
"componentName": "Title",
|
||||||
"id": "node$b",
|
"id": "node_b",
|
||||||
"props": {
|
"props": {
|
||||||
"text": "请填写以下人员信息表单",
|
"text": "请填写以下人员信息表单",
|
||||||
"type": "primary",
|
"type": "primary",
|
||||||
@ -98,7 +98,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Paragraph",
|
"componentName": "Paragraph",
|
||||||
"id": "node$e",
|
"id": "node_e",
|
||||||
"props": {
|
"props": {
|
||||||
"content": "人最宝贵的是生命。它给予我们只有一次。人的一生应当这样度过:当他回首往事时不因虚度年华而悔恨,也不因碌碌无为而羞耻。这样在他临死的时侯就能够说:我已把我整个的生命和全部精力都献给最壮丽的事业——为人类的解放而斗争。",
|
"content": "人最宝贵的是生命。它给予我们只有一次。人的一生应当这样度过:当他回首往事时不因虚度年华而悔恨,也不因碌碌无为而羞耻。这样在他临死的时侯就能够说:我已把我整个的生命和全部精力都献给最壮丽的事业——为人类的解放而斗争。",
|
||||||
"size": "medium",
|
"size": "medium",
|
||||||
@ -109,7 +109,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "ColumnsLayout",
|
"componentName": "ColumnsLayout",
|
||||||
"id": "node$r",
|
"id": "node_r",
|
||||||
"props": {
|
"props": {
|
||||||
"layout": "6:6",
|
"layout": "6:6",
|
||||||
"columnGap": "16px",
|
"columnGap": "16px",
|
||||||
@ -122,7 +122,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "Column",
|
"componentName": "Column",
|
||||||
"id": "node$s",
|
"id": "node_s",
|
||||||
"props": {
|
"props": {
|
||||||
"fieldId": "column_kadcb0o9",
|
"fieldId": "column_kadcb0o9",
|
||||||
"__style__": {}
|
"__style__": {}
|
||||||
@ -130,7 +130,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "Card",
|
"componentName": "Card",
|
||||||
"id": "node$n",
|
"id": "node_n",
|
||||||
"props": {
|
"props": {
|
||||||
"title": "基本信息",
|
"title": "基本信息",
|
||||||
"subTitle": {
|
"subTitle": {
|
||||||
@ -144,7 +144,7 @@
|
|||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"componentName": "Icon",
|
"componentName": "Icon",
|
||||||
"id": "node$q",
|
"id": "node_q",
|
||||||
"props": {
|
"props": {
|
||||||
"type": {
|
"type": {
|
||||||
"useType": true,
|
"useType": true,
|
||||||
@ -168,12 +168,12 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "CardContent",
|
"componentName": "CardContent",
|
||||||
"id": "node$o",
|
"id": "node_o",
|
||||||
"props": {},
|
"props": {},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "Form",
|
"componentName": "Form",
|
||||||
"id": "node$f",
|
"id": "node_f",
|
||||||
"props": {
|
"props": {
|
||||||
"labelAlign": "top",
|
"labelAlign": "top",
|
||||||
"size": "medium",
|
"size": "medium",
|
||||||
@ -190,7 +190,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "TextField",
|
"componentName": "TextField",
|
||||||
"id": "node$g",
|
"id": "node_g",
|
||||||
"props": {
|
"props": {
|
||||||
"__category__": "form",
|
"__category__": "form",
|
||||||
"__useMediator": "value",
|
"__useMediator": "value",
|
||||||
@ -256,7 +256,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "RadioField",
|
"componentName": "RadioField",
|
||||||
"id": "node$14",
|
"id": "node_14",
|
||||||
"props": {
|
"props": {
|
||||||
"__category__": "form",
|
"__category__": "form",
|
||||||
"__useMediator": "value",
|
"__useMediator": "value",
|
||||||
@ -324,7 +324,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "SelectField",
|
"componentName": "SelectField",
|
||||||
"id": "node$h",
|
"id": "node_h",
|
||||||
"props": {
|
"props": {
|
||||||
"__category__": "form",
|
"__category__": "form",
|
||||||
"__useMediator": "value",
|
"__useMediator": "value",
|
||||||
@ -404,7 +404,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Div",
|
"componentName": "Div",
|
||||||
"id": "node$i",
|
"id": "node_i",
|
||||||
"props": {
|
"props": {
|
||||||
"behavior": "NORMAL",
|
"behavior": "NORMAL",
|
||||||
"__style__": {},
|
"__style__": {},
|
||||||
@ -413,7 +413,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "Button",
|
"componentName": "Button",
|
||||||
"id": "node$j",
|
"id": "node_j",
|
||||||
"props": {
|
"props": {
|
||||||
"content": {
|
"content": {
|
||||||
"type": "i18n",
|
"type": "i18n",
|
||||||
@ -449,7 +449,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Button",
|
"componentName": "Button",
|
||||||
"id": "node$k",
|
"id": "node_k",
|
||||||
"props": {
|
"props": {
|
||||||
"content": {
|
"content": {
|
||||||
"type": "i18n",
|
"type": "i18n",
|
||||||
@ -495,7 +495,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Column",
|
"componentName": "Column",
|
||||||
"id": "node$t",
|
"id": "node_t",
|
||||||
"props": {
|
"props": {
|
||||||
"fieldId": "column_kadcb0oa",
|
"fieldId": "column_kadcb0oa",
|
||||||
"__style__": {}
|
"__style__": {}
|
||||||
@ -503,7 +503,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "Card",
|
"componentName": "Card",
|
||||||
"id": "node$u",
|
"id": "node_u",
|
||||||
"props": {
|
"props": {
|
||||||
"title": {
|
"title": {
|
||||||
"type": "JSSlot",
|
"type": "JSSlot",
|
||||||
@ -511,7 +511,7 @@
|
|||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"componentName": "Icon",
|
"componentName": "Icon",
|
||||||
"id": "node$18",
|
"id": "node_18",
|
||||||
"props": {
|
"props": {
|
||||||
"type": {
|
"type": {
|
||||||
"useType": true,
|
"useType": true,
|
||||||
@ -525,7 +525,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Link",
|
"componentName": "Link",
|
||||||
"id": "node$19",
|
"id": "node_19",
|
||||||
"props": {
|
"props": {
|
||||||
"content": {
|
"content": {
|
||||||
"type": "i18n",
|
"type": "i18n",
|
||||||
@ -559,7 +559,7 @@
|
|||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"componentName": "Icon",
|
"componentName": "Icon",
|
||||||
"id": "node$1a",
|
"id": "node_1a",
|
||||||
"props": {
|
"props": {
|
||||||
"type": {
|
"type": {
|
||||||
"useType": true,
|
"useType": true,
|
||||||
@ -583,12 +583,12 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "CardContent",
|
"componentName": "CardContent",
|
||||||
"id": "node$v",
|
"id": "node_v",
|
||||||
"props": {},
|
"props": {},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "Form",
|
"componentName": "Form",
|
||||||
"id": "node$x",
|
"id": "node_x",
|
||||||
"props": {
|
"props": {
|
||||||
"labelAlign": "top",
|
"labelAlign": "top",
|
||||||
"size": "medium",
|
"size": "medium",
|
||||||
@ -605,7 +605,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "TextField",
|
"componentName": "TextField",
|
||||||
"id": "node$y",
|
"id": "node_y",
|
||||||
"props": {
|
"props": {
|
||||||
"__category__": "form",
|
"__category__": "form",
|
||||||
"__useMediator": "value",
|
"__useMediator": "value",
|
||||||
@ -671,7 +671,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "DateField",
|
"componentName": "DateField",
|
||||||
"id": "node$15",
|
"id": "node_15",
|
||||||
"props": {
|
"props": {
|
||||||
"__category__": "form",
|
"__category__": "form",
|
||||||
"__useMediator": "value",
|
"__useMediator": "value",
|
||||||
@ -716,7 +716,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "SelectField",
|
"componentName": "SelectField",
|
||||||
"id": "node$z",
|
"id": "node_z",
|
||||||
"props": {
|
"props": {
|
||||||
"__category__": "form",
|
"__category__": "form",
|
||||||
"__useMediator": "value",
|
"__useMediator": "value",
|
||||||
@ -796,7 +796,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Div",
|
"componentName": "Div",
|
||||||
"id": "node$10",
|
"id": "node_10",
|
||||||
"props": {
|
"props": {
|
||||||
"behavior": "NORMAL",
|
"behavior": "NORMAL",
|
||||||
"__style__": {},
|
"__style__": {},
|
||||||
@ -805,7 +805,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"componentName": "Button",
|
"componentName": "Button",
|
||||||
"id": "node$11",
|
"id": "node_11",
|
||||||
"props": {
|
"props": {
|
||||||
"content": {
|
"content": {
|
||||||
"type": "i18n",
|
"type": "i18n",
|
||||||
@ -841,7 +841,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "Button",
|
"componentName": "Button",
|
||||||
"id": "node$12",
|
"id": "node_12",
|
||||||
"props": {
|
"props": {
|
||||||
"content": {
|
"content": {
|
||||||
"type": "i18n",
|
"type": "i18n",
|
||||||
|
|||||||
@ -64,14 +64,19 @@ export default {
|
|||||||
type: 'PanelIcon',
|
type: 'PanelIcon',
|
||||||
props: {
|
props: {
|
||||||
align: 'top',
|
align: 'top',
|
||||||
icon: 'zujianku',
|
icon: 'wenjian',
|
||||||
description: '资源面板',
|
description: '资源面板',
|
||||||
panelProps: {
|
panelProps: {
|
||||||
floatable: true,
|
floatable: true,
|
||||||
defaultWidth: 500,
|
height: 300,
|
||||||
|
help: undefined,
|
||||||
|
hideTitleBar: true,
|
||||||
|
maxHeight: 800,
|
||||||
|
maxWidth: 1200,
|
||||||
|
title: "动作面板",
|
||||||
|
width: 600
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
pluginProps: {},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pluginKey: 'zhEn',
|
pluginKey: 'zhEn',
|
||||||
@ -82,7 +87,6 @@ export default {
|
|||||||
pluginProps: {},
|
pluginProps: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
/*
|
|
||||||
centerArea: [
|
centerArea: [
|
||||||
{
|
{
|
||||||
pluginKey: 'eventBindDialog',
|
pluginKey: 'eventBindDialog',
|
||||||
@ -90,7 +94,7 @@ export default {
|
|||||||
{
|
{
|
||||||
pluginKey: 'variableBindDialog',
|
pluginKey: 'variableBindDialog',
|
||||||
},
|
},
|
||||||
],*/
|
]
|
||||||
},
|
},
|
||||||
shortCuts: [],
|
shortCuts: [],
|
||||||
lifeCycles: {
|
lifeCycles: {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import GeneralWorkbench from '@ali/lowcode-editor-preset-general';
|
import GeneralWorkbench, { editor } from '../../../editor-preset-general/src';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import components from './components';
|
import components from './components';
|
||||||
import './global.scss';
|
import './global.scss';
|
||||||
|
|||||||
@ -787,7 +787,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
this.sensing = true;
|
this.sensing = true;
|
||||||
this.scroller.scrolling(e);
|
this.scroller.scrolling(e);
|
||||||
const dropContainer = this.getDropContainer(e);
|
const dropContainer = this.getDropContainer(e);
|
||||||
if (!dropContainer) {
|
if (!dropContainer ||
|
||||||
|
(typeof dropContainer.container?.componentMeta?.prototype?.options?.canDropIn === 'function' &&
|
||||||
|
!dropContainer.container?.componentMeta?.prototype?.options?.canDropIn(e.dragObject.nodes[0]))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -158,6 +158,13 @@ export class NodeChildren {
|
|||||||
return this.children.indexOf(node);
|
return this.children.indexOf(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
splice(start: number, deleteCount: number, node: Node): Node[] {
|
||||||
|
return this.children.splice(start, deleteCount, node);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据索引获得节点
|
* 根据索引获得节点
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -144,7 +144,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
|
|
||||||
constructor(readonly document: DocumentModel, nodeSchema: Schema) {
|
constructor(readonly document: DocumentModel, nodeSchema: Schema) {
|
||||||
const { componentName, id, children, props, ...extras } = nodeSchema;
|
const { componentName, id, children, props, ...extras } = nodeSchema;
|
||||||
this.id = id || `node$${document.nextId()}`;
|
this.id = id || `node_${document.nextId()}`;
|
||||||
this.componentName = componentName;
|
this.componentName = componentName;
|
||||||
if (this.componentName === 'Leaf') {
|
if (this.componentName === 'Leaf') {
|
||||||
this.props = new Props(this, {
|
this.props = new Props(this, {
|
||||||
@ -175,9 +175,9 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
if (!autoruns || autoruns.length < 1) {
|
if (!autoruns || autoruns.length < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.autoruns = autoruns.map(item => {
|
this.autoruns = autoruns.map((item) => {
|
||||||
return autorun(() => {
|
return autorun(() => {
|
||||||
item.autorun(this.props.get(item.name, true) as any)
|
item.autorun(this.props.get(item.name, true) as any);
|
||||||
}, true);
|
}, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -384,9 +384,33 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
// todo
|
// todo
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceWith(schema: Schema, migrate = true) {
|
replaceWith(schema: Schema, migrate = false) {
|
||||||
// reuse the same id? or replaceSelection
|
// reuse the same id? or replaceSelection
|
||||||
//
|
schema = Object.assign({}, migrate ? this.export() : {}, schema);
|
||||||
|
return this.parent?.replaceChild(this, schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换子节点
|
||||||
|
*
|
||||||
|
* @param {Node} node
|
||||||
|
* @param {object} data
|
||||||
|
*/
|
||||||
|
replaceChild(node: Node, data: any) {
|
||||||
|
if (this.children?.has(node)) {
|
||||||
|
const selected = this.document.selection.has(node.id);
|
||||||
|
|
||||||
|
delete data.id;
|
||||||
|
const newNode = this.document.createNode(data);
|
||||||
|
|
||||||
|
this.insertBefore(newNode, node);
|
||||||
|
node.remove();
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
this.document.selection.select(newNode.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
getProp(path: string, stash = true): Prop | null {
|
getProp(path: string, stash = true): Prop | null {
|
||||||
@ -442,7 +466,6 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
return this.parent.children.indexOf(this);
|
return this.parent.children.indexOf(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取下一个兄弟节点
|
* 获取下一个兄弟节点
|
||||||
*/
|
*/
|
||||||
@ -607,7 +630,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
if (this.isParental()) {
|
if (this.isParental()) {
|
||||||
this.children.purge();
|
this.children.purge();
|
||||||
}
|
}
|
||||||
this.autoruns?.forEach(dispose => dispose());
|
this.autoruns?.forEach((dispose) => dispose());
|
||||||
this.props.purge();
|
this.props.purge();
|
||||||
this.document.internalRemoveAndPurgeNode(this);
|
this.document.internalRemoveAndPurgeNode(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,15 +24,12 @@
|
|||||||
"@alifd/next": "^1.19.12",
|
"@alifd/next": "^1.19.12",
|
||||||
"@alife/theme-lowcode-dark": "^0.1.0",
|
"@alife/theme-lowcode-dark": "^0.1.0",
|
||||||
"@alife/theme-lowcode-light": "^0.1.0",
|
"@alife/theme-lowcode-light": "^0.1.0",
|
||||||
"domready": "^1.0.8",
|
|
||||||
"immutable": "^3.8.1",
|
|
||||||
"react": "^16.8.1",
|
"react": "^16.8.1",
|
||||||
"react-dom": "^16.8.1"
|
"react-dom": "^16.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ali/lowcode-editor-setters": "^0.9.3",
|
"@ali/lowcode-editor-setters": "^0.9.3",
|
||||||
"@alib/build-scripts": "^0.1.18",
|
"@alib/build-scripts": "^0.1.18",
|
||||||
"@types/domready": "^1.0.0",
|
|
||||||
"@types/events": "^3.0.0",
|
"@types/events": "^3.0.0",
|
||||||
"@types/react": "^16.8.3",
|
"@types/react": "^16.8.3",
|
||||||
"@types/react-dom": "^16.8.2",
|
"@types/react-dom": "^16.8.2",
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { createElement } from 'react';
|
import { createElement } from 'react';
|
||||||
import { Workbench } from '@ali/lowcode-editor-skeleton';
|
import { Workbench, Skeleton, SettingsPrimaryPane } from '@ali/lowcode-editor-skeleton';
|
||||||
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||||
import { Skeleton, SettingsPrimaryPane } from '@ali/lowcode-editor-skeleton';
|
|
||||||
import { Designer } from '@ali/lowcode-designer';
|
import { Designer } from '@ali/lowcode-designer';
|
||||||
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
||||||
import DesignerPlugin from '@ali/lowcode-plugin-designer';
|
import DesignerPlugin from '@ali/lowcode-plugin-designer';
|
||||||
@ -66,7 +65,10 @@ export default function GeneralWorkbench(props: any) {
|
|||||||
...props,
|
...props,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
window.__ctx = {
|
||||||
|
editor,
|
||||||
|
appHelper: editor,
|
||||||
|
};
|
||||||
export function init(container?: Element) {
|
export function init(container?: Element) {
|
||||||
if (!container) {
|
if (!container) {
|
||||||
container = document.createElement('div');
|
container = document.createElement('div');
|
||||||
|
|||||||
@ -1,130 +1,17 @@
|
|||||||
// mixin
|
.expression-setter-item-inner {
|
||||||
.lowcode-setter-mixin > * {
|
.next-menu-item-text {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
.lowcode-setter-mixin {
|
.next-menu-item {
|
||||||
width: 86%;
|
padding: 0 10px;
|
||||||
}
|
|
||||||
.lowcode-setter-mixin .next-input {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.lowcode-setter-mixin .next-select-trigger {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
// json-setter
|
|
||||||
// :global {
|
|
||||||
.nrs-monaco-form {
|
|
||||||
.next-form-item:last-child {
|
|
||||||
margin: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.monaco-editor-wrap {
|
|
||||||
.luna-monaco-button .next-icon-first {
|
|
||||||
height: 26px;
|
|
||||||
}
|
|
||||||
.monaco_fullscreen_icon {
|
|
||||||
position: absolute;
|
|
||||||
line-height: 1;
|
|
||||||
z-index: 7;
|
|
||||||
color: #ddd;
|
|
||||||
&:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.btns-eare {
|
|
||||||
text-align: left;
|
|
||||||
line-height: initial;
|
|
||||||
margin-top: 5px;
|
|
||||||
// button{
|
|
||||||
// margin-right: 10px;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
&.monaco-nofullscreen {
|
|
||||||
position: relative !important;
|
|
||||||
.monaco_fullscreen_icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 5px;
|
|
||||||
line-height: 1;
|
|
||||||
z-index: 7;
|
|
||||||
i:before {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.monaco-fullscreen {
|
|
||||||
position: fixed !important;
|
|
||||||
height: 100% !important;
|
|
||||||
width: 100% !important;
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1001;
|
|
||||||
overflow: hidden;
|
|
||||||
.monaco_fullscreen_icon {
|
|
||||||
top: 10px;
|
|
||||||
right: 10px;
|
|
||||||
i:before {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.luna-monaco-button button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.luna-monaco-button-dialog {
|
|
||||||
.next-dialog-body {
|
|
||||||
padding: 0;
|
|
||||||
.next-form-item {
|
|
||||||
height: 100%;
|
|
||||||
margin-bottom: 0;
|
|
||||||
.next-form-item-control,
|
|
||||||
.next-form-item-control > div {
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
.next-form-item-help {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
// color-setter
|
|
||||||
.lowcode-color-box {
|
|
||||||
margin-right: -5px;
|
|
||||||
padding: 3px 0 3px 3px;
|
|
||||||
width: 26px;
|
|
||||||
height: 26px;
|
|
||||||
display: inline-block;
|
|
||||||
div {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.next-balloon-normal.lowcode-color-content {
|
|
||||||
padding: 0;
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 0;
|
|
||||||
border: 1px solid #e5e5e5;
|
|
||||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
&:after {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.sketch-picker {
|
|
||||||
border-radius: 0 !important;
|
|
||||||
border: none !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
.flexbox-fix {
|
|
||||||
input {
|
|
||||||
width: 100% !important;
|
|
||||||
min-width: 30px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.code-input-value {
|
||||||
|
float: left;
|
||||||
}
|
}
|
||||||
|
.code-input-help {
|
||||||
|
float: right;
|
||||||
|
color: #6897f2;
|
||||||
}
|
}
|
||||||
@ -1,24 +1,26 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Select, Balloon } from '@alife/next';
|
import { Select, Balloon, Icon } from '@alife/next';
|
||||||
import * as acorn from 'acorn';
|
import * as acorn from 'acorn';
|
||||||
|
|
||||||
import { isJSExpression, generateI18n } from './locale/utils';
|
import { isJSExpression, generateI18n } from './locale/utils';
|
||||||
import zhCN from './locale/zh-CN';
|
import zhCN from './locale/zh-CN';
|
||||||
|
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
const { Option, AutoComplete } = Select;
|
const { Option, AutoComplete } = Select;
|
||||||
const { Tooltip } = Balloon;
|
const { Tooltip } = Balloon;
|
||||||
const helpMap = {
|
const helpMap = {
|
||||||
this: '容器上下文对象',
|
this: '容器上下文对象',
|
||||||
'this.state': '容器的state',
|
'state': '容器的state',
|
||||||
'this.props': '容器的props',
|
'props': '容器的props',
|
||||||
'this.context': '容器的context',
|
'context': '容器的context',
|
||||||
'this.page': '页面上下文对象',
|
'schema': '页面上下文对象',
|
||||||
'this.component': '组件上下文对象',
|
'component': '组件上下文对象',
|
||||||
'this.constants': '应用常量对象',
|
'constants': '应用常量对象',
|
||||||
'this.utils': '应用工具对象',
|
'utils': '应用工具对象',
|
||||||
'this.dataSourceMap': '容器数据源Map',
|
'dataSourceMap': '容器数据源Map',
|
||||||
'this.field': '表单Field对象'
|
'field': '表单Field对象'
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ExpressionView extends PureComponent {
|
export default class ExpressionView extends PureComponent {
|
||||||
@ -45,7 +47,7 @@ export default class ExpressionView extends PureComponent {
|
|||||||
i18n: any;
|
i18n: any;
|
||||||
t: void;
|
t: void;
|
||||||
$input: any;
|
$input: any;
|
||||||
listenerFun: (event: any) => void;
|
listenerFun: ((event: any) => void) | undefined;
|
||||||
|
|
||||||
static getInitValue(val: { value: any; match: (arg0: RegExp) => any; }) {
|
static getInitValue(val: { value: any; match: (arg0: RegExp) => any; }) {
|
||||||
if (isJSExpression(val)) {
|
if (isJSExpression(val)) {
|
||||||
@ -81,51 +83,12 @@ export default class ExpressionView extends PureComponent {
|
|||||||
onChange(value: string, actionType: string) {
|
onChange(value: string, actionType: string) {
|
||||||
let realInputValue = value;
|
let realInputValue = value;
|
||||||
let realDataSource = null;
|
let realDataSource = null;
|
||||||
const cursorIndex = this.getInputCursorPosition();
|
|
||||||
let nextCursorIndex: number;
|
let nextCursorIndex: number;
|
||||||
//更新值
|
//更新值
|
||||||
if (actionType === 'itemClick' || actionType === 'enter') {
|
if (actionType === 'itemClick' || actionType === 'enter') {
|
||||||
let curValue = this.state.value;
|
let curValue = this.state.value;
|
||||||
if (curValue) {
|
if (curValue) {
|
||||||
//如果是非.结束,则替换当前这个变量;
|
realInputValue = curValue + realInputValue;
|
||||||
let preStr = curValue.substr(0, cursorIndex);
|
|
||||||
let nextStr = curValue.substr(cursorIndex);
|
|
||||||
let preArr = preStr.split('.');
|
|
||||||
let preArrLen = preArr.length;
|
|
||||||
let tarPreStr = '';
|
|
||||||
if (!preArr[preArrLen - 1]) {
|
|
||||||
//如果是.结束,则增加到.后面
|
|
||||||
if (preArr[preArrLen - 2] === 'this') {
|
|
||||||
preArr = preArr.slice(0, preArrLen - 2);
|
|
||||||
preArr.push(value);
|
|
||||||
tarPreStr = preArr.join('.');
|
|
||||||
} else {
|
|
||||||
tarPreStr = preStr + value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (preArr[preArrLen - 2] === 'this') {
|
|
||||||
preArr = preArr.slice(0, preArrLen - 2);
|
|
||||||
} else {
|
|
||||||
preArr = preArr.slice(0, preArrLen - 1);
|
|
||||||
}
|
|
||||||
preArr.push(value);
|
|
||||||
tarPreStr = preArr.join('.');
|
|
||||||
}
|
|
||||||
realInputValue = tarPreStr + nextStr;
|
|
||||||
realDataSource = this.getDataSource(tarPreStr + '.') || [];
|
|
||||||
nextCursorIndex = tarPreStr.length;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let tarPreStr = value.substr(0, cursorIndex);
|
|
||||||
if (tarPreStr) {
|
|
||||||
let lastChar = tarPreStr.charAt(tarPreStr.length - 1);
|
|
||||||
if (lastChar === '.') {
|
|
||||||
realDataSource = this.getDataSource(tarPreStr) || [];
|
|
||||||
} else {
|
|
||||||
realDataSource = this.getDataSource(tarPreStr + '.');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
realDataSource = this.getDataSource('this.');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//更新数据源
|
//更新数据源
|
||||||
@ -154,21 +117,16 @@ export default class ExpressionView extends PureComponent {
|
|||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
getDataSource(tempStr: string): Array<any> {
|
getDataSource(tempStr: string): Array<any> {
|
||||||
if (tempStr === '' || /[^\w\.]$/.test(tempStr)) {
|
if (/[^\w\.]$/.test(tempStr)) {
|
||||||
return this.getDataSource('this.') || [];
|
return [];
|
||||||
|
} else if (tempStr === null || tempStr === '') {
|
||||||
|
return this.getContextKeys([]);
|
||||||
} else if (/\w\.$/.test(tempStr)) {
|
} else if (/\w\.$/.test(tempStr)) {
|
||||||
let currentField = this.getCurrentFiled(tempStr);
|
let currentField = this.getCurrentFiled(tempStr);
|
||||||
if (!currentField) return null;
|
if (!currentField) return null;
|
||||||
let tempKeys = this.getObjectKeys(currentField.str);
|
let tempKeys = this.getObjectKeys(currentField.str);
|
||||||
tempKeys = this.getContextKeys(tempKeys);
|
tempKeys = this.getContextKeys(tempKeys);
|
||||||
if (!tempKeys) return null;
|
if (!tempKeys) return null;
|
||||||
//给默认情况增加this
|
|
||||||
if (tempStr === 'this.') {
|
|
||||||
tempKeys = tempKeys.map((item: string) => {
|
|
||||||
return 'this.' + item;
|
|
||||||
});
|
|
||||||
tempKeys.unshift('this');
|
|
||||||
}
|
|
||||||
return tempKeys;
|
return tempKeys;
|
||||||
} else if (/\.$/.test(tempStr)) {
|
} else if (/\.$/.test(tempStr)) {
|
||||||
return [];
|
return [];
|
||||||
@ -202,34 +160,31 @@ export default class ExpressionView extends PureComponent {
|
|||||||
* @param {Array}
|
* @param {Array}
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
getContextKeys(keys: any) {
|
getContextKeys(keys: []) {
|
||||||
// let context = {};
|
const editor = this.props.field.editor;
|
||||||
// const { appHelper } = this.context;
|
console.log(editor);
|
||||||
// const activeKey = appHelper && appHelper.activeKey;
|
const limitKeys = ['schema', 'utils', 'constants'];
|
||||||
// if (!activeKey) return;
|
if (keys.length === 0) return limitKeys;
|
||||||
// const activeCtx = appHelper.schemaHelper.compCtxMap && appHelper.schemaHelper.compCtxMap[activeKey];
|
if (!limitKeys.includes(keys[0])) return [];
|
||||||
// if (!activeCtx) return null;
|
let result = [];
|
||||||
// let __self = activeCtx;
|
let keyValue = editor;
|
||||||
// if (keys && keys.length > 1) {
|
let assert = false;
|
||||||
// keys.shift(0);
|
keys.forEach(item => {
|
||||||
// let path = '/' + keys.join('/');
|
if (!keyValue[item] || typeof keyValue[item] !== 'object') {
|
||||||
// path = path.replace(/[\[\]]/g, '/');
|
assert = true;
|
||||||
// context = jsonuri.get(__self, path);
|
}
|
||||||
// if (context && typeof context === 'object') {
|
if (keyValue[item]) {
|
||||||
// return this.filterKey(context);
|
keyValue = keyValue[item];
|
||||||
// }
|
}
|
||||||
// } else if (keys && keys[0] === 'this') {
|
})
|
||||||
// return this.filterKey(__self);
|
if (assert) return [];
|
||||||
// }
|
result = Object.keys(keyValue);
|
||||||
// return null;
|
return result;
|
||||||
return [
|
// return utilsKeys.concat(constantsKeys).concat(schemaKeys);
|
||||||
"page",
|
|
||||||
"component"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*过滤key */
|
/*过滤key */
|
||||||
filterKey(obj: any) {
|
filterKey(obj: any, name: string) {
|
||||||
let filterKeys = [
|
let filterKeys = [
|
||||||
'reloadDataSource',
|
'reloadDataSource',
|
||||||
'REACT_HOT_LOADER_RENDERED_GENERATION',
|
'REACT_HOT_LOADER_RENDERED_GENERATION',
|
||||||
@ -244,7 +199,7 @@ export default class ExpressionView extends PureComponent {
|
|||||||
let result = [];
|
let result = [];
|
||||||
for (let key in obj) {
|
for (let key in obj) {
|
||||||
if (key.indexOf('_') !== 0 && filterKeys.indexOf(key) === -1) {
|
if (key.indexOf('_') !== 0 && filterKeys.indexOf(key) === -1) {
|
||||||
result.push(key);
|
result.push(`${name}.${key}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -259,12 +214,16 @@ export default class ExpressionView extends PureComponent {
|
|||||||
filterOption(inputValue: string, item: { value: string | any[]; }) {
|
filterOption(inputValue: string, item: { value: string | any[]; }) {
|
||||||
const cursorIndex = this.getInputCursorPosition();
|
const cursorIndex = this.getInputCursorPosition();
|
||||||
let preStr = inputValue.substr(0, cursorIndex);
|
let preStr = inputValue.substr(0, cursorIndex);
|
||||||
let lastKey = preStr.split('.').slice(-1);
|
let lastKey: string[] = preStr.split('.').slice(-1);
|
||||||
if (!lastKey) return true;
|
if (!lastKey) return true;
|
||||||
if (item.value.indexOf(lastKey) > -1) return true;
|
if (item.value.indexOf(lastKey) > -1) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleClick = () => {
|
||||||
|
// this.props.field.editor.emit('variableBindDialog.open');
|
||||||
|
// }
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { value, dataSource } = this.state;
|
const { value, dataSource } = this.state;
|
||||||
const { placeholder } = this.props;
|
const { placeholder } = this.props;
|
||||||
@ -293,6 +252,7 @@ export default class ExpressionView extends PureComponent {
|
|||||||
isValObject ? (
|
isValObject ? (
|
||||||
value
|
value
|
||||||
) : (
|
) : (
|
||||||
|
<div>
|
||||||
<AutoComplete
|
<AutoComplete
|
||||||
{...this.props}
|
{...this.props}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
@ -302,7 +262,9 @@ export default class ExpressionView extends PureComponent {
|
|||||||
disabled={isValObject}
|
disabled={isValObject}
|
||||||
innerBefore={<span style={{ color: '#999', marginLeft: 4 }}>{'{{'}</span>}
|
innerBefore={<span style={{ color: '#999', marginLeft: 4 }}>{'{{'}</span>}
|
||||||
innerAfter={<span style={{ color: '#999', marginRight: 4 }}>{'}}'}</span>}
|
innerAfter={<span style={{ color: '#999', marginRight: 4 }}>{'}}'}</span>}
|
||||||
|
popupClassName="expression-setter-item-inner"
|
||||||
itemRender={({ value }) => {
|
itemRender={({ value }) => {
|
||||||
|
console.log(value);
|
||||||
return (
|
return (
|
||||||
<Option key={value} text={value} value={value}>
|
<Option key={value} text={value} value={value}>
|
||||||
<div className="code-input-value">{value}</div>
|
<div className="code-input-value">{value}</div>
|
||||||
@ -313,6 +275,7 @@ export default class ExpressionView extends PureComponent {
|
|||||||
onChange={this.onChange.bind(this)}
|
onChange={this.onChange.bind(this)}
|
||||||
filter={this.filterOption.bind(this)}
|
filter={this.filterOption.bind(this)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -363,7 +326,7 @@ export default class ExpressionView extends PureComponent {
|
|||||||
* 字符串取得对象keys
|
* 字符串取得对象keys
|
||||||
*/
|
*/
|
||||||
getObjectKeys(str: string) {
|
getObjectKeys(str: string) {
|
||||||
let keys = [];
|
let keys: string | any[] = [];
|
||||||
if (str) keys = str.split('.');
|
if (str) keys = str.split('.');
|
||||||
return keys.slice(0, keys.length - 1);
|
return keys.slice(0, keys.length - 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { registerSetter } from '@ali/lowcode-globals';
|
import { registerSetter } from '@ali/lowcode-editor-core';
|
||||||
import { DatePicker, Input, Radio, Select, Switch, NumberPicker } from '@alifd/next';
|
import { DatePicker, Input, Radio, Select, Switch, NumberPicker } from '@alifd/next';
|
||||||
import ExpressionSetter from './expression-setter';
|
import ExpressionSetter from './expression-setter';
|
||||||
import ColorSetter from './color-setter';
|
import ColorSetter from './color-setter';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
.source-editor-container{
|
.source-editor-container{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.next-tabs {
|
.next-tabs {
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
@ -13,6 +13,18 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor-context-container{
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 35px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-context{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.next-tabs-tabpane.active {
|
.next-tabs-tabpane.active {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {Editor} from '@ali/lowcode-editor-core';
|
|||||||
import { js_beautify, css_beautify } from 'js-beautify';
|
import { js_beautify, css_beautify } from 'js-beautify';
|
||||||
import MonacoEditor from 'react-monaco-editor';
|
import MonacoEditor from 'react-monaco-editor';
|
||||||
import { Designer } from '@ali/lowcode-designer';
|
import { Designer } from '@ali/lowcode-designer';
|
||||||
|
import * as monaco from 'monaco-editor/esm/vs/editor/editor.main.js';
|
||||||
const TAB_KEY = {
|
const TAB_KEY = {
|
||||||
JS_TAB: 'js_tab',
|
JS_TAB: 'js_tab',
|
||||||
CSS_TAB: 'css_tab',
|
CSS_TAB: 'css_tab',
|
||||||
@ -45,8 +46,10 @@ export default class SourceEditor extends Component<{
|
|||||||
editor: Editor;
|
editor: Editor;
|
||||||
}> {
|
}> {
|
||||||
private monocoEditor: Object;
|
private monocoEditor: Object;
|
||||||
|
private monocoEditorCss: Object;
|
||||||
private editorCmd: Object;
|
private editorCmd: Object;
|
||||||
private editorRef = React.createRef();
|
private editorJsRef = React.createRef();
|
||||||
|
private editorCssRef = React.createRef();
|
||||||
private editorNode: Object;
|
private editorNode: Object;
|
||||||
private editorParentNode: Object;
|
private editorParentNode: Object;
|
||||||
|
|
||||||
@ -58,18 +61,18 @@ export default class SourceEditor extends Component<{
|
|||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const { editor } = this.props;
|
const { editor } = this.props;
|
||||||
editor.on('leftPanel.show', (key: String) => {
|
editor.on('leftPanel.show', (key: String) => {
|
||||||
debugger;
|
// debugger;
|
||||||
if (key === 'sourceEditor' && !this.monocoEditor) {
|
if (key === 'sourceEditor' && !this.monocoEditor) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
setTimeout(()=>{
|
// this.editorNode = this.editorCssRef.current; //记录当前dom节点;
|
||||||
this.editorNode = this.editorRef.current; //记录当前dom节点;
|
// debugger
|
||||||
this.editorParentNode = this.editorNode.parentNode; //记录父节点;
|
// this.editorParentNode = this.editorNode.parentNode; //记录父节点;
|
||||||
console.log(this.editorNode);
|
// console.log(this.editorNode);
|
||||||
},0)
|
// }, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -123,10 +126,7 @@ export default class SourceEditor extends Component<{
|
|||||||
//});
|
//});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(){
|
componentDidMount() {}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
openPluginPannel = () => {
|
openPluginPannel = () => {
|
||||||
const { editor } = this.props;
|
const { editor } = this.props;
|
||||||
@ -224,17 +224,6 @@ export default class SourceEditor extends Component<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
editorDidMount = (editor, monaco) => {
|
editorDidMount = (editor, monaco) => {
|
||||||
console.log('editorDidMount', editor);
|
|
||||||
|
|
||||||
// var commandId = editor.addCommand(
|
|
||||||
// 0,
|
|
||||||
// function() {
|
|
||||||
// // services available in `ctx`
|
|
||||||
// alert('my command is executing!');
|
|
||||||
// },
|
|
||||||
// '',
|
|
||||||
// );
|
|
||||||
|
|
||||||
if (this.state.selectTab == TAB_KEY.JS_TAB) {
|
if (this.state.selectTab == TAB_KEY.JS_TAB) {
|
||||||
this.monocoEditor = editor;
|
this.monocoEditor = editor;
|
||||||
}
|
}
|
||||||
@ -248,6 +237,14 @@ export default class SourceEditor extends Component<{
|
|||||||
this.setState({
|
this.setState({
|
||||||
selectTab: key,
|
selectTab: key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (key === TAB_KEY.JS_TAB) {
|
||||||
|
document.getElementById('cssEditorDom').setAttribute('style', 'display:none');
|
||||||
|
document.getElementById('jsEditorDom').setAttribute('style', 'block');
|
||||||
|
} else {
|
||||||
|
document.getElementById('jsEditorDom').setAttribute('style', 'display:none');
|
||||||
|
document.getElementById('cssEditorDom').setAttribute('style', 'block');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateCode = (newCode) => {
|
updateCode = (newCode) => {
|
||||||
@ -276,21 +273,32 @@ export default class SourceEditor extends Component<{
|
|||||||
<div className="source-editor-container">
|
<div className="source-editor-container">
|
||||||
<Tab size="small" shape="wrapped" onChange={this.onTabChange} activeKey={selectTab}>
|
<Tab size="small" shape="wrapped" onChange={this.onTabChange} activeKey={selectTab}>
|
||||||
{tabs.map((item) => (
|
{tabs.map((item) => (
|
||||||
<Tab.Item key={item.key} title={item.tab}>
|
<Tab.Item key={item.key} title={item.tab} />
|
||||||
|
))}
|
||||||
|
</Tab>
|
||||||
|
|
||||||
{isShow && (
|
{isShow && (
|
||||||
<div style={{ height: '100%' }} ref={this.editorRef}>
|
<div style={{ height: '100%' }} className="editor-context-container">
|
||||||
|
<div id="jsEditorDom" className="editor-context">
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
value={selectTab == TAB_KEY.JS_TAB ? jsCode : css}
|
value={jsCode}
|
||||||
{...defaultEditorOption}
|
{...defaultEditorOption}
|
||||||
{...{ language: selectTab == TAB_KEY.JS_TAB ? 'typescript' : 'css' }}
|
{...{ language: 'typescript' }}
|
||||||
onChange={(newCode) => this.updateCode(newCode)}
|
onChange={(newCode) => this.updateCode(newCode)}
|
||||||
editorDidMount={(editor, monaco) => this.editorDidMount.call(this, editor, monaco)}
|
editorDidMount={(editor, monaco) => this.editorDidMount.call(this, editor, monaco)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="editor-context" id="cssEditorDom">
|
||||||
|
<MonacoEditor
|
||||||
|
value={css}
|
||||||
|
{...defaultEditorOption}
|
||||||
|
{...{ language: 'css' }}
|
||||||
|
onChange={(newCode) => this.updateCode(newCode)}
|
||||||
|
editorDidMount={(editor, monaco) => this.editorDidMount.call(this, editor, monaco)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</Tab.Item>
|
|
||||||
))}
|
|
||||||
</Tab>
|
|
||||||
|
|
||||||
<div className="full-screen-container" onClick={this.fullScreen}>
|
<div className="full-screen-container" onClick={this.fullScreen}>
|
||||||
<img src="https://gw.alicdn.com/tfs/TB1d7XqE1T2gK0jSZFvXXXnFXXa-200-200.png"></img>
|
<img src="https://gw.alicdn.com/tfs/TB1d7XqE1T2gK0jSZFvXXXnFXXa-200-200.png"></img>
|
||||||
|
|||||||
4
packages/rax-provider/CHANGELOG.md
Normal file
4
packages/rax-provider/CHANGELOG.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
1
packages/rax-provider/README.md
Normal file
1
packages/rax-provider/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# 低代码引擎运行时框架
|
||||||
11
packages/rax-provider/build.json
Normal file
11
packages/rax-provider/build.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"build-plugin-rax-component",
|
||||||
|
{
|
||||||
|
"type": "rax",
|
||||||
|
"targets": ["web"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
30
packages/rax-provider/package.json
Normal file
30
packages/rax-provider/package.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/lowcode-rax-provider",
|
||||||
|
"version": "0.8.14-beta.0",
|
||||||
|
"description": "Rax Provider for Runtime",
|
||||||
|
"files": [
|
||||||
|
"es",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "es/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "build-scripts start",
|
||||||
|
"build": "build-scripts build"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/lowcode-runtime": "^0.8.14-beta.0",
|
||||||
|
"rax": "1.1.2",
|
||||||
|
"driver-universal": "^3.1.3",
|
||||||
|
"rax-use-router": "^3.0.0",
|
||||||
|
"history": "^4.10.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@alib/build-scripts": "^0.1.18",
|
||||||
|
"build-plugin-rax-component": "^0.2.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
packages/rax-provider/src/index.js
Normal file
5
packages/rax-provider/src/index.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import RaxProvider from './provider';
|
||||||
|
import getRouter from './router';
|
||||||
|
|
||||||
|
export { getRouter };
|
||||||
|
export default RaxProvider;
|
||||||
28
packages/rax-provider/src/lazy-component.js
Normal file
28
packages/rax-provider/src/lazy-component.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { createElement, useState, useEffect } from 'rax';
|
||||||
|
import { app } from '@ali/lowcode-runtime';
|
||||||
|
|
||||||
|
export default function LazyComponent(props) {
|
||||||
|
const [schema, setSchema] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const { getPageData } = props || {};
|
||||||
|
if (getPageData && !schema) {
|
||||||
|
const data = await getPageData();
|
||||||
|
setSchema(data);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
|
||||||
|
const { getPageData, ...restProps } = props || {};
|
||||||
|
const Renderer = app.getRenderer();
|
||||||
|
const Loading = app.getLoading();
|
||||||
|
if (!Renderer || !schema) {
|
||||||
|
if (!Loading) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// loading扩展点
|
||||||
|
return createElement(Loading);
|
||||||
|
}
|
||||||
|
return createElement(Renderer, { schema, loading: Loading ? createElement(Loading) : null, ...restProps });
|
||||||
|
}
|
||||||
103
packages/rax-provider/src/provider.js
Normal file
103
packages/rax-provider/src/provider.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { createElement, render } from 'rax';
|
||||||
|
import UniversalDriver from 'driver-universal';
|
||||||
|
import { app, Provider } from '@ali/lowcode-runtime';
|
||||||
|
import LazyComponent from './lazy-component';
|
||||||
|
import getRouter from './router';
|
||||||
|
|
||||||
|
export default class RaxProvider extends Provider {
|
||||||
|
// 定制构造根组件的逻辑,如切换路由机制
|
||||||
|
createApp() {
|
||||||
|
const RouterView = this.getRouterView();
|
||||||
|
let App;
|
||||||
|
const layoutConfig = this.getLayoutConfig();
|
||||||
|
if (!layoutConfig || !layoutConfig.componentName) {
|
||||||
|
App = (props) => (RouterView ? createElement(RouterView, { ...props }) : null);
|
||||||
|
return App;
|
||||||
|
}
|
||||||
|
const { componentName: layoutName, props: layoutProps } = layoutConfig;
|
||||||
|
const { content: Layout, props: extraLayoutProps } = app.getLayout(layoutName) || {};
|
||||||
|
const sectionalRender = this.isSectionalRender();
|
||||||
|
if (!sectionalRender && Layout) {
|
||||||
|
App = (props) =>
|
||||||
|
createElement(
|
||||||
|
Layout,
|
||||||
|
{ ...layoutProps, ...extraLayoutProps },
|
||||||
|
RouterView ? createElement(RouterView, props) : null,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
App = (props) => (RouterView ? createElement(RouterView, props) : null);
|
||||||
|
}
|
||||||
|
return App;
|
||||||
|
}
|
||||||
|
|
||||||
|
runApp(App, config) {
|
||||||
|
render(createElement(App), document.getElementById(config?.containerId || 'App'), { driver: UniversalDriver });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内置实现 for 动态化渲染
|
||||||
|
getRouterView() {
|
||||||
|
const routerConfig = this.getRouterConfig();
|
||||||
|
if (!routerConfig) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const routes = [];
|
||||||
|
let homePageId = this.getHomePage();
|
||||||
|
Object.keys(routerConfig).forEach((pageId, idx) => {
|
||||||
|
if (!pageId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const path = routerConfig[pageId];
|
||||||
|
routes.push({
|
||||||
|
path,
|
||||||
|
component: (props: any) =>
|
||||||
|
this.getLazyComponent(pageId, {
|
||||||
|
components: this.getComponents(),
|
||||||
|
utils: this.getUtils(),
|
||||||
|
componentsMap: this.getComponentsMapObj(),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
if (homePageId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (idx === 0 || path === '/') {
|
||||||
|
homePageId = pageId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (homePageId) {
|
||||||
|
routes.push({
|
||||||
|
path: '**',
|
||||||
|
component: (props) =>
|
||||||
|
this.getLazyComponent(homePageId, {
|
||||||
|
components: this.getComponents(),
|
||||||
|
utils: this.getUtils(),
|
||||||
|
componentsMap: this.getComponentsMapObj(),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const Router = getRouter({
|
||||||
|
history: this.getHistory(),
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
const RouterView = (props) => createElement(Router, props);
|
||||||
|
return RouterView;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLazyComponent(pageId, props) {
|
||||||
|
if (!pageId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (this.getlazyElement(pageId)) {
|
||||||
|
return this.getlazyElement(pageId);
|
||||||
|
}
|
||||||
|
const lazyElement = createElement(LazyComponent, {
|
||||||
|
// eslint-disable-next-line no-return-await
|
||||||
|
getPageData: async () => await this.getPageData(pageId),
|
||||||
|
key: pageId,
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
this.setlazyElement(pageId, lazyElement);
|
||||||
|
return lazyElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
packages/rax-provider/src/router.js
Normal file
26
packages/rax-provider/src/router.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { useRouter } from 'rax-use-router';
|
||||||
|
import { createHashHistory, createBrowserHistory } from 'history';
|
||||||
|
|
||||||
|
const getConfig = (config) => {
|
||||||
|
let { history } = config;
|
||||||
|
const { routes } = config;
|
||||||
|
if (typeof history === 'string') {
|
||||||
|
if (history === 'hash') {
|
||||||
|
history = createHashHistory();
|
||||||
|
} else if (history === 'browser') {
|
||||||
|
history = createBrowserHistory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return () => ({
|
||||||
|
history,
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function getRouter(config) {
|
||||||
|
return function Router() {
|
||||||
|
const configWrapper = getConfig(config);
|
||||||
|
const { component } = useRouter(configWrapper);
|
||||||
|
return component;
|
||||||
|
};
|
||||||
|
}
|
||||||
49
packages/rax-render/README.md
Normal file
49
packages/rax-render/README.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# Rax Renderer
|
||||||
|
|
||||||
|
Rax 渲染模块。
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install @ali/lowcode-engine-rax-renderer --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { createElement, render } from 'rax';
|
||||||
|
import DriverUniversal from 'driver-universal';
|
||||||
|
import RaxRenderer from '@ali/lowcode-engine-rax-renderer';
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
View,
|
||||||
|
Text
|
||||||
|
};
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
componentName: 'Page',
|
||||||
|
fileName: 'home',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
props: {
|
||||||
|
type: 'primary'
|
||||||
|
},
|
||||||
|
children: ['Welcome to Your Rax App']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<RaxRenderer
|
||||||
|
schema={schema}
|
||||||
|
components={components}
|
||||||
|
/>,
|
||||||
|
document.getElementById('root'), { driver: DriverUniversal }
|
||||||
|
);
|
||||||
|
```
|
||||||
11
packages/rax-render/build.json
Normal file
11
packages/rax-render/build.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"build-plugin-rax-component",
|
||||||
|
{
|
||||||
|
"type": "rax",
|
||||||
|
"targets": ["web"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
35
packages/rax-render/demo/index.jsx
Normal file
35
packages/rax-render/demo/index.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { createElement, render } from 'rax';
|
||||||
|
import DriverUniversal from 'driver-universal';
|
||||||
|
import View from 'rax-view';
|
||||||
|
import Text from 'rax-text';
|
||||||
|
import { Engine } from '../src/index';
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
};
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
componentName: 'Page',
|
||||||
|
fileName: 'home',
|
||||||
|
props: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'View',
|
||||||
|
props: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
children: ['Welcome to Your Rax App!'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<Engine schema={schema} components={components} />, document.getElementById('root'), {
|
||||||
|
driver: DriverUniversal,
|
||||||
|
});
|
||||||
1
packages/rax-render/demo/miniapp/app.js
Normal file
1
packages/rax-render/demo/miniapp/app.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
App({});
|
||||||
6
packages/rax-render/demo/miniapp/app.json
Normal file
6
packages/rax-render/demo/miniapp/app.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"pages": ["pages/index"],
|
||||||
|
"window": {
|
||||||
|
"defaultTitle": "demo"
|
||||||
|
}
|
||||||
|
}
|
||||||
0
packages/rax-render/demo/miniapp/pages/index.acss
Normal file
0
packages/rax-render/demo/miniapp/pages/index.acss
Normal file
1
packages/rax-render/demo/miniapp/pages/index.axml
Normal file
1
packages/rax-render/demo/miniapp/pages/index.axml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<my-component></my-component>
|
||||||
4
packages/rax-render/demo/miniapp/pages/index.js
Normal file
4
packages/rax-render/demo/miniapp/pages/index.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Page({
|
||||||
|
onLoad() {},
|
||||||
|
onShow() {}
|
||||||
|
});
|
||||||
6
packages/rax-render/demo/miniapp/pages/index.json
Normal file
6
packages/rax-render/demo/miniapp/pages/index.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"defaultTitle": "Miniapp Rax Text demo",
|
||||||
|
"usingComponents": {
|
||||||
|
"my-component": "../components/Target/index"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
packages/rax-render/demo/wechat-miniprogram/app.js
Normal file
1
packages/rax-render/demo/wechat-miniprogram/app.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
App({});
|
||||||
6
packages/rax-render/demo/wechat-miniprogram/app.json
Normal file
6
packages/rax-render/demo/wechat-miniprogram/app.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"pages": ["pages/index"],
|
||||||
|
"window": {
|
||||||
|
"title": "demo"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
Page({
|
||||||
|
onLoad() {},
|
||||||
|
onShow() {}
|
||||||
|
});
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"title": "Wechat MiniProgram Rax Text demo",
|
||||||
|
"usingComponents": {
|
||||||
|
"my-component": "../components/Target/index"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<my-component></my-component>
|
||||||
64
packages/rax-render/package.json
Normal file
64
packages/rax-render/package.json
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/lowcode-engine-rax-renderer",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Rax renderer for Ali lowCode engine",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "lib/index.js",
|
||||||
|
"miniappConfig": {
|
||||||
|
"main": "lib/miniapp/index",
|
||||||
|
"main:wechat": "lib/wechat-miniprogram/index"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"es",
|
||||||
|
"lib",
|
||||||
|
"src",
|
||||||
|
"types"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"low-code",
|
||||||
|
"lowcode",
|
||||||
|
"Rax"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"npm": ">=3.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rax": "^1.1.0",
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "build-scripts start",
|
||||||
|
"build": "build-scripts build",
|
||||||
|
"prepublish": "npm run build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/b3-one": "^0.0.17",
|
||||||
|
"@ali/bzb-request": "2.6.1",
|
||||||
|
"@ali/lib-mtop": "^2.5.1",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"events": "^3.0.0",
|
||||||
|
"fetch-jsonp": "^1.1.3",
|
||||||
|
"intl-messageformat": "^7.7.2",
|
||||||
|
"jsonuri": "^2.1.2",
|
||||||
|
"keymaster": "^1.6.2",
|
||||||
|
"lodash": "^4.17.11",
|
||||||
|
"moment": "^2.24.0",
|
||||||
|
"rax-find-dom-node": "^1.0.1",
|
||||||
|
"rax-text": "^1.1.6",
|
||||||
|
"rax-view": "^1.0.0",
|
||||||
|
"react-is": "^16.10.1",
|
||||||
|
"serialize-javascript": "^1.7.0",
|
||||||
|
"whatwg-fetch": "^3.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@alib/build-scripts": "^0.1.0",
|
||||||
|
"build-plugin-rax-component": "^0.1.4",
|
||||||
|
"driver-universal": "^3.1.3"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
19
packages/rax-render/src/comp/visualDom/index.css
Normal file
19
packages/rax-render/src/comp/visualDom/index.css
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
.visual-dom .panel-container {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #e9e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visual-dom .panel-container .title {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
background-color: #ebecf0;
|
||||||
|
line-height: 28px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-bottom: 1px solid #e9e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visual-dom .panel-container .content {
|
||||||
|
min-height: 20px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
23
packages/rax-render/src/comp/visualDom/index.jsx
Normal file
23
packages/rax-render/src/comp/visualDom/index.jsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Component } from 'rax';
|
||||||
|
import View from 'rax-view';
|
||||||
|
import Text from 'rax-text';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
export default class VisualDom extends Component {
|
||||||
|
static displayName = 'VisualDom';
|
||||||
|
static defaultProps = {
|
||||||
|
children: null
|
||||||
|
};
|
||||||
|
render() {
|
||||||
|
const { children, title, label, text, __componentName } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View className="visual-dom">
|
||||||
|
<View className="panel-container">
|
||||||
|
<Text className="title">{title || label || text || __componentName}</Text>
|
||||||
|
<View className="content">{children}</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
4
packages/rax-render/src/context/appContext.js
Normal file
4
packages/rax-render/src/context/appContext.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { createContext } from 'rax';
|
||||||
|
|
||||||
|
const context = createContext({});
|
||||||
|
export default context;
|
||||||
512
packages/rax-render/src/engine/base.jsx
Normal file
512
packages/rax-render/src/engine/base.jsx
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
import { Component, createElement } from 'rax';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Debug from 'debug';
|
||||||
|
import View from 'rax-view';
|
||||||
|
import DataHelper from '../utils/dataHelper';
|
||||||
|
import {
|
||||||
|
forEach,
|
||||||
|
getValue,
|
||||||
|
parseData,
|
||||||
|
parseExpression,
|
||||||
|
isEmpty,
|
||||||
|
isSchema,
|
||||||
|
isFileSchema,
|
||||||
|
isJSExpression,
|
||||||
|
isJSSlot,
|
||||||
|
isJSFunction,
|
||||||
|
transformArrayToMap,
|
||||||
|
checkPropTypes,
|
||||||
|
generateI18n,
|
||||||
|
acceptsRef,
|
||||||
|
} from '../utils';
|
||||||
|
import VisualDom from '../comp/visualDom';
|
||||||
|
import AppContext from '../context/appContext';
|
||||||
|
import CompWrapper from '../hoc/compWrapper';
|
||||||
|
|
||||||
|
const debug = Debug('engine:base');
|
||||||
|
const DESIGN_MODE = {
|
||||||
|
EXTEND: 'extend',
|
||||||
|
BORDER: 'border',
|
||||||
|
PREVIEW: 'preview',
|
||||||
|
};
|
||||||
|
const OVERLAY_LIST = ['Dialog', 'Overlay'];
|
||||||
|
let scopeIdx = 0;
|
||||||
|
|
||||||
|
export default class BaseEngine extends Component {
|
||||||
|
static dislayName = 'base-engine';
|
||||||
|
static propTypes = {
|
||||||
|
locale: PropTypes.string,
|
||||||
|
messages: PropTypes.object,
|
||||||
|
__appHelper: PropTypes.object,
|
||||||
|
__components: PropTypes.object,
|
||||||
|
__componentsMap: PropTypes.object,
|
||||||
|
__ctx: PropTypes.object,
|
||||||
|
__schema: PropTypes.object
|
||||||
|
};
|
||||||
|
static defaultProps = {
|
||||||
|
__schema: {}
|
||||||
|
};
|
||||||
|
static contextType = AppContext;
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.appHelper = props.__appHelper;
|
||||||
|
this.__compScopes = {};
|
||||||
|
const { locale, messages } = props;
|
||||||
|
this.i18n = generateI18n(locale, messages);
|
||||||
|
this.__bindCustomMethods(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSnapshotBeforeUpdate() {
|
||||||
|
this.__setLifeCycleMethods('getSnapshotBeforeUpdate', arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
this.reloadDataSource();
|
||||||
|
this.__setLifeCycleMethods('componentDidMount', arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidUpdate() {
|
||||||
|
this.__setLifeCycleMethods('componentDidUpdate', arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentWillUnmount() {
|
||||||
|
this.__setLifeCycleMethods('componentWillUnmount', arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidCatch(e) {
|
||||||
|
this.__setLifeCycleMethods('componentDidCatch', arguments);
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadDataSource = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
debug('reload data source');
|
||||||
|
if (!this.__dataHelper) {
|
||||||
|
this.__showPlaceholder = false;
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
this.__dataHelper
|
||||||
|
.getInitData()
|
||||||
|
.then(res => {
|
||||||
|
this.__showPlaceholder = false;
|
||||||
|
if (isEmpty(res)) {
|
||||||
|
this.forceUpdate();
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
this.setState(res, resolve);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (this.__showPlaceholder) {
|
||||||
|
this.__showPlaceholder = false;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
__setLifeCycleMethods = (method, args) => {
|
||||||
|
const lifeCycleMethods = getValue(this.props.__schema, 'lifeCycles', {});
|
||||||
|
if (lifeCycleMethods[method]) {
|
||||||
|
try {
|
||||||
|
return lifeCycleMethods[method].apply(this, args);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`[${this.props.__schema.componentName}]生命周期${method}出错`, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
__bindCustomMethods = (props = this.props) => {
|
||||||
|
const { __schema } = props;
|
||||||
|
const customMethodsList = Object.keys(__schema.methods || {}) || [];
|
||||||
|
this.__customMethodsList &&
|
||||||
|
this.__customMethodsList.forEach(item => {
|
||||||
|
if (!customMethodsList.includes(item)) {
|
||||||
|
delete this[item];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.__customMethodsList = customMethodsList;
|
||||||
|
forEach(__schema.methods, (val, key) => {
|
||||||
|
this[key] = val.bind(this);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
__generateCtx = ctx => {
|
||||||
|
const { pageContext, compContext } = this.context;
|
||||||
|
const obj = {
|
||||||
|
page: pageContext,
|
||||||
|
component: compContext,
|
||||||
|
...ctx
|
||||||
|
};
|
||||||
|
forEach(obj, (val, key) => {
|
||||||
|
this[key] = val;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
__parseData = (data, ctx) => {
|
||||||
|
const { __ctx } = this.props;
|
||||||
|
return parseData(data, ctx || __ctx || this);
|
||||||
|
};
|
||||||
|
|
||||||
|
__initDataSource = (props = this.props) => {
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
const appHelper = props.__appHelper;
|
||||||
|
const dataSource = (schema && schema.dataSource) || {};
|
||||||
|
this.__dataHelper = new DataHelper(this, dataSource, appHelper, config => this.__parseData(config));
|
||||||
|
this.dataSourceMap = this.__dataHelper.dataSourceMap;
|
||||||
|
// 设置容器组件占位,若设置占位则在初始异步请求完成之前用loading占位且不渲染容器组件内部内容
|
||||||
|
this.__showPlaceholder =
|
||||||
|
this.__parseData(schema.props && schema.props.autoLoading) &&
|
||||||
|
(dataSource.list || []).some(item => !!this.__parseData(item.isInit));
|
||||||
|
};
|
||||||
|
|
||||||
|
__render = () => {
|
||||||
|
const schema = this.props.__schema;
|
||||||
|
this.__setLifeCycleMethods('render');
|
||||||
|
|
||||||
|
const engine = this.context.engine;
|
||||||
|
if (engine) {
|
||||||
|
engine.props.onCompGetCtx(schema, this);
|
||||||
|
// 画布场景才需要每次渲染bind自定义方法
|
||||||
|
if (engine.props.designMode) {
|
||||||
|
this.__bindCustomMethods();
|
||||||
|
this.dataSourceMap = this.__dataHelper && this.__dataHelper.updateConfig(schema.dataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
__getRef = ref => {
|
||||||
|
this.__ref = ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
__createDom = () => {
|
||||||
|
const { __schema, __ctx, __components = {} } = this.props;
|
||||||
|
const self = {};
|
||||||
|
self.__proto__ = __ctx || this;
|
||||||
|
return this.__createVirtualDom(__schema.children, self, {
|
||||||
|
schema: __schema,
|
||||||
|
Comp: __components[__schema.componentName]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 将模型结构转换成react Element
|
||||||
|
// schema 模型结构
|
||||||
|
// self 为每个渲染组件构造的上下文,self是自上而下继承的
|
||||||
|
// parentInfo 父组件的信息,包含schema和Comp
|
||||||
|
// idx 若为循环渲染的循环Index
|
||||||
|
__createVirtualDom = (schema, self, parentInfo, idx) => {
|
||||||
|
if (!schema) return null;
|
||||||
|
// rax text prop 兼容处理
|
||||||
|
if (schema.componentName === 'Text') {
|
||||||
|
if (typeof schema.props.text === 'string') {
|
||||||
|
schema = Object.assign({}, schema);
|
||||||
|
schema.children = [schema.props.text];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { __appHelper: appHelper, __components: components = {}, __componentsMap: componentsMap = {} } =
|
||||||
|
this.props || {};
|
||||||
|
const { engine } = this.context || {};
|
||||||
|
if (isJSExpression(schema)) {
|
||||||
|
return parseExpression(schema, self);
|
||||||
|
}
|
||||||
|
if (typeof schema === 'string') return schema;
|
||||||
|
if (typeof schema === 'number' || typeof schema === 'boolean') {
|
||||||
|
return schema.toString();
|
||||||
|
}
|
||||||
|
if (Array.isArray(schema)) {
|
||||||
|
if (schema.length === 1) return this.__createVirtualDom(schema[0], self, parentInfo);
|
||||||
|
return schema.map((item, idx) =>
|
||||||
|
this.__createVirtualDom(item, self, parentInfo, item && item.__ctx && item.__ctx.lunaKey ? '' : idx)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//解析占位组件
|
||||||
|
if (schema.componentName === 'Flagment' && schema.children) {
|
||||||
|
let tarChildren = isJSExpression(schema.children) ? parseExpression(schema.children, self) : schema.children;
|
||||||
|
return this.__createVirtualDom(tarChildren, self, parentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (schema.$$typeof) {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
if (!isSchema(schema)) return null;
|
||||||
|
let Comp = components[schema.componentName] || View;
|
||||||
|
|
||||||
|
if (schema.loop !== undefined) {
|
||||||
|
return this.__createLoopVirtualDom(
|
||||||
|
{
|
||||||
|
...schema,
|
||||||
|
loop: parseData(schema.loop, self)
|
||||||
|
},
|
||||||
|
self,
|
||||||
|
parentInfo,
|
||||||
|
idx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const condition = schema.condition === undefined ? true : parseData(schema.condition, self);
|
||||||
|
if (!condition) return null;
|
||||||
|
|
||||||
|
let scopeKey = '';
|
||||||
|
// 判断组件是否需要生成scope,且只生成一次,挂在this.__compScopes上
|
||||||
|
if (Comp.generateScope) {
|
||||||
|
const key = parseExpression(schema.props.key, self);
|
||||||
|
if (key) {
|
||||||
|
// 如果组件自己设置key则使用组件自己的key
|
||||||
|
scopeKey = key;
|
||||||
|
} else if (!schema.__ctx) {
|
||||||
|
// 在生产环境schema没有__ctx上下文,需要手动生成一个lunaKey
|
||||||
|
schema.__ctx = {
|
||||||
|
lunaKey: `luna${++scopeIdx}`
|
||||||
|
};
|
||||||
|
scopeKey = schema.__ctx.lunaKey;
|
||||||
|
} else {
|
||||||
|
// 需要判断循环的情况
|
||||||
|
scopeKey = schema.__ctx.lunaKey + (idx !== undefined ? `_${idx}` : '');
|
||||||
|
}
|
||||||
|
if (!this.__compScopes[scopeKey]) {
|
||||||
|
this.__compScopes[scopeKey] = Comp.generateScope(this, schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果组件有设置scope,需要为组件生成一个新的scope上下文
|
||||||
|
if (scopeKey && this.__compScopes[scopeKey]) {
|
||||||
|
const compSelf = { ...this.__compScopes[scopeKey] };
|
||||||
|
compSelf.__proto__ = self;
|
||||||
|
self = compSelf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 容器类组件的上下文通过props传递,避免context传递带来的嵌套问题
|
||||||
|
const otherProps = isFileSchema(schema)
|
||||||
|
? {
|
||||||
|
__schema: schema,
|
||||||
|
__appHelper: appHelper,
|
||||||
|
__components: components,
|
||||||
|
__componentsMap: componentsMap
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
if (engine && engine.props.designMode) {
|
||||||
|
otherProps.__designMode = engine.props.designMode;
|
||||||
|
}
|
||||||
|
const componentInfo = componentsMap[schema.componentName] || {};
|
||||||
|
const props = this.__parseProps(schema.props, self, '', {
|
||||||
|
schema,
|
||||||
|
Comp,
|
||||||
|
componentInfo: {
|
||||||
|
...componentInfo,
|
||||||
|
props: transformArrayToMap(componentInfo.props, 'name')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 对于可以获取到ref的组件做特殊处理
|
||||||
|
if (!acceptsRef(Comp)) {
|
||||||
|
Comp = CompWrapper(Comp);
|
||||||
|
}
|
||||||
|
otherProps.ref = ref => {
|
||||||
|
const refProps = props.ref;
|
||||||
|
if (refProps && typeof refProps === 'string') {
|
||||||
|
this[refProps] = ref;
|
||||||
|
}
|
||||||
|
engine && engine.props.onCompGetRef(schema, ref);
|
||||||
|
};
|
||||||
|
// scope需要传入到组件上
|
||||||
|
if (scopeKey && this.__compScopes[scopeKey]) {
|
||||||
|
props.__scope = this.__compScopes[scopeKey];
|
||||||
|
}
|
||||||
|
if (schema.__ctx && schema.__ctx.lunaKey) {
|
||||||
|
if (!isFileSchema(schema)) {
|
||||||
|
engine && engine.props.onCompGetCtx(schema, self);
|
||||||
|
}
|
||||||
|
props.key = props.key || `${schema.__ctx.lunaKey}_${schema.__ctx.idx || 0}_${idx !== undefined ? idx : ''}`;
|
||||||
|
} else if (typeof idx === 'number' && !props.key) {
|
||||||
|
props.key = idx;
|
||||||
|
}
|
||||||
|
const renderComp = props => (
|
||||||
|
<Comp {...props}>
|
||||||
|
{(!isFileSchema(schema) &&
|
||||||
|
!!schema.children &&
|
||||||
|
this.__createVirtualDom(
|
||||||
|
isJSExpression(schema.children) ? parseExpression(schema.children, self) : schema.children,
|
||||||
|
self,
|
||||||
|
{
|
||||||
|
schema,
|
||||||
|
Comp
|
||||||
|
}
|
||||||
|
)) ||
|
||||||
|
null}
|
||||||
|
</Comp>
|
||||||
|
);
|
||||||
|
//设计模式下的特殊处理
|
||||||
|
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
|
||||||
|
//对于overlay,dialog等组件为了使其在设计模式下显示,外层需要增加一个div容器
|
||||||
|
if (OVERLAY_LIST.includes(schema.componentName)) {
|
||||||
|
const { ref, ...overlayProps } = otherProps;
|
||||||
|
return (
|
||||||
|
<Div ref={ref} __designMode={engine.props.designMode}>
|
||||||
|
{renderComp({ ...props, ...overlayProps })}
|
||||||
|
</Div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 虚拟dom显示
|
||||||
|
if (componentInfo && componentInfo.parentRule) {
|
||||||
|
const parentList = componentInfo.parentRule.split(',');
|
||||||
|
const { schema: parentSchema, Comp: parentComp } = parentInfo;
|
||||||
|
if (!parentList.includes(parentSchema.componentName) || parentComp !== components[parentSchema.componentName]) {
|
||||||
|
props.__componentName = schema.componentName;
|
||||||
|
Comp = VisualDom;
|
||||||
|
} else {
|
||||||
|
// 若虚拟dom在正常的渲染上下文中,就不显示设计模式了
|
||||||
|
props.__disableDesignMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return renderComp({ ...props, ...otherProps });
|
||||||
|
};
|
||||||
|
|
||||||
|
__createLoopVirtualDom = (schema, self, parentInfo, idx) => {
|
||||||
|
if (isFileSchema(schema)) {
|
||||||
|
console.warn('file type not support Loop');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(schema.loop)) return null;
|
||||||
|
const itemArg = (schema.loopArgs && schema.loopArgs[0]) || 'item';
|
||||||
|
const indexArg = (schema.loopArgs && schema.loopArgs[1]) || 'index';
|
||||||
|
return schema.loop.map((item, i) => {
|
||||||
|
const loopSelf = {
|
||||||
|
[itemArg]: item,
|
||||||
|
[indexArg]: i
|
||||||
|
};
|
||||||
|
loopSelf.__proto__ = self;
|
||||||
|
return this.__createVirtualDom(
|
||||||
|
{
|
||||||
|
...schema,
|
||||||
|
loop: undefined
|
||||||
|
},
|
||||||
|
loopSelf,
|
||||||
|
parentInfo,
|
||||||
|
idx ? `${idx}_${i}` : i
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
__createContextDom = (childCtx, currCtx) => {
|
||||||
|
return (
|
||||||
|
<AppContext.Consumer>
|
||||||
|
{context => {
|
||||||
|
this.context = context;
|
||||||
|
this.__generateCtx(currCtx);
|
||||||
|
this.__render();
|
||||||
|
return (
|
||||||
|
<AppContext.Provider
|
||||||
|
value={{
|
||||||
|
...this.context,
|
||||||
|
...childCtx
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.__createDom()}
|
||||||
|
</AppContext.Provider>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</AppContext.Consumer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
__parseProps = (props, self, path, info) => {
|
||||||
|
const { schema, Comp, componentInfo = {} } = info;
|
||||||
|
const propInfo = getValue(componentInfo.props, path);
|
||||||
|
const propType = propInfo && propInfo.extra && propInfo.extra.propType;
|
||||||
|
const ignoreParse = schema.__ignoreParse || [];
|
||||||
|
const checkProps = value => {
|
||||||
|
if (!propType) return value;
|
||||||
|
return checkPropTypes(value, path, propType, componentInfo.name) ? value : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseReactNode = (data, params) => {
|
||||||
|
if (isEmpty(params)) {
|
||||||
|
return checkProps(this.__createVirtualDom(data, self, { schema, Comp }));
|
||||||
|
} else {
|
||||||
|
return checkProps(function() {
|
||||||
|
const args = {};
|
||||||
|
if (Array.isArray(params) && params.length) {
|
||||||
|
params.map((item, idx) => {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
args[item] = arguments[idx];
|
||||||
|
} else if (item && typeof item === 'object') {
|
||||||
|
args[item.name] = arguments[idx];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
args.__proto__ = self;
|
||||||
|
return self.__createVirtualDom(data, args, { schema, Comp });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 判断是否需要解析变量
|
||||||
|
if (
|
||||||
|
ignoreParse.some(item => {
|
||||||
|
if (item instanceof RegExp) {
|
||||||
|
return item.test(path);
|
||||||
|
}
|
||||||
|
return item === path;
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
return checkProps(props);
|
||||||
|
}
|
||||||
|
if (isJSExpression(props)) {
|
||||||
|
props = parseExpression(props, self);
|
||||||
|
// 只有当变量解析出来为模型结构的时候才会继续解析
|
||||||
|
if (!isSchema(props) && !isJSSlot(props)) return checkProps(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJSFunction(props)) {
|
||||||
|
props = props.value;
|
||||||
|
}
|
||||||
|
if (isJSSlot(props)) {
|
||||||
|
const { params, value } = props;
|
||||||
|
if (!isSchema(value) || isEmpty(value)) return undefined;
|
||||||
|
return parseReactNode(value, params);
|
||||||
|
}
|
||||||
|
// 兼容通过componentInfo判断的情况
|
||||||
|
if (isSchema(props)) {
|
||||||
|
return parseReactNode(props);
|
||||||
|
} else if (Array.isArray(props)) {
|
||||||
|
return checkProps(props.map((item, idx) => this.__parseProps(item, self, path ? `${path}.${idx}` : idx, info)));
|
||||||
|
} else if (typeof props === 'function') {
|
||||||
|
return checkProps(props.bind(self));
|
||||||
|
} else if (props && typeof props === 'object') {
|
||||||
|
if (props.$$typeof) return checkProps(props);
|
||||||
|
const res = {};
|
||||||
|
forEach(props, (val, key) => {
|
||||||
|
if (key.startsWith('__')) {
|
||||||
|
res[key] = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res[key] = this.__parseProps(val, self, path ? `${path}.${key}` : key, info);
|
||||||
|
});
|
||||||
|
return checkProps(res);
|
||||||
|
} else if (typeof props === 'string') {
|
||||||
|
return checkProps(props.trim());
|
||||||
|
}
|
||||||
|
return checkProps(props);
|
||||||
|
};
|
||||||
|
|
||||||
|
get utils() {
|
||||||
|
return this.appHelper && this.appHelper.utils;
|
||||||
|
}
|
||||||
|
get constants() {
|
||||||
|
return this.appHelper && this.appHelper.constants;
|
||||||
|
}
|
||||||
|
get history() {
|
||||||
|
return this.appHelper && this.appHelper.history;
|
||||||
|
}
|
||||||
|
get location() {
|
||||||
|
return this.appHelper && this.appHelper.location;
|
||||||
|
}
|
||||||
|
get match() {
|
||||||
|
return this.appHelper && this.appHelper.match;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
83
packages/rax-render/src/engine/blockEngine.jsx
Normal file
83
packages/rax-render/src/engine/blockEngine.jsx
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { createElement } from 'rax';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Debug from 'debug';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { isSchema, getFileCssName } from '../utils';
|
||||||
|
import BaseEngine from './base';
|
||||||
|
|
||||||
|
const debug = Debug('engine:block');
|
||||||
|
|
||||||
|
export default class BlockEngine extends BaseEngine {
|
||||||
|
static dislayName = 'block-engine';
|
||||||
|
static propTypes = {
|
||||||
|
__schema: PropTypes.object
|
||||||
|
};
|
||||||
|
static defaultProps = {
|
||||||
|
__schema: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props, state) {
|
||||||
|
debug(`block.getDerivedStateFromProps`);
|
||||||
|
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
||||||
|
if (func) {
|
||||||
|
return func(props, state);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.__generateCtx();
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
this.state = this.__parseData(schema.state || {});
|
||||||
|
this.__initDataSource(props);
|
||||||
|
this.__setLifeCycleMethods('constructor', arguments);
|
||||||
|
debug(`block.constructor - ${schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSnapshotBeforeUpdate() {
|
||||||
|
super.getSnapshotBeforeUpdate(...arguments);
|
||||||
|
debug(`block.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidMount() {
|
||||||
|
super.componentDidMount(...arguments);
|
||||||
|
debug(`block.componentDidMount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidUpdate() {
|
||||||
|
super.componentDidUpdate(...arguments);
|
||||||
|
debug(`block.componentDidUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentWillUnmount() {
|
||||||
|
super.componentWillUnmount(...arguments);
|
||||||
|
debug(`block.componentWillUnmount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidCatch() {
|
||||||
|
await super.componentDidCatch(...arguments);
|
||||||
|
debug(`block.componentDidCatch - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema } = this.props;
|
||||||
|
|
||||||
|
if (!isSchema(__schema, true) || __schema.componentName !== 'Block') {
|
||||||
|
return '区块schema结构异常!';
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(`block.render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
const { id, className, style } = this.__parseData(__schema.props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={this.__getRef}
|
||||||
|
className={classnames('luna-block', getFileCssName(__schema.fileName), className, this.props.className)}
|
||||||
|
id={id}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
{this.__createContextDom({
|
||||||
|
blockContext: this
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
103
packages/rax-render/src/engine/compEngine.jsx
Normal file
103
packages/rax-render/src/engine/compEngine.jsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { createElement } from 'rax';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Debug from 'debug';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { isSchema, getFileCssName } from '../utils';
|
||||||
|
import BaseEngine from './base';
|
||||||
|
|
||||||
|
const debug = Debug('engine:comp');
|
||||||
|
|
||||||
|
export default class CompEngine extends BaseEngine {
|
||||||
|
static dislayName = 'comp-engine';
|
||||||
|
static propTypes = {
|
||||||
|
__schema: PropTypes.object
|
||||||
|
};
|
||||||
|
static defaultProps = {
|
||||||
|
__schema: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props, state) {
|
||||||
|
debug(`comp.getDerivedStateFromProps`);
|
||||||
|
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
||||||
|
if (func) {
|
||||||
|
return func(props, state);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.__generateCtx({
|
||||||
|
component: this
|
||||||
|
});
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
this.state = this.__parseData(schema.state || {});
|
||||||
|
this.__initDataSource(props);
|
||||||
|
this.__setLifeCycleMethods('constructor', arguments);
|
||||||
|
debug(`comp.constructor - ${schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSnapshotBeforeUpdate() {
|
||||||
|
super.getSnapshotBeforeUpdate(...arguments);
|
||||||
|
debug(`comp.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidMount() {
|
||||||
|
super.componentDidMount(...arguments);
|
||||||
|
debug(`comp.componentDidMount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidUpdate() {
|
||||||
|
super.componentDidUpdate(...arguments);
|
||||||
|
debug(`comp.componentDidUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentWillUnmount() {
|
||||||
|
super.componentWillUnmount(...arguments);
|
||||||
|
debug(`comp.componentWillUnmount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidCatch(e) {
|
||||||
|
super.componentDidCatch(...arguments);
|
||||||
|
debug(`comp.componentDidCatch - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema } = this.props;
|
||||||
|
|
||||||
|
if (!isSchema(__schema, true) || __schema.componentName !== 'Component') {
|
||||||
|
return '自定义组件schema结构异常!';
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(`comp.render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
const { id, className, style, noContainer } = this.__parseData(__schema.props);
|
||||||
|
|
||||||
|
if (noContainer) {
|
||||||
|
return this.__createContextDom(
|
||||||
|
{
|
||||||
|
compContext: this,
|
||||||
|
blockContext: this
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: this
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={this.__getRef}
|
||||||
|
className={classnames('luna-comp', getFileCssName(__schema.fileName), className, this.props.className)}
|
||||||
|
id={this.props.id || id}
|
||||||
|
style={{ ...style, ...this.props.style }}
|
||||||
|
>
|
||||||
|
{this.__createContextDom(
|
||||||
|
{
|
||||||
|
compContext: this,
|
||||||
|
blockContext: this
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: this
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
122
packages/rax-render/src/engine/index.jsx
Normal file
122
packages/rax-render/src/engine/index.jsx
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import { Component, createElement } from 'rax';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Debug from 'debug';
|
||||||
|
import * as isEmpty from 'lodash/isEmpty';
|
||||||
|
import findDOMNode from 'rax-find-dom-node';
|
||||||
|
import { isFileSchema, goldlog } from '../utils';
|
||||||
|
import AppContext from '../context/appContext';
|
||||||
|
import Page from './pageEngine';
|
||||||
|
import CustomComp from './compEngine';
|
||||||
|
import Block from './blockEngine';
|
||||||
|
import Temp from './tempEngine';
|
||||||
|
|
||||||
|
const debug = Debug('engine:entry');
|
||||||
|
const ENGINE_COMPS = {
|
||||||
|
Page,
|
||||||
|
Component: CustomComp,
|
||||||
|
Block,
|
||||||
|
Temp,
|
||||||
|
};
|
||||||
|
export default class Engine extends Component {
|
||||||
|
static dislayName = 'engine';
|
||||||
|
static propTypes = {
|
||||||
|
appHelper: PropTypes.object,
|
||||||
|
components: PropTypes.object,
|
||||||
|
componentsMap: PropTypes.object,
|
||||||
|
designMode: PropTypes.string,
|
||||||
|
suspended: PropTypes.bool,
|
||||||
|
schema: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||||
|
onCompGetRef: PropTypes.func,
|
||||||
|
onCompGetCtx: PropTypes.func
|
||||||
|
};
|
||||||
|
static defaultProps = {
|
||||||
|
appHelper: null,
|
||||||
|
components: {},
|
||||||
|
componentsMap: {},
|
||||||
|
designMode: '',
|
||||||
|
suspended: false,
|
||||||
|
schema: {},
|
||||||
|
onCompGetRef: () => {},
|
||||||
|
onCompGetCtx: () => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.state = {};
|
||||||
|
debug(`entry.constructor - ${props.schema && props.schema.componentName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
goldlog(
|
||||||
|
'EXP',
|
||||||
|
{
|
||||||
|
action: 'appear',
|
||||||
|
value: !!this.props.designMode
|
||||||
|
},
|
||||||
|
'engine'
|
||||||
|
);
|
||||||
|
debug(`entry.componentDidMount - ${this.props.schema && this.props.schema.componentName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidUpdate() {
|
||||||
|
debug(`entry.componentDidUpdate - ${this.props.schema && this.props.schema.componentName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentWillUnmount() {
|
||||||
|
debug(`entry.componentWillUnmount - ${this.props.schema && this.props.schema.componentName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidCatch(e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps) {
|
||||||
|
return !nextProps.suspended;
|
||||||
|
}
|
||||||
|
|
||||||
|
__getRef = ref => {
|
||||||
|
this.__ref = ref;
|
||||||
|
if (ref) {
|
||||||
|
this.props.onCompGetRef(this.props.schema, ref, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { schema, designMode, appHelper, components, componentsMap } = this.props;
|
||||||
|
if (isEmpty(schema)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!isFileSchema(schema)) {
|
||||||
|
return '模型结构异常';
|
||||||
|
}
|
||||||
|
debug('entry.render');
|
||||||
|
const allComponents = { ...ENGINE_COMPS, ...components };
|
||||||
|
const Comp = allComponents[schema.componentName];
|
||||||
|
if (Comp) {
|
||||||
|
return (
|
||||||
|
<AppContext.Provider
|
||||||
|
value={{
|
||||||
|
appHelper,
|
||||||
|
components: allComponents,
|
||||||
|
componentsMap,
|
||||||
|
engine: this
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Comp
|
||||||
|
key={schema.__ctx && `${schema.__ctx.lunaKey}_${schema.__ctx.idx || '0'}`}
|
||||||
|
ref={this.__getRef}
|
||||||
|
__appHelper={appHelper}
|
||||||
|
__components={allComponents}
|
||||||
|
__componentsMap={componentsMap}
|
||||||
|
__schema={schema}
|
||||||
|
__designMode={designMode}
|
||||||
|
{...this.props}
|
||||||
|
/>
|
||||||
|
</AppContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine.findDOMNode = findDOMNode;
|
||||||
90
packages/rax-render/src/engine/pageEngine.jsx
Normal file
90
packages/rax-render/src/engine/pageEngine.jsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { createElement } from 'rax';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Debug from 'debug';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { isSchema, getFileCssName } from '../utils';
|
||||||
|
import BaseEngine from './base';
|
||||||
|
|
||||||
|
const debug = Debug('engine:page');
|
||||||
|
|
||||||
|
export default class PageEngine extends BaseEngine {
|
||||||
|
static dislayName = 'page-engine';
|
||||||
|
static propTypes = {
|
||||||
|
__schema: PropTypes.object
|
||||||
|
};
|
||||||
|
static defaultProps = {
|
||||||
|
__schema: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props, state) {
|
||||||
|
debug(`page.getDerivedStateFromProps`);
|
||||||
|
const func = props.__schema.lifeCycles && props.__schema.lifeCycles.getDerivedStateFromProps;
|
||||||
|
if (func) {
|
||||||
|
return func(props, state);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.__generateCtx({
|
||||||
|
page: this
|
||||||
|
});
|
||||||
|
const schema = props.__schema || {};
|
||||||
|
this.state = this.__parseData(schema.state || {});
|
||||||
|
this.__initDataSource(props);
|
||||||
|
this.__setLifeCycleMethods('constructor', arguments);
|
||||||
|
|
||||||
|
debug(`page.constructor - ${schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSnapshotBeforeUpdate() {
|
||||||
|
super.getSnapshotBeforeUpdate(...arguments);
|
||||||
|
debug(`page.getSnapshotBeforeUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidMount() {
|
||||||
|
super.componentDidMount(...arguments);
|
||||||
|
debug(`page.componentDidMount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidUpdate() {
|
||||||
|
super.componentDidUpdate(...arguments);
|
||||||
|
debug(`page.componentDidUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentWillUnmount() {
|
||||||
|
super.componentWillUnmount(...arguments);
|
||||||
|
debug(`page.componentWillUnmount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
async componentDidCatch() {
|
||||||
|
await super.componentDidCatch(...arguments);
|
||||||
|
debug(`page.componentDidCatch - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema } = this.props;
|
||||||
|
if (!isSchema(__schema, true) || __schema.componentName !== 'Page') {
|
||||||
|
return '页面schema结构异常!';
|
||||||
|
}
|
||||||
|
debug(`page.render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
const { id, className, style } = this.__parseData(__schema.props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={this.__getRef}
|
||||||
|
className={classnames('luna-page', getFileCssName(__schema.fileName), className, this.props.className)}
|
||||||
|
id={id}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
{this.__createContextDom(
|
||||||
|
{
|
||||||
|
pageContext: this,
|
||||||
|
blockContext: this
|
||||||
|
},
|
||||||
|
{
|
||||||
|
page: this
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
67
packages/rax-render/src/engine/tempEngine.jsx
Normal file
67
packages/rax-render/src/engine/tempEngine.jsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { createElement } from 'rax';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Debug from 'debug';
|
||||||
|
import { isSchema } from '../utils';
|
||||||
|
import AppContext from '../context/appContext';
|
||||||
|
import BaseEngine from './base';
|
||||||
|
|
||||||
|
const debug = Debug('engine:temp');
|
||||||
|
export default class TempEngine extends BaseEngine {
|
||||||
|
static dislayName = 'temp-engine';
|
||||||
|
static propTypes = {
|
||||||
|
__ctx: PropTypes.object,
|
||||||
|
__schema: PropTypes.object
|
||||||
|
};
|
||||||
|
static defaultProps = {
|
||||||
|
__ctx: {},
|
||||||
|
__schema: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.state = {};
|
||||||
|
this.cacheSetState = {};
|
||||||
|
debug(`temp.constructor - ${props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const ctx = this.props.__ctx;
|
||||||
|
if (!ctx) return;
|
||||||
|
const setState = ctx.setState;
|
||||||
|
this.cacheSetState = setState;
|
||||||
|
ctx.setState = (...args) => {
|
||||||
|
setState.call(ctx, ...args);
|
||||||
|
setTimeout(() => this.forceUpdate(), 0);
|
||||||
|
};
|
||||||
|
debug(`temp.componentDidMount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||||
|
debug(`temp.componentDidUpdate - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
const ctx = this.props.__ctx;
|
||||||
|
if (!ctx || !this.cacheSetState) return;
|
||||||
|
ctx.setState = this.cacheSetState;
|
||||||
|
delete this.cacheSetState;
|
||||||
|
debug(`temp.componentWillUnmount - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
componentDidCatch(e) {
|
||||||
|
console.warn(e);
|
||||||
|
debug(`temp.componentDidCatch - ${this.props.__schema.fileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { __schema, __ctx } = this.props;
|
||||||
|
if (!isSchema(__schema, true) || __schema.componentName !== 'Temp') {
|
||||||
|
return '下钻编辑schema结构异常!';
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(`temp.render - ${__schema.fileName}`);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={this.__getRef} className="luna-temp">
|
||||||
|
<AppContext.Provider value={{ ...this.context, ...__ctx }}>{this.__createDom()}</AppContext.Provider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
packages/rax-render/src/hoc/compFactory.js
Normal file
71
packages/rax-render/src/hoc/compFactory.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { Component, createElement } from 'rax';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import AppHelper from '../utils/appHelper';
|
||||||
|
import { forEach, isFileSchema } from '../utils';
|
||||||
|
import CompEngine from '../engine/compEngine';
|
||||||
|
import BlockEngine from '../engine/blockEngine';
|
||||||
|
import AppContext from '../context/appContext';
|
||||||
|
|
||||||
|
export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) {
|
||||||
|
// 自定义组件需要有自己独立的appHelper
|
||||||
|
const appHelper = new AppHelper(config);
|
||||||
|
class LNCompView extends Component {
|
||||||
|
static dislayName = 'luna-comp-factory';
|
||||||
|
static version = config.version || '0.0.0';
|
||||||
|
static contextType = AppContext;
|
||||||
|
static propTypes = {
|
||||||
|
forwardedRef: PropTypes.func
|
||||||
|
};
|
||||||
|
render() {
|
||||||
|
if (!schema || schema.componentName !== 'Component' || !isFileSchema(schema)) {
|
||||||
|
console.warn('自定义组件模型结构异常!');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { forwardedRef, ...otherProps } = this.props;
|
||||||
|
// 低代码组件透传应用上下文
|
||||||
|
const ctx = ['utils', 'constants', 'history', 'location', 'match'];
|
||||||
|
ctx.forEach(key => {
|
||||||
|
if (!appHelper[key] && this.context && this.context.appHelper && this.context.appHelper[key]) {
|
||||||
|
appHelper.set(key, this.context.appHelper[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 支持通过context透传国际化配置
|
||||||
|
const localeProps = {};
|
||||||
|
const { locale, messages } = this.context;
|
||||||
|
if (locale && messages && messages[schema.fileName]) {
|
||||||
|
localeProps.locale = locale;
|
||||||
|
localeProps.messages = messages[schema.fileName];
|
||||||
|
}
|
||||||
|
const props = {
|
||||||
|
...schema.defaultProps,
|
||||||
|
...localeProps,
|
||||||
|
...otherProps,
|
||||||
|
__schema: schema,
|
||||||
|
ref: forwardedRef
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppContext.Consumer>
|
||||||
|
{context => {
|
||||||
|
this.context = context;
|
||||||
|
return (
|
||||||
|
<CompEngine
|
||||||
|
{...props}
|
||||||
|
__appHelper={appHelper}
|
||||||
|
__components={{ ...components, Component: CompEngine, Block: BlockEngine }}
|
||||||
|
__componentsMap={componentsMap}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</AppContext.Consumer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ResComp = React.forwardRef((props, ref) => <LNCompView {...props} forwardedRef={ref} />);
|
||||||
|
forEach(schema.static, (val, key) => {
|
||||||
|
ResComp[key] = val;
|
||||||
|
});
|
||||||
|
ResComp.version = config.version || '0.0.0';
|
||||||
|
return ResComp;
|
||||||
|
}
|
||||||
15
packages/rax-render/src/hoc/compWrapper.js
Normal file
15
packages/rax-render/src/hoc/compWrapper.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { createElement, Component } from 'rax';
|
||||||
|
|
||||||
|
export default function(Comp) {
|
||||||
|
class CompWrapper extends Component {
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <Comp {...this.props} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompWrapper;
|
||||||
|
}
|
||||||
5
packages/rax-render/src/index.jsx
Normal file
5
packages/rax-render/src/index.jsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import Engine from './engine';
|
||||||
|
|
||||||
|
export { default as Engine } from './engine';
|
||||||
|
export { default as CompFactory } from './hoc/compFactory';
|
||||||
|
export default Engine;
|
||||||
49
packages/rax-render/src/utils/appHelper.js
Normal file
49
packages/rax-render/src/utils/appHelper.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
|
let instance = null;
|
||||||
|
|
||||||
|
EventEmitter.defaultMaxListeners = 100;
|
||||||
|
|
||||||
|
export default class AppHelper extends EventEmitter {
|
||||||
|
static getInstance = () => {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new AppHelper();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(config) {
|
||||||
|
super();
|
||||||
|
instance = this;
|
||||||
|
Object.assign(this, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key) {
|
||||||
|
return this[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key, val) {
|
||||||
|
if (typeof key === 'string') {
|
||||||
|
this[key] = val;
|
||||||
|
} else if (typeof key === 'object') {
|
||||||
|
Object.keys(key).forEach((item) => {
|
||||||
|
this[item] = key[item];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
batchOn(events, lisenter) {
|
||||||
|
if (!Array.isArray(events)) return;
|
||||||
|
events.forEach((event) => this.on(event, lisenter));
|
||||||
|
}
|
||||||
|
|
||||||
|
batchOnce(events, lisenter) {
|
||||||
|
if (!Array.isArray(events)) return;
|
||||||
|
events.forEach((event) => this.once(event, lisenter));
|
||||||
|
}
|
||||||
|
|
||||||
|
batchOff(events, lisenter) {
|
||||||
|
if (!Array.isArray(events)) return;
|
||||||
|
events.forEach((event) => this.off(event, lisenter));
|
||||||
|
}
|
||||||
|
}
|
||||||
299
packages/rax-render/src/utils/dataHelper.js
Normal file
299
packages/rax-render/src/utils/dataHelper.js
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
import { transformArrayToMap, isJSFunction, transformStringToFunction, clone } from './index';
|
||||||
|
import { jsonp, mtop, request, get, post, bzb } from './request';
|
||||||
|
|
||||||
|
const DS_STATUS = {
|
||||||
|
INIT: 'init',
|
||||||
|
LOADING: 'loading',
|
||||||
|
LOADED: 'loaded',
|
||||||
|
ERROR: 'error'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DataHelper {
|
||||||
|
constructor(comp, config = {}, appHelper, parser) {
|
||||||
|
this.host = comp;
|
||||||
|
this.config = config;
|
||||||
|
this.parser = parser;
|
||||||
|
this.ajaxList = (config && config.list) || [];
|
||||||
|
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||||
|
this.dataSourceMap = this.generateDataSourceMap();
|
||||||
|
this.appHelper = appHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置config,dataSourceMap状态会被重置;
|
||||||
|
resetConfig(config = {}) {
|
||||||
|
this.config = config;
|
||||||
|
this.ajaxList = (config && config.list) || [];
|
||||||
|
this.ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||||
|
this.dataSourceMap = this.generateDataSourceMap();
|
||||||
|
return this.dataSourceMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新config,只会更新配置,状态保存;
|
||||||
|
updateConfig(config = {}) {
|
||||||
|
this.config = config;
|
||||||
|
this.ajaxList = (config && config.list) || [];
|
||||||
|
const ajaxMap = transformArrayToMap(this.ajaxList, 'id');
|
||||||
|
// 删除已经移除的接口
|
||||||
|
Object.keys(this.ajaxMap).forEach(key => {
|
||||||
|
if (!ajaxMap[key]) {
|
||||||
|
delete this.dataSourceMap[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.ajaxMap = ajaxMap;
|
||||||
|
// 添加未加入到dataSourceMap中的接口
|
||||||
|
this.ajaxList.forEach(item => {
|
||||||
|
if (!this.dataSourceMap[item.id]) {
|
||||||
|
this.dataSourceMap[item.id] = {
|
||||||
|
status: DS_STATUS.INIT,
|
||||||
|
load: (...args) => {
|
||||||
|
return this.getDataSource(item.id, ...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this.dataSourceMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateDataSourceMap() {
|
||||||
|
const res = {};
|
||||||
|
this.ajaxList.forEach(item => {
|
||||||
|
res[item.id] = {
|
||||||
|
status: DS_STATUS.INIT,
|
||||||
|
load: (...args) => {
|
||||||
|
return this.getDataSource(item.id, ...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDataSourceMap(id, data, error) {
|
||||||
|
this.dataSourceMap[id].error = error ? error : undefined;
|
||||||
|
this.dataSourceMap[id].data = data;
|
||||||
|
this.dataSourceMap[id].status = error ? DS_STATUS.ERROR : DS_STATUS.LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInitData() {
|
||||||
|
const initSyncData = this.parser(this.ajaxList).filter(item => {
|
||||||
|
if (item.isInit) {
|
||||||
|
this.dataSourceMap[item.id].status = DS_STATUS.LOADING;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return this.asyncDataHandler(initSyncData).then(res => {
|
||||||
|
let dataHandler = this.config.dataHandler;
|
||||||
|
if (isJSFunction(dataHandler)) {
|
||||||
|
dataHandler = transformStringToFunction(dataHandler.value);
|
||||||
|
}
|
||||||
|
if (!dataHandler || typeof dataHandler !== 'function') return res;
|
||||||
|
try {
|
||||||
|
return dataHandler.call(this.host, res);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('请求数据处理函数运行出错', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getDataSource(id, params, otherOptions, callback) {
|
||||||
|
const req = this.parser(this.ajaxMap[id]);
|
||||||
|
const options = req.options || {};
|
||||||
|
if (typeof otherOptions === 'function') {
|
||||||
|
callback = otherOptions;
|
||||||
|
otherOptions = {};
|
||||||
|
}
|
||||||
|
const { headers, ...otherProps } = otherOptions || {};
|
||||||
|
if (!req) {
|
||||||
|
console.warn(`getDataSource API named ${id} not exist`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return this.asyncDataHandler([
|
||||||
|
{
|
||||||
|
...req,
|
||||||
|
options: {
|
||||||
|
...options,
|
||||||
|
// 支持参数为array的情况,当参数为array时,不做参数合并
|
||||||
|
params:
|
||||||
|
Array.isArray(options.params) || Array.isArray(params)
|
||||||
|
? params || options.params
|
||||||
|
: {
|
||||||
|
...options.params,
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
...options.headers,
|
||||||
|
...headers
|
||||||
|
},
|
||||||
|
...otherProps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.then(res => {
|
||||||
|
try {
|
||||||
|
callback && callback(res && res[id]);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('load请求回调函数报错', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res && res[id];
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
try {
|
||||||
|
callback && callback(null, err);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('load请求回调函数报错', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
asyncDataHandler(asyncDataList) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const allReq = [];
|
||||||
|
const doserReq = [];
|
||||||
|
const doserList = [];
|
||||||
|
const beforeRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.beforeRequest;
|
||||||
|
const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest;
|
||||||
|
const csrfInput = document.getElementById('_csrf_token');
|
||||||
|
const _tb_token_ = csrfInput && csrfInput.value;
|
||||||
|
asyncDataList.map(req => {
|
||||||
|
const { id, type, options } = req;
|
||||||
|
if (!id || !type) return;
|
||||||
|
if (type === 'doServer') {
|
||||||
|
const { uri, params } = options || {};
|
||||||
|
if (!uri) return;
|
||||||
|
doserList.push(id);
|
||||||
|
doserReq.push({ name: uri, package: 'cms', params });
|
||||||
|
} else {
|
||||||
|
allReq.push(req);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (doserReq.length > 0) {
|
||||||
|
allReq.push({
|
||||||
|
type: 'doServer',
|
||||||
|
options: {
|
||||||
|
uri: '/nrsService.do',
|
||||||
|
cors: true,
|
||||||
|
method: 'POST',
|
||||||
|
params: {
|
||||||
|
data: JSON.stringify(doserReq),
|
||||||
|
_tb_token_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (allReq.length === 0) resolve({});
|
||||||
|
const res = {};
|
||||||
|
Promise.all(
|
||||||
|
allReq.map(item => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const { type, id, dataHandler, options } = item;
|
||||||
|
const doFetch = (type, options) => {
|
||||||
|
this.fetchOne(type, options)
|
||||||
|
.then(async data => {
|
||||||
|
if (afterRequest) {
|
||||||
|
this.appHelper.utils.afterRequest(item, data, undefined, async (data, error) => {
|
||||||
|
await fetchHandler(data, error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await fetchHandler(data, undefined);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(async err => {
|
||||||
|
if (afterRequest) {
|
||||||
|
// 必须要这么调用,否则beforeRequest中的this会丢失
|
||||||
|
this.appHelper.utils.afterRequest(item, undefined, err, async (data, error) => {
|
||||||
|
await fetchHandler(data, error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await fetchHandler(undefined, err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const fetchHandler = async (data, error) => {
|
||||||
|
if (type === 'doServer') {
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
data = [data];
|
||||||
|
}
|
||||||
|
doserList.forEach(async (id, idx) => {
|
||||||
|
const req = this.ajaxMap[id];
|
||||||
|
if (req) {
|
||||||
|
res[id] = await this.dataHandler(id, req.dataHandler, data && data[idx], error);
|
||||||
|
this.updateDataSourceMap(id, res[id], error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res[id] = await this.dataHandler(id, dataHandler, data, error);
|
||||||
|
this.updateDataSourceMap(id, res[id], error);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type === 'doServer') {
|
||||||
|
doserList.forEach(item => {
|
||||||
|
this.dataSourceMap[item].status = DS_STATUS.LOADING;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.dataSourceMap[id].status = DS_STATUS.LOADING;
|
||||||
|
}
|
||||||
|
// 请求切片
|
||||||
|
if (beforeRequest) {
|
||||||
|
// 必须要这么调用,否则beforeRequest中的this会丢失
|
||||||
|
this.appHelper.utils.beforeRequest(item, clone(options), options => doFetch(type, options));
|
||||||
|
} else {
|
||||||
|
doFetch(type, options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
resolve(res);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
reject(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async dataHandler(id, dataHandler, data, error) {
|
||||||
|
if (isJSFunction(dataHandler)) {
|
||||||
|
dataHandler = transformStringToFunction(dataHandler.value);
|
||||||
|
}
|
||||||
|
if (!dataHandler || typeof dataHandler !== 'function') return data;
|
||||||
|
try {
|
||||||
|
return await dataHandler.call(this.host, data, error);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[' + id + ']单个请求数据处理函数运行出错', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchOne(type, options) {
|
||||||
|
let { uri, method = 'GET', headers, params, ...otherProps } = options;
|
||||||
|
otherProps = otherProps || {};
|
||||||
|
switch (type) {
|
||||||
|
case 'mtop':
|
||||||
|
method && (otherProps.method = method);
|
||||||
|
return mtop(uri, params, otherProps);
|
||||||
|
case 'jsonp':
|
||||||
|
return jsonp(uri, params, otherProps);
|
||||||
|
case 'bzb':
|
||||||
|
return bzb(uri, params, {
|
||||||
|
method,
|
||||||
|
headers,
|
||||||
|
...otherProps
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
method = method.toUpperCase();
|
||||||
|
if (method === 'GET') {
|
||||||
|
return get(uri, params, headers, otherProps);
|
||||||
|
} else if (method === 'POST') {
|
||||||
|
return post(uri, params, headers, otherProps);
|
||||||
|
}
|
||||||
|
return request(uri, method, params, headers, otherProps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
718
packages/rax-render/src/utils/index.js
Normal file
718
packages/rax-render/src/utils/index.js
Normal file
@ -0,0 +1,718 @@
|
|||||||
|
import Debug from 'debug';
|
||||||
|
import _keymaster from 'keymaster';
|
||||||
|
import { forEach as _forEach, shallowEqual as _shallowEqual } from '@ali/b3-one/lib/obj';
|
||||||
|
import { serialize as serializeParams } from '@ali/b3-one/lib/url';
|
||||||
|
import _moment from 'moment';
|
||||||
|
import 'moment/locale/zh-cn';
|
||||||
|
import _pick from 'lodash/pick';
|
||||||
|
import _deepEqual from 'lodash/isEqualWith';
|
||||||
|
import _clone from 'lodash/cloneDeep';
|
||||||
|
import _isEmpty from 'lodash/isEmpty';
|
||||||
|
import _throttle from 'lodash/throttle';
|
||||||
|
import _debounce from 'lodash/debounce';
|
||||||
|
import _serialize from 'serialize-javascript';
|
||||||
|
import * as _jsonuri from 'jsonuri';
|
||||||
|
import IntlMessageFormat from 'intl-messageformat';
|
||||||
|
import pkg from '../../package.json';
|
||||||
|
|
||||||
|
window.sdkVersion = pkg.version;
|
||||||
|
|
||||||
|
export const moment = _moment;
|
||||||
|
moment.locale('zh-cn');
|
||||||
|
export const forEach = _forEach;
|
||||||
|
export const shallowEqual = _shallowEqual;
|
||||||
|
export const keymaster = _keymaster;
|
||||||
|
export const pick = _pick;
|
||||||
|
export const deepEqual = _deepEqual;
|
||||||
|
export const clone = _clone;
|
||||||
|
export const isEmpty = _isEmpty;
|
||||||
|
export const throttle = _throttle;
|
||||||
|
export const debounce = _debounce;
|
||||||
|
export const serialize = _serialize;
|
||||||
|
export const jsonuri = _jsonuri;
|
||||||
|
export { get, post, jsonp, mtop, request } from './request';
|
||||||
|
|
||||||
|
const ReactIs = require('react-is');
|
||||||
|
|
||||||
|
const ReactPropTypesSecret = require('prop-types/lib/ReactPropTypesSecret');
|
||||||
|
|
||||||
|
const factoryWithTypeCheckers = require('prop-types/factoryWithTypeCheckers');
|
||||||
|
|
||||||
|
const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true);
|
||||||
|
|
||||||
|
const EXPRESSION_TYPE = {
|
||||||
|
JSEXPRESSION: 'JSExpression',
|
||||||
|
JSFUNCTION: 'JSFunction',
|
||||||
|
JSSLOT: 'JSSlot'
|
||||||
|
};
|
||||||
|
const EXPRESSION_REG = /^\{\{(\{.*\}|.*?)\}\}$/;
|
||||||
|
const hasSymbol = typeof Symbol === 'function' && Symbol['for'];
|
||||||
|
const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol['for']('react.forward_ref') : 0xead0;
|
||||||
|
const debug = Debug('utils:index');
|
||||||
|
|
||||||
|
const ENV = {
|
||||||
|
TBE: 'TBE',
|
||||||
|
WEBIDE: 'WEB-IDE',
|
||||||
|
VSCODE: 'VSCODE',
|
||||||
|
WEB: 'WEB'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name isSchema
|
||||||
|
* @description 判断是否是模型结构
|
||||||
|
*/
|
||||||
|
export function isSchema(schema, ignoreArr) {
|
||||||
|
if (isEmpty(schema)) return false;
|
||||||
|
if (!ignoreArr && Array.isArray(schema)) return schema.every(item => isSchema(item));
|
||||||
|
return !!(schema.componentName && schema.props && (typeof schema.props === 'object' || isJSExpression(schema.props)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFileSchema(schema) {
|
||||||
|
if (isEmpty(schema)) return false;
|
||||||
|
return ['Page', 'Block', 'Component', 'Addon', 'Temp'].includes(schema.componentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断当前页面是否被嵌入到同域的页面中
|
||||||
|
export function inSameDomain() {
|
||||||
|
try {
|
||||||
|
return window.parent !== window && window.parent.location.host === window.location.host;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFileCssName(fileName) {
|
||||||
|
if (!fileName) return;
|
||||||
|
let name = fileName.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
|
return ('luna-' + name)
|
||||||
|
.split('-')
|
||||||
|
.filter(p => !!p)
|
||||||
|
.join('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isJSSlot(obj) {
|
||||||
|
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSSLOT === obj.type;
|
||||||
|
}
|
||||||
|
export function isJSFunction(obj) {
|
||||||
|
return obj && typeof obj === 'object' && EXPRESSION_TYPE.JSFUNCTION === obj.type;
|
||||||
|
}
|
||||||
|
export function isJSExpression(obj) {
|
||||||
|
//兼容两种写法,有js构造表达式的情况
|
||||||
|
const isJSExpressionObj =
|
||||||
|
obj && typeof obj === 'object' && EXPRESSION_TYPE.JSEXPRESSION === obj.type && typeof obj.value === 'string';
|
||||||
|
const isJSExpressionStr = typeof obj === 'string' && EXPRESSION_REG.test(obj.trim());
|
||||||
|
return isJSExpressionObj || isJSExpressionStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name wait
|
||||||
|
* @description 等待函数
|
||||||
|
*/
|
||||||
|
export function wait(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(() => resolve(true), ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function curry(Comp, hocs = []) {
|
||||||
|
return hocs.reverse().reduce((pre, cur) => {
|
||||||
|
return cur(pre);
|
||||||
|
}, Comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取parent window上的值,需要做同域判断
|
||||||
|
* @param {string} key
|
||||||
|
*/
|
||||||
|
export function getParentWinValue(key) {
|
||||||
|
if (inSameDomain()) {
|
||||||
|
return window.parent && window.parent[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getValue(obj, path, defaultValue) {
|
||||||
|
if (isEmpty(obj) || typeof obj !== 'object') return defaultValue;
|
||||||
|
const res = path.split('.').reduce((pre, cur) => {
|
||||||
|
return pre && pre[cur];
|
||||||
|
}, obj);
|
||||||
|
if (res === undefined) return defaultValue;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseObj(schemaStr) {
|
||||||
|
if (typeof schemaStr !== 'string') return schemaStr;
|
||||||
|
//默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
||||||
|
try {
|
||||||
|
if (inSameDomain() && window.parent.__newFunc) {
|
||||||
|
return window.parent.__newFunc(`"use strict"; return ${schemaStr}`)();
|
||||||
|
}
|
||||||
|
return new Function(`"use strict"; return ${schemaStr}`)();
|
||||||
|
} catch (err) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseSearch(search) {
|
||||||
|
if (!search || typeof search !== 'string') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const str = search.replace(/^\?/, '');
|
||||||
|
const paramStr = str.split('&');
|
||||||
|
const res = {};
|
||||||
|
paramStr.forEach(item => {
|
||||||
|
const regRes = item.split('=');
|
||||||
|
if (regRes[0] && regRes[1]) {
|
||||||
|
res[regRes[0]] = decodeURIComponent(regRes[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fastClone(obj) {
|
||||||
|
return parseObj(serialize(obj, { unsafe: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新obj的内容但不改变obj的指针
|
||||||
|
export function fillObj(receiver = {}, ...suppliers) {
|
||||||
|
Object.keys(receiver).forEach(item => {
|
||||||
|
delete receiver[item];
|
||||||
|
});
|
||||||
|
Object.assign(receiver, ...suppliers);
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 中划线转驼峰
|
||||||
|
export function toHump(name) {
|
||||||
|
return name.replace(/\-(\w)/g, function(all, letter) {
|
||||||
|
return letter.toUpperCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 驼峰转中划线
|
||||||
|
export function toLine(name) {
|
||||||
|
return name.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前环境
|
||||||
|
export function getEnv() {
|
||||||
|
const userAgent = navigator.userAgent;
|
||||||
|
const isVscode = /Electron\//.test(userAgent);
|
||||||
|
if (isVscode) return ENV.VSCODE;
|
||||||
|
const isTheia = window.is_theia === true;
|
||||||
|
if (isTheia) return ENV.WEBIDE;
|
||||||
|
return ENV.WEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并skeleton配置
|
||||||
|
* @param {*} 骨架默认配置
|
||||||
|
* @param {*} 用户自定义配置
|
||||||
|
*/
|
||||||
|
export function comboSkeletonConfig(defaultConfig = {}, customConfig) {
|
||||||
|
const { skeleton, theme, addons, hooks, shortCuts, extensions, constants, utils, i18n } = customConfig || {};
|
||||||
|
|
||||||
|
if (skeleton && skeleton.handler && typeof skeleton.handler === 'function') {
|
||||||
|
return skeleton.handler({
|
||||||
|
skeleton,
|
||||||
|
...defaultConfig
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultShortCuts = transformArrayToMap(defaultConfig.shortCuts || [], 'keyboard');
|
||||||
|
const customShortCuts = transformArrayToMap(shortCuts || [], 'keyboard');
|
||||||
|
const localeList = ['zh-CN', 'zh-TW', 'en-US', 'ja-JP'];
|
||||||
|
const i18nConfig = {};
|
||||||
|
localeList.forEach(key => {
|
||||||
|
i18nConfig[key] = {
|
||||||
|
...(defaultConfig.i18n && defaultConfig.i18n[key]),
|
||||||
|
...(i18n && i18n[key])
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
skeleton,
|
||||||
|
theme: {
|
||||||
|
...defaultConfig.theme,
|
||||||
|
...theme
|
||||||
|
},
|
||||||
|
addons: {
|
||||||
|
...defaultConfig.addons,
|
||||||
|
...addons
|
||||||
|
},
|
||||||
|
hooks: [...(defaultConfig.hooks || []), ...(hooks || [])],
|
||||||
|
shortCuts: Object.values({
|
||||||
|
...defaultShortCuts,
|
||||||
|
...customShortCuts
|
||||||
|
}),
|
||||||
|
extensions: {
|
||||||
|
...defaultConfig.extensions,
|
||||||
|
...extensions
|
||||||
|
},
|
||||||
|
constants: {
|
||||||
|
...defaultConfig.constants,
|
||||||
|
...constants
|
||||||
|
},
|
||||||
|
utils: [...(defaultConfig.utils || []), ...(utils || [])],
|
||||||
|
i18n: i18nConfig
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于构造国际化字符串处理函数
|
||||||
|
* @param {*} locale 国际化标识,例如 zh-CN、en-US
|
||||||
|
* @param {*} messages 国际化语言包
|
||||||
|
*/
|
||||||
|
export function generateI18n(locale = 'zh-CN', messages = {}) {
|
||||||
|
return (key, values = {}) => {
|
||||||
|
if (!messages || !messages[key]) return '';
|
||||||
|
const formater = new IntlMessageFormat(messages[key], locale);
|
||||||
|
return formater.format(values);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前组件是否能够设置ref
|
||||||
|
* @param {*} Comp 需要判断的组件
|
||||||
|
*/
|
||||||
|
export function acceptsRef(Comp) {
|
||||||
|
return (
|
||||||
|
(Comp.$$typeof && Comp.$$typeof === REACT_FORWARD_REF_TYPE) || (Comp.prototype && Comp.prototype.isReactComponent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 黄金令箭埋点
|
||||||
|
* @param {String} gmKey 为黄金令箭业务类型
|
||||||
|
* @param {Object} params 参数
|
||||||
|
* @param {String} logKey 属性串
|
||||||
|
*/
|
||||||
|
export function goldlog(gmKey, params = {}, logKey = 'other') {
|
||||||
|
// vscode 黄金令箭API
|
||||||
|
const sendIDEMessage = window.sendIDEMessage || getParentWinValue('sendIDEMessage');
|
||||||
|
const goKey = serializeParams({
|
||||||
|
sdkVersion: pkg.version,
|
||||||
|
env: getEnv(),
|
||||||
|
...params
|
||||||
|
});
|
||||||
|
if (sendIDEMessage) {
|
||||||
|
sendIDEMessage({
|
||||||
|
action: 'goldlog',
|
||||||
|
data: {
|
||||||
|
logKey: `/iceluna.core.${logKey}`,
|
||||||
|
gmKey,
|
||||||
|
goKey
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.goldlog && window.goldlog.record(`/iceluna.core.${logKey}`, gmKey, goKey, 'POST');
|
||||||
|
}
|
||||||
|
|
||||||
|
// utils为编辑器打包生成的utils文件内容,utilsConfig为数据库存放的utils配置
|
||||||
|
export function generateUtils(utils, utilsConfig) {
|
||||||
|
if (!Array.isArray(utilsConfig)) return { ...utils };
|
||||||
|
const res = {};
|
||||||
|
utilsConfig.forEach(item => {
|
||||||
|
if (!item.name || !item.type || !item.content) return;
|
||||||
|
if (item.type === 'function' && typeof item.content === 'function') {
|
||||||
|
res[item.name] = item.content;
|
||||||
|
} else if (item.type === 'npm' && utils[item.name]) {
|
||||||
|
res[item.name] = utils[item.name];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// 复制到粘贴板
|
||||||
|
export function setClipboardData(str) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (typeof str !== 'string') reject('不支持拷贝');
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(str)
|
||||||
|
.then(() => {
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject('复制失败,请重试!', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = str;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
try {
|
||||||
|
let successful = document.execCommand('copy');
|
||||||
|
if (successful) {
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
reject('复制失败,请重试!', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 获取粘贴板数据
|
||||||
|
export function getClipboardData() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (window.clipboardData) {
|
||||||
|
resolve(window.clipboardData.getData('text'));
|
||||||
|
} else if (navigator.clipboard) {
|
||||||
|
return navigator.clipboard
|
||||||
|
.readText()
|
||||||
|
.then(res => {
|
||||||
|
resolve(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject('粘贴板获取失败', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
reject('粘贴板获取失败');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 将函数返回结果转成promise形式,如果函数有返回值则根据返回值的bool类型判断是reject还是resolve,若函数无返回值默认执行resolve
|
||||||
|
export function transformToPromise(input) {
|
||||||
|
if (input instanceof Promise) return input;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (input || input === undefined) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moveArrayItem(arr, sourceIdx, distIdx, direction) {
|
||||||
|
if (
|
||||||
|
!Array.isArray(arr) ||
|
||||||
|
sourceIdx === distIdx ||
|
||||||
|
sourceIdx < 0 ||
|
||||||
|
sourceIdx >= arr.length ||
|
||||||
|
distIdx < 0 ||
|
||||||
|
distIdx >= arr.length
|
||||||
|
)
|
||||||
|
return arr;
|
||||||
|
const item = arr[sourceIdx];
|
||||||
|
if (direction === 'after') {
|
||||||
|
arr.splice(distIdx + 1, 0, item);
|
||||||
|
} else {
|
||||||
|
arr.splice(distIdx, 0, item);
|
||||||
|
}
|
||||||
|
if (sourceIdx < distIdx) {
|
||||||
|
arr.splice(sourceIdx, 1);
|
||||||
|
} else {
|
||||||
|
arr.splice(sourceIdx + 1, 1);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformArrayToMap(arr, key, overwrite = true) {
|
||||||
|
if (isEmpty(arr) || !Array.isArray(arr)) return {};
|
||||||
|
const res = {};
|
||||||
|
arr.forEach(item => {
|
||||||
|
const curKey = item[key];
|
||||||
|
if (item[key] === undefined) return;
|
||||||
|
if (res[curKey] && !overwrite) return;
|
||||||
|
res[curKey] = item;
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkPropTypes(value, name, rule, componentName) {
|
||||||
|
if (typeof rule === 'string') {
|
||||||
|
rule = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2);
|
||||||
|
}
|
||||||
|
if (!rule || typeof rule !== 'function') {
|
||||||
|
console.warn('checkPropTypes should have a function type rule argument');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const err = rule(
|
||||||
|
{
|
||||||
|
[name]: value
|
||||||
|
},
|
||||||
|
name,
|
||||||
|
componentName,
|
||||||
|
'prop',
|
||||||
|
null,
|
||||||
|
ReactPropTypesSecret
|
||||||
|
);
|
||||||
|
if (err) {
|
||||||
|
console.warn(err);
|
||||||
|
}
|
||||||
|
return !err;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformSchemaToPure(obj) {
|
||||||
|
const pureObj = obj => {
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map(item => pureObj(item));
|
||||||
|
} else if (typeof obj === 'object') {
|
||||||
|
// 对于undefined及null直接返回
|
||||||
|
if (!obj) return obj;
|
||||||
|
const res = {};
|
||||||
|
forEach(obj, (val, key) => {
|
||||||
|
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
||||||
|
res[key] = pureObj(val);
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
return pureObj(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformSchemaToStandard(obj) {
|
||||||
|
const standardObj = obj => {
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map(item => standardObj(item));
|
||||||
|
} else if (typeof obj === 'object') {
|
||||||
|
// 对于undefined及null直接返回
|
||||||
|
if (!obj) return obj;
|
||||||
|
const res = {};
|
||||||
|
forEach(obj, (val, key) => {
|
||||||
|
if (key.startsWith('__') && key !== '__ignoreParse') return;
|
||||||
|
if (isSchema(val) && key !== 'children' && obj.type !== 'JSSlot') {
|
||||||
|
res[key] = {
|
||||||
|
type: 'JSSlot',
|
||||||
|
value: standardObj(val)
|
||||||
|
};
|
||||||
|
// table特殊处理
|
||||||
|
if (key === 'cell') {
|
||||||
|
res[key].params = ['value', 'index', 'record'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res[key] = standardObj(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
} else if (typeof obj === 'function') {
|
||||||
|
return {
|
||||||
|
type: 'JSFunction',
|
||||||
|
value: obj.toString()
|
||||||
|
};
|
||||||
|
} else if (typeof obj === 'string' && EXPRESSION_REG.test(obj.trim())) {
|
||||||
|
const regRes = obj.trim().match(EXPRESSION_REG);
|
||||||
|
return {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: (regRes && regRes[1]) || ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
return standardObj(obj, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformStringToFunction(str) {
|
||||||
|
if (typeof str !== 'string') return str;
|
||||||
|
if (inSameDomain() && window.parent.__newFunc) {
|
||||||
|
return window.parent.__newFunc(`"use strict"; return ${str}`)();
|
||||||
|
} else {
|
||||||
|
return new Function(`"use strict"; return ${str}`)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addCssTag(id, content) {
|
||||||
|
let styleTag = document.getElementById(id);
|
||||||
|
if (styleTag) {
|
||||||
|
styleTag.innerHTML = content;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
styleTag = document.createElement('style');
|
||||||
|
styleTag.id = id;
|
||||||
|
styleTag.class = 'luna-style';
|
||||||
|
styleTag.innerHTML = content;
|
||||||
|
document.head.appendChild(styleTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册快捷
|
||||||
|
export function registShortCuts(config, appHelper) {
|
||||||
|
const keyboardFilter = (keymaster.filter = event => {
|
||||||
|
const eTarget = event.target || event.srcElement;
|
||||||
|
const tagName = eTarget.tagName;
|
||||||
|
const isInput = !!(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
|
||||||
|
const isContenteditable = target => {
|
||||||
|
while (target) {
|
||||||
|
if (target.contentEditable === 'true') return true;
|
||||||
|
target = target.parentNode;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if (isInput || isContenteditable(eTarget)) {
|
||||||
|
if (event.metaKey === true && [70, 83].includes(event.keyCode)) event.preventDefault(); //禁止触发chrome原生的页面保存或查找
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ideMessage = appHelper.utils && appHelper.utils.ideMessage;
|
||||||
|
|
||||||
|
//复制
|
||||||
|
if (!document.copyListener) {
|
||||||
|
document.copyListener = e => {
|
||||||
|
if (!keyboardFilter(e) || appHelper.isCopying) return;
|
||||||
|
const schema = appHelper.schemaHelper && appHelper.schemaHelper.schemaMap[appHelper.activeKey];
|
||||||
|
if (!schema || !isSchema(schema)) return;
|
||||||
|
appHelper.isCopying = true;
|
||||||
|
const schemaStr = serialize(transformSchemaToPure(schema), {
|
||||||
|
unsafe: true
|
||||||
|
});
|
||||||
|
setClipboardData(schemaStr)
|
||||||
|
.then(() => {
|
||||||
|
ideMessage && ideMessage('success', '当前内容已复制到剪贴板,请使用快捷键Command+v进行粘贴');
|
||||||
|
appHelper.emit('schema.copy', schemaStr, schema);
|
||||||
|
appHelper.isCopying = false;
|
||||||
|
})
|
||||||
|
.catch(errMsg => {
|
||||||
|
ideMessage && ideMessage('error', errMsg);
|
||||||
|
appHelper.isCopying = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
document.addEventListener('copy', document.copyListener);
|
||||||
|
if (getParentWinValue('vscode')) {
|
||||||
|
keymaster('command+c', document.copyListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//粘贴
|
||||||
|
if (!document.pasteListener) {
|
||||||
|
const doPaste = (e, text) => {
|
||||||
|
if (!keyboardFilter(e) || appHelper.isPasting) return;
|
||||||
|
const schemaHelper = appHelper.schemaHelper;
|
||||||
|
let targetKey = appHelper.activeKey;
|
||||||
|
let direction = 'after';
|
||||||
|
const topKey = schemaHelper.schema && schemaHelper.schema.__ctx && schemaHelper.schema.__ctx.lunaKey;
|
||||||
|
if (!targetKey || topKey === targetKey) {
|
||||||
|
const schemaHelper = appHelper.schemaHelper;
|
||||||
|
const topKey = schemaHelper.schema && schemaHelper.schema.__ctx && schemaHelper.schema.__ctx.lunaKey;
|
||||||
|
if (!topKey) return;
|
||||||
|
targetKey = topKey;
|
||||||
|
direction = 'in';
|
||||||
|
}
|
||||||
|
appHelper.isPasting = true;
|
||||||
|
const schema = parseObj(text);
|
||||||
|
if (!isSchema(schema)) {
|
||||||
|
appHelper.emit('illegalSchema.paste', text);
|
||||||
|
// ideMessage && ideMessage('error', '当前内容不是模型结构,不能粘贴进来!');
|
||||||
|
console.warn('paste schema illegal');
|
||||||
|
appHelper.isPasting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
appHelper.emit('material.add', {
|
||||||
|
schema,
|
||||||
|
targetKey,
|
||||||
|
direction
|
||||||
|
});
|
||||||
|
appHelper.isPasting = false;
|
||||||
|
appHelper.emit('schema.paste', schema);
|
||||||
|
};
|
||||||
|
document.pasteListener = e => {
|
||||||
|
const clipboardData = e.clipboardData || window.clipboardData;
|
||||||
|
const text = clipboardData && clipboardData.getData('text');
|
||||||
|
doPaste(e, text);
|
||||||
|
};
|
||||||
|
document.addEventListener('paste', document.pasteListener);
|
||||||
|
if (getParentWinValue('vscode')) {
|
||||||
|
keymaster('command+v', e => {
|
||||||
|
const sendIDEMessage = getParentWinValue('sendIDEMessage');
|
||||||
|
sendIDEMessage &&
|
||||||
|
sendIDEMessage({
|
||||||
|
action: 'readClipboard'
|
||||||
|
})
|
||||||
|
.then(text => {
|
||||||
|
doPaste(e, text);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.warn(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(config || []).forEach(item => {
|
||||||
|
keymaster(item.keyboard, ev => {
|
||||||
|
ev.preventDefault();
|
||||||
|
item.handler(ev, appHelper, keymaster);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消注册快捷
|
||||||
|
export function unRegistShortCuts(config) {
|
||||||
|
(config || []).forEach(item => {
|
||||||
|
keymaster.unbind(item.keyboard);
|
||||||
|
});
|
||||||
|
if (getParentWinValue('vscode')) {
|
||||||
|
keymaster.unbind('command+c');
|
||||||
|
keymaster.unbind('command+v');
|
||||||
|
}
|
||||||
|
if (document.copyListener) {
|
||||||
|
document.removeEventListener('copy', document.copyListener);
|
||||||
|
delete document.copyListener;
|
||||||
|
}
|
||||||
|
if (document.pasteListener) {
|
||||||
|
document.removeEventListener('paste', document.pasteListener);
|
||||||
|
delete document.pasteListener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseData(schema, self) {
|
||||||
|
if (isJSExpression(schema)) {
|
||||||
|
return parseExpression(schema, self);
|
||||||
|
} else if (typeof schema === 'string') {
|
||||||
|
return schema.trim();
|
||||||
|
} else if (Array.isArray(schema)) {
|
||||||
|
return schema.map(item => parseData(item, self));
|
||||||
|
} else if (typeof schema === 'function') {
|
||||||
|
return schema.bind(self);
|
||||||
|
} else if (typeof schema === 'object') {
|
||||||
|
// 对于undefined及null直接返回
|
||||||
|
if (!schema) return schema;
|
||||||
|
const res = {};
|
||||||
|
forEach(schema, (val, key) => {
|
||||||
|
if (key.startsWith('__')) return;
|
||||||
|
res[key] = parseData(val, self);
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*全匹配{{开头,}}结尾的变量表达式,或者对象类型JSExpression,且均不支持省略this */
|
||||||
|
export function parseExpression(str, self) {
|
||||||
|
try {
|
||||||
|
const contextArr = ['"use strict";', 'var __self = arguments[0];'];
|
||||||
|
contextArr.push('return ');
|
||||||
|
let tarStr;
|
||||||
|
//向前兼容,支持标准协议新格式
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
const regRes = str.trim().match(EXPRESSION_REG);
|
||||||
|
tarStr = regRes[1];
|
||||||
|
} else {
|
||||||
|
tarStr = (str.value || '').trim();
|
||||||
|
}
|
||||||
|
tarStr = tarStr.replace(/this(\W|$)/g, (a, b) => `__self${b}`);
|
||||||
|
tarStr = contextArr.join('\n') + tarStr;
|
||||||
|
//默认调用顶层窗口的parseObj,保障new Function的window对象是顶层的window对象
|
||||||
|
if (inSameDomain() && window.parent.__newFunc) {
|
||||||
|
return window.parent.__newFunc(tarStr)(self);
|
||||||
|
}
|
||||||
|
return new Function(tarStr)(self);
|
||||||
|
} catch (err) {
|
||||||
|
debug('parseExpression.error', err, str, self);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断组件配置中是否有reactNode且type为function的props
|
||||||
|
* @param {*} componentInfo
|
||||||
|
*/
|
||||||
|
export function hasReactNodeFuncProps(componentInfo) {
|
||||||
|
const isReactNodeFuncProps = config => {
|
||||||
|
if (config.type === 'ReactNode') {
|
||||||
|
return config.props && config.props.type === 'function';
|
||||||
|
} else if (config.type === 'Mixin') {
|
||||||
|
return config.props && config.props.reactNodeProps && config.props.reactNodeProps.type === 'function';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return componentInfo && (componentInfo.props || []).some(item => isReactNodeFuncProps(item));
|
||||||
|
}
|
||||||
171
packages/rax-render/src/utils/request.js
Normal file
171
packages/rax-render/src/utils/request.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import 'whatwg-fetch';
|
||||||
|
import fetchMtop from '@ali/lib-mtop';
|
||||||
|
import fetchJsonp from 'fetch-jsonp';
|
||||||
|
import bzbRequest from '@ali/bzb-request';
|
||||||
|
import { serialize, buildUrl, parseUrl } from '@ali/b3-one/lib/url';
|
||||||
|
|
||||||
|
export function get(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
||||||
|
headers = {
|
||||||
|
Accept: 'application/json',
|
||||||
|
...headers
|
||||||
|
};
|
||||||
|
dataAPI = buildUrl(dataAPI, params);
|
||||||
|
return request(dataAPI, 'GET', null, headers, otherProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function post(dataAPI, params = {}, headers = {}, otherProps = {}) {
|
||||||
|
headers = {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
...headers
|
||||||
|
};
|
||||||
|
return request(
|
||||||
|
dataAPI,
|
||||||
|
'POST',
|
||||||
|
headers['Content-Type'].indexOf('application/json') > -1 || Array.isArray(params)
|
||||||
|
? JSON.stringify(params)
|
||||||
|
: serialize(params),
|
||||||
|
headers,
|
||||||
|
otherProps
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function request(dataAPI, method = 'GET', data, headers = {}, otherProps = {}) {
|
||||||
|
switch (method) {
|
||||||
|
case 'PUT':
|
||||||
|
case 'DELETE':
|
||||||
|
headers = {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...headers
|
||||||
|
};
|
||||||
|
data = JSON.stringify(data || {});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (otherProps.timeout) {
|
||||||
|
setTimeout(() => {
|
||||||
|
reject(new Error('timeout'));
|
||||||
|
}, otherProps.timeout);
|
||||||
|
}
|
||||||
|
fetch(dataAPI, {
|
||||||
|
method,
|
||||||
|
credentials: 'include',
|
||||||
|
headers,
|
||||||
|
body: data,
|
||||||
|
...otherProps
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
switch (response.status) {
|
||||||
|
case 200:
|
||||||
|
case 201:
|
||||||
|
case 202:
|
||||||
|
return response.json();
|
||||||
|
case 204:
|
||||||
|
if (method === 'DELETE') {
|
||||||
|
return {
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
__success: false,
|
||||||
|
code: response.status
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 400:
|
||||||
|
case 401:
|
||||||
|
case 403:
|
||||||
|
case 404:
|
||||||
|
case 406:
|
||||||
|
case 410:
|
||||||
|
case 422:
|
||||||
|
case 500:
|
||||||
|
return response
|
||||||
|
.json()
|
||||||
|
.then(res => {
|
||||||
|
return {
|
||||||
|
__success: false,
|
||||||
|
code: response.status,
|
||||||
|
data: res
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return {
|
||||||
|
__success: false,
|
||||||
|
code: response.status
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.then(json => {
|
||||||
|
if (json && json.__success !== false) {
|
||||||
|
resolve(json);
|
||||||
|
} else {
|
||||||
|
delete json.__success;
|
||||||
|
reject(json);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function jsonp(dataAPI, params = {}, otherProps = {}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
otherProps = {
|
||||||
|
timeout: 5000,
|
||||||
|
...otherProps
|
||||||
|
};
|
||||||
|
fetchJsonp(buildUrl(dataAPI, params), otherProps)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(json => {
|
||||||
|
if (json) {
|
||||||
|
resolve(json);
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mtop(dataAPI, params, otherProps = {}) {
|
||||||
|
fetchMtop.config.subDomain = otherProps.subDomain || 'm';
|
||||||
|
return fetchMtop.request({
|
||||||
|
api: dataAPI,
|
||||||
|
v: '1.0',
|
||||||
|
data: params,
|
||||||
|
ecode: otherProps.ecode || 0,
|
||||||
|
type: otherProps.method || 'GET',
|
||||||
|
dataType: otherProps.dataType || 'jsonp',
|
||||||
|
AntiFlood: true, // 防刷
|
||||||
|
timeout: otherProps.timeout || 20000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bzb(apiCode, params, otherProps = {}) {
|
||||||
|
// 通过url参数设置小二工作台请求环境
|
||||||
|
const getUrlEnv = () => {
|
||||||
|
try {
|
||||||
|
if (window.parent && window.parent.location.host === window.location.host) {
|
||||||
|
const urlInfo = parseUrl(window.parent && window.parent.location.href);
|
||||||
|
return urlInfo && urlInfo.params && urlInfo.params._env;
|
||||||
|
}
|
||||||
|
const urlInfo = parseUrl(window.location.href);
|
||||||
|
return urlInfo && urlInfo.params && urlInfo.params._env;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
otherProps.method = otherProps.method || 'GET';
|
||||||
|
otherProps.env = getUrlEnv() || otherProps.env || 'prod';
|
||||||
|
return bzbRequest(apiCode, {
|
||||||
|
data: params,
|
||||||
|
...otherProps
|
||||||
|
});
|
||||||
|
}
|
||||||
4
packages/react-provider/CHANGELOG.md
Normal file
4
packages/react-provider/CHANGELOG.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
1
packages/react-provider/README.md
Normal file
1
packages/react-provider/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# 低代码引擎运行时框架
|
||||||
5
packages/react-provider/build.json
Normal file
5
packages/react-provider/build.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"build-plugin-component"
|
||||||
|
]
|
||||||
|
}
|
||||||
43
packages/react-provider/package.json
Normal file
43
packages/react-provider/package.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/lowcode-react-provider",
|
||||||
|
"version": "0.8.14",
|
||||||
|
"description": "React Provider for Runtime",
|
||||||
|
"files": [
|
||||||
|
"es",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "es/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "build-scripts build --skip-demo",
|
||||||
|
"test": "ava",
|
||||||
|
"test:snapshot": "ava --update-snapshots"
|
||||||
|
},
|
||||||
|
"ava": {
|
||||||
|
"compileEnhancements": false,
|
||||||
|
"snapshotDir": "test/fixtures/__snapshots__",
|
||||||
|
"extensions": [
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
|
"require": [
|
||||||
|
"ts-node/register"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/lowcode-runtime": "^0.8.13",
|
||||||
|
"react": "^16",
|
||||||
|
"react-dom": "^16",
|
||||||
|
"@recore/router": "^1.0.11"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@alib/build-scripts": "^0.1.18",
|
||||||
|
"build-plugin-component": "^0.2.16",
|
||||||
|
"@types/node": "^13.7.1",
|
||||||
|
"@types/react": "^16",
|
||||||
|
"@types/react-dom": "^16"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
packages/react-provider/src/index.ts
Normal file
5
packages/react-provider/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import ReactProvider from './provider';
|
||||||
|
import { Router } from '@recore/router';
|
||||||
|
|
||||||
|
export { Router };
|
||||||
|
export default ReactProvider;
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { Component, createElement } from 'react';
|
import { Component, createElement } from 'react';
|
||||||
import app from '../../index';
|
import { app } from '@ali/lowcode-runtime';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
getPageData: () => any;
|
getPageData: () => any;
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { createElement, ReactType, ReactElement } from 'react';
|
import { createElement, ReactType, ReactElement } from 'react';
|
||||||
import { Router } from '@ali/recore';
|
import ReactDOM from 'react-dom';
|
||||||
import app from '../../index';
|
import { Router } from '@recore/router';
|
||||||
import Provider from '..';
|
import { app, Provider } from '@ali/lowcode-runtime';
|
||||||
import LazyComponent from './lazy-component';
|
import LazyComponent from './lazy-component';
|
||||||
|
|
||||||
export default class ReactProvider extends Provider {
|
export default class ReactProvider extends Provider {
|
||||||
@ -30,6 +30,10 @@ export default class ReactProvider extends Provider {
|
|||||||
return App;
|
return App;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runApp(App: any, config: any) {
|
||||||
|
ReactDOM.render(<App />, document.getElementById(config?.containerId || 'App'));
|
||||||
|
}
|
||||||
|
|
||||||
// 内置实现 for 动态化渲染
|
// 内置实现 for 动态化渲染
|
||||||
getRouterView(): ReactType | null {
|
getRouterView(): ReactType | null {
|
||||||
const routerConfig = this.getRouterConfig();
|
const routerConfig = this.getRouterConfig();
|
||||||
9
packages/react-provider/tsconfig.json
Normal file
9
packages/react-provider/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,9 +1,5 @@
|
|||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"build-plugin-component",
|
"build-plugin-component"
|
||||||
"build-plugin-fusion",
|
|
||||||
["build-plugin-moment-locales", {
|
|
||||||
"locales": ["zh-cn"]
|
|
||||||
}]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
3
packages/runtime/index.d.ts
vendored
3
packages/runtime/index.d.ts
vendored
@ -1,8 +1,7 @@
|
|||||||
import { ReactType } from 'react';
|
|
||||||
type HistoryMode = 'browser' | 'hash';
|
type HistoryMode = 'browser' | 'hash';
|
||||||
|
|
||||||
interface ComponentsMap {
|
interface ComponentsMap {
|
||||||
[key: string]: ReactType;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UtilsMap {
|
interface UtilsMap {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ali/lowcode-runtime",
|
"name": "@ali/lowcode-runtime",
|
||||||
"version": "0.8.13",
|
"version": "0.8.15",
|
||||||
"description": "Runtime for Ali lowCode engine",
|
"description": "Runtime for Ali lowCode engine",
|
||||||
"files": [
|
"files": [
|
||||||
"es",
|
"es",
|
||||||
@ -26,14 +26,12 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ali/offline-events": "^1.0.0",
|
"@ali/offline-events": "^1.0.0",
|
||||||
"@ali/recore": "^1.6.9"
|
"history": "^4.10.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@alib/build-scripts": "^0.1.18",
|
"@alib/build-scripts": "^0.1.18",
|
||||||
"@types/node": "^13.7.1",
|
"@types/node": "^13.7.1",
|
||||||
"@types/react": "^16",
|
"build-plugin-component": "^0.2.16"
|
||||||
"@types/react-dom": "^16",
|
|
||||||
"build-plugin-component": "^0.2.11"
|
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npm.alibaba-inc.com"
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { ReactType } from 'react';
|
|
||||||
import Provider from './provider';
|
import Provider from './provider';
|
||||||
|
|
||||||
export interface ILayoutOptions {
|
export interface ILayoutOptions {
|
||||||
@ -7,16 +6,16 @@ export interface ILayoutOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class Container {
|
export default class Container {
|
||||||
private renderer: ReactType | null = null;
|
private renderer: any = null;
|
||||||
private layouts: { [key: string]: { content: ReactType; props: any } } = {};
|
private layouts: { [key: string]: { content: any; props: any } } = {};
|
||||||
private loading: ReactType | null = null;
|
private loading: any = null;
|
||||||
private provider: any;
|
private provider: any;
|
||||||
|
|
||||||
registerRenderer(renderer: ReactType): any {
|
registerRenderer(renderer: any): any {
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerLayout(Layout: ReactType, options: ILayoutOptions): any {
|
registerLayout(Layout: any, options: ILayoutOptions): any {
|
||||||
if (!options) {
|
if (!options) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -27,7 +26,7 @@ export default class Container {
|
|||||||
this.layouts[componentName] = { content: Layout, props };
|
this.layouts[componentName] = { content: Layout, props };
|
||||||
}
|
}
|
||||||
|
|
||||||
registerLoading(component: ReactType) {
|
registerLoading(component: any) {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -50,11 +49,11 @@ export default class Container {
|
|||||||
return this.layouts[componentName];
|
return this.layouts[componentName];
|
||||||
}
|
}
|
||||||
|
|
||||||
getRenderer(): ReactType | null {
|
getRenderer(): any {
|
||||||
return this.renderer;
|
return this.renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
getLoading(): ReactType | null {
|
getLoading(): any {
|
||||||
return this.loading;
|
return this.loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { ReactType } from 'react';
|
|
||||||
import Container, { ILayoutOptions } from './container';
|
import Container, { ILayoutOptions } from './container';
|
||||||
import { IProvider } from './provider';
|
import { IProvider } from './provider';
|
||||||
import run from './run';
|
import runApp from './runApp';
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
private container: Container;
|
private container: Container;
|
||||||
@ -11,18 +10,18 @@ class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
run() {
|
run() {
|
||||||
run();
|
runApp();
|
||||||
}
|
}
|
||||||
|
|
||||||
registerRenderer(renderer: ReactType): any {
|
registerRenderer(renderer: any): any {
|
||||||
this.container.registerRenderer(renderer);
|
this.container.registerRenderer(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerLayout(Layout: ReactType, options: ILayoutOptions): any {
|
registerLayout(Layout: any, options: ILayoutOptions): any {
|
||||||
this.container.registerLayout(Layout, options);
|
this.container.registerLayout(Layout, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerLoading(component: ReactType) {
|
registerLoading(component: any) {
|
||||||
this.container.registerLoading(component);
|
this.container.registerLoading(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,11 +33,11 @@ class App {
|
|||||||
return this.container.getLayout(componentName);
|
return this.container.getLayout(componentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRenderer(): ReactType | null {
|
getRenderer(): any | null {
|
||||||
return this.container.getRenderer();
|
return this.container.getRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
getLoading(): ReactType | null {
|
getLoading(): any | null {
|
||||||
return this.container.getLoading();
|
return this.container.getLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { IAppConfig, IUtils, IComponents, HistoryMode } from '../run';
|
import { IAppConfig, IUtils, IComponents, HistoryMode } from './runApp';
|
||||||
import EventEmitter from '@ali/offline-events';
|
import EventEmitter from '@ali/offline-events';
|
||||||
|
|
||||||
interface IConstants {
|
interface IConstants {
|
||||||
@ -110,6 +110,7 @@ export interface IProvider {
|
|||||||
getPageData(pageId: string): Promise<ComponentModel | undefined>;
|
getPageData(pageId: string): Promise<ComponentModel | undefined>;
|
||||||
getLazyComponent(pageId: string, props: any): any;
|
getLazyComponent(pageId: string, props: any): any;
|
||||||
createApp(): void;
|
createApp(): void;
|
||||||
|
runApp(App: any, config: IAppConfig): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Provider implements IProvider {
|
export default class Provider implements IProvider {
|
||||||
@ -181,7 +182,7 @@ export default class Provider implements IProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAppData(): any {
|
getAppData(): any {
|
||||||
throw new Error('Method called "getPageData" not implemented.');
|
throw new Error('Method called "getAppData" not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
getPageData(pageId?: string): any {
|
getPageData(pageId?: string): any {
|
||||||
@ -197,6 +198,10 @@ export default class Provider implements IProvider {
|
|||||||
throw new Error('Method called "createApp" not implemented.');
|
throw new Error('Method called "createApp" not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runApp(App: any, config: IAppConfig) {
|
||||||
|
throw new Error('Method called "runApp" not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
registerComponents(components: IComponents | undefined) {
|
registerComponents(components: IComponents | undefined) {
|
||||||
if (!components) {
|
if (!components) {
|
||||||
return;
|
return;
|
||||||
@ -1,65 +0,0 @@
|
|||||||
import { ReactType } from 'react';
|
|
||||||
import { runApp } from '@ali/recore';
|
|
||||||
import { HashHistoryBuildOptions, BrowserHistoryBuildOptions, MemoryHistoryBuildOptions } from '@recore/history';
|
|
||||||
import app from './index';
|
|
||||||
|
|
||||||
export type HistoryOptions = {
|
|
||||||
mode?: HistoryMode;
|
|
||||||
} & (HashHistoryBuildOptions | BrowserHistoryBuildOptions | MemoryHistoryBuildOptions);
|
|
||||||
|
|
||||||
export interface IComponents {
|
|
||||||
[key: string]: ReactType;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUtils {
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type HistoryMode = 'browser' | 'hash';
|
|
||||||
|
|
||||||
export interface IAppConfig {
|
|
||||||
history?: HistoryMode;
|
|
||||||
components?: IComponents;
|
|
||||||
utils?: IUtils;
|
|
||||||
containerId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRecoreAppConfig {
|
|
||||||
history?: HistoryMode;
|
|
||||||
globalComponents?: IComponents;
|
|
||||||
globalUtils?: IUtils;
|
|
||||||
containerId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformConfig(config: IAppConfig | (() => IAppConfig)): IRecoreAppConfig {
|
|
||||||
if (!config) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (typeof config === 'function') {
|
|
||||||
config = config();
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
history: config.history,
|
|
||||||
globalComponents: config.components,
|
|
||||||
globalUtils: config.utils,
|
|
||||||
containerId: config.containerId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function run() {
|
|
||||||
const provider = app.getProvider();
|
|
||||||
if (!provider) {
|
|
||||||
throw new Error('');
|
|
||||||
}
|
|
||||||
provider.onReady(() => {
|
|
||||||
const promise = provider.async();
|
|
||||||
promise.then((config: IAppConfig) => {
|
|
||||||
if (!config) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const App = provider.createApp();
|
|
||||||
config = transformConfig(config);
|
|
||||||
runApp(App, config);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
41
packages/runtime/src/core/runApp.ts
Normal file
41
packages/runtime/src/core/runApp.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { HashHistoryBuildOptions, BrowserHistoryBuildOptions, MemoryHistoryBuildOptions } from 'history';
|
||||||
|
import app from './index';
|
||||||
|
|
||||||
|
export type HistoryOptions = {
|
||||||
|
mode?: HistoryMode;
|
||||||
|
} & (HashHistoryBuildOptions | BrowserHistoryBuildOptions | MemoryHistoryBuildOptions);
|
||||||
|
|
||||||
|
export interface IComponents {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IUtils {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HistoryMode = 'browser' | 'hash';
|
||||||
|
|
||||||
|
export interface IAppConfig {
|
||||||
|
history?: HistoryMode;
|
||||||
|
components?: IComponents;
|
||||||
|
utils?: IUtils;
|
||||||
|
containerId?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function runApp() {
|
||||||
|
const provider = app.getProvider();
|
||||||
|
if (!provider) {
|
||||||
|
throw new Error('Please register class Provider');
|
||||||
|
}
|
||||||
|
provider.onReady(() => {
|
||||||
|
const promise = provider.async();
|
||||||
|
promise.then((config: IAppConfig) => {
|
||||||
|
if (!config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const App = provider.createApp();
|
||||||
|
provider.runApp(App, config);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -1,7 +1,5 @@
|
|||||||
import { navigator, Router } from '@ali/recore';
|
|
||||||
import Provider from './core/provider';
|
import Provider from './core/provider';
|
||||||
import ReactProvider from './core/provider/react';
|
|
||||||
import app from './core';
|
import app from './core';
|
||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
|
|
||||||
export { app, Router, Provider, ReactProvider, navigator, Utils };
|
export { app, Provider, Utils };
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user