mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-05 09:47:20 +00:00
chore: merge from develop
This commit is contained in:
commit
7b90462109
@ -36,6 +36,12 @@ sidebar_position: 12
|
|||||||
|
|
||||||
`@type {boolean}`
|
`@type {boolean}`
|
||||||
|
|
||||||
|
### clipboard
|
||||||
|
全局剪贴板实例
|
||||||
|
|
||||||
|
`@type {IPublicModelClipboard}`
|
||||||
|
|
||||||
|
相关类型:[IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts)
|
||||||
|
|
||||||
## 方法
|
## 方法
|
||||||
|
|
||||||
|
|||||||
43
docs/docs/api/model/clipboard.md
Normal file
43
docs/docs/api/model/clipboard.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
title: Clipboard
|
||||||
|
sidebar_position: 14
|
||||||
|
---
|
||||||
|
|
||||||
|
> **@types** [IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts)<br/>
|
||||||
|
> **@since** v1.1.0
|
||||||
|
|
||||||
|
## 方法
|
||||||
|
|
||||||
|
### setData
|
||||||
|
|
||||||
|
给剪贴板赋值
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 给剪贴板赋值
|
||||||
|
* set data to clipboard
|
||||||
|
*
|
||||||
|
* @param {*} data
|
||||||
|
* @since v1.1.0
|
||||||
|
*/
|
||||||
|
setData(data: any): void;
|
||||||
|
```
|
||||||
|
|
||||||
|
### waitPasteData
|
||||||
|
|
||||||
|
设置剪贴板数据设置的回调
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
* 设置剪贴板数据设置的回调
|
||||||
|
* set callback for clipboard provide paste data
|
||||||
|
*
|
||||||
|
* @param {KeyboardEvent} keyboardEvent
|
||||||
|
* @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb
|
||||||
|
* @since v1.1.0
|
||||||
|
*/
|
||||||
|
waitPasteData(
|
||||||
|
keyboardEvent: KeyboardEvent,
|
||||||
|
cb: (data: any, clipboardEvent: ClipboardEvent) => void,
|
||||||
|
): void;
|
||||||
|
```
|
||||||
@ -160,7 +160,7 @@ sidebar_position: 1
|
|||||||
|
|
||||||
`@type {IPublicModelComponentMeta | null}`
|
`@type {IPublicModelComponentMeta | null}`
|
||||||
|
|
||||||
相关类型:[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
|
相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
|
||||||
|
|
||||||
|
|
||||||
### document
|
### document
|
||||||
@ -644,4 +644,4 @@ isConditionalVisible(): boolean | undefined;
|
|||||||
setConditionalVisible(): void;
|
setConditionalVisible(): void;
|
||||||
```
|
```
|
||||||
|
|
||||||
**@since v1.1.0**
|
**@since v1.1.0**
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Resource
|
title: Resource
|
||||||
sidebar_position: 12
|
sidebar_position: 13
|
||||||
---
|
---
|
||||||
|
|
||||||
> **[@experimental](./#experimental)**<br/>
|
> **[@experimental](./#experimental)**<br/>
|
||||||
|
|||||||
@ -23,7 +23,7 @@ sidebar_position: 1
|
|||||||
|
|
||||||
对于低代码物料来说,A 平台创建的物料无法使用到 B 平台上,如果想在 B 平台实现同样的物料,需要按照 B 平台的标准搭建一份物料。
|
对于低代码物料来说,A 平台创建的物料无法使用到 B 平台上,如果想在 B 平台实现同样的物料,需要按照 B 平台的标准搭建一份物料。
|
||||||
|
|
||||||
对于 ProCode 物料来说,需要在低代码平台进行消费,是需要进行转换的,包括搭建配置项的生成、物料搭建试图等,可能还需要特殊的描述文件进行描述。由于这一层没有统一,同一份 ProCode 物料每接入一个低代码,可能需要的描述文件格式不同,转换的代码不同,使用的工具也不同。
|
对于 ProCode 物料来说,需要在低代码平台进行消费,是需要进行转换的,包括搭建配置项的生成、物料搭建视图等,可能还需要特殊的描述文件进行描述。由于这一层没有统一,同一份 ProCode 物料每接入一个低代码,可能需要的描述文件格式不同,转换的代码不同,使用的工具也不同。
|
||||||
|
|
||||||
### 生态隔离
|
### 生态隔离
|
||||||
|
|
||||||
|
|||||||
@ -84,7 +84,7 @@ component // 组件名称, 比如 biz-button
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### README.md
|
##### README.md
|
||||||
|
|
||||||
- README.md 应该包含业务组件的源信息、使用说明以及 API,示例如下:
|
- README.md 应该包含业务组件的源信息、使用说明以及 API,示例如下:
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ npm install @alifd/ice-layout -S
|
|||||||
| type | type | String | `primray`、`normal` | normal |
|
| type | type | String | `primray`、`normal` | normal |
|
||||||
```
|
```
|
||||||
|
|
||||||
#### package.json
|
##### package.json
|
||||||
`package.json` 中包含了一些依赖信息和配置信息,示例如下:
|
`package.json` 中包含了一些依赖信息和配置信息,示例如下:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@ -159,7 +159,7 @@ npm install @alifd/ice-layout -S
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### src/index.js
|
##### src/index.js
|
||||||
|
|
||||||
包含组件的出口文件,示例如下:
|
包含组件的出口文件,示例如下:
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ export default Button;
|
|||||||
import Button, { Group } form '@scope/button';
|
import Button, { Group } form '@scope/button';
|
||||||
```
|
```
|
||||||
|
|
||||||
#### src/index.scss
|
##### src/index.scss
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* 不引入依赖组件的样式,比如组件 import { Button } from '@alifd/next'; */
|
/* 不引入依赖组件的样式,比如组件 import { Button } from '@alifd/next'; */
|
||||||
@ -193,7 +193,7 @@ import Button, { Group } form '@scope/button';
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### demo
|
##### demo
|
||||||
demo 目录存放的是组件的文档,无文档的业务组件无法带来任何价值,因此 demo 是必选项。demo 目录下的文件采取 markdown 的写法,可以是多个文件,示例(demo/basic.md)如下:
|
demo 目录存放的是组件的文档,无文档的业务组件无法带来任何价值,因此 demo 是必选项。demo 目录下的文件采取 markdown 的写法,可以是多个文件,示例(demo/basic.md)如下:
|
||||||
|
|
||||||
demo/basic.md
|
demo/basic.md
|
||||||
@ -236,12 +236,12 @@ ReactDOM.render(<div className="test">
|
|||||||
|
|
||||||
API 是组件的属性解释,给开发者作为组件属性配置的参考。为了保持 API 的一致性,我们制定这个 API 命名规范。对于业界通用的,约定俗成的命名,我们遵循社区的约定。对于业界有多种规则难以确定的,我们确定其中一种,大家共同遵守。
|
API 是组件的属性解释,给开发者作为组件属性配置的参考。为了保持 API 的一致性,我们制定这个 API 命名规范。对于业界通用的,约定俗成的命名,我们遵循社区的约定。对于业界有多种规则难以确定的,我们确定其中一种,大家共同遵守。
|
||||||
|
|
||||||
#### 通用规则
|
##### 通用规则
|
||||||
|
|
||||||
- 所有的 API 采用小驼峰的书写规则,如 `onChange`、`direction`、`defaultVisible`。
|
- 所有的 API 采用小驼峰的书写规则,如 `onChange`、`direction`、`defaultVisible`。
|
||||||
- 标签名采用大驼峰书写规则,如 `Menu`、`Slider`、`DatePicker`。
|
- 标签名采用大驼峰书写规则,如 `Menu`、`Slider`、`DatePicker`。
|
||||||
|
|
||||||
#### 通用命名
|
##### 通用命名
|
||||||
|
|
||||||
| API 名称 | 类型 | 描述 | 常见变量 |
|
| API 名称 | 类型 | 描述 | 常见变量 |
|
||||||
| :------------- | :------------- | :----------------------------------------------------------- | :---------------------------------------------------- |
|
| :------------- | :------------- | :----------------------------------------------------------- | :---------------------------------------------------- |
|
||||||
@ -261,7 +261,7 @@ API 是组件的属性解释,给开发者作为组件属性配置的参考。
|
|||||||
| has+'属性' | boolean | 拥有某个属性 | 例如 `hasArrow`, `hasHeader`, `hasClose` 等等 |
|
| has+'属性' | boolean | 拥有某个属性 | 例如 `hasArrow`, `hasHeader`, `hasClose` 等等 |
|
||||||
|
|
||||||
|
|
||||||
#### 多选枚举
|
##### 多选枚举
|
||||||
|
|
||||||
当某个 API 的接口,允许用户指定多个枚举值的时候,我们把这个接口定义为多选枚举。一个很典型的例子是某个弹层组件的 `closable` 属性,我们会允许:键盘 esc 按键、点击 mask、点击 close 按钮、点击组件以外的任何区域进行关闭。
|
当某个 API 的接口,允许用户指定多个枚举值的时候,我们把这个接口定义为多选枚举。一个很典型的例子是某个弹层组件的 `closable` 属性,我们会允许:键盘 esc 按键、点击 mask、点击 close 按钮、点击组件以外的任何区域进行关闭。
|
||||||
|
|
||||||
@ -280,11 +280,11 @@ true 表示触发规则都会关闭,false 表示触发规则不会关闭。
|
|||||||
- `<Dialog closable={false} />`,任何情况下都不关闭,只能通过受控设置 visible
|
- `<Dialog closable={false} />`,任何情况下都不关闭,只能通过受控设置 visible
|
||||||
- `<Dialog closable closeMode={['close', 'esc']} />`,用户按 esc 或者点击关闭按钮会关闭
|
- `<Dialog closable closeMode={['close', 'esc']} />`,用户按 esc 或者点击关闭按钮会关闭
|
||||||
|
|
||||||
#### 事件
|
##### 事件
|
||||||
|
|
||||||
- 标准事件或者自定义的符合 w3c 标准的事件,命名必须 on 开头, 即 `on` + 事件名,如 onExpand。
|
- 标准事件或者自定义的符合 w3c 标准的事件,命名必须 on 开头, 即 `on` + 事件名,如 onExpand。
|
||||||
|
|
||||||
#### 表单规范
|
##### 表单规范
|
||||||
|
|
||||||
- 支持[受控模式](https://reactjs.org/docs/forms.html#controlled-components)(value + onChange) (A)
|
- 支持[受控模式](https://reactjs.org/docs/forms.html#controlled-components)(value + onChange) (A)
|
||||||
- value 控制组件数据展现
|
- value 控制组件数据展现
|
||||||
@ -292,7 +292,7 @@ true 表示触发规则都会关闭,false 表示触发规则不会关闭。
|
|||||||
- `value={undefined}`的时候清空数据,field 的 reset 函数会给所有组件下发 undefined 数据 (AA))
|
- `value={undefined}`的时候清空数据,field 的 reset 函数会给所有组件下发 undefined 数据 (AA))
|
||||||
- 一次完整操作抛一次 onChange 事件 `建议` 比如有 Process 表示进展中的状态,建议增加 API `onProcess`;如果有 Start 表示启动状态,建议增加 API `onStart` (AA)
|
- 一次完整操作抛一次 onChange 事件 `建议` 比如有 Process 表示进展中的状态,建议增加 API `onProcess`;如果有 Start 表示启动状态,建议增加 API `onStart` (AA)
|
||||||
|
|
||||||
#### 属性的传递
|
##### 属性的传递
|
||||||
**1. 原子组件(Atomic Component)**
|
**1. 原子组件(Atomic Component)**
|
||||||
> 最小粒子,不能再拆分的组件
|
> 最小粒子,不能再拆分的组件
|
||||||
|
|
||||||
@ -354,7 +354,7 @@ $ iceworks sync
|
|||||||
|
|
||||||
文件命名采取 [bcp47](https://tools.ietf.org/html/bcp47) 规范
|
文件命名采取 [bcp47](https://tools.ietf.org/html/bcp47) 规范
|
||||||
|
|
||||||
#### 目录规范
|
##### 目录规范
|
||||||
|
|
||||||
在 `src` 目录新增 `locale` 目录用于管理不同语言的文案。
|
在 `src` 目录新增 `locale` 目录用于管理不同语言的文案。
|
||||||
|
|
||||||
@ -367,7 +367,7 @@ $ iceworks sync
|
|||||||
|------ ja-JP.js
|
|------ ja-JP.js
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 定义不同的语言
|
##### 定义不同的语言
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// zh-CN.js
|
// zh-CN.js
|
||||||
@ -390,7 +390,7 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 组件支持多语言建议方案
|
##### 组件支持多语言建议方案
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
// index.jsx
|
// index.jsx
|
||||||
@ -417,7 +417,7 @@ export default class BizHello extends Component {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 组件支持全局替换国际化文案
|
##### 组件支持全局替换国际化文案
|
||||||
|
|
||||||
配合 ConfigProvider 支持全局替换国际化文案。
|
配合 ConfigProvider 支持全局替换国际化文案。
|
||||||
|
|
||||||
@ -451,7 +451,7 @@ export default ConfigProvider.config(BizHello, {
|
|||||||
|
|
||||||
业务组件中如果有自定义的需要跟随主题色的 UI,一定要引入变量的形式,增加组件的流通性。
|
业务组件中如果有自定义的需要跟随主题色的 UI,一定要引入变量的形式,增加组件的流通性。
|
||||||
|
|
||||||
#### src/index.scss
|
##### src/index.scss
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* 如果需要引入主题变量引入此段 */
|
/* 如果需要引入主题变量引入此段 */
|
||||||
@ -503,7 +503,7 @@ api 属性标准参考 [https://fusion.design/help.html#/dev-biz](https://fusio
|
|||||||
无障碍需要符合 [WCAG 2.1 A 级标准](https://www.w3.org/TR/WCAG21/),可参考 [W3C 无障碍最佳实践](https://www.w3.org/TR/wai-aria-practices-1.1/)、[Fusion 无障碍指引 2.3.1](https://alibaba-fusion.github.io/next/part1/basics.html) 章节等。
|
无障碍需要符合 [WCAG 2.1 A 级标准](https://www.w3.org/TR/WCAG21/),可参考 [W3C 无障碍最佳实践](https://www.w3.org/TR/wai-aria-practices-1.1/)、[Fusion 无障碍指引 2.3.1](https://alibaba-fusion.github.io/next/part1/basics.html) 章节等。
|
||||||
|
|
||||||
|
|
||||||
#### 增加 a11y.md 无障碍 demo
|
##### 增加 a11y.md 无障碍 demo
|
||||||
|
|
||||||
必须借助 API 才能完成无障碍工作的组件必须为开发者提供无障碍的使用文档,请[参考](https://fusion.design/pc/component/select?themeid=2#accessibility-container)组件 API 中 `ARIA and Keyboard` ,建议在 `demo` 目录新增 `a11y.md` 文件用于演示组件的无障碍使用。
|
必须借助 API 才能完成无障碍工作的组件必须为开发者提供无障碍的使用文档,请[参考](https://fusion.design/pc/component/select?themeid=2#accessibility-container)组件 API 中 `ARIA and Keyboard` ,建议在 `demo` 目录新增 `a11y.md` 文件用于演示组件的无障碍使用。
|
||||||
|
|
||||||
@ -517,7 +517,7 @@ component
|
|||||||
详细指引查看无障碍开发指南 [https://alibaba-fusion.github.io/next/part1/basics.html](https://alibaba-fusion.github.io/next/part1/basics.html)。
|
详细指引查看无障碍开发指南 [https://alibaba-fusion.github.io/next/part1/basics.html](https://alibaba-fusion.github.io/next/part1/basics.html)。
|
||||||
|
|
||||||
|
|
||||||
#### 通过键盘快速访问
|
##### 通过键盘快速访问
|
||||||
|
|
||||||
一般键盘事件有 Up Arrow/Down Arrow/Enter/Esc/Tab
|
一般键盘事件有 Up Arrow/Down Arrow/Enter/Esc/Tab
|
||||||
|
|
||||||
@ -531,7 +531,7 @@ component
|
|||||||
| Esc | 关闭列表 |
|
| Esc | 关闭列表 |
|
||||||
|
|
||||||
|
|
||||||
#### 对读屏软件友好
|
##### 对读屏软件友好
|
||||||
|
|
||||||
- 对于组件,我们为开发者内置 `role` 和特定 `aria-_属性`,开发者也可以对非组件 API 属性都可以透传至 DOM 元素,进行修改 `role` 和 `aria-_参数`,但是要注意对应关系,请[参考](https://alibaba-fusion.github.io/next/part1/WAI-ARIA.html)。
|
- 对于组件,我们为开发者内置 `role` 和特定 `aria-_属性`,开发者也可以对非组件 API 属性都可以透传至 DOM 元素,进行修改 `role` 和 `aria-_参数`,但是要注意对应关系,请[参考](https://alibaba-fusion.github.io/next/part1/WAI-ARIA.html)。
|
||||||
- 对一些特殊的组件传递参数才能支持无障碍,设置 `id`,`autoFocus` 和传参数,如下:
|
- 对一些特殊的组件传递参数才能支持无障碍,设置 `id`,`autoFocus` 和传参数,如下:
|
||||||
@ -925,18 +925,18 @@ props 数组下对象字段描述:
|
|||||||
|initialChildren | 组件拖入“设计器”时根据此配置自动生成 children 节点 schema |NodeData[]/Function NodeData[] | ((target: SettingTarget) => NodeData[]);|
|
|initialChildren | 组件拖入“设计器”时根据此配置自动生成 children 节点 schema |NodeData[]/Function NodeData[] | ((target: SettingTarget) => NodeData[]);|
|
||||||
|getResizingHandlers| 用于配置设计器中组件 resize 操作工具的样式和内容 | Function| (currentNode: any) => Array<{ type: 'N' | 'W' | 'S' | 'E' | 'NW' | 'NE' | 'SE' | 'SW'; content?: ReactElement; propTarget?: string; appearOn?: 'mouse-enter' | 'mouse-hover' | 'selected' | 'always'; }> / ReactElement[];
|
|getResizingHandlers| 用于配置设计器中组件 resize 操作工具的样式和内容 | Function| (currentNode: any) => Array<{ type: 'N' | 'W' | 'S' | 'E' | 'NW' | 'NE' | 'SE' | 'SW'; content?: ReactElement; propTarget?: string; appearOn?: 'mouse-enter' | 'mouse-hover' | 'selected' | 'always'; }> / ReactElement[];
|
||||||
|callbacks| 配置 callbacks 可捕获引擎抛出的一些事件,例如 onNodeAdd、onResize 等 | Callback| -
|
|callbacks| 配置 callbacks 可捕获引擎抛出的一些事件,例如 onNodeAdd、onResize 等 | Callback| -
|
||||||
|callbacks.onNodeAdd| 在容器中拖入组件时触发的事件回调| Function| (e: MouseEvent, currentNode: any) => any
|
|callbacks.onNodeAdd| 在容器中拖入组件时触发的事件回调 | Function| (e: MouseEvent, currentNode: any) => any
|
||||||
|callbacks.onNodeRemove| 在容器中删除组件时触发的事件回调| Function| (e: MouseEvent, currentNode: any) => any
|
|callbacks.onNodeRemove| 在容器中删除组件时触发的事件回调 | Function| (e: MouseEvent, currentNode: any) => any
|
||||||
|callbacks.onResize| 调整容器尺寸时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义
|
|callbacks.onResize| 调整容器尺寸时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义
|
||||||
|callbacks.onResizeStart| 调整容器尺寸开始时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义
|
|callbacks.onResizeStart| 调整容器尺寸开始时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义
|
||||||
|callbacks.onResizeEnd| 调整容器尺寸结束时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义
|
|callbacks.onResizeEnd| 调整容器尺寸结束时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义
|
||||||
|callbacks.onSubtreeModified| 容器节点结构树发生变化时触发的回调| Function| (currentNode: any, options: any) => void;
|
|callbacks.onSubtreeModified| 容器节点结构树发生变化时触发的回调 | Function| (currentNode: any, options: any) => void;
|
||||||
|callbacks.onMouseDownHook| 鼠标按下操作回调| Function| (e: MouseEvent, currentNode: any) => any;
|
|callbacks.onMouseDownHook| 鼠标按下操作回调 | Function| (e: MouseEvent, currentNode: any) => any;
|
||||||
|callbacks.onClickHook| 鼠标单击操作回调| Function| (e: MouseEvent, currentNode: any) => any;
|
|callbacks.onClickHook| 鼠标单击操作回调 | Function| (e: MouseEvent, currentNode: any) => any;
|
||||||
|callbacks.onDblClickHook| 鼠标双击操作回调| Function| (e: MouseEvent, currentNode: any) => any;
|
|callbacks.onDblClickHook| 鼠标双击操作回调 | Function| (e: MouseEvent, currentNode: any) => any;
|
||||||
|callbacks.onMoveHook| 节点被拖动回调 | Function| (currentNode: any) => boolean;
|
|callbacks.onMoveHook| 节点被拖动回调 | Function| (currentNode: any) => boolean;
|
||||||
|callbacks.onHoverHook| 节点被 hover 回调 | Function| (currentNode: any) => boolean;
|
|callbacks.onHoverHook| 节点被 hover 回调 | Function| (currentNode: any) => boolean;
|
||||||
|callbacks.onChildMoveHook| 容器节点的子节点被拖动回调| Function| (childNode: any, currentNode: any) => boolean;
|
|callbacks.onChildMoveHook| 容器节点的子节点被拖动回调 | Function| (childNode: any, currentNode: any) => boolean;
|
||||||
|
|
||||||
|
|
||||||
描述举例:
|
描述举例:
|
||||||
@ -1543,7 +1543,7 @@ block/
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### 入口文件
|
##### 入口文件
|
||||||
|
|
||||||
(/src/index.jsx)
|
(/src/index.jsx)
|
||||||
|
|
||||||
@ -1559,7 +1559,7 @@ const App = hot(router);
|
|||||||
ReactDOM.render(<App />, document.getElementById(pkg.config && pkg.config.targetRootID || 'root'));
|
ReactDOM.render(<App />, document.getElementById(pkg.config && pkg.config.targetRootID || 'root'));
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 应用参数配置文件
|
##### 应用参数配置文件
|
||||||
|
|
||||||
(/src/config/app.js)
|
(/src/config/app.js)
|
||||||
|
|
||||||
@ -1596,7 +1596,7 @@ export default {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 应用扩展配置规范:
|
##### 应用扩展配置规范:
|
||||||
|
|
||||||
(/src/utils/index.js)
|
(/src/utils/index.js)
|
||||||
|
|
||||||
@ -1618,7 +1618,7 @@ export default {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 应用常量配置
|
##### 应用常量配置
|
||||||
|
|
||||||
(/src/config/constants.js)
|
(/src/config/constants.js)
|
||||||
|
|
||||||
@ -1628,7 +1628,7 @@ export default {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 应用样式配置
|
##### 应用样式配置
|
||||||
|
|
||||||
(/src/global.scss)
|
(/src/global.scss)
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,6 @@ const config = {
|
|||||||
presets: [
|
presets: [
|
||||||
[
|
[
|
||||||
'classic',
|
'classic',
|
||||||
/** @type {import('@docusaurus/preset-classic').Options} */
|
|
||||||
({
|
({
|
||||||
docs: {
|
docs: {
|
||||||
sidebarPath: require.resolve('./config/sidebars.js'),
|
sidebarPath: require.resolve('./config/sidebars.js'),
|
||||||
@ -55,7 +54,6 @@ const config = {
|
|||||||
],
|
],
|
||||||
|
|
||||||
themeConfig:
|
themeConfig:
|
||||||
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
|
|
||||||
({
|
({
|
||||||
docs: {
|
docs: {
|
||||||
sidebar: {
|
sidebar: {
|
||||||
@ -76,7 +74,7 @@ const config = {
|
|||||||
metadata: [{ name: 'referrer', content: 'no-referrer' }],
|
metadata: [{ name: 'referrer', content: 'no-referrer' }],
|
||||||
tableOfContents: {
|
tableOfContents: {
|
||||||
minHeadingLevel: 2,
|
minHeadingLevel: 2,
|
||||||
maxHeadingLevel: 5,
|
maxHeadingLevel: 6,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
@ -13,9 +13,9 @@ import {
|
|||||||
IPublicTypeMetadataTransducer,
|
IPublicTypeMetadataTransducer,
|
||||||
IPublicModelComponentMeta,
|
IPublicModelComponentMeta,
|
||||||
} from '@alilc/lowcode-types';
|
} from '@alilc/lowcode-types';
|
||||||
import { deprecate, isRegExp, isTitleConfig } from '@alilc/lowcode-utils';
|
import { deprecate, isRegExp, isTitleConfig, isNode } from '@alilc/lowcode-utils';
|
||||||
import { computed, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
import { computed, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
||||||
import { isNode, Node, INode } from './document';
|
import { Node, INode } from './document';
|
||||||
import { Designer } from './designer';
|
import { Designer } from './designer';
|
||||||
import {
|
import {
|
||||||
IconContainer,
|
IconContainer,
|
||||||
@ -161,6 +161,9 @@ export class ComponentMeta implements IComponentMeta {
|
|||||||
return this._acceptable!;
|
return this._acceptable!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compatiable vision
|
||||||
|
prototype?: any;
|
||||||
|
|
||||||
constructor(readonly designer: Designer, metadata: IPublicTypeComponentMetadata) {
|
constructor(readonly designer: Designer, metadata: IPublicTypeComponentMetadata) {
|
||||||
this.parseMetadata(metadata);
|
this.parseMetadata(metadata);
|
||||||
}
|
}
|
||||||
@ -347,8 +350,6 @@ export class ComponentMeta implements IComponentMeta {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// compatiable vision
|
|
||||||
prototype?: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isComponentMeta(obj: any): obj is ComponentMeta {
|
export function isComponentMeta(obj: any): obj is ComponentMeta {
|
||||||
@ -373,4 +374,3 @@ function preprocessMetadata(metadata: IPublicTypeComponentMetadata): IPublicType
|
|||||||
configure: {},
|
configure: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { IPublicModelClipboard } from '@alilc/lowcode-types';
|
||||||
|
|
||||||
function getDataFromPasteEvent(event: ClipboardEvent) {
|
function getDataFromPasteEvent(event: ClipboardEvent) {
|
||||||
const { clipboardData } = event;
|
const { clipboardData } = event;
|
||||||
if (!clipboardData) {
|
if (!clipboardData) {
|
||||||
@ -23,7 +25,13 @@ function getDataFromPasteEvent(event: ClipboardEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Clipboard {
|
export interface IClipboard extends IPublicModelClipboard {
|
||||||
|
|
||||||
|
initCopyPaster(el: HTMLTextAreaElement): void;
|
||||||
|
|
||||||
|
injectCopyPaster(document: Document): void;
|
||||||
|
}
|
||||||
|
class Clipboard implements IClipboard {
|
||||||
private copyPasters: HTMLTextAreaElement[] = [];
|
private copyPasters: HTMLTextAreaElement[] = [];
|
||||||
|
|
||||||
private waitFn?: (data: any, e: ClipboardEvent) => void;
|
private waitFn?: (data: any, e: ClipboardEvent) => void;
|
||||||
@ -56,7 +64,7 @@ class Clipboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
injectCopyPaster(document: Document) {
|
injectCopyPaster(document: Document) {
|
||||||
if (this.copyPasters.find(x => x.ownerDocument === document)) {
|
if (this.copyPasters.find((x) => x.ownerDocument === document)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const copyPaster = document.createElement<'textarea'>('textarea');
|
const copyPaster = document.createElement<'textarea'>('textarea');
|
||||||
@ -69,8 +77,8 @@ class Clipboard {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setData(data: any) {
|
setData(data: any): void {
|
||||||
const copyPaster = this.copyPasters.find(x => x.ownerDocument);
|
const copyPaster = this.copyPasters.find((x) => x.ownerDocument);
|
||||||
if (!copyPaster) {
|
if (!copyPaster) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -81,12 +89,12 @@ class Clipboard {
|
|||||||
copyPaster.blur();
|
copyPaster.blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
waitPasteData(e: KeyboardEvent, cb: (data: any, e: ClipboardEvent) => void) {
|
waitPasteData(keyboardEvent: KeyboardEvent, cb: (data: any, e: ClipboardEvent) => void) {
|
||||||
const win = e.view;
|
const win = keyboardEvent.view;
|
||||||
if (!win) {
|
if (!win) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const copyPaster = this.copyPasters.find(cp => cp.ownerDocument === win.document);
|
const copyPaster = this.copyPasters.find((cp) => cp.ownerDocument === win.document);
|
||||||
if (copyPaster) {
|
if (copyPaster) {
|
||||||
copyPaster.select();
|
copyPaster.select();
|
||||||
this.waitFn = cb;
|
this.waitFn = cb;
|
||||||
|
|||||||
@ -30,7 +30,6 @@ import { ActiveTracker, IActiveTracker } from './active-tracker';
|
|||||||
import { Detecting } from './detecting';
|
import { Detecting } from './detecting';
|
||||||
import { DropLocation } from './location';
|
import { DropLocation } from './location';
|
||||||
import { OffsetObserver, createOffsetObserver } from './offset-observer';
|
import { OffsetObserver, createOffsetObserver } from './offset-observer';
|
||||||
import { focusing } from './focusing';
|
|
||||||
import { SettingTopEntry } from './setting';
|
import { SettingTopEntry } from './setting';
|
||||||
import { BemToolsManager } from '../builtin-simulator/bem-tools/manager';
|
import { BemToolsManager } from '../builtin-simulator/bem-tools/manager';
|
||||||
import { ComponentActions } from '../component-actions';
|
import { ComponentActions } from '../component-actions';
|
||||||
@ -241,9 +240,6 @@ export class Designer implements IDesigner {
|
|||||||
this.postEvent('init', this);
|
this.postEvent('init', this);
|
||||||
this.setupSelection();
|
this.setupSelection();
|
||||||
setupHistory();
|
setupHistory();
|
||||||
|
|
||||||
// TODO: 先简单实现,后期通过焦点赋值
|
|
||||||
focusing.focusDesigner = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupSelection = () => {
|
setupSelection = () => {
|
||||||
@ -341,6 +337,7 @@ export class Designer implements IDesigner {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得合适的插入位置
|
* 获得合适的插入位置
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
getSuitableInsertion(
|
getSuitableInsertion(
|
||||||
insertNode?: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[],
|
insertNode?: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[],
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
import { Designer } from './designer';
|
|
||||||
|
|
||||||
// TODO: use focus-tracker replace
|
|
||||||
class Focusing {
|
|
||||||
focusDesigner?: Designer;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const focusing = new Focusing();
|
|
||||||
@ -7,6 +7,5 @@ export * from './offset-observer';
|
|||||||
export * from './scroller';
|
export * from './scroller';
|
||||||
export * from './setting';
|
export * from './setting';
|
||||||
export * from './active-tracker';
|
export * from './active-tracker';
|
||||||
export * from './focusing';
|
|
||||||
export * from '../document';
|
export * from '../document';
|
||||||
export * from './clipboard';
|
export * from './clipboard';
|
||||||
|
|||||||
@ -17,11 +17,11 @@ import { IProject, Project } from '../project';
|
|||||||
import { ISimulatorHost } from '../simulator';
|
import { ISimulatorHost } from '../simulator';
|
||||||
import { ComponentMeta } from '../component-meta';
|
import { ComponentMeta } from '../component-meta';
|
||||||
import { IDropLocation, Designer, IHistory } from '../designer';
|
import { IDropLocation, Designer, IHistory } from '../designer';
|
||||||
import { Node, insertChildren, insertChild, isNode, RootNode, INode } from './node/node';
|
import { Node, insertChildren, insertChild, RootNode, INode } from './node/node';
|
||||||
import { Selection, ISelection } from './selection';
|
import { Selection, ISelection } from './selection';
|
||||||
import { History } from './history';
|
import { History } from './history';
|
||||||
import { IModalNodesManager, ModalNodesManager } from './node';
|
import { IModalNodesManager, ModalNodesManager } from './node';
|
||||||
import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject } from '@alilc/lowcode-utils';
|
import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isNode } from '@alilc/lowcode-utils';
|
||||||
import { EDITOR_EVENT } from '../types';
|
import { EDITOR_EVENT } from '../types';
|
||||||
|
|
||||||
export type GetDataType<T, NodeType> = T extends undefined
|
export type GetDataType<T, NodeType> = T extends undefined
|
||||||
@ -32,7 +32,7 @@ export type GetDataType<T, NodeType> = T extends undefined
|
|||||||
: any
|
: any
|
||||||
: T;
|
: T;
|
||||||
|
|
||||||
export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' > {
|
export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' | 'checkNesting' > {
|
||||||
|
|
||||||
readonly designer: Designer;
|
readonly designer: Designer;
|
||||||
|
|
||||||
@ -59,6 +59,11 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'select
|
|||||||
|
|
||||||
get rootNode(): INode | null;
|
get rootNode(): INode | null;
|
||||||
|
|
||||||
|
checkNesting(
|
||||||
|
dropTarget: INode,
|
||||||
|
dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject,
|
||||||
|
): boolean;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DocumentModel implements IDocumentModel {
|
export class DocumentModel implements IDocumentModel {
|
||||||
@ -569,7 +574,10 @@ export class DocumentModel implements IDocumentModel {
|
|||||||
this.rootNode = null;
|
this.rootNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkNesting(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | Node | IPublicTypeDragNodeDataObject): boolean {
|
checkNesting(
|
||||||
|
dropTarget: INode,
|
||||||
|
dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject,
|
||||||
|
): boolean {
|
||||||
let items: Array<Node | IPublicTypeNodeSchema>;
|
let items: Array<Node | IPublicTypeNodeSchema>;
|
||||||
if (isDragNodeDataObject(dragObject)) {
|
if (isDragNodeDataObject(dragObject)) {
|
||||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
IPublicModelExclusiveGroup,
|
IPublicModelExclusiveGroup,
|
||||||
IPublicEnumTransformStage,
|
IPublicEnumTransformStage,
|
||||||
} from '@alilc/lowcode-types';
|
} from '@alilc/lowcode-types';
|
||||||
import { compatStage, isDOMText, isJSExpression } from '@alilc/lowcode-utils';
|
import { compatStage, isDOMText, isJSExpression, isNode } from '@alilc/lowcode-utils';
|
||||||
import { SettingTopEntry } from '@alilc/lowcode-designer';
|
import { SettingTopEntry } from '@alilc/lowcode-designer';
|
||||||
import { Props, getConvertedExtraKey, IProps } from './props/props';
|
import { Props, getConvertedExtraKey, IProps } from './props/props';
|
||||||
import { DocumentModel, IDocumentModel } from '../document-model';
|
import { DocumentModel, IDocumentModel } from '../document-model';
|
||||||
@ -109,6 +109,8 @@ export interface INode extends IPublicModelNode {
|
|||||||
getExtraProp(key: string, createIfNone?: boolean): IProp | null;
|
getExtraProp(key: string, createIfNone?: boolean): IProp | null;
|
||||||
|
|
||||||
replaceChild(node: INode, data: any): INode;
|
replaceChild(node: INode, data: any): INode;
|
||||||
|
|
||||||
|
getSuitablePlace(node: INode, ref: any): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -913,7 +915,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
|
|||||||
/**
|
/**
|
||||||
* 判断是否包含特定节点
|
* 判断是否包含特定节点
|
||||||
*/
|
*/
|
||||||
contains(node: Node): boolean {
|
contains(node: INode): boolean {
|
||||||
return contains(this, node);
|
return contains(this, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1147,16 +1149,16 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: replace non standard metas with standard ones.
|
* @deprecated no one is using this, will be removed in a future release
|
||||||
*/
|
*/
|
||||||
getSuitablePlace(node: Node, ref: any): any {
|
getSuitablePlace(node: INode, ref: any): any {
|
||||||
const focusNode = this.document?.focusNode;
|
const focusNode = this.document?.focusNode;
|
||||||
// 如果节点是模态框,插入到根节点下
|
// 如果节点是模态框,插入到根节点下
|
||||||
if (node?.componentMeta?.isModal) {
|
if (node?.componentMeta?.isModal) {
|
||||||
return { container: focusNode, ref };
|
return { container: focusNode, ref };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ref && this.contains(focusNode)) {
|
if (!ref && focusNode && this.contains(focusNode)) {
|
||||||
const rootCanDropIn = focusNode.componentMeta?.prototype?.options?.canDropIn;
|
const rootCanDropIn = focusNode.componentMeta?.prototype?.options?.canDropIn;
|
||||||
if (
|
if (
|
||||||
rootCanDropIn === undefined ||
|
rootCanDropIn === undefined ||
|
||||||
@ -1171,7 +1173,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
|
|||||||
|
|
||||||
if (this.isRoot() && this.children) {
|
if (this.isRoot() && this.children) {
|
||||||
const dropElement = this.children.filter((c) => {
|
const dropElement = this.children.filter((c) => {
|
||||||
if (!c.isContainer()) {
|
if (!c.isContainerNode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const canDropIn = c.componentMeta?.prototype?.options?.canDropIn;
|
const canDropIn = c.componentMeta?.prototype?.options?.canDropIn;
|
||||||
@ -1304,22 +1306,15 @@ export type PageNode = Node<IPublicTypePageSchema>;
|
|||||||
export type ComponentNode = Node<IPublicTypeComponentSchema>;
|
export type ComponentNode = Node<IPublicTypeComponentSchema>;
|
||||||
export type RootNode = PageNode | ComponentNode;
|
export type RootNode = PageNode | ComponentNode;
|
||||||
|
|
||||||
/**
|
export function isRootNode(node: INode): node is INode {
|
||||||
* @deprecated use same function from '@alilc/lowcode-utils' instead
|
return node && node.isRootNode;
|
||||||
*/
|
|
||||||
export function isNode(node: any): node is Node {
|
|
||||||
return node && node.isNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isRootNode(node: Node): node is RootNode {
|
export function isLowCodeComponent(node: INode): node is INode {
|
||||||
return node && node.isRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isLowCodeComponent(node: Node): boolean {
|
|
||||||
return node.componentMeta?.getMetadata().devMode === 'lowCode';
|
return node.componentMeta?.getMetadata().devMode === 'lowCode';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getZLevelTop(child: Node, zLevel: number): Node | null {
|
export function getZLevelTop(child: INode, zLevel: number): INode | null {
|
||||||
let l = child.zLevel;
|
let l = child.zLevel;
|
||||||
if (l < zLevel || zLevel < 0) {
|
if (l < zLevel || zLevel < 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -1340,12 +1335,12 @@ export function getZLevelTop(child: Node, zLevel: number): Node | null {
|
|||||||
* @param node2 测试的被包含节点
|
* @param node2 测试的被包含节点
|
||||||
* @returns 是否包含
|
* @returns 是否包含
|
||||||
*/
|
*/
|
||||||
export function contains(node1: Node, node2: Node): boolean {
|
export function contains(node1: INode, node2: INode): boolean {
|
||||||
if (node1 === node2) {
|
if (node1 === node2) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node1.isParental() || !node2.parent) {
|
if (!node1.isParentalNode || !node2.parent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1367,7 +1362,7 @@ export enum PositionNO {
|
|||||||
BeforeOrAfter = 2,
|
BeforeOrAfter = 2,
|
||||||
TheSame = 0,
|
TheSame = 0,
|
||||||
}
|
}
|
||||||
export function comparePosition(node1: Node, node2: Node): PositionNO {
|
export function comparePosition(node1: INode, node2: INode): PositionNO {
|
||||||
if (node1 === node2) {
|
if (node1 === node2) {
|
||||||
return PositionNO.TheSame;
|
return PositionNO.TheSame;
|
||||||
}
|
}
|
||||||
@ -1396,11 +1391,11 @@ export function comparePosition(node1: Node, node2: Node): PositionNO {
|
|||||||
|
|
||||||
export function insertChild(
|
export function insertChild(
|
||||||
container: INode,
|
container: INode,
|
||||||
thing: Node | IPublicTypeNodeData,
|
thing: INode | IPublicTypeNodeData,
|
||||||
at?: number | null,
|
at?: number | null,
|
||||||
copy?: boolean,
|
copy?: boolean,
|
||||||
): Node {
|
): INode {
|
||||||
let node: Node;
|
let node: INode;
|
||||||
if (isNode(thing) && (copy || thing.isSlot())) {
|
if (isNode(thing) && (copy || thing.isSlot())) {
|
||||||
thing = thing.export(IPublicEnumTransformStage.Clone);
|
thing = thing.export(IPublicEnumTransformStage.Clone);
|
||||||
}
|
}
|
||||||
@ -1410,20 +1405,20 @@ export function insertChild(
|
|||||||
node = container.document.createNode(thing);
|
node = container.document.createNode(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
container.children.internalInsert(node, at);
|
container.children.insert(node, at);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function insertChildren(
|
export function insertChildren(
|
||||||
container: INode,
|
container: INode,
|
||||||
nodes: Node[] | IPublicTypeNodeData[],
|
nodes: INode[] | IPublicTypeNodeData[],
|
||||||
at?: number | null,
|
at?: number | null,
|
||||||
copy?: boolean,
|
copy?: boolean,
|
||||||
): Node[] {
|
): INode[] {
|
||||||
let index = at;
|
let index = at;
|
||||||
let node: any;
|
let node: any;
|
||||||
const results: Node[] = [];
|
const results: INode[] = [];
|
||||||
// eslint-disable-next-line no-cond-assign
|
// eslint-disable-next-line no-cond-assign
|
||||||
while ((node = nodes.pop())) {
|
while ((node = nodes.pop())) {
|
||||||
node = insertChild(container, node, index, copy);
|
node = insertChild(container, node, index, copy);
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import { DocumentModel } from '../../../src/document/document-model';
|
|||||||
import {
|
import {
|
||||||
isRootNode,
|
isRootNode,
|
||||||
Node,
|
Node,
|
||||||
isNode,
|
|
||||||
comparePosition,
|
comparePosition,
|
||||||
contains,
|
contains,
|
||||||
PositionNO,
|
PositionNO,
|
||||||
@ -23,6 +22,7 @@ import rootHeaderMetadata from '../../fixtures/component-metadata/root-header';
|
|||||||
import rootContentMetadata from '../../fixtures/component-metadata/root-content';
|
import rootContentMetadata from '../../fixtures/component-metadata/root-content';
|
||||||
import rootFooterMetadata from '../../fixtures/component-metadata/root-footer';
|
import rootFooterMetadata from '../../fixtures/component-metadata/root-footer';
|
||||||
import { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';
|
import { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory';
|
||||||
|
import { isNode } from '@alilc/lowcode-utils';
|
||||||
|
|
||||||
describe('Node 方法测试', () => {
|
describe('Node 方法测试', () => {
|
||||||
let editor: Editor;
|
let editor: Editor;
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
import { IPublicTypeTransformedComponentMetadata, IPublicTypeFieldConfig, IPublicModelSettingTarget } from '@alilc/lowcode-types';
|
import {
|
||||||
|
IPublicTypeTransformedComponentMetadata,
|
||||||
|
IPublicTypeFieldConfig,
|
||||||
|
IPublicModelSettingTarget,
|
||||||
|
} from '@alilc/lowcode-types';
|
||||||
import { IconSlot } from '../icons/slot';
|
import { IconSlot } from '../icons/slot';
|
||||||
import { getConvertedExtraKey } from '@alilc/lowcode-designer';
|
import { getConvertedExtraKey } from '@alilc/lowcode-designer';
|
||||||
|
|
||||||
export default function (metadata: IPublicTypeTransformedComponentMetadata): IPublicTypeTransformedComponentMetadata {
|
export default function (
|
||||||
|
metadata: IPublicTypeTransformedComponentMetadata,
|
||||||
|
): IPublicTypeTransformedComponentMetadata {
|
||||||
const { componentName, configure = {} } = metadata;
|
const { componentName, configure = {} } = metadata;
|
||||||
|
|
||||||
// 如果已经处理过,不再重新执行一遍
|
// 如果已经处理过,不再重新执行一遍
|
||||||
@ -111,35 +117,33 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
/*
|
// propsGroup.push({
|
||||||
propsGroup.push({
|
// name: '#generals',
|
||||||
name: '#generals',
|
// title: { type: 'i18n', 'zh-CN': '通用', 'en-US': 'General' },
|
||||||
title: { type: 'i18n', 'zh-CN': '通用', 'en-US': 'General' },
|
// items: [
|
||||||
items: [
|
// {
|
||||||
{
|
// name: 'id',
|
||||||
name: 'id',
|
// title: 'ID',
|
||||||
title: 'ID',
|
// setter: 'StringSetter',
|
||||||
setter: 'StringSetter',
|
// },
|
||||||
},
|
// {
|
||||||
{
|
// name: 'key',
|
||||||
name: 'key',
|
// title: 'Key',
|
||||||
title: 'Key',
|
// // todo: use Mixin
|
||||||
// todo: use Mixin
|
// setter: 'StringSetter',
|
||||||
setter: 'StringSetter',
|
// },
|
||||||
},
|
// {
|
||||||
{
|
// name: 'ref',
|
||||||
name: 'ref',
|
// title: 'Ref',
|
||||||
title: 'Ref',
|
// setter: 'StringSetter',
|
||||||
setter: 'StringSetter',
|
// },
|
||||||
},
|
// {
|
||||||
{
|
// name: '!more',
|
||||||
name: '!more',
|
// title: '更多',
|
||||||
title: '更多',
|
// setter: 'PropertiesSetter',
|
||||||
setter: 'PropertiesSetter',
|
// },
|
||||||
},
|
// ],
|
||||||
],
|
// });
|
||||||
});
|
|
||||||
*/
|
|
||||||
const stylesGroup: IPublicTypeFieldConfig[] = [];
|
const stylesGroup: IPublicTypeFieldConfig[] = [];
|
||||||
const advancedGroup: IPublicTypeFieldConfig[] = [];
|
const advancedGroup: IPublicTypeFieldConfig[] = [];
|
||||||
if (propsGroup) {
|
if (propsGroup) {
|
||||||
@ -216,18 +220,24 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu
|
|||||||
|
|
||||||
setValue(field: IPublicModelSettingTarget, eventData) {
|
setValue(field: IPublicModelSettingTarget, eventData) {
|
||||||
const { eventDataList, eventList } = eventData;
|
const { eventDataList, eventList } = eventData;
|
||||||
Array.isArray(eventList) && eventList.map((item) => {
|
Array.isArray(eventList) &&
|
||||||
field.parent.clearPropValue(item.name);
|
eventList.map((item) => {
|
||||||
return item;
|
field.parent.clearPropValue(item.name);
|
||||||
});
|
return item;
|
||||||
Array.isArray(eventDataList) && eventDataList.map((item) => {
|
});
|
||||||
field.parent.setPropValue(item.name, {
|
Array.isArray(eventDataList) &&
|
||||||
type: 'JSFunction',
|
eventDataList.map((item) => {
|
||||||
// 需要传下入参
|
field.parent.setPropValue(item.name, {
|
||||||
value: `function(){return this.${item.relatedEventName}.apply(this,Array.prototype.slice.call(arguments).concat([${item.paramStr ? item.paramStr : ''}])) }`,
|
type: 'JSFunction',
|
||||||
|
// 需要传下入参
|
||||||
|
value: `function(){return this.${
|
||||||
|
item.relatedEventName
|
||||||
|
}.apply(this,Array.prototype.slice.call(arguments).concat([${
|
||||||
|
item.paramStr ? item.paramStr : ''
|
||||||
|
}])) }`,
|
||||||
|
});
|
||||||
|
return item;
|
||||||
});
|
});
|
||||||
return item;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -296,7 +306,7 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'key',
|
name: 'key',
|
||||||
title: '循环 Key',
|
title: { type: 'i18n', 'zh-CN': '循环 Key', 'en-US': 'Loop Key' },
|
||||||
setter: [
|
setter: [
|
||||||
{
|
{
|
||||||
componentName: 'StringSetter',
|
componentName: 'StringSetter',
|
||||||
@ -317,8 +327,16 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu
|
|||||||
advancedGroup.push({
|
advancedGroup.push({
|
||||||
name: 'key',
|
name: 'key',
|
||||||
title: {
|
title: {
|
||||||
label: '渲染唯一标识(key)',
|
label: {
|
||||||
tip: '搭配「条件渲染」或「循环渲染」时使用,和 react 组件中的 key 原理相同,点击查看帮助',
|
type: 'i18n',
|
||||||
|
'zh-CN': '渲染唯一标识 (key)',
|
||||||
|
'en-US': 'Render unique identifier (key)',
|
||||||
|
},
|
||||||
|
tip: {
|
||||||
|
type: 'i18n',
|
||||||
|
'zh-CN': '搭配「条件渲染」或「循环渲染」时使用,和 react 组件中的 key 原理相同,点击查看帮助',
|
||||||
|
'en-US': 'Used with 「Conditional Rendering」or「Cycle Rendering」, the same principle as the key in the react component, click to view the help',
|
||||||
|
},
|
||||||
docUrl: 'https://www.yuque.com/lce/doc/qm75w3',
|
docUrl: 'https://www.yuque.com/lce/doc/qm75w3',
|
||||||
},
|
},
|
||||||
setter: [
|
setter: [
|
||||||
|
|||||||
@ -1,18 +1,102 @@
|
|||||||
/* eslint-disable max-len */
|
/* eslint-disable max-len */
|
||||||
import { isFormEvent } from '@alilc/lowcode-utils';
|
import { isFormEvent, isNodeSchema, isNode } from '@alilc/lowcode-utils';
|
||||||
import {
|
|
||||||
focusing,
|
|
||||||
insertChildren,
|
|
||||||
clipboard,
|
|
||||||
} from '@alilc/lowcode-designer';
|
|
||||||
import {
|
import {
|
||||||
IPublicModelPluginContext,
|
IPublicModelPluginContext,
|
||||||
IPublicEnumTransformStage,
|
IPublicEnumTransformStage,
|
||||||
IPublicModelNode,
|
IPublicModelNode,
|
||||||
|
IPublicTypeNodeSchema,
|
||||||
|
IPublicTypeNodeData,
|
||||||
|
IPublicEnumDragObjectType,
|
||||||
|
IPublicTypeDragNodeObject,
|
||||||
} from '@alilc/lowcode-types';
|
} from '@alilc/lowcode-types';
|
||||||
import symbols from '../modules/symbols';
|
|
||||||
|
|
||||||
const { nodeSymbol, documentSymbol } = symbols;
|
function insertChild(
|
||||||
|
container: IPublicModelNode,
|
||||||
|
originalChild: IPublicModelNode | IPublicTypeNodeData,
|
||||||
|
at?: number | null,
|
||||||
|
): IPublicModelNode | null {
|
||||||
|
let child = originalChild;
|
||||||
|
if (isNode(child) && (child as IPublicModelNode).isSlotNode) {
|
||||||
|
child = (child as IPublicModelNode).exportSchema(IPublicEnumTransformStage.Clone);
|
||||||
|
}
|
||||||
|
let node = null;
|
||||||
|
if (isNode(child)) {
|
||||||
|
node = (child as IPublicModelNode);
|
||||||
|
container.children?.insert(node, at);
|
||||||
|
} else {
|
||||||
|
node = container.document?.createNode(child) || null;
|
||||||
|
if (node) {
|
||||||
|
container.children?.insert(node, at);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (node as IPublicModelNode) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertChildren(
|
||||||
|
container: IPublicModelNode,
|
||||||
|
nodes: IPublicModelNode[] | IPublicTypeNodeData[],
|
||||||
|
at?: number | null,
|
||||||
|
): IPublicModelNode[] {
|
||||||
|
let index = at;
|
||||||
|
let node: any;
|
||||||
|
const results: IPublicModelNode[] = [];
|
||||||
|
// eslint-disable-next-line no-cond-assign
|
||||||
|
while ((node = nodes.pop())) {
|
||||||
|
node = insertChild(container, node, index);
|
||||||
|
results.push(node);
|
||||||
|
index = node.index;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得合适的插入位置
|
||||||
|
*/
|
||||||
|
function getSuitableInsertion(
|
||||||
|
pluginContext: IPublicModelPluginContext,
|
||||||
|
insertNode?: IPublicModelNode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[],
|
||||||
|
): { target: IPublicModelNode; index?: number } | null {
|
||||||
|
const { project, material } = pluginContext;
|
||||||
|
const activeDoc = project.currentDocument;
|
||||||
|
if (!activeDoc) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
Array.isArray(insertNode) &&
|
||||||
|
isNodeSchema(insertNode[0]) &&
|
||||||
|
material.getComponentMeta(insertNode[0].componentName)?.isModal
|
||||||
|
) {
|
||||||
|
if (!activeDoc.root) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
target: activeDoc.root,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const focusNode = activeDoc.focusNode!;
|
||||||
|
const nodes = activeDoc.selection.getNodes();
|
||||||
|
const refNode = nodes.find((item) => focusNode.contains(item));
|
||||||
|
let target;
|
||||||
|
let index: number | undefined;
|
||||||
|
if (!refNode || refNode === focusNode) {
|
||||||
|
target = focusNode;
|
||||||
|
} else if (refNode.componentMeta?.isContainer) {
|
||||||
|
target = refNode;
|
||||||
|
} else {
|
||||||
|
// FIXME!!, parent maybe null
|
||||||
|
target = refNode.parent!;
|
||||||
|
index = refNode.index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target && insertNode && !target.componentMeta?.checkNestingDown(target, insertNode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { target, index };
|
||||||
|
}
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
function getNextForSelect(next: IPublicModelNode | null, head?: any, parent?: IPublicModelNode | null): any {
|
function getNextForSelect(next: IPublicModelNode | null, head?: any, parent?: IPublicModelNode | null): any {
|
||||||
@ -76,11 +160,73 @@ function getPrevForSelect(prev: IPublicModelNode | null, head?: any, parent?: IP
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSuitablePlaceForNode(targetNode: IPublicModelNode, node: IPublicModelNode, ref: any): any {
|
||||||
|
const { document } = targetNode;
|
||||||
|
if (!document) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dragNodeObject: IPublicTypeDragNodeObject = {
|
||||||
|
type: IPublicEnumDragObjectType.Node,
|
||||||
|
nodes: [node],
|
||||||
|
};
|
||||||
|
|
||||||
|
const focusNode = document?.focusNode;
|
||||||
|
// 如果节点是模态框,插入到根节点下
|
||||||
|
if (node?.componentMeta?.isModal) {
|
||||||
|
return { container: focusNode, ref };
|
||||||
|
}
|
||||||
|
const canDropInFn = document.checkNesting;
|
||||||
|
|
||||||
|
if (!ref && focusNode && targetNode.contains(focusNode)) {
|
||||||
|
if (canDropInFn(focusNode, dragNodeObject)) {
|
||||||
|
return { container: focusNode };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetNode.isRootNode && targetNode.children) {
|
||||||
|
const dropElement = targetNode.children.filter((c) => {
|
||||||
|
if (!c.isContainerNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (canDropInFn(c, dragNodeObject)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
if (dropElement) {
|
||||||
|
return { container: dropElement, ref };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canDropInFn(targetNode, dragNodeObject)) {
|
||||||
|
return { container: targetNode, ref };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetNode.isContainerNode) {
|
||||||
|
if (canDropInFn(targetNode, dragNodeObject)) {
|
||||||
|
return { container: targetNode, ref };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetNode.parent) {
|
||||||
|
return getSuitablePlaceForNode(targetNode.parent, node, { index: targetNode.index });
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// 注册默认的 setters
|
// 注册默认的 setters
|
||||||
export const builtinHotkey = (ctx: IPublicModelPluginContext) => {
|
export const builtinHotkey = (ctx: IPublicModelPluginContext) => {
|
||||||
return {
|
return {
|
||||||
init() {
|
init() {
|
||||||
const { hotkey, project, logger, canvas } = ctx;
|
const { hotkey, project, logger, canvas } = ctx;
|
||||||
|
const { clipboard } = canvas;
|
||||||
// hotkey binding
|
// hotkey binding
|
||||||
hotkey.bind(['backspace', 'del'], (e: KeyboardEvent, action) => {
|
hotkey.bind(['backspace', 'del'], (e: KeyboardEvent, action) => {
|
||||||
logger.info(`action ${action} is triggered`);
|
logger.info(`action ${action} is triggered`);
|
||||||
@ -108,11 +254,11 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => {
|
|||||||
|
|
||||||
hotkey.bind('escape', (e: KeyboardEvent, action) => {
|
hotkey.bind('escape', (e: KeyboardEvent, action) => {
|
||||||
logger.info(`action ${action} is triggered`);
|
logger.info(`action ${action} is triggered`);
|
||||||
// const currentFocus = focusing.current;
|
|
||||||
if (canvas.isInLiveEditing) {
|
if (canvas.isInLiveEditing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sel = focusing.focusDesigner?.currentDocument?.selection;
|
const sel = project.currentDocument?.selection;
|
||||||
if (isFormEvent(e) || !sel) {
|
if (isFormEvent(e) || !sel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -168,26 +314,31 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO
|
// TODO
|
||||||
const designer = focusing.focusDesigner;
|
|
||||||
const doc = project?.currentDocument;
|
const doc = project?.currentDocument;
|
||||||
if (isFormEvent(e) || !designer || !doc) {
|
if (isFormEvent(e) || !doc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
clipboard.waitPasteData(e, ({ componentsTree }) => {
|
clipboard.waitPasteData(e, ({ componentsTree }) => {
|
||||||
if (componentsTree) {
|
if (componentsTree) {
|
||||||
const { target, index } = designer.getSuitableInsertion(componentsTree) || {};
|
const { target, index } = getSuitableInsertion(ctx, componentsTree) || {};
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let canAddComponentsTree = componentsTree.filter((i) => {
|
let canAddComponentsTree = componentsTree.filter((node: IPublicModelNode) => {
|
||||||
return (doc as any)[documentSymbol].checkNestingUp(target, i);
|
const dragNodeObject: IPublicTypeDragNodeObject = {
|
||||||
|
type: IPublicEnumDragObjectType.Node,
|
||||||
|
nodes: [node],
|
||||||
|
};
|
||||||
|
return doc.checkNesting(target, dragNodeObject);
|
||||||
});
|
});
|
||||||
if (canAddComponentsTree.length === 0) return;
|
if (canAddComponentsTree.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const nodes = insertChildren(target, canAddComponentsTree, index);
|
const nodes = insertChildren(target, canAddComponentsTree, index);
|
||||||
if (nodes) {
|
if (nodes) {
|
||||||
doc.selection.selectAll(nodes.map((o) => o.id));
|
doc.selection.selectAll(nodes.map((o) => o.id));
|
||||||
setTimeout(() => designer.activeTracker.track(nodes[0]), 10);
|
setTimeout(() => canvas.activeTracker?.track(nodes[0]), 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -333,14 +484,14 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => {
|
|||||||
const silbing = firstNode.prevSibling;
|
const silbing = firstNode.prevSibling;
|
||||||
if (silbing) {
|
if (silbing) {
|
||||||
if (silbing.isContainerNode) {
|
if (silbing.isContainerNode) {
|
||||||
const place = (silbing as any)[nodeSymbol].getSuitablePlace(firstNode, null);
|
const place = getSuitablePlaceForNode(silbing, firstNode, null);
|
||||||
silbing.insertAfter(firstNode, place.ref, true);
|
silbing.insertAfter(firstNode, place.ref, true);
|
||||||
} else {
|
} else {
|
||||||
parent.insertBefore(firstNode, silbing, true);
|
parent.insertBefore(firstNode, silbing, true);
|
||||||
}
|
}
|
||||||
firstNode?.select();
|
firstNode?.select();
|
||||||
} else {
|
} else {
|
||||||
const place = (parent as any)[nodeSymbol].getSuitablePlace(firstNode, null); // upwards
|
const place = getSuitablePlaceForNode(parent, firstNode, null); // upwards
|
||||||
if (place) {
|
if (place) {
|
||||||
const container = place.container.internalToShellNode();
|
const container = place.container.internalToShellNode();
|
||||||
container.insertBefore(firstNode, place.ref);
|
container.insertBefore(firstNode, place.ref);
|
||||||
@ -381,7 +532,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => {
|
|||||||
}
|
}
|
||||||
firstNode?.select();
|
firstNode?.select();
|
||||||
} else {
|
} else {
|
||||||
const place = (parent as any)[nodeSymbol].getSuitablePlace(firstNode, null); // upwards
|
const place = getSuitablePlaceForNode(parent, firstNode, null); // upwards
|
||||||
if (place) {
|
if (place) {
|
||||||
const container = place.container.internalToShellNode();
|
const container = place.container.internalToShellNode();
|
||||||
container.insertAfter(firstNode, place.ref, true);
|
container.insertAfter(firstNode, place.ref, true);
|
||||||
|
|||||||
@ -11,5 +11,12 @@
|
|||||||
"Slots": "Slots",
|
"Slots": "Slots",
|
||||||
"Slot for {prop}": "Slot for {prop}",
|
"Slot for {prop}": "Slot for {prop}",
|
||||||
"Outline Tree": "Outline Tree",
|
"Outline Tree": "Outline Tree",
|
||||||
|
"Filter Node": "Filter Node",
|
||||||
|
"Check All": "Check All",
|
||||||
|
"Conditional rendering": "Conditional rendering",
|
||||||
|
"Loop rendering": "Loop rendering",
|
||||||
|
"Locked": "Locked",
|
||||||
|
"Hidden": "Hidden",
|
||||||
|
"Modal View": "Modal View",
|
||||||
"Rename": "Rename"
|
"Rename": "Rename"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,5 +11,12 @@
|
|||||||
"Slots": "插槽",
|
"Slots": "插槽",
|
||||||
"Slot for {prop}": "属性 {prop} 的插槽",
|
"Slot for {prop}": "属性 {prop} 的插槽",
|
||||||
"Outline Tree": "大纲树",
|
"Outline Tree": "大纲树",
|
||||||
|
"Filter Node": "过滤节点",
|
||||||
|
"Check All": "全选",
|
||||||
|
"Conditional rendering": "条件渲染",
|
||||||
|
"Loop rendering": "循环渲染",
|
||||||
|
"Locked": "已锁定",
|
||||||
|
"Hidden": "已隐藏",
|
||||||
|
"Modal View": "模态视图层",
|
||||||
"Rename": "重命名"
|
"Rename": "重命名"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,16 +9,16 @@ export const FilterType = {
|
|||||||
|
|
||||||
export const FILTER_OPTIONS = [{
|
export const FILTER_OPTIONS = [{
|
||||||
value: FilterType.CONDITION,
|
value: FilterType.CONDITION,
|
||||||
label: '条件渲染',
|
label: 'Conditional rendering',
|
||||||
}, {
|
}, {
|
||||||
value: FilterType.LOOP,
|
value: FilterType.LOOP,
|
||||||
label: '循环渲染',
|
label: 'Loop rendering',
|
||||||
}, {
|
}, {
|
||||||
value: FilterType.LOCKED,
|
value: FilterType.LOCKED,
|
||||||
label: '已锁定',
|
label: 'Locked',
|
||||||
}, {
|
}, {
|
||||||
value: FilterType.HIDDEN,
|
value: FilterType.HIDDEN,
|
||||||
label: '已隐藏',
|
label: 'Hidden',
|
||||||
}];
|
}];
|
||||||
|
|
||||||
export const matchTreeNode = (
|
export const matchTreeNode = (
|
||||||
|
|||||||
@ -5,10 +5,11 @@ import { Search, Checkbox, Balloon, Divider } from '@alifd/next';
|
|||||||
import TreeNode from '../controllers/tree-node';
|
import TreeNode from '../controllers/tree-node';
|
||||||
import { Tree } from '../controllers/tree';
|
import { Tree } from '../controllers/tree';
|
||||||
import { matchTreeNode, FILTER_OPTIONS } from './filter-tree';
|
import { matchTreeNode, FILTER_OPTIONS } from './filter-tree';
|
||||||
|
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||||
|
|
||||||
export default class Filter extends Component<{
|
export default class Filter extends Component<{
|
||||||
tree: Tree;
|
tree: Tree;
|
||||||
|
pluginContext: IPublicModelPluginContext;
|
||||||
}, {
|
}, {
|
||||||
keywords: string;
|
keywords: string;
|
||||||
filterOps: string[];
|
filterOps: string[];
|
||||||
@ -55,7 +56,7 @@ export default class Filter extends Component<{
|
|||||||
<Search
|
<Search
|
||||||
hasClear
|
hasClear
|
||||||
shape="simple"
|
shape="simple"
|
||||||
placeholder="过滤节点"
|
placeholder={this.props.pluginContext.intl('Filter Node')}
|
||||||
className="lc-outline-filter-search-input"
|
className="lc-outline-filter-search-input"
|
||||||
value={keywords}
|
value={keywords}
|
||||||
onChange={this.handleSearchChange}
|
onChange={this.handleSearchChange}
|
||||||
@ -76,7 +77,7 @@ export default class Filter extends Component<{
|
|||||||
indeterminate={indeterminate}
|
indeterminate={indeterminate}
|
||||||
onChange={this.handleCheckAll}
|
onChange={this.handleCheckAll}
|
||||||
>
|
>
|
||||||
全选
|
{this.props.pluginContext.intlNode('Check All')}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Checkbox.Group
|
<Checkbox.Group
|
||||||
@ -90,7 +91,7 @@ export default class Filter extends Component<{
|
|||||||
value={op.value}
|
value={op.value}
|
||||||
key={op.value}
|
key={op.value}
|
||||||
>
|
>
|
||||||
{op.label}
|
{this.props.pluginContext.intlNode(op.label)}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
))}
|
))}
|
||||||
</Checkbox.Group>
|
</Checkbox.Group>
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
|||||||
import Filter from './filter';
|
import Filter from './filter';
|
||||||
import { TreeMaster } from '../controllers/tree-master';
|
import { TreeMaster } from '../controllers/tree-master';
|
||||||
|
|
||||||
|
|
||||||
export class Pane extends Component<{
|
export class Pane extends Component<{
|
||||||
config: any;
|
config: any;
|
||||||
pluginContext: IPublicModelPluginContext;
|
pluginContext: IPublicModelPluginContext;
|
||||||
@ -40,7 +39,7 @@ export class Pane extends Component<{
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="lc-outline-pane">
|
<div className="lc-outline-pane">
|
||||||
<Filter tree={tree} />
|
<Filter tree={tree} pluginContext={this.props.pluginContext} />
|
||||||
<div ref={(shell) => this.controller.mount(shell)} className="lc-outline-tree-container">
|
<div ref={(shell) => this.controller.mount(shell)} className="lc-outline-tree-container">
|
||||||
<TreeView key={tree.id} tree={tree} pluginContext={this.props.pluginContext} />
|
<TreeView key={tree.id} tree={tree} pluginContext={this.props.pluginContext} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class ModalTreeNodeView extends Component<{
|
|||||||
return (
|
return (
|
||||||
<div className="tree-node-modal">
|
<div className="tree-node-modal">
|
||||||
<div className="tree-node-modal-title">
|
<div className="tree-node-modal-title">
|
||||||
<span>模态视图层</span>
|
<span>{this.pluginContext.intlNode('Modal View')}</span>
|
||||||
<div
|
<div
|
||||||
className="tree-node-modal-title-visible-icon"
|
className="tree-node-modal-title-visible-icon"
|
||||||
onClick={this.hideAllNodes.bind(this)}
|
onClick={this.hideAllNodes.bind(this)}
|
||||||
|
|||||||
4
packages/react-simulator-renderer/src/locale/en-US.json
Normal file
4
packages/react-simulator-renderer/src/locale/en-US.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"Drag and drop components or templates here": "Drag and drop components or templates here",
|
||||||
|
"Locked elements and child elements cannot be edited": "Locked elements and child elements cannot be edited"
|
||||||
|
}
|
||||||
21
packages/react-simulator-renderer/src/locale/index.ts
Normal file
21
packages/react-simulator-renderer/src/locale/index.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { createElement } from 'react';
|
||||||
|
import enUS from './en-US.json';
|
||||||
|
import zhCN from './zh-CN.json';
|
||||||
|
|
||||||
|
const instance: Record<string, Record<string, string>> = {
|
||||||
|
'zh-CN': zhCN as Record<string, string>,
|
||||||
|
'en-US': enUS as Record<string, string>,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createIntl(locale: string = 'zh-CN') {
|
||||||
|
const intl = (id: string) => {
|
||||||
|
return instance[locale][id];
|
||||||
|
};
|
||||||
|
|
||||||
|
const intlNode = (id: string) => createElement('span', instance[locale][id]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
intl,
|
||||||
|
intlNode,
|
||||||
|
};
|
||||||
|
}
|
||||||
4
packages/react-simulator-renderer/src/locale/zh-CN.json
Normal file
4
packages/react-simulator-renderer/src/locale/zh-CN.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"Drag and drop components or templates here": "拖拽组件或模板到这里",
|
||||||
|
"Locked elements and child elements cannot be edited": "锁定元素及子元素无法编辑"
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import { SimulatorRendererContainer, DocumentInstance } from './renderer';
|
|||||||
import { host } from './host';
|
import { host } from './host';
|
||||||
import { isRendererDetached } from './utils/misc';
|
import { isRendererDetached } from './utils/misc';
|
||||||
import './renderer.less';
|
import './renderer.less';
|
||||||
|
import { createIntl } from './locale';
|
||||||
|
|
||||||
// patch cloneElement avoid lost keyProps
|
// patch cloneElement avoid lost keyProps
|
||||||
const originCloneElement = window.React.cloneElement;
|
const originCloneElement = window.React.cloneElement;
|
||||||
@ -130,6 +131,7 @@ class Renderer extends Component<{
|
|||||||
documentInstance: DocumentInstance;
|
documentInstance: DocumentInstance;
|
||||||
}> {
|
}> {
|
||||||
startTime: number | null = null;
|
startTime: number | null = null;
|
||||||
|
schemaChangedSymbol = false;
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.recordTime();
|
this.recordTime();
|
||||||
@ -152,8 +154,6 @@ class Renderer extends Component<{
|
|||||||
this.recordTime();
|
this.recordTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
schemaChangedSymbol = false;
|
|
||||||
|
|
||||||
getSchemaChangedSymbol = () => {
|
getSchemaChangedSymbol = () => {
|
||||||
return this.schemaChangedSymbol;
|
return this.schemaChangedSymbol;
|
||||||
};
|
};
|
||||||
@ -172,6 +172,8 @@ class Renderer extends Component<{
|
|||||||
|
|
||||||
if (!container.autoRender || isRendererDetached()) return null;
|
if (!container.autoRender || isRendererDetached()) return null;
|
||||||
|
|
||||||
|
const { intl } = createIntl(locale);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LowCodeRenderer
|
<LowCodeRenderer
|
||||||
locale={locale}
|
locale={locale}
|
||||||
@ -206,12 +208,12 @@ class Renderer extends Component<{
|
|||||||
(children == null || (Array.isArray(children) && !children.length)) &&
|
(children == null || (Array.isArray(children) && !children.length)) &&
|
||||||
(!viewProps.style || Object.keys(viewProps.style).length === 0)
|
(!viewProps.style || Object.keys(viewProps.style).length === 0)
|
||||||
) {
|
) {
|
||||||
let defaultPlaceholder = '拖拽组件或模板到这里';
|
let defaultPlaceholder = intl('Drag and drop components or templates here');
|
||||||
const lockedNode = getClosestNode(leaf, (node) => {
|
const lockedNode = getClosestNode(leaf, (node) => {
|
||||||
return node?.getExtraProp('isLocked')?.getValue() === true;
|
return node?.getExtraProp('isLocked')?.getValue() === true;
|
||||||
});
|
});
|
||||||
if (lockedNode) {
|
if (lockedNode) {
|
||||||
defaultPlaceholder = '锁定元素及子元素无法编辑';
|
defaultPlaceholder = intl('Locked elements and child elements cannot be edited');
|
||||||
}
|
}
|
||||||
children = (
|
children = (
|
||||||
<div className={cn('lc-container-placeholder', { 'lc-container-locked': !!lockedNode })} style={viewProps.placeholderStyle}>
|
<div className={cn('lc-container-placeholder', { 'lc-container-locked': !!lockedNode })} style={viewProps.placeholderStyle}>
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
IPublicModelEditor,
|
IPublicModelEditor,
|
||||||
IPublicModelDragon,
|
IPublicModelDragon,
|
||||||
IPublicModelActiveTracker,
|
IPublicModelActiveTracker,
|
||||||
|
IPublicModelClipboard,
|
||||||
} from '@alilc/lowcode-types';
|
} from '@alilc/lowcode-types';
|
||||||
import {
|
import {
|
||||||
ScrollTarget as InnerScrollTarget,
|
ScrollTarget as InnerScrollTarget,
|
||||||
@ -18,10 +19,14 @@ import {
|
|||||||
Dragon as ShellDragon,
|
Dragon as ShellDragon,
|
||||||
DropLocation as ShellDropLocation,
|
DropLocation as ShellDropLocation,
|
||||||
ActiveTracker as ShellActiveTracker,
|
ActiveTracker as ShellActiveTracker,
|
||||||
|
Clipboard as ShellClipboard,
|
||||||
} from '../model';
|
} from '../model';
|
||||||
|
|
||||||
|
const clipboardInstanceSymbol = Symbol('clipboardInstace');
|
||||||
|
|
||||||
export class Canvas implements IPublicApiCanvas {
|
export class Canvas implements IPublicApiCanvas {
|
||||||
private readonly [editorSymbol]: IPublicModelEditor;
|
private readonly [editorSymbol]: IPublicModelEditor;
|
||||||
|
private readonly [clipboardInstanceSymbol]: IPublicModelClipboard;
|
||||||
|
|
||||||
private get [designerSymbol](): IDesigner {
|
private get [designerSymbol](): IDesigner {
|
||||||
return this[editorSymbol].get('designer') as IDesigner;
|
return this[editorSymbol].get('designer') as IDesigner;
|
||||||
@ -40,8 +45,13 @@ export class Canvas implements IPublicApiCanvas {
|
|||||||
return Boolean(this[editorSymbol].get('designer')?.project?.simulator?.liveEditing?.editing);
|
return Boolean(this[editorSymbol].get('designer')?.project?.simulator?.liveEditing?.editing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get clipboard(): IPublicModelClipboard {
|
||||||
|
return this[clipboardInstanceSymbol];
|
||||||
|
}
|
||||||
|
|
||||||
constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) {
|
constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) {
|
||||||
this[editorSymbol] = editor;
|
this[editorSymbol] = editor;
|
||||||
|
this[clipboardInstanceSymbol] = new ShellClipboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
createScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget {
|
createScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
Dragon,
|
Dragon,
|
||||||
SettingPropEntry,
|
SettingPropEntry,
|
||||||
SettingTopEntry,
|
SettingTopEntry,
|
||||||
|
Clipboard,
|
||||||
} from './model';
|
} from './model';
|
||||||
import {
|
import {
|
||||||
Project,
|
Project,
|
||||||
@ -57,4 +58,5 @@ export {
|
|||||||
Logger,
|
Logger,
|
||||||
Canvas,
|
Canvas,
|
||||||
Workspace,
|
Workspace,
|
||||||
|
Clipboard,
|
||||||
};
|
};
|
||||||
22
packages/shell/src/model/clipboard.ts
Normal file
22
packages/shell/src/model/clipboard.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { IPublicModelClipboard } from '@alilc/lowcode-types';
|
||||||
|
import { clipboardSymbol } from '../symbols';
|
||||||
|
import { IClipboard, clipboard } from '@alilc/lowcode-designer';
|
||||||
|
|
||||||
|
export class Clipboard implements IPublicModelClipboard {
|
||||||
|
private readonly [clipboardSymbol]: IClipboard;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this[clipboardSymbol] = clipboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
setData(data: any): void {
|
||||||
|
this[clipboardSymbol].setData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
waitPasteData(
|
||||||
|
keyboardEvent: KeyboardEvent,
|
||||||
|
cb: (data: any, clipboardEvent: ClipboardEvent) => void,
|
||||||
|
): void {
|
||||||
|
this[clipboardSymbol].waitPasteData(keyboardEvent, cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,6 @@ import {
|
|||||||
GlobalEvent,
|
GlobalEvent,
|
||||||
IPublicModelDocumentModel,
|
IPublicModelDocumentModel,
|
||||||
IPublicTypeOnChangeOptions,
|
IPublicTypeOnChangeOptions,
|
||||||
IPublicModelDragObject,
|
|
||||||
IPublicTypeDragNodeObject,
|
IPublicTypeDragNodeObject,
|
||||||
IPublicTypeDragNodeDataObject,
|
IPublicTypeDragNodeDataObject,
|
||||||
IPublicModelNode,
|
IPublicModelNode,
|
||||||
@ -227,9 +226,11 @@ export class DocumentModel implements IPublicModelDocumentModel {
|
|||||||
dropTarget: IPublicModelNode,
|
dropTarget: IPublicModelNode,
|
||||||
dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject,
|
dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject,
|
||||||
): boolean {
|
): boolean {
|
||||||
let innerDragObject: IPublicModelDragObject = dragObject;
|
let innerDragObject = dragObject;
|
||||||
if (isDragNodeObject(dragObject)) {
|
if (isDragNodeObject(dragObject)) {
|
||||||
innerDragObject.nodes = innerDragObject.nodes.map((node: Node) => (node[nodeSymbol] || node));
|
innerDragObject.nodes = innerDragObject.nodes?.map(
|
||||||
|
(node: IPublicModelNode) => ((node as any)[nodeSymbol] || node),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return this[documentSymbol].checkNesting(
|
return this[documentSymbol].checkNesting(
|
||||||
((dropTarget as any)[nodeSymbol] || dropTarget) as any,
|
((dropTarget as any)[nodeSymbol] || dropTarget) as any,
|
||||||
|
|||||||
@ -17,4 +17,5 @@ export * from './setting-top-entry';
|
|||||||
export * from './resource';
|
export * from './resource';
|
||||||
export * from './active-tracker';
|
export * from './active-tracker';
|
||||||
export * from './plugin-instance';
|
export * from './plugin-instance';
|
||||||
export * from './window';
|
export * from './window';
|
||||||
|
export * from './clipboard';
|
||||||
@ -30,4 +30,5 @@ export const workspaceSymbol = Symbol('workspace');
|
|||||||
export const windowSymbol = Symbol('window');
|
export const windowSymbol = Symbol('window');
|
||||||
export const pluginInstanceSymbol = Symbol('plugin-instance');
|
export const pluginInstanceSymbol = Symbol('plugin-instance');
|
||||||
export const resourceTypeSymbol = Symbol('resourceType');
|
export const resourceTypeSymbol = Symbol('resourceType');
|
||||||
export const resourceSymbol = Symbol('resource');
|
export const resourceSymbol = Symbol('resource');
|
||||||
|
export const clipboardSymbol = Symbol('clipboard');
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller, IPublicModelActiveTracker } from '../model';
|
import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller, IPublicModelActiveTracker, IPublicModelClipboard } from '../model';
|
||||||
import { IPublicTypeLocationData } from '../type';
|
import { IPublicTypeLocationData } from '../type';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,4 +54,12 @@ export interface IPublicApiCanvas {
|
|||||||
* @since v1.1.0
|
* @since v1.1.0
|
||||||
*/
|
*/
|
||||||
get isInLiveEditing(): boolean;
|
get isInLiveEditing(): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取全局剪贴板实例
|
||||||
|
* get clipboard instance
|
||||||
|
*
|
||||||
|
* @since v1.1.0
|
||||||
|
*/
|
||||||
|
get clipboard(): IPublicModelClipboard;
|
||||||
}
|
}
|
||||||
|
|||||||
25
packages/types/src/shell/model/clipboard.ts
Normal file
25
packages/types/src/shell/model/clipboard.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
export interface IPublicModelClipboard {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给剪贴板赋值
|
||||||
|
* set data to clipboard
|
||||||
|
*
|
||||||
|
* @param {*} data
|
||||||
|
* @since v1.1.0
|
||||||
|
*/
|
||||||
|
setData(data: any): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置剪贴板数据设置的回调
|
||||||
|
* set callback for clipboard provide paste data
|
||||||
|
*
|
||||||
|
* @param {KeyboardEvent} keyboardEvent
|
||||||
|
* @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb
|
||||||
|
* @since v1.1.0
|
||||||
|
*/
|
||||||
|
waitPasteData(
|
||||||
|
keyboardEvent: KeyboardEvent,
|
||||||
|
cb: (data: any, clipboardEvent: ClipboardEvent) => void,
|
||||||
|
): void;
|
||||||
|
}
|
||||||
@ -29,3 +29,4 @@ export * from './preference';
|
|||||||
export * from './plugin-instance';
|
export * from './plugin-instance';
|
||||||
export * from './sensor';
|
export * from './sensor';
|
||||||
export * from './resource';
|
export * from './resource';
|
||||||
|
export * from './clipboard';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
export interface IPublicResourceData {
|
export interface IPublicResourceData {
|
||||||
resourceName: string;
|
resourceName: string;
|
||||||
title: string;
|
title: string;
|
||||||
category: string;
|
category?: string;
|
||||||
options: {
|
options: {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
|
||||||
/* eslint-disable max-len */
|
|
||||||
import {
|
import {
|
||||||
Editor,
|
Editor,
|
||||||
engineConfig, Setters as InnerSetters,
|
engineConfig, Setters as InnerSetters,
|
||||||
@ -33,8 +31,8 @@ import {
|
|||||||
IPublicTypePluginMeta,
|
IPublicTypePluginMeta,
|
||||||
} from '@alilc/lowcode-types';
|
} from '@alilc/lowcode-types';
|
||||||
import { getLogger } from '@alilc/lowcode-utils';
|
import { getLogger } from '@alilc/lowcode-utils';
|
||||||
import { Workspace as InnerWorkspace } from './workspace';
|
import { Workspace as InnerWorkspace } from '../workspace';
|
||||||
import { EditorWindow } from './editor-window/context';
|
import { EditorWindow } from '../window';
|
||||||
|
|
||||||
export class BasicContext {
|
export class BasicContext {
|
||||||
skeleton: Skeleton;
|
skeleton: Skeleton;
|
||||||
@ -2,8 +2,8 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
|||||||
import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types';
|
import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types';
|
||||||
import { flow } from 'mobx';
|
import { flow } from 'mobx';
|
||||||
import { Workspace as InnerWorkspace } from '../workspace';
|
import { Workspace as InnerWorkspace } from '../workspace';
|
||||||
import { BasicContext } from '../base-context';
|
import { BasicContext } from './base-context';
|
||||||
import { EditorWindow } from '../editor-window/context';
|
import { EditorWindow } from '../window';
|
||||||
import { getWebviewPlugin } from '../inner-plugins/webview';
|
import { getWebviewPlugin } from '../inner-plugins/webview';
|
||||||
|
|
||||||
export class Context extends BasicContext {
|
export class Context extends BasicContext {
|
||||||
@ -17,6 +17,10 @@ export class Context extends BasicContext {
|
|||||||
|
|
||||||
@obx isInit: boolean = false;
|
@obx isInit: boolean = false;
|
||||||
|
|
||||||
|
get active() {
|
||||||
|
return this._activate;
|
||||||
|
}
|
||||||
|
|
||||||
init = flow(function* (this: any) {
|
init = flow(function* (this: any) {
|
||||||
if (this.viewType === 'webview') {
|
if (this.viewType === 'webview') {
|
||||||
const url = yield this.instance?.url?.();
|
const url = yield this.instance?.url?.();
|
||||||
@ -44,10 +48,6 @@ export class Context extends BasicContext {
|
|||||||
this.innerHotkey.activate(this._activate);
|
this.innerHotkey.activate(this._activate);
|
||||||
};
|
};
|
||||||
|
|
||||||
get active() {
|
|
||||||
return this._activate;
|
|
||||||
}
|
|
||||||
|
|
||||||
async save() {
|
async save() {
|
||||||
return await this.instance?.save?.();
|
return await this.instance?.save?.();
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
export { Workspace } from './workspace';
|
export { Workspace } from './workspace';
|
||||||
export * from './editor-window/context';
|
export * from './window';
|
||||||
export * from './layouts/workbench';
|
export * from './layouts/workbench';
|
||||||
export { Resource } from './resource';
|
export { Resource } from './resource';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
import { TipContainer, observer } from '@alilc/lowcode-editor-core';
|
import { TipContainer, observer } from '@alilc/lowcode-editor-core';
|
||||||
import { EditorWindowView } from '../editor-window/view';
|
import { WindowView } from '../view/window-view';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import TopArea from './top-area';
|
import TopArea from './top-area';
|
||||||
import LeftArea from './left-area';
|
import LeftArea from './left-area';
|
||||||
@ -46,9 +46,9 @@ export class Workbench extends Component<{
|
|||||||
<div className="lc-workspace-workbench-window">
|
<div className="lc-workspace-workbench-window">
|
||||||
{
|
{
|
||||||
workspace.windows.map(d => (
|
workspace.windows.map(d => (
|
||||||
<EditorWindowView
|
<WindowView
|
||||||
active={d.id === workspace.window.id}
|
active={d.id === workspace.window.id}
|
||||||
editorWindow={d}
|
window={d}
|
||||||
key={d.id}
|
key={d.id}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { IPublicTypeEditorView, IPublicModelResource, IPublicResourceData, IPublicResourceTypeConfig } from '@alilc/lowcode-types';
|
import { IPublicTypeEditorView, IPublicModelResource, IPublicResourceData, IPublicResourceTypeConfig } from '@alilc/lowcode-types';
|
||||||
import { Logger } from '@alilc/lowcode-utils';
|
import { Logger } from '@alilc/lowcode-utils';
|
||||||
import { BasicContext } from './base-context';
|
import { BasicContext } from './context/base-context';
|
||||||
import { ResourceType } from './resource-type';
|
import { ResourceType } from './resource-type';
|
||||||
import { Workspace as InnerWorkSpace } from './workspace';
|
import { Workspace as InnerWorkSpace } from './workspace';
|
||||||
|
|
||||||
@ -13,20 +13,6 @@ export class Resource implements IPublicModelResource {
|
|||||||
|
|
||||||
editorViewMap: Map<string, IPublicTypeEditorView> = new Map<string, IPublicTypeEditorView>();
|
editorViewMap: Map<string, IPublicTypeEditorView> = new Map<string, IPublicTypeEditorView>();
|
||||||
|
|
||||||
constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) {
|
|
||||||
this.context = new BasicContext(workspace, '');
|
|
||||||
this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, {});
|
|
||||||
this.init();
|
|
||||||
if (this.resourceTypeInstance.editorViews) {
|
|
||||||
this.resourceTypeInstance.editorViews.forEach((d: any) => {
|
|
||||||
this.editorViewMap.set(d.viewName, d);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!resourceType) {
|
|
||||||
logger.error(`resourceType[${resourceType}] is unValid.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return this.resourceType.name;
|
return this.resourceType.name;
|
||||||
}
|
}
|
||||||
@ -55,6 +41,24 @@ export class Resource implements IPublicModelResource {
|
|||||||
return this.resourceData?.category;
|
return this.resourceData?.category;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get skeleton() {
|
||||||
|
return this.context.innerSkeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) {
|
||||||
|
this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`);
|
||||||
|
this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, {});
|
||||||
|
this.init();
|
||||||
|
if (this.resourceTypeInstance.editorViews) {
|
||||||
|
this.resourceTypeInstance.editorViews.forEach((d: any) => {
|
||||||
|
this.editorViewMap.set(d.viewName, d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!resourceType) {
|
||||||
|
logger.error(`resourceType[${resourceType}] is unValid.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
await this.resourceTypeInstance.init?.();
|
await this.resourceTypeInstance.init?.();
|
||||||
await this.context.innerPlugins.init();
|
await this.context.innerPlugins.init();
|
||||||
@ -63,6 +67,7 @@ export class Resource implements IPublicModelResource {
|
|||||||
async import(schema: any) {
|
async import(schema: any) {
|
||||||
return await this.resourceTypeInstance.import?.(schema);
|
return await this.resourceTypeInstance.import?.(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
async save(value: any) {
|
async save(value: any) {
|
||||||
return await this.resourceTypeInstance.save?.(value);
|
return await this.resourceTypeInstance.save?.(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,9 +4,9 @@ import {
|
|||||||
Workbench,
|
Workbench,
|
||||||
} from '@alilc/lowcode-editor-skeleton';
|
} from '@alilc/lowcode-editor-skeleton';
|
||||||
import { PureComponent } from 'react';
|
import { PureComponent } from 'react';
|
||||||
import { Context } from './context';
|
import { Context } from '../context/view-context';
|
||||||
|
|
||||||
export * from '../base-context';
|
export * from '../context/base-context';
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class EditorView extends PureComponent<{
|
export class EditorView extends PureComponent<{
|
||||||
@ -23,13 +23,11 @@ export class EditorView extends PureComponent<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Workbench
|
||||||
<Workbench
|
skeleton={skeleton}
|
||||||
skeleton={skeleton}
|
className={active ? 'active engine-editor-view' : 'engine-editor-view'}
|
||||||
className={active ? 'active engine-editor-view' : 'engine-editor-view'}
|
topAreaItemClassName="engine-actionitem"
|
||||||
topAreaItemClassName="engine-actionitem"
|
/>
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
14
packages/workspace/src/view/resource-view.less
Normal file
14
packages/workspace/src/view/resource-view.less
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.workspace-resource-view {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
flex-direction: column;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-editor-body {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
36
packages/workspace/src/view/resource-view.tsx
Normal file
36
packages/workspace/src/view/resource-view.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { PureComponent } from 'react';
|
||||||
|
import { EditorView } from './editor-view';
|
||||||
|
import { observer } from '@alilc/lowcode-editor-core';
|
||||||
|
import TopArea from '../layouts/top-area';
|
||||||
|
import { Resource } from '../resource';
|
||||||
|
import { EditorWindow } from '../window';
|
||||||
|
import './resource-view.less';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class ResourceView extends PureComponent<{
|
||||||
|
window: EditorWindow;
|
||||||
|
resource: Resource;
|
||||||
|
}, any> {
|
||||||
|
render() {
|
||||||
|
const { skeleton } = this.props.resource;
|
||||||
|
const { editorViews } = this.props.window;
|
||||||
|
return (
|
||||||
|
<div className="workspace-resource-view">
|
||||||
|
<TopArea area={skeleton.topArea} itemClassName="engine-actionitem" />
|
||||||
|
<div className="workspace-editor-body">
|
||||||
|
{
|
||||||
|
Array.from(editorViews.values()).map((editorView: any) => {
|
||||||
|
return (
|
||||||
|
<EditorView
|
||||||
|
key={editorView.name}
|
||||||
|
active={editorView.active}
|
||||||
|
editorView={editorView}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +1,17 @@
|
|||||||
import { PureComponent } from 'react';
|
import { PureComponent } from 'react';
|
||||||
import { EditorView } from '../editor-view/view';
|
import { ResourceView } from './resource-view';
|
||||||
import { engineConfig, observer } from '@alilc/lowcode-editor-core';
|
import { engineConfig, observer } from '@alilc/lowcode-editor-core';
|
||||||
import { EditorWindow } from './context';
|
import { EditorWindow } from '../window';
|
||||||
import { BuiltinLoading } from '@alilc/lowcode-designer';
|
import { BuiltinLoading } from '@alilc/lowcode-designer';
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class EditorWindowView extends PureComponent<{
|
export class WindowView extends PureComponent<{
|
||||||
editorWindow: EditorWindow;
|
window: EditorWindow;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
}, any> {
|
}, any> {
|
||||||
render() {
|
render() {
|
||||||
const { active } = this.props;
|
const { active } = this.props;
|
||||||
const { editorView, editorViews } = this.props.editorWindow;
|
const { editorView, resource } = this.props.window;
|
||||||
if (!editorView) {
|
if (!editorView) {
|
||||||
const Loading = engineConfig.get('loadingComponent', BuiltinLoading);
|
const Loading = engineConfig.get('loadingComponent', BuiltinLoading);
|
||||||
return (
|
return (
|
||||||
@ -23,17 +23,10 @@ export class EditorWindowView extends PureComponent<{
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`workspace-engine-main ${active ? 'active' : ''}`}>
|
<div className={`workspace-engine-main ${active ? 'active' : ''}`}>
|
||||||
{
|
<ResourceView
|
||||||
Array.from(editorViews.values()).map((editorView: any) => {
|
resource={resource}
|
||||||
return (
|
window={this.props.window}
|
||||||
<EditorView
|
/>
|
||||||
key={editorView.name}
|
|
||||||
active={editorView.active}
|
|
||||||
editorView={editorView}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { uniqueId } from '@alilc/lowcode-utils';
|
import { uniqueId } from '@alilc/lowcode-utils';
|
||||||
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||||
import { Context } from '../editor-view/context';
|
import { Context } from './context/view-context';
|
||||||
import { Workspace } from '../workspace';
|
import { Workspace } from './workspace';
|
||||||
import { Resource } from '../resource';
|
import { Resource } from './resource';
|
||||||
|
|
||||||
export class EditorWindow {
|
export class EditorWindow {
|
||||||
id: string = uniqueId('window');
|
id: string = uniqueId('window');
|
||||||
@ -2,8 +2,8 @@ import { Designer } from '@alilc/lowcode-designer';
|
|||||||
import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||||
import { Plugins } from '@alilc/lowcode-shell';
|
import { Plugins } from '@alilc/lowcode-shell';
|
||||||
import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types';
|
import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types';
|
||||||
import { BasicContext } from './base-context';
|
import { BasicContext } from './context/base-context';
|
||||||
import { EditorWindow } from './editor-window/context';
|
import { EditorWindow } from './window';
|
||||||
import { Resource } from './resource';
|
import { Resource } from './resource';
|
||||||
import { ResourceType } from './resource-type';
|
import { ResourceType } from './resource-type';
|
||||||
|
|
||||||
@ -20,6 +20,12 @@ export class Workspace implements IPublicApiWorkspace {
|
|||||||
|
|
||||||
private emitter: IEventBus = createModuleEventBus('workspace');
|
private emitter: IEventBus = createModuleEventBus('workspace');
|
||||||
|
|
||||||
|
private _isActive = false;
|
||||||
|
|
||||||
|
private resourceTypeMap: Map<string, ResourceType> = new Map();
|
||||||
|
|
||||||
|
private resourceList: Resource[] = [];
|
||||||
|
|
||||||
get skeleton() {
|
get skeleton() {
|
||||||
return this.context.innerSkeleton;
|
return this.context.innerSkeleton;
|
||||||
}
|
}
|
||||||
@ -28,7 +34,17 @@ export class Workspace implements IPublicApiWorkspace {
|
|||||||
return this.context.innerPlugins;
|
return this.context.innerPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _isActive = false;
|
get isActive() {
|
||||||
|
return this._isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
get defaultResourceType(): ResourceType | null {
|
||||||
|
if (this.resourceTypeMap.size >= 1) {
|
||||||
|
return Array.from(this.resourceTypeMap.values())[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
windows: EditorWindow[] = [];
|
windows: EditorWindow[] = [];
|
||||||
|
|
||||||
@ -36,10 +52,6 @@ export class Workspace implements IPublicApiWorkspace {
|
|||||||
|
|
||||||
@obx.ref window: EditorWindow;
|
@obx.ref window: EditorWindow;
|
||||||
|
|
||||||
private resourceTypeMap: Map<string, ResourceType> = new Map();
|
|
||||||
|
|
||||||
private resourceList: Resource[] = [];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise<void>,
|
readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise<void>,
|
||||||
readonly shellModelFactory: any,
|
readonly shellModelFactory: any,
|
||||||
@ -66,10 +78,6 @@ export class Workspace implements IPublicApiWorkspace {
|
|||||||
this.emitChangeActiveWindow();
|
this.emitChangeActiveWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
get isActive() {
|
|
||||||
return this._isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
setActive(value: boolean) {
|
setActive(value: boolean) {
|
||||||
this._isActive = value;
|
this._isActive = value;
|
||||||
}
|
}
|
||||||
@ -105,14 +113,6 @@ export class Workspace implements IPublicApiWorkspace {
|
|||||||
return this.resourceTypeMap.get(resourceName)!;
|
return this.resourceTypeMap.get(resourceName)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultResourceType(): ResourceType | null {
|
|
||||||
if (this.resourceTypeMap.size >= 1) {
|
|
||||||
return Array.from(this.resourceTypeMap.values())[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeResourceType(resourceName: string) {
|
removeResourceType(resourceName: string) {
|
||||||
if (this.resourceTypeMap.has(resourceName)) {
|
if (this.resourceTypeMap.has(resourceName)) {
|
||||||
this.resourceTypeMap.delete(resourceName);
|
this.resourceTypeMap.delete(resourceName);
|
||||||
@ -153,13 +153,17 @@ export class Workspace implements IPublicApiWorkspace {
|
|||||||
console.error(`${name} is not available`);
|
console.error(`${name} is not available`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filterWindows = this.windows.filter(d => (d.resource.name === name && d.title == title));
|
const filterWindows = this.windows.filter(d => (d.resource.name === name && d.resource.title == title));
|
||||||
if (filterWindows && filterWindows.length) {
|
if (filterWindows && filterWindows.length) {
|
||||||
this.window = filterWindows[0];
|
this.window = filterWindows[0];
|
||||||
this.emitChangeActiveWindow();
|
this.emitChangeActiveWindow();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const resource = new Resource({}, resourceType, this);
|
const resource = new Resource({
|
||||||
|
resourceName: name,
|
||||||
|
title,
|
||||||
|
options,
|
||||||
|
}, resourceType, this);
|
||||||
this.window = new EditorWindow(resource, this, title, options);
|
this.window = new EditorWindow(resource, this, title, options);
|
||||||
this.windows.push(this.window);
|
this.windows.push(this.window);
|
||||||
this.editorWindowMap.set(this.window.id, this.window);
|
this.editorWindowMap.set(this.window.id, this.window);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user