Merge branch 'release/1.3.0'
This commit is contained in:
commit
f9fe38e65a
|
@ -5,4 +5,4 @@
|
|||
* @liujuping @JackLian
|
||||
|
||||
/modules/material-parser @akirakai
|
||||
/modules/code-generator @leoyuan
|
||||
/modules/code-generator @qingniaotonghua
|
||||
|
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
- name: Get version
|
||||
id: get_version
|
||||
run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")"
|
||||
run: echo "version=$(node -p "require('./docs/package.json').version")" >> $GITHUB_OUTPUT
|
||||
|
||||
comment-pr:
|
||||
needs: publish-docs
|
||||
|
|
|
@ -27,4 +27,4 @@ jobs:
|
|||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
- name: Get version
|
||||
id: get_version
|
||||
run: echo "::set-output name=version::$(node -p "require('./package.json').version")"
|
||||
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||||
|
|
|
@ -30,4 +30,4 @@ jobs:
|
|||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
- name: Get version
|
||||
id: get_version
|
||||
run: echo "::set-output name=version::$(node -p "require('./package.json').version")"
|
||||
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||||
|
|
|
@ -108,3 +108,5 @@ typings/
|
|||
# codealike
|
||||
codealike.json
|
||||
.node
|
||||
|
||||
.must.config.js
|
|
@ -145,6 +145,22 @@ const { intl, getLocale, setLocale } = common.utils.createIntl({
|
|||
|
||||
```
|
||||
|
||||
#### intl
|
||||
|
||||
i18n 转换方法
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* i18n 转换方法
|
||||
*/
|
||||
intl(data: IPublicTypeI18nData | string, params?: object): string;
|
||||
```
|
||||
|
||||
##### 示例
|
||||
```
|
||||
const title = common.utils.intl(node.title)
|
||||
```
|
||||
|
||||
### skeletonCabin
|
||||
#### Workbench
|
||||
编辑器框架 View
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
---
|
||||
title: commonUI - UI 组件库
|
||||
sidebar_position: 11
|
||||
---
|
||||
|
||||
## 简介
|
||||
CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开发的插件,可以保证在不同项目和主题切换中能够保持一致性和兼容性。
|
||||
|
||||
## 组件列表
|
||||
|
||||
### Tip
|
||||
|
||||
提示组件
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|-----------|--------------|---------------------------------------|--------|
|
||||
| className | className | string (optional) | |
|
||||
| children | tip 的内容 | IPublicTypeI18nData \| ReactNode | |
|
||||
| direction | tip 的方向 | 'top' \| 'bottom' \| 'left' \| 'right' | |
|
||||
|
||||
|
||||
### HelpTip
|
||||
|
||||
带 help icon 的提示组件
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|-----------|--------|-----------------------------------|--------|
|
||||
| help | 描述 | IPublicTypeHelpTipConfig | |
|
||||
| direction | 方向 | IPublicTypeTipConfig['direction'] | 'top' |
|
||||
| size | 方向 | IconProps['size'] | 'small'|
|
||||
|
||||
### Title
|
||||
|
||||
标题组件
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|-----------|------------|-----------------------------|--------|
|
||||
| title | 标题内容 | IPublicTypeTitleContent | |
|
||||
| className | className | string (optional) | |
|
||||
| onClick | 点击事件 | () => void (optional) | |
|
||||
|
||||
### ContextMenu
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|--------|----------------------------------------------------|------------------------------------|--------|
|
||||
| menus | 定义上下文菜单的动作数组 | IPublicTypeContextMenuAction[] | |
|
||||
| children | 组件的子元素 | React.ReactElement[] | |
|
||||
|
||||
**IPublicTypeContextMenuAction Interface**
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------|
|
||||
| name | 动作的唯一标识符<br/>Unique identifier for the action | string | |
|
||||
| title | 显示的标题,可以是字符串或国际化数据<br/>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | |
|
||||
| type | 菜单项类型<br/>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumContextMenuType.MENU_ITEM |
|
||||
| action | 点击时执行的动作,可选<br/>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | |
|
||||
| items | 子菜单项或生成子节点的函数,可选,仅支持两级<br/>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | |
|
||||
| condition | 显示条件函数<br/>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | |
|
||||
| disabled | 禁用条件函数,可选<br/>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | |
|
||||
|
||||
**ContextMenu 示例**
|
||||
|
||||
```typescript
|
||||
const App = () => {
|
||||
const menuItems: IPublicTypeContextMenuAction[] = [
|
||||
{
|
||||
name: 'a',
|
||||
title: '选项 1',
|
||||
action: () => console.log('选项 1 被点击'),
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
title: '选项 2',
|
||||
action: () => console.log('选项 2 被点击'),
|
||||
},
|
||||
];
|
||||
|
||||
const ContextMenu = ctx.commonUI.ContextMenu;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ContextMenu menus={menuItems}>
|
||||
<div>右键点击这里</div>
|
||||
</ContextMenu>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
**ContextMenu.create 示例**
|
||||
|
||||
```typescript
|
||||
const App = () => {
|
||||
const menuItems: IPublicTypeContextMenuAction[] = [
|
||||
{
|
||||
name: 'a',
|
||||
title: '选项 1',
|
||||
action: () => console.log('选项 1 被点击'),
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
title: '选项 2',
|
||||
action: () => console.log('选项 2 被点击'),
|
||||
},
|
||||
];
|
||||
|
||||
const ContextMenu = ctx.commonUI.ContextMenu;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div onClick={(e) => {
|
||||
ContextMenu.create(menuItems, e);
|
||||
}}>点击这里</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Balloon
|
||||
|
||||
详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon)
|
||||
|
||||
### Breadcrumb
|
||||
详细文档: [Breadcrumb Documentation](https://fusion.design/pc/component/breadcrumb)
|
||||
|
||||
### Button
|
||||
详细文档: [Button Documentation](https://fusion.design/pc/component/button)
|
||||
|
||||
### Card
|
||||
详细文档:[Card Documentation](https://fusion.design/pc/component/card)
|
||||
|
||||
### Checkbox
|
||||
详细文档:[Checkbox Documentation](https://fusion.design/pc/component/checkbox)
|
||||
|
||||
### DatePicker
|
||||
详细文档:[DatePicker Documentation](https://fusion.design/pc/component/datepicker)
|
||||
|
||||
### Dialog
|
||||
详细文档:[Dialog Documentation](https://fusion.design/pc/component/dialog)
|
||||
|
||||
### Dropdown
|
||||
详细文档:[Dropdown Documentation](https://fusion.design/pc/component/dropdown)
|
||||
|
||||
### Form
|
||||
详细文档:[Form Documentation](https://fusion.design/pc/component/form)
|
||||
|
||||
### Icon
|
||||
详细文档:[Icon Documentation](https://fusion.design/pc/component/icon)
|
||||
|
||||
引擎默认主题支持的 icon 列表:https://fusion.design/64063/component/icon?themeid=20133
|
||||
|
||||
|
||||
### Input
|
||||
详细文档:[Input Documentation](https://fusion.design/pc/component/input)
|
||||
|
||||
### Loading
|
||||
详细文档:[Loading Documentation](https://fusion.design/pc/component/loading)
|
||||
|
||||
### Message
|
||||
详细文档:[Message Documentation](https://fusion.design/pc/component/message)
|
||||
|
||||
### Overlay
|
||||
详细文档:[Overlay Documentation](https://fusion.design/pc/component/overlay)
|
||||
|
||||
### Pagination
|
||||
详细文档:[Pagination Documentation](https://fusion.design/pc/component/pagination)
|
||||
|
||||
### Radio
|
||||
详细文档:[Radio Documentation](https://fusion.design/pc/component/radio)
|
||||
|
||||
### Search
|
||||
详细文档:[Search Documentation](https://fusion.design/pc/component/search)
|
||||
|
||||
### Select
|
||||
详细文档:[Select Documentation](https://fusion.design/pc/component/select)
|
||||
|
||||
### SplitButton
|
||||
详细文档:[SplitButton Documentation](https://fusion.design/pc/component/splitbutton)
|
||||
|
||||
### Step
|
||||
详细文档:[Step Documentation](https://fusion.design/pc/component/step)
|
||||
|
||||
### Switch
|
||||
详细文档:[Switch Documentation](https://fusion.design/pc/component/switch)
|
||||
|
||||
### Tab
|
||||
详细文档:[Tab Documentation](https://fusion.design/pc/component/tab)
|
||||
|
||||
### Table
|
||||
详细文档:[Table Documentation](https://fusion.design/pc/component/table)
|
||||
|
||||
### Tree
|
||||
详细文档:[Tree Documentation](https://fusion.design/pc/component/tree)
|
||||
|
||||
### TreeSelect
|
||||
详细文档:[TreeSelect Documentation](https://fusion.design/pc/component/treeselect)
|
||||
|
||||
### Upload
|
||||
详细文档:[Upload Documentation](https://fusion.design/pc/component/upload)
|
||||
|
||||
### Divider
|
||||
详细文档:[Divider Documentation](https://fusion.design/pc/component/divider)
|
||||
|
||||
## 说明
|
||||
|
||||
如果需要其他组件,可以提 issue 给我们。
|
|
@ -185,6 +185,12 @@ config.set('enableCondition', false)
|
|||
|
||||
`@type {boolean}` `@default {false}`
|
||||
|
||||
#### enableContextMenu - 开启右键菜单
|
||||
|
||||
`@type {boolean}` `@default {false}`
|
||||
|
||||
是否开启右键菜单
|
||||
|
||||
#### disableDetecting
|
||||
|
||||
`@type {boolean}` `@default {false}`
|
||||
|
@ -216,6 +222,12 @@ config.set('enableCondition', false)
|
|||
|
||||
是否在只有一个 item 的时候隐藏设置 tabs
|
||||
|
||||
#### hideComponentAction
|
||||
|
||||
`@type {boolean}` `@default {false}`
|
||||
|
||||
隐藏设计器辅助层
|
||||
|
||||
#### thisRequiredInJSE
|
||||
|
||||
`@type {boolean}` `@default {true}`
|
||||
|
|
|
@ -237,7 +237,90 @@ material.modifyBuiltinComponentAction('remove', (action) => {
|
|||
});
|
||||
```
|
||||
|
||||
### 右键菜单项
|
||||
#### addContextMenuOption
|
||||
|
||||
添加右键菜单项
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 添加右键菜单项
|
||||
* @param action
|
||||
*/
|
||||
addContextMenuOption(action: IPublicTypeContextMenuAction): void;
|
||||
```
|
||||
|
||||
示例
|
||||
|
||||
```typescript
|
||||
import { IPublicEnumContextMenuType } from '@alilc/lowcode-types';
|
||||
|
||||
material.addContextMenuOption({
|
||||
name: 'parentItem',
|
||||
title: 'Parent Item',
|
||||
condition: (nodes) => true,
|
||||
items: [
|
||||
{
|
||||
name: 'childItem1',
|
||||
title: 'Child Item 1',
|
||||
action: (nodes) => console.log('Child Item 1 clicked', nodes),
|
||||
condition: (nodes) => true
|
||||
},
|
||||
// 分割线
|
||||
{
|
||||
type: IPublicEnumContextMenuType.SEPARATOR
|
||||
name: 'separator.1'
|
||||
}
|
||||
// 更多子菜单项...
|
||||
]
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
#### removeContextMenuOption
|
||||
|
||||
删除特定右键菜单项
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 删除特定右键菜单项
|
||||
* @param name
|
||||
*/
|
||||
removeContextMenuOption(name: string): void;
|
||||
```
|
||||
|
||||
#### adjustContextMenuLayout
|
||||
|
||||
调整右键菜单项布局,每次调用都会覆盖之前注册的调整函数,只有最后注册的函数会被应用。
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 调整右键菜单项布局
|
||||
* @param actions
|
||||
*/
|
||||
adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void;
|
||||
```
|
||||
|
||||
**示例**
|
||||
|
||||
通过 adjustContextMenuLayout 补充分割线
|
||||
|
||||
```typescript
|
||||
material.adjustContextMenuLayout((actions: IPublicTypeContextMenuAction) => {
|
||||
const names = ['a', 'b'];
|
||||
const newActions = [];
|
||||
actions.forEach(d => {
|
||||
newActions.push(d);
|
||||
if (names.include(d.name)) {
|
||||
newActions.push({ type: 'separator' })
|
||||
}
|
||||
});
|
||||
return newActions
|
||||
})
|
||||
```
|
||||
|
||||
### 物料元数据
|
||||
|
||||
#### getComponentMeta
|
||||
获取指定名称的物料元数据
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@ sidebar_position: 3
|
|||
| @alilc/lowcode-engine | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/engine |
|
||||
| @alilc/lowcode-plugin-designer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-designer |
|
||||
| @alilc/lowcode-plugin-outline-pane | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-outline-pane |
|
||||
| @alilc/lowcode-rax-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/rax-renderer |
|
||||
| @alilc/lowcode-rax-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/rax-simulator-renderer |
|
||||
| @alilc/lowcode-react-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-renderer |
|
||||
| @alilc/lowcode-react-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-simulator-renderer |
|
||||
| @alilc/lowcode-renderer-core | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/renderer-core |
|
||||
|
|
|
@ -15,15 +15,13 @@ sidebar_position: 2
|
|||
5. ignitor
|
||||
6. plugin-designer
|
||||
7. plugin-outline-pane
|
||||
8. rax-renderer
|
||||
9. rax-simulator-renderer
|
||||
10. react-renderer
|
||||
11. react-simulator-renderer
|
||||
12. renderer-core
|
||||
13. types
|
||||
14. utils
|
||||
15. material-parser
|
||||
16. code-generator
|
||||
8. react-renderer
|
||||
9. react-simulator-renderer
|
||||
10. renderer-core
|
||||
11. types
|
||||
12. utils
|
||||
13. material-parser
|
||||
14. code-generator
|
||||
|
||||
## 2. 引擎官方扩展包
|
||||
包含了常用的设置器(setter)、跟 setter 绑定的插件等
|
||||
|
|
|
@ -11,7 +11,6 @@ sidebar_position: 4
|
|||
## npm 包与仓库信息
|
||||
|
||||
- React 框架渲染 npm 包:@alilc/lowcode-react-renderer
|
||||
- Rax 框架渲染 npm 包:@alilc/lowcode-rax-renderer
|
||||
- 仓库:[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) 下的
|
||||
- packages/renderer-core
|
||||
- packages/react-renderer
|
||||
|
|
|
@ -53,6 +53,11 @@ sidebar_position: 9
|
|||
- `--color-text-reverse`: 反色情况下,文字颜色
|
||||
- `--color-text-disabled`: 禁用态文字颜色
|
||||
|
||||
#### 菜单颜色
|
||||
- `--color-context-menu-text`: 菜单项颜色
|
||||
- `--color-context-menu-text-hover`: 菜单项 hover 颜色
|
||||
- `--color-context-menu-text-disabled`: 菜单项 disabled 颜色
|
||||
|
||||
#### 字段和边框颜色
|
||||
|
||||
- `--color-field-label`: field 标签颜色
|
||||
|
@ -128,6 +133,7 @@ sidebar_position: 9
|
|||
- `--pane-title-height`: 面板标题高度
|
||||
- `--pane-title-font-size`: 面板标题字体大小
|
||||
- `--pane-title-padding`: 面板标题边距
|
||||
- `--context-menu-item-height`: 右键菜单项高度
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ ReactDOM.render((
|
|||
), document.getElementById('root'));
|
||||
```
|
||||
|
||||
- rax-renderer:npm 包替换为 @alilc/lowcode-rax-renderer
|
||||
####
|
||||
### 项目使用示例
|
||||
> [设计器 demo](https://lowcode-engine.cn/demo/demo-general/index.html)
|
||||
|
|
|
@ -47,15 +47,7 @@ npm install && npm run setup
|
|||
[
|
||||
"https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css",
|
||||
"http://localhost:5555/css/ReactSimulatorRenderer.css"
|
||||
],
|
||||
[
|
||||
"https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js",
|
||||
"http://localhost:5555/js/RaxSimulatorRenderer.js"
|
||||
],
|
||||
[
|
||||
"https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css",
|
||||
"http://localhost:5555/css/RaxSimulatorRenderer.css"
|
||||
],
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
|
|
@ -499,7 +499,6 @@ try {
|
|||
- 说明:组件即将从 DOM 中移除
|
||||
- componentDidCatch(error, info)
|
||||
- 说明:组件捕获到异常
|
||||
- Rax:目前没有使用生命周期,使用 hooks 替代生命周期;
|
||||
|
||||
该对象由一系列 key-value 组成,key 为生命周期方法名,value 为 JSFunction 的描述,详见下方示例:
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-engine-docs",
|
||||
"version": "1.2.17",
|
||||
"version": "1.2.27",
|
||||
"description": "低代码引擎版本化文档",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"lerna": "4.0.0",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"packages": [
|
||||
|
|
|
@ -94,16 +94,26 @@ await CodeGenerator.init();
|
|||
4. 出码
|
||||
|
||||
```js
|
||||
const result = await CodeGenerator.generateCode({
|
||||
const project = await CodeGenerator.generateCode({
|
||||
solution: 'icejs', // 出码方案 (目前内置有 icejs 和 rax )
|
||||
schema, // 编排搭建出来的 schema
|
||||
});
|
||||
|
||||
console.log(result); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果)
|
||||
console.log(project); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果)
|
||||
```
|
||||
|
||||
注:一般来说在浏览器中出码适合做即时预览功能。
|
||||
|
||||
5. 下载 zip 包
|
||||
|
||||
```js
|
||||
// 写入到 zip 包
|
||||
await CodeGenerator.publishers.zip().publish({
|
||||
project, // 上一步生成的 project
|
||||
projectSlug: 'your-project-slug', // 项目标识 -- 对应下载 your-project-slug.zip 文件
|
||||
});
|
||||
```
|
||||
|
||||
### 5)自定义出码
|
||||
|
||||
前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 欢迎参考 ./src/plugins/xxx 来编写您自己的出码插件,然后参考 ./src/solutions/xxx 将各种插件组合成一套适合您的业务场景的出码方案。
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-code-generator",
|
||||
"version": "1.1.6",
|
||||
"version": "1.1.7",
|
||||
"description": "出码引擎 for LowCode Engine",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
|
@ -80,6 +80,7 @@
|
|||
"change-case": "^3.1.0",
|
||||
"commander": "^6.1.0",
|
||||
"debug": "^4.3.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"fp-ts": "^2.11.9",
|
||||
"fs-extra": "9.x",
|
||||
"glob": "^7.2.0",
|
||||
|
@ -109,6 +110,7 @@
|
|||
"devDependencies": {
|
||||
"@iceworks/spec": "^1.4.2",
|
||||
"@types/babel__traverse": "^7.11.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/lodash": "^4.14.162",
|
||||
"@types/node": "^14.14.20",
|
||||
|
|
|
@ -2,9 +2,9 @@ import { ResultDir } from '@alilc/lowcode-types';
|
|||
import { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types';
|
||||
import { getErrorMessage } from '../../utils/errors';
|
||||
import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils';
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
// export type ZipBuffer = Buffer | Blob;
|
||||
export type ZipBuffer = Buffer;
|
||||
export type ZipBuffer = Buffer | Blob;
|
||||
|
||||
declare type ZipPublisherResponse = string | ZipBuffer;
|
||||
|
||||
|
@ -44,10 +44,16 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher
|
|||
try {
|
||||
const zipContent = await generateProjectZip(projectToPublish);
|
||||
|
||||
// If not output path is provided, zip is not written to disk
|
||||
const projectOutputPath = options.outputPath || outputPath;
|
||||
if (projectOutputPath && isNodeProcess()) {
|
||||
await writeZipToDisk(projectOutputPath, zipContent, zipName);
|
||||
if (isNodeProcess()) {
|
||||
// If not output path is provided on the node side, zip is not written to disk
|
||||
const projectOutputPath = options.outputPath || outputPath;
|
||||
if (projectOutputPath) {
|
||||
await writeZipToDisk(projectOutputPath, zipContent, zipName);
|
||||
}
|
||||
} else {
|
||||
// the browser end does not require a path
|
||||
// auto download zip files
|
||||
saveAs(zipContent as Blob, `${zipName}.zip`);
|
||||
}
|
||||
|
||||
return { success: true, payload: zipContent };
|
||||
|
|
|
@ -40,8 +40,7 @@ export const writeZipToDisk = (
|
|||
export const generateProjectZip = async (project: ResultDir): Promise<ZipBuffer> => {
|
||||
let zip = new JSZip();
|
||||
zip = writeFolderToZip(project, zip, true);
|
||||
// const zipType = isNodeProcess() ? 'nodebuffer' : 'blob';
|
||||
const zipType = 'nodebuffer'; // 目前先只支持 node 调用
|
||||
const zipType = isNodeProcess() ? 'nodebuffer' : 'blob';
|
||||
return zip.generateAsync({ type: zipType });
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
import CodeGen from '../../../../src';
|
||||
import fileSaver from 'file-saver';
|
||||
import * as utils from '../../../../src/publisher/zip/utils';
|
||||
|
||||
jest.mock('file-saver');
|
||||
|
||||
describe('public/publisher/zip/zip', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should works', async () => {
|
||||
const zip = CodeGen.publishers.zip({
|
||||
outputPath: 'demo-output',
|
||||
|
@ -19,15 +27,15 @@ describe('public/publisher/zip/zip', () => {
|
|||
],
|
||||
};
|
||||
|
||||
expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
|
||||
expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"');
|
||||
|
||||
expect(zip.getProject()).toMatchInlineSnapshot(`undefined`);
|
||||
expect(zip.getProject()).toMatchInlineSnapshot('undefined');
|
||||
zip.setProject(demoProject);
|
||||
expect(zip.getProject()).toBeTruthy();
|
||||
|
||||
expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`);
|
||||
expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"');
|
||||
expect(zip.setOutputPath('output')).toBe(undefined);
|
||||
expect(zip.getOutputPath()).toMatchInlineSnapshot(`"output"`);
|
||||
expect(zip.getOutputPath()).toMatchInlineSnapshot('"output"');
|
||||
|
||||
const publishRes = await zip.publish({
|
||||
project: demoProject,
|
||||
|
@ -41,4 +49,39 @@ describe('public/publisher/zip/zip', () => {
|
|||
const zip = CodeGen.publishers.zip({});
|
||||
expect(zip.publish()).rejects.toBeTruthy();
|
||||
});
|
||||
|
||||
it('should publish the project as a zip file in the browser', async () => {
|
||||
const zipContent = 'zip content';
|
||||
const zipName = 'example-project';
|
||||
jest.spyOn(utils, 'isNodeProcess').mockReturnValue(false);
|
||||
// new Zip 里面也有平台判断,所以这里 mock
|
||||
jest.spyOn(utils, 'generateProjectZip').mockResolvedValue(zipContent as any);
|
||||
const spy = jest.spyOn(fileSaver, 'saveAs');
|
||||
|
||||
const zip = CodeGen.publishers.zip({
|
||||
projectSlug: zipName,
|
||||
});
|
||||
|
||||
const demoProject = {
|
||||
name: 'demo',
|
||||
dirs: [],
|
||||
files: [
|
||||
{
|
||||
name: 'package',
|
||||
ext: 'json',
|
||||
content: '{ "name": "demo", "version": "1.0.0" }',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
zip.setProject(demoProject);
|
||||
const publishRes = await zip.publish({
|
||||
project: demoProject,
|
||||
});
|
||||
|
||||
expect(publishRes.success).toBeTruthy();
|
||||
expect(spy).toBeCalledWith(zipContent, `${zipName}.zip`);
|
||||
spy.mockReset();
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
"yarn": "^1.22.17",
|
||||
"rimraf": "^3.0.2",
|
||||
"@types/react-router": "5.1.18",
|
||||
"@alilc/build-plugin-lce": "^0.0.3",
|
||||
"@alilc/build-plugin-lce": "^0.0.4",
|
||||
"babel-jest": "^26.5.2",
|
||||
"@alilc/lowcode-test-mate": "^1.0.1"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-designer",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"description": "Designer for Ali LowCode Engine",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -15,9 +15,9 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alilc/lowcode-editor-core": "1.2.5",
|
||||
"@alilc/lowcode-types": "1.2.5",
|
||||
"@alilc/lowcode-utils": "1.2.5",
|
||||
"@alilc/lowcode-editor-core": "1.3.0",
|
||||
"@alilc/lowcode-types": "1.3.0",
|
||||
"@alilc/lowcode-utils": "1.3.0",
|
||||
"classnames": "^2.2.6",
|
||||
"react": "^16",
|
||||
"react-dom": "^16.7.0",
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
ComponentType,
|
||||
} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer, computed, Tip } from '@alilc/lowcode-editor-core';
|
||||
import { observer, computed, Tip, engineConfig } from '@alilc/lowcode-editor-core';
|
||||
import { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils';
|
||||
import { IPublicTypeActionContentObject } from '@alilc/lowcode-types';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
|
@ -47,14 +47,18 @@ export class BorderSelectingInstance extends Component<{
|
|||
});
|
||||
|
||||
const { hideSelectTools } = observed.node.componentMeta.advanced;
|
||||
const hideComponentAction = engineConfig.get('hideComponentAction');
|
||||
|
||||
if (hideSelectTools) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
{!dragging && <Toolbar observed={observed} />}
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
{(!dragging && !hideComponentAction) ? <Toolbar observed={observed} /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import {
|
|||
isDragAnyObject,
|
||||
isDragNodeObject,
|
||||
isLocationData,
|
||||
Logger,
|
||||
} from '@alilc/lowcode-utils';
|
||||
import {
|
||||
isShaken,
|
||||
|
@ -72,6 +73,8 @@ import { IScroller } from '../designer/scroller';
|
|||
import { isElementNode, isDOMNodeVisible } from '../utils/misc';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
const logger = new Logger({ level: 'warn', bizName: 'designer' });
|
||||
|
||||
export type LibraryItem = IPublicTypePackage & {
|
||||
package: string;
|
||||
library: string;
|
||||
|
@ -122,21 +125,6 @@ const defaultSimulatorUrl = (() => {
|
|||
return urls;
|
||||
})();
|
||||
|
||||
const defaultRaxSimulatorUrl = (() => {
|
||||
const publicPath = getPublicPath();
|
||||
let urls;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [_, prefix = '', dev] = /^(.+?)(\/js)?\/?$/.exec(publicPath) || [];
|
||||
if (dev) {
|
||||
urls = [`${prefix}/css/rax-simulator-renderer.css`, `${prefix}/js/rax-simulator-renderer.js`];
|
||||
} else if (process.env.NODE_ENV === 'production') {
|
||||
urls = [`${prefix}/rax-simulator-renderer.css`, `${prefix}/rax-simulator-renderer.js`];
|
||||
} else {
|
||||
urls = [`${prefix}/rax-simulator-renderer.css`, `${prefix}/rax-simulator-renderer.js`];
|
||||
}
|
||||
return urls;
|
||||
})();
|
||||
|
||||
const defaultEnvironment = [
|
||||
// https://g.alicdn.com/mylib/??react/16.11.0/umd/react.production.min.js,react-dom/16.8.6/umd/react-dom.production.min.js,prop-types/15.7.2/prop-types.min.js
|
||||
assetItem(
|
||||
|
@ -151,17 +139,6 @@ const defaultEnvironment = [
|
|||
),
|
||||
];
|
||||
|
||||
const defaultRaxEnvironment = [
|
||||
assetItem(
|
||||
AssetType.JSText,
|
||||
'window.Rax=parent.Rax;window.React=parent.React;window.ReactDOM=parent.ReactDOM;window.VisualEngineUtils=parent.VisualEngineUtils;window.VisualEngine=parent.VisualEngine',
|
||||
),
|
||||
assetItem(
|
||||
AssetType.JSText,
|
||||
'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',
|
||||
),
|
||||
];
|
||||
|
||||
export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProps> {
|
||||
readonly isSimulator = true;
|
||||
|
||||
|
@ -467,11 +444,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||
|
||||
const libraryAsset: AssetList = this.buildLibrary();
|
||||
|
||||
if (this.renderEnv === 'rax') {
|
||||
logger.error('After LowcodeEngine v1.3.0, Rax is no longer supported.');
|
||||
}
|
||||
|
||||
const vendors = [
|
||||
// required & use once
|
||||
assetBundle(
|
||||
this.get('environment') ||
|
||||
(this.renderEnv === 'rax' ? defaultRaxEnvironment : defaultEnvironment),
|
||||
defaultEnvironment,
|
||||
AssetLevel.Environment,
|
||||
),
|
||||
// required & use once
|
||||
|
@ -484,7 +465,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||
// required & use once
|
||||
assetBundle(
|
||||
this.get('simulatorUrl') ||
|
||||
(this.renderEnv === 'rax' ? defaultRaxSimulatorUrl : defaultSimulatorUrl),
|
||||
defaultSimulatorUrl,
|
||||
AssetLevel.Runtime,
|
||||
),
|
||||
];
|
||||
|
@ -851,16 +832,22 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||
doc.addEventListener('contextmenu', (e: MouseEvent) => {
|
||||
const targetElement = e.target as HTMLElement;
|
||||
const nodeInst = this.getNodeInstanceFromElement(targetElement);
|
||||
const editor = this.designer?.editor;
|
||||
if (!nodeInst) {
|
||||
editor?.eventBus.emit('designer.builtinSimulator.contextmenu', {
|
||||
originalEvent: e,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const node = nodeInst.node || this.project.currentDocument?.focusNode;
|
||||
if (!node) {
|
||||
editor?.eventBus.emit('designer.builtinSimulator.contextmenu', {
|
||||
originalEvent: e,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// dirty code should refector
|
||||
const editor = this.designer?.editor;
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
|
|
|
@ -48,13 +48,17 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti
|
|||
return rule;
|
||||
}
|
||||
if (isRegExp(rule)) {
|
||||
return (testNode: Node | IPublicTypeNodeSchema) => rule.test(testNode.componentName);
|
||||
return (testNode: Node | IPublicTypeNodeSchema) => {
|
||||
return rule.test(testNode.componentName);
|
||||
};
|
||||
}
|
||||
const list = ensureAList(rule);
|
||||
if (!list) {
|
||||
return null;
|
||||
}
|
||||
return (testNode: Node | IPublicTypeNodeSchema) => list.includes(testNode.componentName);
|
||||
return (testNode: Node | IPublicTypeNodeSchema) => {
|
||||
return list.includes(testNode.componentName);
|
||||
};
|
||||
}
|
||||
|
||||
export interface IComponentMeta extends IPublicModelComponentMeta<INode> {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
.engine-context-menu {
|
||||
&.next-menu.next-ver .next-menu-item {
|
||||
padding-right: 30px;
|
||||
|
||||
.next-menu-item-inner {
|
||||
height: var(--context-menu-item-height, 30px);
|
||||
line-height: var(--context-menu-item-height, 30px);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial, IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
import { IDesigner, INode } from './designer';
|
||||
import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils';
|
||||
import { Menu } from '@alifd/next';
|
||||
import { engineConfig } from '@alilc/lowcode-editor-core';
|
||||
import './context-menu-actions.scss';
|
||||
|
||||
export interface IContextMenuActions {
|
||||
actions: IPublicTypeContextMenuAction[];
|
||||
|
||||
adjustMenuLayoutFn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[];
|
||||
|
||||
addMenuAction: IPublicApiMaterial['addContextMenuOption'];
|
||||
|
||||
removeMenuAction: IPublicApiMaterial['removeContextMenuOption'];
|
||||
|
||||
adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout'];
|
||||
}
|
||||
|
||||
let adjustMenuLayoutFn: Function = (actions: IPublicTypeContextMenuAction[]) => actions;
|
||||
|
||||
export class GlobalContextMenuActions {
|
||||
enableContextMenu: boolean;
|
||||
|
||||
dispose: Function[];
|
||||
|
||||
contextMenuActionsMap: Map<string, ContextMenuActions> = new Map();
|
||||
|
||||
constructor() {
|
||||
this.dispose = [];
|
||||
|
||||
engineConfig.onGot('enableContextMenu', (enable) => {
|
||||
if (this.enableContextMenu === enable) {
|
||||
return;
|
||||
}
|
||||
this.enableContextMenu = enable;
|
||||
this.dispose.forEach(d => d());
|
||||
if (enable) {
|
||||
this.initEvent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleContextMenu = (
|
||||
event: MouseEvent,
|
||||
) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
const actions: IPublicTypeContextMenuAction[] = [];
|
||||
let contextMenu: ContextMenuActions = this.contextMenuActionsMap.values().next().value;
|
||||
this.contextMenuActionsMap.forEach((contextMenu) => {
|
||||
actions.push(...contextMenu.actions);
|
||||
});
|
||||
|
||||
let destroyFn: Function | undefined;
|
||||
|
||||
const destroy = () => {
|
||||
destroyFn?.();
|
||||
};
|
||||
const pluginContext: IPublicModelPluginContext = contextMenu.designer.editor.get('pluginContext') as IPublicModelPluginContext;
|
||||
|
||||
const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, {
|
||||
nodes: [],
|
||||
destroy,
|
||||
event,
|
||||
pluginContext,
|
||||
});
|
||||
|
||||
if (!menus.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const layoutMenu = adjustMenuLayoutFn(menus);
|
||||
|
||||
const menuNode = parseContextMenuAsReactNode(layoutMenu, {
|
||||
destroy,
|
||||
nodes: [],
|
||||
pluginContext,
|
||||
});
|
||||
|
||||
const target = event.target;
|
||||
|
||||
const { top, left } = target?.getBoundingClientRect();
|
||||
|
||||
const menuInstance = Menu.create({
|
||||
target: event.target,
|
||||
offset: [event.clientX - left, event.clientY - top],
|
||||
children: menuNode,
|
||||
className: 'engine-context-menu',
|
||||
});
|
||||
|
||||
destroyFn = (menuInstance as any).destroy;
|
||||
};
|
||||
|
||||
initEvent() {
|
||||
this.dispose.push(
|
||||
(() => {
|
||||
const handleContextMenu = (e: MouseEvent) => {
|
||||
this.handleContextMenu(e);
|
||||
};
|
||||
|
||||
document.addEventListener('contextmenu', handleContextMenu);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('contextmenu', handleContextMenu);
|
||||
};
|
||||
})(),
|
||||
);
|
||||
}
|
||||
|
||||
registerContextMenuActions(contextMenu: ContextMenuActions) {
|
||||
this.contextMenuActionsMap.set(contextMenu.id, contextMenu);
|
||||
}
|
||||
}
|
||||
|
||||
const globalContextMenuActions = new GlobalContextMenuActions();
|
||||
|
||||
export class ContextMenuActions implements IContextMenuActions {
|
||||
actions: IPublicTypeContextMenuAction[] = [];
|
||||
|
||||
designer: IDesigner;
|
||||
|
||||
dispose: Function[];
|
||||
|
||||
enableContextMenu: boolean;
|
||||
|
||||
id: string = uniqueId('contextMenu');;
|
||||
|
||||
constructor(designer: IDesigner) {
|
||||
this.designer = designer;
|
||||
this.dispose = [];
|
||||
|
||||
engineConfig.onGot('enableContextMenu', (enable) => {
|
||||
if (this.enableContextMenu === enable) {
|
||||
return;
|
||||
}
|
||||
this.enableContextMenu = enable;
|
||||
this.dispose.forEach(d => d());
|
||||
if (enable) {
|
||||
this.initEvent();
|
||||
}
|
||||
});
|
||||
|
||||
globalContextMenuActions.registerContextMenuActions(this);
|
||||
}
|
||||
|
||||
handleContextMenu = (
|
||||
nodes: INode[],
|
||||
event: MouseEvent,
|
||||
) => {
|
||||
const designer = this.designer;
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
const actions = designer.contextMenuActions.actions;
|
||||
|
||||
const { bounds } = designer.project.simulator?.viewport || { bounds: { left: 0, top: 0 } };
|
||||
const { left: simulatorLeft, top: simulatorTop } = bounds;
|
||||
|
||||
let destroyFn: Function | undefined;
|
||||
|
||||
const destroy = () => {
|
||||
destroyFn?.();
|
||||
};
|
||||
|
||||
const pluginContext: IPublicModelPluginContext = this.designer.editor.get('pluginContext') as IPublicModelPluginContext;
|
||||
|
||||
const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, {
|
||||
nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!),
|
||||
destroy,
|
||||
event,
|
||||
pluginContext,
|
||||
});
|
||||
|
||||
if (!menus.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const layoutMenu = adjustMenuLayoutFn(menus);
|
||||
|
||||
const menuNode = parseContextMenuAsReactNode(layoutMenu, {
|
||||
destroy,
|
||||
nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!),
|
||||
pluginContext,
|
||||
});
|
||||
|
||||
destroyFn = createContextMenu(menuNode, {
|
||||
event,
|
||||
offset: [simulatorLeft, simulatorTop],
|
||||
});
|
||||
};
|
||||
|
||||
initEvent() {
|
||||
const designer = this.designer;
|
||||
this.dispose.push(
|
||||
designer.editor.eventBus.on('designer.builtinSimulator.contextmenu', ({
|
||||
node,
|
||||
originalEvent,
|
||||
}: {
|
||||
node: INode;
|
||||
originalEvent: MouseEvent;
|
||||
}) => {
|
||||
originalEvent.stopPropagation();
|
||||
originalEvent.preventDefault();
|
||||
// 如果右键的节点不在 当前选中的节点中,选中该节点
|
||||
if (!designer.currentSelection.has(node.id)) {
|
||||
designer.currentSelection.select(node.id);
|
||||
}
|
||||
const nodes = designer.currentSelection.getNodes();
|
||||
this.handleContextMenu(nodes, originalEvent);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
addMenuAction(action: IPublicTypeContextMenuAction) {
|
||||
this.actions.push({
|
||||
type: IPublicEnumContextMenuType.MENU_ITEM,
|
||||
...action,
|
||||
});
|
||||
}
|
||||
|
||||
removeMenuAction(name: string) {
|
||||
const i = this.actions.findIndex((action) => action.name === name);
|
||||
if (i > -1) {
|
||||
this.actions.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
adjustMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) {
|
||||
adjustMenuLayoutFn = fn;
|
||||
}
|
||||
}
|
|
@ -36,6 +36,10 @@ class Clipboard implements IClipboard {
|
|||
|
||||
private waitFn?: (data: any, e: ClipboardEvent) => void;
|
||||
|
||||
constructor() {
|
||||
this.injectCopyPaster(document);
|
||||
}
|
||||
|
||||
isCopyPasteEvent(e: Event) {
|
||||
this.isCopyPaster(e.target);
|
||||
}
|
||||
|
@ -69,7 +73,13 @@ class Clipboard implements IClipboard {
|
|||
}
|
||||
const copyPaster = document.createElement<'textarea'>('textarea');
|
||||
copyPaster.style.cssText = 'position: absolute;left: -9999px;top:-100px';
|
||||
document.body.appendChild(copyPaster);
|
||||
if (document.body) {
|
||||
document.body.appendChild(copyPaster);
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.body.appendChild(copyPaster);
|
||||
});
|
||||
}
|
||||
const dispose = this.initCopyPaster(copyPaster);
|
||||
return () => {
|
||||
dispose();
|
||||
|
|
|
@ -4,7 +4,6 @@ import BuiltinDragGhostComponent from './drag-ghost';
|
|||
import { Designer, DesignerProps } from './designer';
|
||||
import { ProjectView } from '../project';
|
||||
import './designer.less';
|
||||
import { clipboard } from './clipboard';
|
||||
|
||||
type IProps = DesignerProps & {
|
||||
designer?: Designer;
|
||||
|
@ -44,7 +43,6 @@ export class DesignerView extends Component<IProps> {
|
|||
if (onMount) {
|
||||
onMount(this.designer);
|
||||
}
|
||||
clipboard.injectCopyPaster(document);
|
||||
this.designer.postEvent('mount', this.designer);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
} from '@alilc/lowcode-types';
|
||||
import { mergeAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils';
|
||||
import { IProject, Project } from '../project';
|
||||
import { Node, DocumentModel, insertChildren, INode } from '../document';
|
||||
import { Node, DocumentModel, insertChildren, INode, ISelection } from '../document';
|
||||
import { ComponentMeta, IComponentMeta } from '../component-meta';
|
||||
import { INodeSelector, Component } from '../simulator';
|
||||
import { Scroller } from './scroller';
|
||||
|
@ -32,6 +32,7 @@ import { OffsetObserver, createOffsetObserver } from './offset-observer';
|
|||
import { ISettingTopEntry, SettingTopEntry } from './setting';
|
||||
import { BemToolsManager } from '../builtin-simulator/bem-tools/manager';
|
||||
import { ComponentActions } from '../component-actions';
|
||||
import { ContextMenuActions, IContextMenuActions } from '../context-menu-actions';
|
||||
|
||||
const logger = new Logger({ level: 'warn', bizName: 'designer' });
|
||||
|
||||
|
@ -72,12 +73,16 @@ export interface IDesigner {
|
|||
|
||||
get componentActions(): ComponentActions;
|
||||
|
||||
get contextMenuActions(): ContextMenuActions;
|
||||
|
||||
get editor(): IPublicModelEditor;
|
||||
|
||||
get detecting(): Detecting;
|
||||
|
||||
get simulatorComponent(): ComponentType<any> | undefined;
|
||||
|
||||
get currentSelection(): ISelection;
|
||||
|
||||
createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller;
|
||||
|
||||
refreshComponentMetasMap(): void;
|
||||
|
@ -122,6 +127,8 @@ export class Designer implements IDesigner {
|
|||
|
||||
readonly componentActions = new ComponentActions();
|
||||
|
||||
readonly contextMenuActions: IContextMenuActions;
|
||||
|
||||
readonly activeTracker = new ActiveTracker();
|
||||
|
||||
readonly detecting = new Detecting();
|
||||
|
@ -198,6 +205,8 @@ export class Designer implements IDesigner {
|
|||
this.postEvent('dragstart', e);
|
||||
});
|
||||
|
||||
this.contextMenuActions = new ContextMenuActions(this);
|
||||
|
||||
this.dragon.onDrag((e) => {
|
||||
if (this.props?.onDrag) {
|
||||
this.props.onDrag(e);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry, IPublicApiSetters } from '@alilc/lowcode-types';
|
||||
import { isCustomView } from '@alilc/lowcode-utils';
|
||||
import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { ISettingEntry } from './setting-entry-type';
|
||||
|
@ -6,7 +6,6 @@ import { ISettingField, SettingField } from './setting-field';
|
|||
import { INode } from '../../document';
|
||||
import type { IComponentMeta } from '../../component-meta';
|
||||
import { IDesigner } from '../designer';
|
||||
import { Setters } from '@alilc/lowcode-shell';
|
||||
|
||||
function generateSessionId(nodes: INode[]) {
|
||||
return nodes
|
||||
|
@ -19,18 +18,18 @@ export interface ISettingTopEntry extends ISettingEntry, IPublicModelSettingTopE
|
|||
INode,
|
||||
ISettingField
|
||||
> {
|
||||
purge(): void;
|
||||
|
||||
items: Array<ISettingField | IPublicTypeCustomView>;
|
||||
|
||||
readonly top: ISettingTopEntry;
|
||||
|
||||
readonly parent: ISettingTopEntry;
|
||||
|
||||
readonly path: never[];
|
||||
|
||||
items: Array<ISettingField | IPublicTypeCustomView>;
|
||||
|
||||
componentMeta: IComponentMeta | null;
|
||||
|
||||
purge(): void;
|
||||
|
||||
getExtraPropValue(propName: string): void;
|
||||
|
||||
setExtraPropValue(propName: string, value: any): void;
|
||||
|
@ -92,7 +91,7 @@ export class SettingTopEntry implements ISettingTopEntry {
|
|||
|
||||
readonly designer: IDesigner | undefined;
|
||||
|
||||
readonly setters: Setters;
|
||||
readonly setters: IPublicApiSetters;
|
||||
|
||||
disposeFunctions: any[] = [];
|
||||
|
||||
|
@ -103,7 +102,7 @@ export class SettingTopEntry implements ISettingTopEntry {
|
|||
this.id = generateSessionId(nodes);
|
||||
this.first = nodes[0];
|
||||
this.designer = this.first.document?.designer;
|
||||
this.setters = editor.get('setters') as Setters;
|
||||
this.setters = editor.get('setters') as IPublicApiSetters;
|
||||
|
||||
// setups
|
||||
this.setupComponentMeta();
|
||||
|
|
|
@ -392,7 +392,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
|
|||
|
||||
this.isInited = true;
|
||||
this.emitter = createModuleEventBus('Node');
|
||||
const editor = this.document.designer.editor;
|
||||
const { editor } = this.document.designer;
|
||||
this.onVisibleChange((visible: boolean) => {
|
||||
editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, this, visible);
|
||||
});
|
||||
|
@ -1219,11 +1219,18 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
|
|||
/**
|
||||
* 获取磁贴相关信息
|
||||
*/
|
||||
getRGL() {
|
||||
getRGL(): {
|
||||
isContainerNode: boolean;
|
||||
isEmptyNode: boolean;
|
||||
isRGLContainerNode: boolean;
|
||||
isRGLNode: boolean;
|
||||
isRGL: boolean;
|
||||
rglNode: Node | null;
|
||||
} {
|
||||
const isContainerNode = this.isContainer();
|
||||
const isEmptyNode = this.isEmpty();
|
||||
const isRGLContainerNode = this.isRGLContainer;
|
||||
const isRGLNode = this.getParent()?.isRGLContainer;
|
||||
const isRGLNode = (this.getParent()?.isRGLContainer) as boolean;
|
||||
const isRGL = isRGLContainerNode || (isRGLNode && (!isContainerNode || !isEmptyNode));
|
||||
let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : null;
|
||||
return { isContainerNode, isEmptyNode, isRGLContainerNode, isRGLNode, isRGL, rglNode };
|
||||
|
|
|
@ -6,3 +6,4 @@ export * from './project';
|
|||
export * from './builtin-simulator';
|
||||
export * from './plugin';
|
||||
export * from './types';
|
||||
export * from './context-menu-actions';
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
IPublicApiWorkspace,
|
||||
IPublicEnumPluginRegisterLevel,
|
||||
IPublicModelWindow,
|
||||
IPublicApiCommonUI,
|
||||
} from '@alilc/lowcode-types';
|
||||
import {
|
||||
IPluginContextOptions,
|
||||
|
@ -45,6 +46,8 @@ export default class PluginContext implements
|
|||
workspace: IPublicApiWorkspace;
|
||||
registerLevel: IPublicEnumPluginRegisterLevel;
|
||||
editorWindow: IPublicModelWindow;
|
||||
commonUI: IPublicApiCommonUI;
|
||||
isPluginRegisteredInWorkspace: false;
|
||||
|
||||
constructor(
|
||||
options: IPluginContextOptions,
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
IPublicTypePluginRegisterOptions,
|
||||
IPublicModelWindow,
|
||||
IPublicEnumPluginRegisterLevel,
|
||||
IPublicApiCommonUI,
|
||||
} from '@alilc/lowcode-types';
|
||||
import PluginContext from './plugin-context';
|
||||
|
||||
|
@ -61,6 +62,7 @@ export interface ILowCodePluginContextPrivate {
|
|||
set editorWindow(window: IPublicModelWindow);
|
||||
set registerLevel(level: IPublicEnumPluginRegisterLevel);
|
||||
set isPluginRegisteredInWorkspace(flag: boolean);
|
||||
set commonUI(commonUI: IPublicApiCommonUI);
|
||||
}
|
||||
export interface ILowCodePluginContextApiAssembler {
|
||||
assembleApis(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-editor-core",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"description": "Core Api for Ali lowCode engine",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
|
@ -14,8 +14,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@alifd/next": "^1.19.16",
|
||||
"@alilc/lowcode-types": "1.2.5",
|
||||
"@alilc/lowcode-utils": "1.2.5",
|
||||
"@alilc/lowcode-types": "1.3.0",
|
||||
"@alilc/lowcode-utils": "1.3.0",
|
||||
"classnames": "^2.2.6",
|
||||
"debug": "^4.1.1",
|
||||
"intl-messageformat": "^9.3.1",
|
||||
|
|
|
@ -44,7 +44,7 @@ const VALID_ENGINE_OPTIONS = {
|
|||
},
|
||||
renderEnv: {
|
||||
type: 'string',
|
||||
enum: ['react', 'rax', 'any string value'],
|
||||
enum: ['react', 'any string value'],
|
||||
default: 'react',
|
||||
description: '渲染器类型',
|
||||
},
|
||||
|
@ -159,6 +159,16 @@ const VALID_ENGINE_OPTIONS = {
|
|||
type: 'function',
|
||||
description: '应用级设计模式下,窗口为空时展示的占位组件',
|
||||
},
|
||||
enableContextMenu: {
|
||||
type: 'boolean',
|
||||
description: '是否开启右键菜单',
|
||||
default: false,
|
||||
},
|
||||
hideComponentAction: {
|
||||
type: 'boolean',
|
||||
description: '是否隐藏设计器辅助层',
|
||||
default: false,
|
||||
},
|
||||
};
|
||||
|
||||
const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { IntlMessageFormat } from 'intl-messageformat';
|
|||
import { globalLocale } from './global-locale';
|
||||
import { isI18nData } from '@alilc/lowcode-utils';
|
||||
import { observer } from '../utils';
|
||||
import { IPublicTypeI18nData } from '@alilc/lowcode-types';
|
||||
|
||||
function generateTryLocales(locale: string) {
|
||||
const tries = [locale, locale.replace('-', '_')];
|
||||
|
@ -26,18 +27,9 @@ function injectVars(msg: string, params: any, locale: string): string {
|
|||
}
|
||||
const formater = new IntlMessageFormat(msg, locale);
|
||||
return formater.format(params as any) as string;
|
||||
/*
|
||||
|
||||
return template.replace(/({\w+})/g, (_, $1) => {
|
||||
const key = (/\d+/.exec($1) || [])[0] as any;
|
||||
if (key && params[key] != null) {
|
||||
return params[key];
|
||||
}
|
||||
return $1;
|
||||
}); */
|
||||
}
|
||||
|
||||
export function intl(data: any, params?: object): ReactNode {
|
||||
export function intl(data: IPublicTypeI18nData | string, params?: object): ReactNode {
|
||||
if (!isI18nData(data)) {
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import { IPublicTypeHelpTipConfig, IPublicTypeTipConfig } from '@alilc/lowcode-types';
|
||||
import { Tip } from './tip';
|
||||
import { Icon } from '@alifd/next';
|
||||
import { IconProps } from '@alifd/next/types/icon';
|
||||
|
||||
export function HelpTip({
|
||||
help,
|
||||
direction = 'top',
|
||||
size = 'small',
|
||||
}: {
|
||||
help: IPublicTypeHelpTipConfig;
|
||||
direction?: IPublicTypeTipConfig['direction'];
|
||||
size?: IconProps['size'];
|
||||
}) {
|
||||
if (typeof help === 'string') {
|
||||
return (
|
||||
<div>
|
||||
<Icon type="help" size={size} className="lc-help-tip" />
|
||||
<Tip direction={direction}>{help}</Tip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof help === 'object' && help.url) {
|
||||
return (
|
||||
<div>
|
||||
<a href={help.url} target="_blank" rel="noopener noreferrer">
|
||||
<Icon type="help" size={size} className="lc-help-tip" />
|
||||
</a>
|
||||
<Tip direction={direction}>{help.content}</Tip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Icon type="help" size="small" className="lc-help-tip" />
|
||||
<Tip direction={direction}>{help.content}</Tip>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -2,3 +2,4 @@ import './style.less';
|
|||
|
||||
export * from './tip';
|
||||
export * from './tip-container';
|
||||
export * from './help-tips';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Component, isValidElement, ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { createIcon, isI18nData, isTitleConfig } from '@alilc/lowcode-utils';
|
||||
import { IPublicTypeTitleContent, IPublicTypeI18nData, IPublicTypeTitleConfig } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeI18nData, IPublicTypeTitleConfig, IPublicTypeTitleProps } from '@alilc/lowcode-types';
|
||||
import { intl } from '../../intl';
|
||||
import { Tip } from '../tip';
|
||||
import './title.less';
|
||||
|
@ -36,13 +36,7 @@ import './title.less';
|
|||
return fragments;
|
||||
}
|
||||
|
||||
export class Title extends Component<{
|
||||
title: IPublicTypeTitleContent;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
match?: boolean;
|
||||
keywords?: string;
|
||||
}> {
|
||||
export class Title extends Component<IPublicTypeTitleProps> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-editor-skeleton",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"description": "alibaba lowcode editor skeleton",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -19,10 +19,10 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@alifd/next": "^1.20.12",
|
||||
"@alilc/lowcode-designer": "1.2.5",
|
||||
"@alilc/lowcode-editor-core": "1.2.5",
|
||||
"@alilc/lowcode-types": "1.2.5",
|
||||
"@alilc/lowcode-utils": "1.2.5",
|
||||
"@alilc/lowcode-designer": "1.3.0",
|
||||
"@alilc/lowcode-editor-core": "1.3.0",
|
||||
"@alilc/lowcode-types": "1.3.0",
|
||||
"@alilc/lowcode-utils": "1.3.0",
|
||||
"classnames": "^2.2.6",
|
||||
"react": "^16.8.1",
|
||||
"react-dom": "^16.8.1"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Component, ReactElement } from 'react';
|
||||
import { Icon } from '@alifd/next';
|
||||
import classNames from 'classnames';
|
||||
import { Title, observer, Tip } from '@alilc/lowcode-editor-core';
|
||||
import { Title, observer, HelpTip } from '@alilc/lowcode-editor-core';
|
||||
import { DockProps } from '../../types';
|
||||
import { PanelDock } from '../../widget/panel-dock';
|
||||
import { composeTitle } from '../../widget/utils';
|
||||
|
@ -26,25 +25,6 @@ export function DockView({ title, icon, description, size, className, onClick }:
|
|||
);
|
||||
}
|
||||
|
||||
function HelpTip({ tip }: any) {
|
||||
if (tip && tip.url) {
|
||||
return (
|
||||
<div>
|
||||
<a href={tip.url} target="_blank" rel="noopener noreferrer">
|
||||
<Icon type="help" size="small" className="lc-help-tip" />
|
||||
</a>
|
||||
<Tip>{tip.content}</Tip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Icon type="help" size="small" className="lc-help-tip" />
|
||||
<Tip>{tip.content}</Tip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@observer
|
||||
export class PanelDockView extends Component<DockProps & { dock: PanelDock }> {
|
||||
private lastActived = false;
|
||||
|
@ -328,7 +308,7 @@ class PanelTitle extends Component<{ panel: Panel; className?: string }> {
|
|||
data-name={panel.name}
|
||||
>
|
||||
<Title title={panel.title || panel.name} />
|
||||
{panel.help ? <HelpTip tip={panel.help} /> : null}
|
||||
{panel.help ? <HelpTip help={panel.help} /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist
|
|||
```
|
||||
|
||||
#### 方式 5:使用自有 cdn
|
||||
将源码中 packages/engine/dist 和 packages/(react|rax)-simulator-renderer/dist 下的文件传至你的 cdn 提供商
|
||||
将源码中 packages/engine/dist 和 packages/react-simulator-renderer/dist 下的文件传至你的 cdn 提供商
|
||||
|
||||
## 🔗 相关链接
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist
|
|||
```
|
||||
|
||||
#### Method 5: Use your own cdn
|
||||
Pass the files under packages/engine/dist and packages/(react|rax)-simulator-renderer/dist in the source code to your cdn provider
|
||||
Pass the files under packages/engine/dist and packages/react-simulator-renderer/dist in the source code to your cdn provider
|
||||
|
||||
## 🔗 Related Links
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-engine",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系",
|
||||
"main": "lib/engine-core.js",
|
||||
"module": "es/engine-core.js",
|
||||
|
@ -19,15 +19,15 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alifd/next": "^1.19.12",
|
||||
"@alilc/lowcode-designer": "1.2.5",
|
||||
"@alilc/lowcode-editor-core": "1.2.5",
|
||||
"@alilc/lowcode-editor-skeleton": "1.2.5",
|
||||
"@alilc/lowcode-designer": "1.3.0",
|
||||
"@alilc/lowcode-editor-core": "1.3.0",
|
||||
"@alilc/lowcode-editor-skeleton": "1.3.0",
|
||||
"@alilc/lowcode-engine-ext": "^1.0.0",
|
||||
"@alilc/lowcode-plugin-designer": "1.2.5",
|
||||
"@alilc/lowcode-plugin-outline-pane": "1.2.5",
|
||||
"@alilc/lowcode-shell": "1.2.5",
|
||||
"@alilc/lowcode-utils": "1.2.5",
|
||||
"@alilc/lowcode-workspace": "1.2.5",
|
||||
"@alilc/lowcode-plugin-designer": "1.3.0",
|
||||
"@alilc/lowcode-plugin-outline-pane": "1.3.0",
|
||||
"@alilc/lowcode-shell": "1.3.0",
|
||||
"@alilc/lowcode-utils": "1.3.0",
|
||||
"@alilc/lowcode-workspace": "1.3.0",
|
||||
"react": "^16.8.1",
|
||||
"react-dom": "^16.8.1"
|
||||
},
|
||||
|
|
|
@ -51,6 +51,7 @@ import {
|
|||
Canvas,
|
||||
Workspace,
|
||||
Config,
|
||||
CommonUI,
|
||||
} from '@alilc/lowcode-shell';
|
||||
import { isPlainObject } from '@alilc/lowcode-utils';
|
||||
import './modules/live-editing';
|
||||
|
@ -61,6 +62,7 @@ import { setterRegistry } from './inner-plugins/setter-registry';
|
|||
import { defaultPanelRegistry } from './inner-plugins/default-panel-registry';
|
||||
import { shellModelFactory } from './modules/shell-model-factory';
|
||||
import { builtinHotkey } from './inner-plugins/builtin-hotkey';
|
||||
import { defaultContextMenu } from './inner-plugins/default-context-menu';
|
||||
import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane';
|
||||
|
||||
export * from './modules/skeleton-types';
|
||||
|
@ -77,6 +79,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins
|
|||
await plugins.register(defaultPanelRegistryPlugin);
|
||||
await plugins.register(builtinHotkey);
|
||||
await plugins.register(registerDefaults, {}, { autoInit: true });
|
||||
await plugins.register(defaultContextMenu);
|
||||
|
||||
return () => {
|
||||
plugins.delete(OutlinePlugin.pluginName);
|
||||
|
@ -85,6 +88,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins
|
|||
plugins.delete(defaultPanelRegistryPlugin.pluginName);
|
||||
plugins.delete(builtinHotkey.pluginName);
|
||||
plugins.delete(registerDefaults.pluginName);
|
||||
plugins.delete(defaultContextMenu.pluginName);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -111,6 +115,7 @@ const innerSetters = new InnerSetters();
|
|||
const setters = new Setters(innerSetters);
|
||||
|
||||
const material = new Material(editor);
|
||||
const commonUI = new CommonUI(editor);
|
||||
editor.set('project', project);
|
||||
editor.set('setters' as any, setters);
|
||||
editor.set('material', material);
|
||||
|
@ -138,8 +143,10 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = {
|
|||
context.plugins = plugins;
|
||||
context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` });
|
||||
context.workspace = workspace;
|
||||
context.commonUI = commonUI;
|
||||
context.registerLevel = IPublicEnumPluginRegisterLevel.Default;
|
||||
context.isPluginRegisteredInWorkspace = false;
|
||||
editor.set('pluginContext', context);
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -161,6 +168,7 @@ export {
|
|||
common,
|
||||
workspace,
|
||||
canvas,
|
||||
commonUI,
|
||||
};
|
||||
// declare this is open-source version
|
||||
export const isOpenSource = true;
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
import {
|
||||
IPublicEnumContextMenuType,
|
||||
IPublicEnumDragObjectType,
|
||||
IPublicEnumTransformStage,
|
||||
IPublicModelNode,
|
||||
IPublicModelPluginContext,
|
||||
IPublicTypeDragNodeDataObject,
|
||||
IPublicTypeNodeSchema,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { isProjectSchema } from '@alilc/lowcode-utils';
|
||||
import { Message } from '@alifd/next';
|
||||
import { intl } from '../locale';
|
||||
|
||||
function getNodesSchema(nodes: IPublicModelNode[]) {
|
||||
const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone));
|
||||
const data = { type: 'nodeSchema', componentsMap: {}, componentsTree };
|
||||
return data;
|
||||
}
|
||||
|
||||
async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 使用 Clipboard API 读取剪贴板内容
|
||||
navigator.clipboard.readText().then(
|
||||
(text) => {
|
||||
try {
|
||||
const data = JSON.parse(text);
|
||||
if (isProjectSchema(data)) {
|
||||
resolve(data.componentsTree);
|
||||
} else {
|
||||
Message.error(intl('NotValidNodeData'));
|
||||
reject(
|
||||
new Error(intl('NotValidNodeData')),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
Message.error(intl('NotValidNodeData'));
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
reject(err);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export const defaultContextMenu = (ctx: IPublicModelPluginContext) => {
|
||||
const { material, canvas, common } = ctx;
|
||||
const { clipboard } = canvas;
|
||||
const { intl: utilsIntl } = common.utils;
|
||||
|
||||
return {
|
||||
init() {
|
||||
material.addContextMenuOption({
|
||||
name: 'selectComponent',
|
||||
title: intl('SelectComponents'),
|
||||
condition: (nodes = []) => {
|
||||
return nodes.length === 1;
|
||||
},
|
||||
items: [
|
||||
{
|
||||
name: 'nodeTree',
|
||||
type: IPublicEnumContextMenuType.NODE_TREE,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
material.addContextMenuOption({
|
||||
name: 'copyAndPaste',
|
||||
title: intl('CopyAndPaste'),
|
||||
disabled: (nodes = []) => {
|
||||
return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0;
|
||||
},
|
||||
condition: (nodes) => {
|
||||
return nodes?.length === 1;
|
||||
},
|
||||
action(nodes) {
|
||||
const node = nodes?.[0];
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
const { document: doc, parent, index } = node;
|
||||
const data = getNodesSchema(nodes);
|
||||
clipboard.setData(data);
|
||||
|
||||
if (parent) {
|
||||
const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true);
|
||||
newNode?.select();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
material.addContextMenuOption({
|
||||
name: 'copy',
|
||||
title: intl('Copy'),
|
||||
disabled: (nodes = []) => {
|
||||
return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0;
|
||||
},
|
||||
condition(nodes = []) {
|
||||
return nodes?.length > 0;
|
||||
},
|
||||
action(nodes) {
|
||||
if (!nodes || nodes.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = getNodesSchema(nodes);
|
||||
clipboard.setData(data);
|
||||
},
|
||||
});
|
||||
|
||||
material.addContextMenuOption({
|
||||
name: 'pasteToBottom',
|
||||
title: intl('PasteToTheBottom'),
|
||||
condition: (nodes) => {
|
||||
return nodes?.length === 1;
|
||||
},
|
||||
async action(nodes) {
|
||||
if (!nodes || nodes.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const node = nodes[0];
|
||||
const { document: doc, parent, index } = node;
|
||||
|
||||
try {
|
||||
const nodeSchema = await getClipboardText();
|
||||
if (nodeSchema.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (parent) {
|
||||
let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => {
|
||||
const dragNodeObject: IPublicTypeDragNodeDataObject = {
|
||||
type: IPublicEnumDragObjectType.NodeData,
|
||||
data: nodeSchema,
|
||||
};
|
||||
return doc?.checkNesting(parent, dragNodeObject);
|
||||
});
|
||||
if (canAddNodes.length === 0) {
|
||||
Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`);
|
||||
return;
|
||||
}
|
||||
const nodes: IPublicModelNode[] = [];
|
||||
canAddNodes.forEach((schema, schemaIndex) => {
|
||||
const node = doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true);
|
||||
node && nodes.push(node);
|
||||
});
|
||||
doc?.selection.selectAll(nodes.map((node) => node?.id));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
material.addContextMenuOption({
|
||||
name: 'pasteToInner',
|
||||
title: intl('PasteToTheInside'),
|
||||
condition: (nodes) => {
|
||||
return nodes?.length === 1;
|
||||
},
|
||||
disabled: (nodes = []) => {
|
||||
// 获取粘贴数据
|
||||
const node = nodes?.[0];
|
||||
return !node.isContainerNode;
|
||||
},
|
||||
async action(nodes) {
|
||||
const node = nodes?.[0];
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
const { document: doc } = node;
|
||||
|
||||
try {
|
||||
const nodeSchema = await getClipboardText();
|
||||
const index = node.children?.size || 0;
|
||||
if (nodeSchema.length === 0) {
|
||||
return;
|
||||
}
|
||||
let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => {
|
||||
const dragNodeObject: IPublicTypeDragNodeDataObject = {
|
||||
type: IPublicEnumDragObjectType.NodeData,
|
||||
data: nodeSchema,
|
||||
};
|
||||
return doc?.checkNesting(node, dragNodeObject);
|
||||
});
|
||||
if (canAddNodes.length === 0) {
|
||||
Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`);
|
||||
return;
|
||||
}
|
||||
|
||||
const nodes: IPublicModelNode[] = [];
|
||||
nodeSchema.forEach((schema, schemaIndex) => {
|
||||
const newNode = doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true);
|
||||
newNode && nodes.push(newNode);
|
||||
});
|
||||
doc?.selection.selectAll(nodes.map((node) => node?.id));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
material.addContextMenuOption({
|
||||
name: 'delete',
|
||||
title: intl('Delete'),
|
||||
disabled(nodes = []) {
|
||||
return nodes?.filter((node) => !node?.canPerformAction('remove')).length > 0;
|
||||
},
|
||||
condition(nodes = []) {
|
||||
return nodes.length > 0;
|
||||
},
|
||||
action(nodes) {
|
||||
nodes?.forEach((node) => {
|
||||
node.remove();
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
defaultContextMenu.pluginName = '___default_context_menu___';
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"NotValidNodeData": "Not valid node data",
|
||||
"SelectComponents": "Select components",
|
||||
"CopyAndPaste": "Copy and Paste",
|
||||
"Copy": "Copy",
|
||||
"PasteToTheBottom": "Paste to the bottom",
|
||||
"PasteToTheInside": "Paste to the inside",
|
||||
"Delete": "Delete"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { createIntl } from '@alilc/lowcode-editor-core';
|
||||
import enUS from './en-US.json';
|
||||
import zhCN from './zh-CN.json';
|
||||
|
||||
const { intl, getLocale } = createIntl?.({
|
||||
'en-US': enUS,
|
||||
'zh-CN': zhCN,
|
||||
}) || {
|
||||
intl: (id) => {
|
||||
return zhCN[id];
|
||||
},
|
||||
};
|
||||
|
||||
export { intl, enUS, zhCN, getLocale };
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"NotValidNodeData": "不是有效的节点数据",
|
||||
"SelectComponents": "选择组件",
|
||||
"CopyAndPaste": "复制",
|
||||
"Copy": "拷贝",
|
||||
"PasteToTheBottom": "粘贴至下方",
|
||||
"PasteToTheInside": "粘贴至内部",
|
||||
"Delete": "删除"
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"entry": {
|
||||
"AliLowCodeEngine": "../engine/src/index.ts",
|
||||
"ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts",
|
||||
"RaxSimulatorRenderer": "../rax-simulator-renderer/src/index.ts"
|
||||
"ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts"
|
||||
},
|
||||
"vendor": false,
|
||||
"devServer": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-ignitor",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"description": "点火器,bootstrap lce project",
|
||||
"main": "lib/index.js",
|
||||
"private": true,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-plugin-designer",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"description": "alibaba lowcode editor designer plugin",
|
||||
"files": [
|
||||
"es",
|
||||
|
@ -18,9 +18,9 @@
|
|||
],
|
||||
"author": "xiayang.xy",
|
||||
"dependencies": {
|
||||
"@alilc/lowcode-designer": "1.2.5",
|
||||
"@alilc/lowcode-editor-core": "1.2.5",
|
||||
"@alilc/lowcode-utils": "1.2.5",
|
||||
"@alilc/lowcode-designer": "1.3.0",
|
||||
"@alilc/lowcode-editor-core": "1.3.0",
|
||||
"@alilc/lowcode-utils": "1.3.0",
|
||||
"react": "^16.8.1",
|
||||
"react-dom": "^16.8.1"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-plugin-outline-pane",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"description": "Outline pane for Ali lowCode engine",
|
||||
"files": [
|
||||
"es",
|
||||
|
@ -13,8 +13,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@alifd/next": "^1.19.16",
|
||||
"@alilc/lowcode-types": "1.2.5",
|
||||
"@alilc/lowcode-utils": "1.2.5",
|
||||
"@alilc/lowcode-types": "1.3.0",
|
||||
"@alilc/lowcode-utils": "1.3.0",
|
||||
"classnames": "^2.2.6",
|
||||
"react": "^16",
|
||||
"react-dom": "^16.7.0",
|
||||
|
|
|
@ -77,6 +77,11 @@ export const matchTreeNode = (
|
|||
return matchTreeNode(childNode, keywords, filterOps);
|
||||
}).find(Boolean);
|
||||
|
||||
// 如果命中了子节点,需要将该节点展开
|
||||
if (matchChild && treeNode.expandable) {
|
||||
treeNode.setExpanded(true);
|
||||
}
|
||||
|
||||
treeNode.setFilterReult({
|
||||
filterWorking: true,
|
||||
matchChild,
|
||||
|
|
|
@ -356,7 +356,7 @@
|
|||
// 选中节点处理
|
||||
&.selected {
|
||||
& > .tree-node-title {
|
||||
background: var(--color-block-background-shallow);
|
||||
background: var(--color-block-background-light);
|
||||
}
|
||||
|
||||
& > .tree-node-branches::before {
|
||||
|
|
|
@ -34,7 +34,7 @@ class ModalTreeNodeView extends PureComponent<{
|
|||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
const rootTreeNode = this.rootTreeNode;
|
||||
const { rootTreeNode } = this;
|
||||
rootTreeNode.onExpandableChanged(() => {
|
||||
this.setState({
|
||||
treeChildren: rootTreeNode.children,
|
||||
|
@ -53,7 +53,7 @@ class ModalTreeNodeView extends PureComponent<{
|
|||
}
|
||||
|
||||
render() {
|
||||
const rootTreeNode = this.rootTreeNode;
|
||||
const { rootTreeNode } = this;
|
||||
const { expanded } = rootTreeNode;
|
||||
|
||||
const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode();
|
||||
|
@ -98,6 +98,9 @@ export default class TreeNodeView extends PureComponent<{
|
|||
conditionFlow: boolean;
|
||||
expandable: boolean;
|
||||
treeChildren: TreeNode[] | null;
|
||||
filterWorking: boolean;
|
||||
matchChild: boolean;
|
||||
matchSelf: boolean;
|
||||
} = {
|
||||
expanded: false,
|
||||
selected: false,
|
||||
|
@ -110,6 +113,9 @@ export default class TreeNodeView extends PureComponent<{
|
|||
conditionFlow: false,
|
||||
expandable: false,
|
||||
treeChildren: [],
|
||||
filterWorking: false,
|
||||
matchChild: false,
|
||||
matchSelf: false,
|
||||
};
|
||||
|
||||
eventOffCallbacks: Array<IPublicTypeDisposable | undefined> = [];
|
||||
|
@ -154,6 +160,10 @@ export default class TreeNodeView extends PureComponent<{
|
|||
treeChildren: treeNode.children,
|
||||
});
|
||||
});
|
||||
treeNode.onFilterResultChanged(() => {
|
||||
const { filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf } = treeNode.filterReult;
|
||||
this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf });
|
||||
});
|
||||
this.eventOffCallbacks.push(
|
||||
doc?.onDropLocationChanged(() => {
|
||||
this.setState({
|
||||
|
@ -216,7 +226,7 @@ export default class TreeNodeView extends PureComponent<{
|
|||
let shouldShowModalTreeNode: boolean = this.shouldShowModalTreeNode();
|
||||
|
||||
// filter 处理
|
||||
const { filterWorking, matchChild, matchSelf } = treeNode.filterReult;
|
||||
const { filterWorking, matchChild, matchSelf } = this.state;
|
||||
if (!isRootNode && filterWorking && !matchChild && !matchSelf) {
|
||||
// 条件过滤生效时,如果未命中本节点或子节点,则不展示该节点
|
||||
// 根节点始终展示
|
||||
|
|
|
@ -29,9 +29,15 @@ export default class TreeTitle extends PureComponent<{
|
|||
title: string;
|
||||
condition?: boolean;
|
||||
visible?: boolean;
|
||||
filterWorking: boolean;
|
||||
keywords: string;
|
||||
matchSelf: boolean;
|
||||
} = {
|
||||
editing: false,
|
||||
title: '',
|
||||
filterWorking: false,
|
||||
keywords: '',
|
||||
matchSelf: false,
|
||||
};
|
||||
|
||||
private lastInput?: HTMLInputElement;
|
||||
|
@ -100,6 +106,10 @@ export default class TreeTitle extends PureComponent<{
|
|||
visible: !hidden,
|
||||
});
|
||||
});
|
||||
treeNode.onFilterResultChanged(() => {
|
||||
const { filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf } = treeNode.filterReult;
|
||||
this.setState({ filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf });
|
||||
});
|
||||
}
|
||||
deleteClick = () => {
|
||||
const { treeNode } = this.props;
|
||||
|
@ -109,7 +119,7 @@ export default class TreeTitle extends PureComponent<{
|
|||
render() {
|
||||
const { treeNode, isModal } = this.props;
|
||||
const { pluginContext } = treeNode;
|
||||
const { editing } = this.state;
|
||||
const { editing, filterWorking, matchSelf, keywords } = this.state;
|
||||
const isCNode = !treeNode.isRoot();
|
||||
const { node } = treeNode;
|
||||
const { componentMeta } = node;
|
||||
|
@ -125,11 +135,9 @@ export default class TreeTitle extends PureComponent<{
|
|||
marginLeft: -indent,
|
||||
};
|
||||
}
|
||||
const { filterWorking, matchSelf, keywords } = treeNode.filterReult;
|
||||
const Extra = pluginContext.extraTitle;
|
||||
const { intlNode, common, config } = pluginContext;
|
||||
const Tip = common.editorCabin.Tip;
|
||||
const Title = common.editorCabin.Title;
|
||||
const { Tip, Title } = common.editorCabin;
|
||||
const couldHide = availableActions.includes('hide');
|
||||
const couldLock = availableActions.includes('lock');
|
||||
const couldUnlock = availableActions.includes('unlock');
|
||||
|
@ -253,7 +261,7 @@ class RenameBtn extends PureComponent<{
|
|||
}> {
|
||||
render() {
|
||||
const { intl, common } = this.props.treeNode.pluginContext;
|
||||
const Tip = common.editorCabin.Tip;
|
||||
const { Tip } = common.editorCabin;
|
||||
return (
|
||||
<div
|
||||
className="tree-node-rename-btn"
|
||||
|
@ -274,7 +282,7 @@ class LockBtn extends PureComponent<{
|
|||
render() {
|
||||
const { treeNode, locked } = this.props;
|
||||
const { intl, common } = this.props.treeNode.pluginContext;
|
||||
const Tip = common.editorCabin.Tip;
|
||||
const { Tip } = common.editorCabin;
|
||||
return (
|
||||
<div
|
||||
className="tree-node-lock-btn"
|
||||
|
@ -300,7 +308,7 @@ class HideBtn extends PureComponent<{
|
|||
render() {
|
||||
const { treeNode, hidden } = this.props;
|
||||
const { intl, common } = treeNode.pluginContext;
|
||||
const Tip = common.editorCabin.Tip;
|
||||
const { Tip } = common.editorCabin;
|
||||
return (
|
||||
<div
|
||||
className="tree-node-hide-btn"
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
# Rax Renderer
|
||||
|
||||
Rax 渲染模块。
|
||||
|
||||
## 安装
|
||||
|
||||
```
|
||||
$ npm install @alilc/lowcode-rax-renderer --save
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
```js
|
||||
import { createElement, render } from 'rax';
|
||||
import DriverUniversal from 'driver-universal';
|
||||
import RaxRenderer from '@ali/lowcode-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 }
|
||||
);
|
||||
```
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"plugins": [
|
||||
[
|
||||
"build-plugin-rax-component",
|
||||
{
|
||||
"type": "rax",
|
||||
"targets": ["web"]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
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 +0,0 @@
|
|||
App({});
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"pages": ["pages/index"],
|
||||
"window": {
|
||||
"defaultTitle": "demo"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<my-component></my-component>
|
|
@ -1,4 +0,0 @@
|
|||
Page({
|
||||
onLoad() {},
|
||||
onShow() {},
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"defaultTitle": "Miniapp Rax Text demo",
|
||||
"usingComponents": {
|
||||
"my-component": "../components/Target/index"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
App({});
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"pages": ["pages/index"],
|
||||
"window": {
|
||||
"title": "demo"
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
Page({
|
||||
onLoad() {},
|
||||
onShow() {},
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"title": "Wechat MiniProgram Rax Text demo",
|
||||
"usingComponents": {
|
||||
"my-component": "../components/Target/index"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<my-component></my-component>
|
|
@ -1,54 +0,0 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-rax-renderer",
|
||||
"version": "1.2.5",
|
||||
"description": "Rax renderer for Ali lowCode engine",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"miniappConfig": {
|
||||
"main": "lib/miniapp/index",
|
||||
"main:wechat": "lib/wechat-miniprogram/index"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"es",
|
||||
"lib"
|
||||
],
|
||||
"keywords": [
|
||||
"low-code",
|
||||
"lowcode",
|
||||
"Rax"
|
||||
],
|
||||
"engines": {
|
||||
"npm": ">=3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prop-types": "^15.7.2",
|
||||
"rax": "^1.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "build-scripts start",
|
||||
"build": "build-scripts build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alilc/lowcode-renderer-core": "1.2.5",
|
||||
"@alilc/lowcode-utils": "1.2.5",
|
||||
"rax-find-dom-node": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alib/build-scripts": "^0.1.0",
|
||||
"build-plugin-rax-component": "^0.2.11",
|
||||
"driver-universal": "^3.1.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"repository": {
|
||||
"type": "http",
|
||||
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-renderer"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/alibaba/lowcode-engine/#readme",
|
||||
"gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6",
|
||||
"bugs": "https://github.com/alibaba/lowcode-engine/issues"
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
// @ts-nocheck
|
||||
|
||||
import { Component, forwardRef } from 'rax';
|
||||
import PropTypes from 'prop-types';
|
||||
import { AppHelper } from '@alilc/lowcode-utils';
|
||||
import { utils, contextFactory } from '@alilc/lowcode-renderer-core';
|
||||
import componentRendererFactory from '../renderer/component';
|
||||
import blockRendererFactory from '../renderer/block';
|
||||
|
||||
const { forEach, isFileSchema } = utils;
|
||||
|
||||
export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) {
|
||||
// 自定义组件需要有自己独立的appHelper
|
||||
const appHelper = new AppHelper(config);
|
||||
const CompRenderer = componentRendererFactory();
|
||||
const BlockRenderer = blockRendererFactory();
|
||||
const AppContext = contextFactory();
|
||||
|
||||
class LNCompView extends Component {
|
||||
static displayName = 'LceCompFactory';
|
||||
|
||||
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?.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 (
|
||||
<CompRenderer
|
||||
{...props}
|
||||
__appHelper={appHelper}
|
||||
__components={{ ...components, Component: CompRenderer, Block: BlockRenderer }}
|
||||
__componentsMap={componentsMap}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</AppContext.Consumer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ResComp = forwardRef((props, ref) => <LNCompView {...props} forwardedRef={ref} />);
|
||||
forEach(schema.static, (val, key) => {
|
||||
ResComp[key] = val;
|
||||
});
|
||||
ResComp.version = config.version || '0.0.0';
|
||||
return ResComp;
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
import { Component, PureComponent, createElement, createContext, forwardRef } from 'rax';
|
||||
import findDOMNode from 'rax-find-dom-node';
|
||||
import {
|
||||
adapter,
|
||||
addonRendererFactory,
|
||||
tempRendererFactory,
|
||||
rendererFactory,
|
||||
} from '@alilc/lowcode-renderer-core';
|
||||
import pageRendererFactory from './renderer/page';
|
||||
import componentRendererFactory from './renderer/component';
|
||||
import blockRendererFactory from './renderer/block';
|
||||
import CompFactory from './hoc/compFactory';
|
||||
|
||||
adapter.setRuntime({
|
||||
Component,
|
||||
PureComponent,
|
||||
createContext,
|
||||
createElement,
|
||||
forwardRef,
|
||||
findDOMNode,
|
||||
});
|
||||
|
||||
adapter.setRenderers({
|
||||
PageRenderer: pageRendererFactory(),
|
||||
ComponentRenderer: componentRendererFactory(),
|
||||
BlockRenderer: blockRendererFactory(),
|
||||
AddonRenderer: addonRendererFactory(),
|
||||
TempRenderer: tempRendererFactory(),
|
||||
});
|
||||
|
||||
function factory() {
|
||||
const Renderer = rendererFactory();
|
||||
return class extends Renderer {
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
isValidComponent(obj: any) {
|
||||
return obj?.prototype?.setState || obj?.prototype instanceof Component;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const RaxRenderer: any = factory();
|
||||
const Engine: any = RaxRenderer;
|
||||
|
||||
export {
|
||||
Engine,
|
||||
CompFactory,
|
||||
};
|
||||
|
||||
export default RaxRenderer;
|
|
@ -1,25 +0,0 @@
|
|||
import { blockRendererFactory, types } from '@alilc/lowcode-renderer-core';
|
||||
|
||||
const raxBlockRendererFactory: () => any = () => {
|
||||
const OriginBlock = blockRendererFactory();
|
||||
return class BlockRenderer extends OriginBlock {
|
||||
render() {
|
||||
// @ts-ignore
|
||||
const that: types.IRenderer = this;
|
||||
const { __schema, __components } = that.props;
|
||||
if (that.__checkSchema(__schema)) {
|
||||
return '区块 schema 结构异常!';
|
||||
}
|
||||
that.__debug(`render - ${__schema.fileName}`);
|
||||
|
||||
const children = ((context) => {
|
||||
that.context = context;
|
||||
that.__generateCtx({});
|
||||
that.__render();
|
||||
return that.__renderComp((__components as any)?.Block, { blockContext: that });
|
||||
});
|
||||
return that.__renderContextConsumer(children);
|
||||
}
|
||||
};
|
||||
};
|
||||
export default raxBlockRendererFactory;
|
|
@ -1,37 +0,0 @@
|
|||
import { componentRendererFactory, types } from '@alilc/lowcode-renderer-core';
|
||||
|
||||
const raxComponentRendererFactory: () => any = () => {
|
||||
const OriginComponent = componentRendererFactory();
|
||||
return class ComponentRenderer extends OriginComponent {
|
||||
render() {
|
||||
// @ts-ignore
|
||||
const that: types.IRenderer = this;
|
||||
const { __schema, __components } = that.props;
|
||||
if (that.__checkSchema(__schema)) {
|
||||
return '自定义组件 schema 结构异常!';
|
||||
}
|
||||
that.__debug(`render - ${__schema.fileName}`);
|
||||
|
||||
const { noContainer } = that.__parseData(__schema.props);
|
||||
|
||||
const children = ((context) => {
|
||||
that.context = context;
|
||||
that.__generateCtx({ component: that });
|
||||
that.__render();
|
||||
// 传 null,使用内置的 div 来渲染,解决在页面中渲染 vc-component 报错的问题
|
||||
return that.__renderComp(null, {
|
||||
compContext: that,
|
||||
blockContext: that,
|
||||
});
|
||||
});
|
||||
const content = that.__renderContextConsumer(children);
|
||||
|
||||
if (noContainer) {
|
||||
return content;
|
||||
}
|
||||
|
||||
return that.__renderContent(content);
|
||||
}
|
||||
};
|
||||
};
|
||||
export default raxComponentRendererFactory;
|
|
@ -1,38 +0,0 @@
|
|||
import { pageRendererFactory, types } from '@alilc/lowcode-renderer-core';
|
||||
|
||||
const raxPageRendererFactory: () => any = () => {
|
||||
const OriginPage = pageRendererFactory();
|
||||
return class PageRenderer extends OriginPage {
|
||||
async componentDidUpdate() {
|
||||
// @ts-ignore
|
||||
super.componentDidUpdate(...arguments);
|
||||
}
|
||||
|
||||
render() {
|
||||
// @ts-ignore
|
||||
const that: types.IRenderer = this;
|
||||
const { __schema, __components } = that.props;
|
||||
if (that.__checkSchema(__schema)) {
|
||||
return '页面 schema 结构异常!';
|
||||
}
|
||||
that.__debug(`render - ${__schema?.fileName}`);
|
||||
|
||||
const { Page } = __components as any;
|
||||
if (Page) {
|
||||
const children = ((context) => {
|
||||
that.context = context;
|
||||
that.__render();
|
||||
return that.__renderComp(Page, { pageContext: that });
|
||||
});
|
||||
return that.__renderContextConsumer(children);
|
||||
}
|
||||
|
||||
return that.__renderContent(that.__renderContextConsumer((context) => {
|
||||
that.context = context;
|
||||
return that.__renderContextProvider({ pageContext: that });
|
||||
}));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default raxPageRendererFactory;
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["es2015", "dom"],
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"strict": false,
|
||||
"strictPropertyInitialization": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "createElement",
|
||||
"importHelpers": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"sourceMap": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib"
|
||||
},
|
||||
"exclude": ["test", "lib", "es", "node_modules"],
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"plugins": [
|
||||
["@babel/plugin-transform-react-jsx", {
|
||||
"pragma": "createElement", // default pragma is React.createElement
|
||||
"pragmaFrag": "createFragment", // default is React.Fragment
|
||||
"throwIfNamespace": false // defaults to true
|
||||
}]
|
||||
]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('../../babel.config');
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"plugins": ["@alilc/build-plugin-lce", "./build.plugin.js"]
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
module.exports = ({ onGetWebpackConfig }) => {
|
||||
onGetWebpackConfig((config) => {
|
||||
config.performance.hints(false);
|
||||
});
|
||||
};
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"entry": {
|
||||
"rax-simulator-renderer": "src/index"
|
||||
},
|
||||
"sourceMap": true,
|
||||
"library": "___RaxSimulatorRenderer___",
|
||||
"libraryTarget": "umd",
|
||||
"externals": {
|
||||
"react": "var window.React",
|
||||
"react-dom": "var window.ReactDOM",
|
||||
"prop-types": "var window.PropTypes",
|
||||
"@alifd/next": "var Next",
|
||||
"@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt",
|
||||
"rax": "var window.Rax",
|
||||
"moment": "var moment",
|
||||
"lodash": "var _"
|
||||
},
|
||||
"polyfill": false,
|
||||
"outputDir": "dist",
|
||||
"vendor": false,
|
||||
"ignoreHtmlTemplate": true,
|
||||
"plugins": [
|
||||
"build-plugin-react-app",
|
||||
[
|
||||
"build-plugin-fusion",
|
||||
{
|
||||
"externalNext": "umd"
|
||||
}
|
||||
],
|
||||
[
|
||||
"build-plugin-moment-locales",
|
||||
{
|
||||
"locales": ["zh-cn"]
|
||||
}
|
||||
],
|
||||
"./build.plugin.js"
|
||||
]
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
{
|
||||
"name": "@alilc/lowcode-rax-simulator-renderer",
|
||||
"version": "1.2.5",
|
||||
"description": "rax simulator renderer for alibaba lowcode designer",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build",
|
||||
"build:umd": "build-scripts build --config build.umd.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alilc/lowcode-designer": "1.2.5",
|
||||
"@alilc/lowcode-rax-renderer": "1.2.5",
|
||||
"@alilc/lowcode-types": "1.2.5",
|
||||
"@alilc/lowcode-utils": "1.2.5",
|
||||
"classnames": "^2.2.6",
|
||||
"driver-universal": "^3.1.3",
|
||||
"history": "^5.0.0",
|
||||
"lodash": "^4.17.19",
|
||||
"mobx": "^6.3.0",
|
||||
"mobx-react": "^7.2.0",
|
||||
"path-to-regexp": "3.2.0",
|
||||
"rax-find-dom-node": "^1.0.0",
|
||||
"react": "^16",
|
||||
"react-dom": "^16.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alib/build-scripts": "^0.1.18",
|
||||
"@babel/plugin-transform-react-jsx": "^7.10.4",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/node": "^13.7.1",
|
||||
"@types/rax": "^1.0.0",
|
||||
"@types/react": "^16",
|
||||
"@types/react-dom": "^16",
|
||||
"build-plugin-rax-component": "^0.2.11"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rax": "^1.1.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"repository": {
|
||||
"type": "http",
|
||||
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-simulator-renderer"
|
||||
},
|
||||
"homepage": "https://github.com/alibaba/lowcode-engine/#readme",
|
||||
"gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6",
|
||||
"bugs": "https://github.com/alibaba/lowcode-engine/issues"
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
import { Component } from 'rax';
|
||||
import lg from '@ali/vu-logger';
|
||||
|
||||
import './index.less';
|
||||
|
||||
export class UnknownComponent extends Component {
|
||||
props: {
|
||||
_componentName: string;
|
||||
};
|
||||
|
||||
render() {
|
||||
lg.log('ERROR_NO_COMPONENT_VIEW');
|
||||
lg.error('Error component information:', this.props);
|
||||
return <div className="engine-unknow-component">组件 {this.props._componentName} 无视图,请打开控制台排查</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export class FaultComponent extends Component {
|
||||
props: {
|
||||
_componentName: string;
|
||||
};
|
||||
|
||||
render() {
|
||||
return <div className="engine-fault-component">组件 {this.props._componentName} 渲染错误,请打开控制台排查</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export class HiddenComponent extends Component {
|
||||
render() {
|
||||
return <div className="engine-hidden-component">在本页面不显示</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default { FaultComponent, HiddenComponent, UnknownComponent };
|
|
@ -1,251 +0,0 @@
|
|||
import { Component } from 'rax';
|
||||
|
||||
class Leaf extends Component {
|
||||
static displayName = 'Leaf';
|
||||
|
||||
static componentMetadata = {
|
||||
componentName: 'Leaf',
|
||||
configure: {
|
||||
props: [{
|
||||
name: 'children',
|
||||
setter: 'StringSetter',
|
||||
}],
|
||||
// events/className/style/general/directives
|
||||
supports: false,
|
||||
},
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
export default Leaf;
|
||||
|
||||
// import { Component, createElement } from 'rax';
|
||||
// import findDOMNode from 'rax-find-dom-node';
|
||||
// import { each, get, omit } from 'lodash';
|
||||
// import { getView, setNativeNode, createNodeStyleSheet } from '../renderUtils';
|
||||
|
||||
// import { FaultComponent, HiddenComponent, UnknownComponent } from '../UnusualComponent';
|
||||
|
||||
// export interface ILeaf {
|
||||
// leaf: any;
|
||||
// }
|
||||
// export default class Leaf extends Component<ILeaf, {}> {
|
||||
// static displayName = 'Leaf';
|
||||
|
||||
// state = {
|
||||
// hasError: false,
|
||||
// };
|
||||
|
||||
// willDetach: any[];
|
||||
|
||||
// styleSheet: any;
|
||||
|
||||
// context: any;
|
||||
// refs: any;
|
||||
|
||||
// componentWillMount() {
|
||||
// const { leaf } = this.props;
|
||||
// this.willDetach = [
|
||||
// leaf.onPropsChange(() => {
|
||||
// // 强制刷新
|
||||
// this.setState(this.state);
|
||||
// }),
|
||||
// leaf.onChildrenChange(() => {
|
||||
// // 强制刷新
|
||||
// this.setState(this.state);
|
||||
// }),
|
||||
// leaf.onStatusChange((status: { dropping: boolean }, field: string) => {
|
||||
// // console.log({...status}, field)
|
||||
// if (status.dropping !== false) {
|
||||
// // 当 dropping 为 Insertion 对象时,强制渲染会出错,原因待查
|
||||
// return;
|
||||
// }
|
||||
// if (field === 'dragging' || field === 'dropping' || field === 'pseudo' || field === 'visibility') {
|
||||
// // 强制刷新
|
||||
// this.setState(this.state);
|
||||
// }
|
||||
// }),
|
||||
// ];
|
||||
|
||||
// /**
|
||||
// * while props replaced
|
||||
// * bind the new event on it
|
||||
// */
|
||||
// leaf.onPropsReplace(() => {
|
||||
// this.willDetach[0]();
|
||||
// this.willDetach[0] = leaf.onPropsChange(() => {
|
||||
// // 强制刷新
|
||||
// this.setState(this.state);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
// componentDidMount() {
|
||||
// this.modifyDOM();
|
||||
// }
|
||||
|
||||
// shouldComponentUpdate() {
|
||||
// // forceUpdate 的替代方案
|
||||
// return true;
|
||||
// // const pageCanRefresh = this.leaf.getPage().canRefresh();
|
||||
// // if (pageCanRefresh) {
|
||||
// // return pageCanRefresh;
|
||||
// // }
|
||||
// // const getExtProps = obj => {
|
||||
// // const { leaf, ...props } = obj;
|
||||
// // return props;
|
||||
// // };
|
||||
// // return !shallowEqual(getExtProps(this.props), getExtProps(nextProps));
|
||||
// }
|
||||
|
||||
// componentDidUpdate() {
|
||||
// this.modifyDOM();
|
||||
// }
|
||||
|
||||
// componentWillUnmount() {
|
||||
// if (this.willDetach) {
|
||||
// this.willDetach.forEach((off) => off());
|
||||
// }
|
||||
// setNativeNode(this.props.leaf, null);
|
||||
// }
|
||||
|
||||
// componentDidCatch() {
|
||||
// this.setState({ hasError: true }, () => {
|
||||
// console.log('error');
|
||||
// });
|
||||
// }
|
||||
|
||||
// modifyDOM() {
|
||||
// const shell = findDOMNode(this);
|
||||
// const { leaf } = this.props;
|
||||
// // 与 React 不同,rax 的 findDOMNode 找不到节点时,
|
||||
// // shell 会是 <!-- empty -->,而不是 null,
|
||||
// // 所以这里进行是否为注释的判断
|
||||
// if (shell && shell.nodeType !== window.Node.COMMENT_NODE) {
|
||||
// setNativeNode(leaf, shell);
|
||||
// if (leaf.getStatus('dragging')) {
|
||||
// get(shell, 'classList').add('engine-dragging');
|
||||
// } else {
|
||||
// get(shell, 'classList').remove('engine-dragging');
|
||||
// }
|
||||
// each(get(shell, 'classList'), (cls) => {
|
||||
// if (cls.substring(0, 8) === '-pseudo-') {
|
||||
// get(shell, 'classList').remove(cls);
|
||||
// }
|
||||
// });
|
||||
// const pseudo = leaf.getStatus('pseudo');
|
||||
// if (pseudo) {
|
||||
// get(shell, 'classList').add(`-pseudo-${pseudo}`);
|
||||
// }
|
||||
// } else {
|
||||
// setNativeNode(leaf, null);
|
||||
// }
|
||||
// }
|
||||
|
||||
// render() {
|
||||
// const props = omit(this.props, ['leaf']);
|
||||
// const { leaf } = this.props;
|
||||
// const componentName = leaf.getComponentName();
|
||||
|
||||
// const View = getView(componentName);
|
||||
|
||||
// const newProps = {
|
||||
// _componentName: componentName,
|
||||
// };
|
||||
|
||||
// if (!View) {
|
||||
// return createElement(UnknownComponent, {
|
||||
// // _componentName: componentName,
|
||||
// ...newProps,
|
||||
// });
|
||||
// }
|
||||
|
||||
// let staticProps = {
|
||||
// ...leaf.getStaticProps(false),
|
||||
// ...props,
|
||||
// _componentName: componentName,
|
||||
// _leaf: leaf,
|
||||
// componentId: leaf.getId(),
|
||||
// };
|
||||
|
||||
// if (!leaf.isVisibleInPane()) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// if (!leaf.isVisible()) {
|
||||
// return createElement(HiddenComponent, {
|
||||
// ...staticProps,
|
||||
// });
|
||||
// }
|
||||
|
||||
// if (this.state.hasError) {
|
||||
// return createElement(FaultComponent, {
|
||||
// // _componentName: componentName,
|
||||
// ...newProps,
|
||||
// });
|
||||
// }
|
||||
|
||||
// if (this.styleSheet) {
|
||||
// this.styleSheet.parentNode.removeChild(this.styleSheet);
|
||||
// }
|
||||
|
||||
// this.styleSheet = createNodeStyleSheet(staticProps);
|
||||
|
||||
// if (leaf.ableToModifyChildren()) {
|
||||
// const children = leaf
|
||||
// .getChildren()
|
||||
// .filter((child: any) => child.getComponentName() !== 'Slot')
|
||||
// .map((child: any) =>
|
||||
// createElement(Leaf, {
|
||||
// key: child.getId(),
|
||||
// leaf: child,
|
||||
// }),
|
||||
// );
|
||||
// // const insertion = leaf.getStatus('dropping');
|
||||
// // InsertionGhost 都是React节点,用Rax渲染会报错,后面这些节点需要通过Rax组件来实现
|
||||
// // if (children.length < 1 && insertion && insertion.getIndex() !== null) {
|
||||
|
||||
// // //children = [];
|
||||
// // children = [<InsertionGhost key="insertion" />];
|
||||
// // } else if (insertion && insertion.isNearEdge()) {
|
||||
// // if (insertion.isNearAfter()) {
|
||||
// // children.push(<InsertionGhost key="insertion" />);
|
||||
// // } else {
|
||||
// // children.unshift(<InsertionGhost key="insertion" />);
|
||||
// // }
|
||||
// // }
|
||||
// staticProps = {
|
||||
// ...staticProps,
|
||||
// ...this.processSlots(this.props.leaf.getChildren()),
|
||||
// };
|
||||
|
||||
// return createElement(
|
||||
// View,
|
||||
// {
|
||||
// ...staticProps,
|
||||
// },
|
||||
// children,
|
||||
// );
|
||||
// }
|
||||
|
||||
// return createElement(View, {
|
||||
// ...staticProps,
|
||||
// });
|
||||
// }
|
||||
|
||||
// processSlots(children: Rax.RaxNodeArray) {
|
||||
// const slots: any = {};
|
||||
// children &&
|
||||
// children.length &&
|
||||
// children.forEach((child: any) => {
|
||||
// if (child.getComponentName() === 'Slot') {
|
||||
// slots[child.getPropValue('slotName')] = <Leaf key={child.getId()} leaf={child} />;
|
||||
// }
|
||||
// });
|
||||
// return slots;
|
||||
// }
|
||||
// }
|
|
@ -1,83 +0,0 @@
|
|||
import { isObject } from 'lodash';
|
||||
import { css } from '@alilc/lowcode-utils';
|
||||
|
||||
const { toCss } = css;
|
||||
const engine = (window as any).VisualEngine;
|
||||
const { Trunk, Viewport } = engine;
|
||||
|
||||
export const NativeNodeCache: any = {};
|
||||
|
||||
function ucfirst(s: string) {
|
||||
return s.charAt(0).toUpperCase() + s.substring(1);
|
||||
}
|
||||
|
||||
export function shallowEqual(obj: { [key: string]: string }, tObj: { [key: string]: string }) {
|
||||
for (const i in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, i) && obj[i] !== tObj[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function createNodeStyleSheet(props: any) {
|
||||
if (props && props.fieldId) {
|
||||
let styleProp = props.__style__;
|
||||
|
||||
if (isObject(styleProp)) {
|
||||
styleProp = toCss(styleProp);
|
||||
}
|
||||
|
||||
if (typeof styleProp === 'string') {
|
||||
const s = document.createElement('style');
|
||||
const cssId = `_style_pesudo_${ props.fieldId}`;
|
||||
const cssClass = `_css_pesudo_${ props.fieldId}`;
|
||||
|
||||
props.className = cssClass;
|
||||
s.setAttribute('type', 'text/css');
|
||||
s.setAttribute('id', cssId);
|
||||
document.getElementsByTagName('head')[0].appendChild(s);
|
||||
|
||||
s.appendChild(
|
||||
document.createTextNode(
|
||||
styleProp
|
||||
.replace(/(\d+)rpx/g, (a, b) => {
|
||||
return `${b / 2}px`;
|
||||
})
|
||||
.replace(/:root/g, `.${ cssClass}`),
|
||||
),
|
||||
);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function setNativeNode(leaf: any, node: Rax.RaxNode) {
|
||||
const id = leaf.getId();
|
||||
if (NativeNodeCache[id] === node) {
|
||||
return;
|
||||
}
|
||||
NativeNodeCache[id] = node;
|
||||
leaf.mountChange();
|
||||
}
|
||||
|
||||
export function getView(componentName: string) {
|
||||
// let view = new Trunk().getPrototypeView(componentName);
|
||||
let view = Trunk.getPrototypeView(componentName);
|
||||
if (!view) {
|
||||
return null;
|
||||
}
|
||||
const viewport = Viewport.getViewport();
|
||||
if (viewport) {
|
||||
const [mode, device] = viewport.split('-', 2).map(ucfirst);
|
||||
if (view.hasOwnProperty(device)) {
|
||||
view = view[device];
|
||||
}
|
||||
|
||||
if (view.hasOwnProperty(mode)) {
|
||||
view = view[mode];
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
import { Component } from 'rax';
|
||||
|
||||
class Slot extends Component {
|
||||
static displayName = 'Slot';
|
||||
|
||||
static componentMetadata = {
|
||||
componentName: 'Slot',
|
||||
configure: {
|
||||
props: [{
|
||||
name: '___title',
|
||||
title: {
|
||||
type: 'i18n',
|
||||
'en-US': 'Slot Title',
|
||||
'zh-CN': '插槽标题',
|
||||
},
|
||||
setter: 'StringSetter',
|
||||
defaultValue: '插槽容器',
|
||||
}, {
|
||||
name: '___params',
|
||||
title: {
|
||||
type: 'i18n',
|
||||
'en-US': 'Slot Params',
|
||||
'zh-CN': '插槽入参',
|
||||
},
|
||||
setter: {
|
||||
componentName: 'ArraySetter',
|
||||
props: {
|
||||
itemSetter: {
|
||||
componentName: 'StringSetter',
|
||||
props: {
|
||||
placeholder: {
|
||||
type: 'i18n',
|
||||
'zh-CN': '参数名称',
|
||||
'en-US': 'Argument Name',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}],
|
||||
// events/className/style/general/directives
|
||||
supports: false,
|
||||
},
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
return (
|
||||
<div className="lc-container">{children}</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Slot;
|
|
@ -1,4 +0,0 @@
|
|||
// NOTE: 仅做类型标注,切勿做其它用途
|
||||
import { BuiltinSimulatorHost } from '@alilc/lowcode-designer';
|
||||
|
||||
export const host: BuiltinSimulatorHost = (window as any).LCSimulatorHost;
|
|
@ -1,2 +0,0 @@
|
|||
declare module 'rax-find-dom-node';
|
||||
declare module '@alilc/lowcode-rax-renderer/lib/index';
|
|
@ -1,7 +0,0 @@
|
|||
import renderer from './renderer';
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).SimulatorRenderer = renderer;
|
||||
}
|
||||
|
||||
export default renderer;
|
|
@ -1,288 +0,0 @@
|
|||
// Inspired by react-router and universal-router
|
||||
import { useState, useEffect, useLayoutEffect, createElement } from 'rax';
|
||||
import pathToRegexp from 'path-to-regexp';
|
||||
|
||||
const cache = {};
|
||||
function decodeParam(val) {
|
||||
try {
|
||||
return decodeURIComponent(val);
|
||||
} catch (err) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
function matchPath(route, pathname, parentParams) {
|
||||
let { path, routes, exact: end = true, strict = false, sensitive = false } = route;
|
||||
// If not has path or has routes that should do not exact match
|
||||
if (path == null || routes) {
|
||||
end = false;
|
||||
}
|
||||
|
||||
// Default path is empty
|
||||
path = path || '';
|
||||
|
||||
const regexpCacheKey = `${path}|${end}|${strict}|${sensitive}`;
|
||||
const keysCacheKey = `${regexpCacheKey }|`;
|
||||
|
||||
let regexp = cache[regexpCacheKey];
|
||||
const keys = cache[keysCacheKey] || [];
|
||||
|
||||
if (!regexp) {
|
||||
regexp = pathToRegexp(path, keys, {
|
||||
end,
|
||||
strict,
|
||||
sensitive,
|
||||
});
|
||||
cache[regexpCacheKey] = regexp;
|
||||
cache[keysCacheKey] = keys;
|
||||
}
|
||||
|
||||
const result = regexp.exec(pathname);
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const url = result[0];
|
||||
const params = { ...parentParams, history: router.history, location: router.history.location };
|
||||
|
||||
for (let i = 1; i < result.length; i++) {
|
||||
const key = keys[i - 1];
|
||||
const prop = key.name;
|
||||
const value = result[i];
|
||||
if (value !== undefined || !Object.prototype.hasOwnProperty.call(params, prop)) {
|
||||
if (key.repeat) {
|
||||
params[prop] = value ? value.split(key.delimiter).map(decodeParam) : [];
|
||||
} else {
|
||||
params[prop] = value ? decodeParam(value) : value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
path: !end && url.charAt(url.length - 1) === '/' ? url.slice(1) : url,
|
||||
params,
|
||||
};
|
||||
}
|
||||
|
||||
function matchRoute(route, baseUrl, pathname, parentParams) {
|
||||
let matched;
|
||||
let childMatches;
|
||||
let childIndex = 0;
|
||||
|
||||
return {
|
||||
next() {
|
||||
if (!matched) {
|
||||
matched = matchPath(route, pathname, parentParams);
|
||||
|
||||
if (matched) {
|
||||
return {
|
||||
done: false,
|
||||
$: {
|
||||
route,
|
||||
baseUrl,
|
||||
path: matched.path,
|
||||
params: matched.params,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (matched && route.routes) {
|
||||
while (childIndex < route.routes.length) {
|
||||
if (!childMatches) {
|
||||
const childRoute = route.routes[childIndex];
|
||||
childRoute.parent = route;
|
||||
|
||||
childMatches = matchRoute(
|
||||
childRoute,
|
||||
baseUrl + matched.path,
|
||||
pathname.slice(matched.path.length),
|
||||
matched.params,
|
||||
);
|
||||
}
|
||||
|
||||
const childMatch = childMatches.next();
|
||||
if (!childMatch.done) {
|
||||
return {
|
||||
done: false,
|
||||
$: childMatch.$,
|
||||
};
|
||||
}
|
||||
|
||||
childMatches = null;
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return { done: true };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let _initialized = false;
|
||||
let _routerConfig = null;
|
||||
const router = {
|
||||
history: null,
|
||||
handles: [],
|
||||
errorHandler() { },
|
||||
addHandle(handle) {
|
||||
return router.handles.push(handle);
|
||||
},
|
||||
removeHandle(handleId) {
|
||||
router.handles[handleId - 1] = null;
|
||||
},
|
||||
triggerHandles(component) {
|
||||
router.handles.forEach((handle) => {
|
||||
handle && handle(component);
|
||||
});
|
||||
},
|
||||
match(fullpath) {
|
||||
if (fullpath == null) return;
|
||||
|
||||
router.fullpath = fullpath;
|
||||
|
||||
const parent = router.root;
|
||||
const matched = matchRoute(
|
||||
parent,
|
||||
parent.path,
|
||||
fullpath,
|
||||
);
|
||||
|
||||
function next(parent) {
|
||||
const current = matched.next();
|
||||
|
||||
if (current.done) {
|
||||
const error = new Error(`No match for ${fullpath}`);
|
||||
return router.errorHandler(error, router.history.location);
|
||||
}
|
||||
|
||||
let { component } = current.$.route;
|
||||
if (typeof component === 'function') {
|
||||
component = component(current.$.params, router.history.location);
|
||||
}
|
||||
if (component instanceof Promise) {
|
||||
// Lazy loading component by import('./Foo')
|
||||
return component.then((component) => {
|
||||
// Check current fullpath avoid router has changed before lazy loading complete
|
||||
if (fullpath === router.fullpath) {
|
||||
router.triggerHandles(component);
|
||||
}
|
||||
});
|
||||
} else if (component != null) {
|
||||
router.triggerHandles(component);
|
||||
return component;
|
||||
} else {
|
||||
return next(parent);
|
||||
}
|
||||
}
|
||||
|
||||
return next(parent);
|
||||
},
|
||||
};
|
||||
|
||||
function matchLocation({ pathname }) {
|
||||
router.match(pathname);
|
||||
}
|
||||
|
||||
|
||||
function getInitialComponent(routerConfig) {
|
||||
let InitialComponent = [];
|
||||
|
||||
if (_routerConfig === null) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (!routerConfig) {
|
||||
throw new Error('Error: useRouter should have routerConfig, see: https://www.npmjs.com/package/rax-use-router.');
|
||||
}
|
||||
if (!routerConfig.history || !routerConfig.routes) {
|
||||
throw new Error('Error: routerConfig should contain history and routes, see: https://www.npmjs.com/package/rax-use-router.');
|
||||
}
|
||||
}
|
||||
_routerConfig = routerConfig;
|
||||
}
|
||||
if (_routerConfig.InitialComponent) {
|
||||
InitialComponent = _routerConfig.InitialComponent;
|
||||
}
|
||||
router.history = _routerConfig.history;
|
||||
|
||||
return InitialComponent;
|
||||
}
|
||||
|
||||
let unlisten = null;
|
||||
let handleId = null;
|
||||
let pathes = '';
|
||||
export function useRouter(routerConfig) {
|
||||
const [component, setComponent] = useState(getInitialComponent(routerConfig));
|
||||
|
||||
let newPathes = '';
|
||||
if (routerConfig) {
|
||||
_routerConfig = routerConfig;
|
||||
const { routes } = _routerConfig;
|
||||
router.root = Array.isArray(routes) ? { routes } : routes;
|
||||
if (Array.isArray(routes)) {
|
||||
newPathes = routes.map(it => it.path).join(',');
|
||||
} else {
|
||||
newPathes = routes.path;
|
||||
}
|
||||
}
|
||||
if (_initialized && _routerConfig.history) {
|
||||
if (newPathes !== pathes) {
|
||||
matchLocation(_routerConfig.history.location);
|
||||
pathes = newPathes;
|
||||
}
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (unlisten) {
|
||||
unlisten();
|
||||
unlisten = null;
|
||||
}
|
||||
|
||||
if (handleId) {
|
||||
router.removeHandle(handleId);
|
||||
handleId = null;
|
||||
}
|
||||
|
||||
const { history } = _routerConfig;
|
||||
const { routes } = _routerConfig;
|
||||
|
||||
router.root = Array.isArray(routes) ? { routes } : routes;
|
||||
|
||||
handleId = router.addHandle((component) => {
|
||||
setComponent(component);
|
||||
});
|
||||
|
||||
// Init path match
|
||||
if (_initialized || !_routerConfig.InitialComponent) {
|
||||
matchLocation(history.location);
|
||||
pathes = newPathes;
|
||||
}
|
||||
|
||||
unlisten = history.listen(({ location }) => {
|
||||
matchLocation(location);
|
||||
pathes = newPathes;
|
||||
});
|
||||
|
||||
_initialized = true;
|
||||
|
||||
return () => {
|
||||
pathes = '';
|
||||
router.removeHandle(handleId);
|
||||
handleId = null;
|
||||
unlisten();
|
||||
unlisten = null;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { component };
|
||||
}
|
||||
|
||||
export function withRouter(Component) {
|
||||
function Wrapper(props) {
|
||||
const { history } = router;
|
||||
return createElement(Component, { ...props, history, location: history.location });
|
||||
}
|
||||
|
||||
Wrapper.displayName = `withRouter(${ Component.displayName || Component.name })`;
|
||||
Wrapper.WrappedComponent = Component;
|
||||
return Wrapper;
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
import RaxRenderer from '@alilc/lowcode-rax-renderer';
|
||||
import { History } from 'history';
|
||||
import { Component, createElement, Fragment } from 'rax';
|
||||
import { useRouter } from './rax-use-router';
|
||||
import { DocumentInstance, SimulatorRendererContainer } from './renderer';
|
||||
import './renderer.less';
|
||||
import { uniqueId } from '@alilc/lowcode-utils';
|
||||
import { GlobalEvent } from '@alilc/lowcode-types';
|
||||
import { host } from './host';
|
||||
|
||||
// patch cloneElement avoid lost keyProps
|
||||
const originCloneElement = (window as any).Rax.cloneElement;
|
||||
(window as any).Rax.cloneElement = (child: any, { _leaf, ...props }: any = {}, ...rest: any[]) => {
|
||||
if (child.ref && props.ref) {
|
||||
const dRef = props.ref;
|
||||
const cRef = child.ref;
|
||||
props.ref = (x: any) => {
|
||||
if (cRef) {
|
||||
if (typeof cRef === 'function') {
|
||||
cRef(x);
|
||||
} else {
|
||||
try {
|
||||
cRef.current = x;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dRef) {
|
||||
if (typeof dRef === 'function') {
|
||||
dRef(x);
|
||||
} else {
|
||||
try {
|
||||
dRef.current = x;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return originCloneElement(child, props, ...rest);
|
||||
};
|
||||
|
||||
export default class SimulatorRendererView extends Component<{ rendererContainer: SimulatorRendererContainer }> {
|
||||
private unlisten: any;
|
||||
|
||||
componentDidMount() {
|
||||
const { rendererContainer } = this.props;
|
||||
this.unlisten = rendererContainer.onLayoutChange(() => {
|
||||
this.forceUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.unlisten) {
|
||||
this.unlisten();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { rendererContainer } = this.props;
|
||||
return (
|
||||
<Layout rendererContainer={rendererContainer}>
|
||||
<Routes rendererContainer={rendererContainer} history={rendererContainer.history} />
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const Routes = (props: {
|
||||
rendererContainer: SimulatorRendererContainer;
|
||||
history: History;
|
||||
}) => {
|
||||
const { rendererContainer, history } = props;
|
||||
const { documentInstances } = rendererContainer;
|
||||
|
||||
const routes = {
|
||||
history,
|
||||
routes: documentInstances.map(instance => {
|
||||
return {
|
||||
path: instance.path,
|
||||
component: (props: any) => <Renderer key={instance.id} rendererContainer={rendererContainer} documentInstance={instance} {...props} />,
|
||||
};
|
||||
}),
|
||||
};
|
||||
const { component } = useRouter(routes);
|
||||
return component;
|
||||
};
|
||||
|
||||
function ucfirst(s: string) {
|
||||
return s.charAt(0).toUpperCase() + s.substring(1);
|
||||
}
|
||||
function getDeviceView(view: any, device: string, mode: string) {
|
||||
if (!view || typeof view === 'string') {
|
||||
return view;
|
||||
}
|
||||
|
||||
// compatible vision Mobile | Preview
|
||||
device = ucfirst(device);
|
||||
if (device === 'Mobile' && view.hasOwnProperty(device)) {
|
||||
view = view[device];
|
||||
}
|
||||
mode = ucfirst(mode);
|
||||
if (mode === 'Preview' && view.hasOwnProperty(mode)) {
|
||||
view = view[mode];
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.props.rendererContainer.onReRender(() => {
|
||||
this.forceUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { rendererContainer, children } = this.props;
|
||||
const { layout } = rendererContainer;
|
||||
|
||||
if (layout) {
|
||||
const { Component, props, componentName } = layout;
|
||||
if (Component) {
|
||||
return <Component props={props}>{children}</Component>;
|
||||
}
|
||||
if (componentName && rendererContainer.getComponent(componentName)) {
|
||||
return createElement(
|
||||
rendererContainer.getComponent(componentName),
|
||||
{
|
||||
...props,
|
||||
rendererContainer,
|
||||
},
|
||||
[children],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return <Fragment>{children}</Fragment>;
|
||||
}
|
||||
}
|
||||
|
||||
class Renderer extends Component<{
|
||||
rendererContainer: SimulatorRendererContainer;
|
||||
documentInstance: DocumentInstance;
|
||||
}> {
|
||||
private unlisten: any;
|
||||
private key: string;
|
||||
private startTime: number | null = null;
|
||||
|
||||
componentWillMount() {
|
||||
this.key = uniqueId('renderer');
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { documentInstance } = this.props;
|
||||
this.unlisten = documentInstance.onReRender((params) => {
|
||||
if (params && params.shouldRemount) {
|
||||
this.key = uniqueId('renderer');
|
||||
}
|
||||
this.forceUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.unlisten) {
|
||||
this.unlisten();
|
||||
}
|
||||
}
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.startTime) {
|
||||
const time = Date.now() - this.startTime;
|
||||
const nodeCount = host.designer.currentDocument?.getNodeCount?.();
|
||||
host.designer.editor?.eventBus.emit(GlobalEvent.Node.Rerender, {
|
||||
componentName: 'Renderer',
|
||||
type: 'All',
|
||||
time,
|
||||
nodeCount,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
schemaChangedSymbol = false;
|
||||
|
||||
getSchemaChangedSymbol = () => {
|
||||
return this.schemaChangedSymbol;
|
||||
};
|
||||
|
||||
setSchemaChangedSymbol = (symbol: boolean) => {
|
||||
this.schemaChangedSymbol = symbol;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { documentInstance } = this.props;
|
||||
const { container, document } = documentInstance;
|
||||
const { designMode, device } = container;
|
||||
const { rendererContainer: renderer } = this.props;
|
||||
this.startTime = Date.now();
|
||||
this.schemaChangedSymbol = false;
|
||||
|
||||
return (
|
||||
<RaxRenderer
|
||||
schema={documentInstance.schema}
|
||||
components={renderer.components}
|
||||
appHelper={renderer.context}
|
||||
context={renderer.context}
|
||||
device={device}
|
||||
designMode={renderer.designMode}
|
||||
key={this.key}
|
||||
__host={host}
|
||||
__container={container}
|
||||
suspended={documentInstance.suspended}
|
||||
self={documentInstance.scope}
|
||||
onCompGetRef={(schema: any, ref: any) => {
|
||||
documentInstance.mountInstance(schema.id, ref);
|
||||
}}
|
||||
thisRequiredInJSE={host.thisRequiredInJSE}
|
||||
documentId={document.id}
|
||||
getNode={(id: string) => documentInstance.getNode(id) as any}
|
||||
rendererName="PageRenderer"
|
||||
customCreateElement={(Component: any, props: any, children: any) => {
|
||||
const { __id, ...viewProps } = props;
|
||||
viewProps.componentId = __id;
|
||||
const leaf = documentInstance.getNode(__id);
|
||||
viewProps._leaf = leaf;
|
||||
viewProps._componentName = leaf?.componentName;
|
||||
// 如果是容器 && 无children && 高宽为空 增加一个占位容器,方便拖动
|
||||
if (
|
||||
!viewProps.dataSource &&
|
||||
leaf?.isContainer() &&
|
||||
(children == null || (Array.isArray(children) && !children.length)) &&
|
||||
(!viewProps.style || Object.keys(viewProps.style).length === 0)
|
||||
) {
|
||||
children = (
|
||||
<div className="lc-container-placeholder" style={viewProps.placeholderStyle}>
|
||||
{viewProps.placeholder || '拖拽组件或模板到这里'}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// if (viewProps._componentName === 'Menu') {
|
||||
// Object.assign(viewProps, {
|
||||
// _componentName: 'Menu',
|
||||
// className: '_css_pesudo_menu_kbrzyh0f',
|
||||
// context: { VE: (window as any).VisualLowCodeRenderer },
|
||||
// direction: undefined,
|
||||
// events: { ignored: true },
|
||||
// fieldId: 'menu_kbrzyh0f',
|
||||
// footer: '',
|
||||
// header: '',
|
||||
// mode: 'inline',
|
||||
// onItemClick: { ignored: true },
|
||||
// onSelect: { ignored: true },
|
||||
// popupAlign: 'follow',
|
||||
// selectMode: false,
|
||||
// triggerType: 'click',
|
||||
// });
|
||||
// console.info('menuprops', viewProps);
|
||||
// }
|
||||
|
||||
return createElement(
|
||||
getDeviceView(Component, device, designMode),
|
||||
viewProps,
|
||||
leaf?.isContainer() ? (children == null ? [] : Array.isArray(children) ? children : [children]) : children,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue