mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-13 07:16:04 +00:00
feat: add some big features to engine
This commit is contained in:
parent
89f4b11303
commit
c2db198415
@ -32,14 +32,14 @@ sidebar_position: 11
|
||||
*引擎版本 >= 1.0.16
|
||||
```typescript
|
||||
import { common } from '@alilc/lowcode-engine';
|
||||
import { TransitionType } from '@alilc/lowcode-types';
|
||||
import { IPublicEnumTransitionType } from '@alilc/lowcode-types';
|
||||
|
||||
common.utils.startTransaction(() => {
|
||||
node1.setProps();
|
||||
node2.setProps();
|
||||
node3.setProps();
|
||||
// ...
|
||||
}, TransitionType.repaint);
|
||||
}, IPublicEnumTransitionType.repaint);
|
||||
```
|
||||
|
||||
### createIntl
|
||||
|
||||
@ -53,7 +53,7 @@ function saveSchema(schema) {
|
||||
// 保存 schema 相关操作
|
||||
}
|
||||
|
||||
const saveSampleHotKey = (ctx: ILowCodePluginContext) => {
|
||||
const saveSampleHotKey = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
name: 'saveSample',
|
||||
async init() {
|
||||
|
||||
@ -3,7 +3,7 @@ title: logger - 日志 API
|
||||
sidebar_position: 9
|
||||
---
|
||||
## 模块简介
|
||||
引擎日志模块,可以按照 **日志级别 **和** 业务类型 **两个维度来定制日志,基于 [zen-logger](https://web.npm.alibaba-inc.com/package/zen-logger) 封装。
|
||||
引擎日志模块,可以按照 **日志级别 **和** 业务类型 **两个维度来定制日志,参考 [zen-logger](https://web.npm.alibaba-inc.com/package/zen-logger) 实现进行封装。
|
||||
> 注:日志级别可以通过 url query 动态调整,详见下方使用示例。
|
||||
|
||||
## 变量(variables)
|
||||
@ -22,8 +22,8 @@ function debug(args: any[]): void
|
||||
```
|
||||
**调用示例**
|
||||
```typescript
|
||||
import { logger } from '@alilc/lowcode-engine';
|
||||
|
||||
import { Logger } from '@alilc/lowcode-utils';
|
||||
const logger = new Logger({ level: 'warn', bizName: 'designer:pluginManager' });
|
||||
logger.log('Awesome Low-Code Engine');
|
||||
```
|
||||
## 事件(events)
|
||||
@ -31,9 +31,9 @@ logger.log('Awesome Low-Code Engine');
|
||||
|
||||
## 使用示例
|
||||
```typescript
|
||||
import { logger } from '@alilc/lowcode-engine';
|
||||
import { Logger } from '@alilc/lowcode-utils';
|
||||
|
||||
// 内部实现:logger = getLogger({ level: 'warn', bizName: 'designer:pluginManager' })
|
||||
const logger = new Logger({ level: 'warn', bizName: 'designer:pluginManager' });
|
||||
|
||||
// 若在 url query 中增加 `__logConf__` 可改变打印日志级别和限定业务类型日志
|
||||
// 默认:__logConf__=warn:*
|
||||
|
||||
@ -30,10 +30,11 @@ material.setAssets(assets);
|
||||
|
||||
通过物料中心接口动态引入资产包
|
||||
```typescript
|
||||
import { ILowCodePluginContext, material, plugins } from '@alilc/lowcode-engine'
|
||||
import { material, plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
// 动态加载 assets
|
||||
plugins.register((ctx: ILowCodePluginContext) => {
|
||||
plugins.register((ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
name: 'ext-assets',
|
||||
async init() {
|
||||
@ -88,9 +89,9 @@ material.loadIncrementalAssets(assets2);
|
||||
在设计器辅助层增加一个扩展 action
|
||||
**类型定义**
|
||||
```typescript
|
||||
function addBuiltinComponentAction(action: ComponentAction): void;
|
||||
function addBuiltinComponentAction(action: IPublicTypeComponentAction): void;
|
||||
|
||||
export interface ComponentAction {
|
||||
export interface IPublicTypeComponentAction {
|
||||
/**
|
||||
* behaviorName
|
||||
*/
|
||||
@ -102,7 +103,7 @@ export interface ComponentAction {
|
||||
/**
|
||||
* 子集
|
||||
*/
|
||||
items?: ComponentAction[];
|
||||
items?: IPublicTypeComponentAction[];
|
||||
/**
|
||||
* 显示与否
|
||||
* always: 无法禁用
|
||||
@ -174,7 +175,7 @@ material.removeBuiltinComponentAction('myIconName');
|
||||
```typescript
|
||||
function modifyBuiltinComponentAction(
|
||||
actionName: string,
|
||||
handle: (action: ComponentAction) => void
|
||||
handle: (action: IPublicTypeComponentAction) => void
|
||||
): void;
|
||||
```
|
||||
**内置设计器辅助 name**
|
||||
@ -293,7 +294,7 @@ material.registerMetadataTransducer(addonCombine, 1, 'parse-func');
|
||||
获取所有物料元数据管道函数
|
||||
**类型定义**
|
||||
```typescript
|
||||
function getRegisteredMetadataTransducers(): MetadataTransducer[];
|
||||
function getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[];
|
||||
```
|
||||
|
||||
**示例**
|
||||
|
||||
@ -13,11 +13,11 @@ sidebar_position: 4
|
||||
#### 类型定义
|
||||
```typescript
|
||||
async function register(
|
||||
pluginConfigCreator: (ctx: ILowCodePluginContext) => ILowCodePluginConfig,
|
||||
pluginConfigCreator: (ctx: IPublicModelPluginContext) => IPublicTypePluginConfig,
|
||||
options?: ILowCodeRegisterOptions,
|
||||
): Promise<void>
|
||||
```
|
||||
pluginConfigCreator 是一个 ILowCodePluginConfig 生成函数,ILowCodePluginConfig 中包含了该插件的 init / destroy 等钩子函数,以及 exports 函数用于返回插件对外暴露的值。
|
||||
pluginConfigCreator 是一个 IPublicTypePluginConfig 生成函数,IPublicTypePluginConfig 中包含了该插件的 init / destroy 等钩子函数,以及 exports 函数用于返回插件对外暴露的值。
|
||||
|
||||
另外,pluginConfigCreator 还必须挂载 pluginName 字段,全局确保唯一,否则 register 时会报错,可以选择性挂载 meta 字段,用于描述插件的元数据信息,比如兼容的引擎版本、支持的参数配置、依赖插件声明等。
|
||||
> 注:pluginConfigCreator 挂载 pluginName / meta 可以通过低代码工具链的插件脚手架生成,写如 package.json 后将会自动注入到代码中,具体见 [插件元数据工程化示例](#RO9YY)
|
||||
@ -26,8 +26,9 @@ pluginConfigCreator 是一个 ILowCodePluginConfig 生成函数,ILowCodePlugin
|
||||
#### 简单示例
|
||||
```typescript
|
||||
import { plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const builtinPluginRegistry = (ctx: ILowCodePluginContext) => {
|
||||
const builtinPluginRegistry = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
async init() {
|
||||
const { skeleton } = ctx;
|
||||
@ -58,8 +59,9 @@ await plugins.register(builtinPluginRegistry);
|
||||
#### 使用 exports 示例
|
||||
```typescript
|
||||
import { plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const pluginA = (ctx: ILowCodePluginContext) => {
|
||||
const pluginA = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
async init() {},
|
||||
exports() { return { x: 1, } },
|
||||
@ -67,7 +69,7 @@ const pluginA = (ctx: ILowCodePluginContext) => {
|
||||
}
|
||||
pluginA.pluginName = 'pluginA';
|
||||
|
||||
const pluginB = (ctx: ILowCodePluginContext) => {
|
||||
const pluginB = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
async init() {
|
||||
// 获取 pluginA 的导出值
|
||||
@ -83,14 +85,15 @@ pluginB.meta = {
|
||||
await plugins.register(pluginA);
|
||||
await plugins.register(pluginB);
|
||||
```
|
||||
> 注:ctx 是在插件 creator 中获取引擎 API 的上下文,具体定义参见 [ILowCodePluginContext](#qEhTb)
|
||||
> 注:ctx 是在插件 creator 中获取引擎 API 的上下文,具体定义参见 [IPublicModelPluginContext](#qEhTb)
|
||||
|
||||
####
|
||||
#### 设置兼容引擎版本示例
|
||||
```typescript
|
||||
import { plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const builtinPluginRegistry = (ctx: ILowCodePluginContext) => {
|
||||
const builtinPluginRegistry = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
async init() {
|
||||
...
|
||||
@ -108,8 +111,9 @@ await plugins.register(builtinPluginRegistry);
|
||||
#### 设置插件参数版本示例
|
||||
```typescript
|
||||
import { plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const builtinPluginRegistry = (ctx: ILowCodePluginContext, options: any) => {
|
||||
const builtinPluginRegistry = (ctx: IPublicModelPluginContext, options: any) => {
|
||||
return {
|
||||
async init() {
|
||||
// 1.0.4 之后的传值方式,通过 register(xxx, options)
|
||||
@ -219,27 +223,27 @@ plugins.delete('builtinPluginRegistry');
|
||||
## 事件(events)
|
||||
无
|
||||
## 相关模块
|
||||
### ILowCodePluginContext
|
||||
### IPublicModelPluginContext
|
||||
**类型定义**
|
||||
```typescript
|
||||
export interface ILowCodePluginContext {
|
||||
skeleton: Skeleton; // 参考面板 API
|
||||
hotkey: Hotkey; // 参考快捷键 API
|
||||
setters: Setters; // 参考设置器 API
|
||||
config: EngineConfig; // 参考配置 API
|
||||
material: Material; // 参考物料 API
|
||||
event: Event; // 参考事件 API
|
||||
project: Project; // 参考模型 API
|
||||
common: Common; // 参考模型 API
|
||||
logger: Logger; // 参考日志 API
|
||||
plugins: ILowCodePluginManager; // 即本文档描述内容
|
||||
export interface IPublicModelPluginContext {
|
||||
get skeleton(): IPublicApiSkeleton;
|
||||
get hotkey(): IPublicApiHotkey;
|
||||
get setters(): IPublicApiSetters;
|
||||
get config(): IEngineConfig;
|
||||
get material(): IPublicApiMaterial;
|
||||
get event(): IPublicApiEvent;
|
||||
get project(): IPublicApiProject;
|
||||
get common(): IPublicApiCommon;
|
||||
logger: IPublicApiLogger;
|
||||
plugins: IPublicApiPlugins;
|
||||
preference: IPluginPreferenceMananger;
|
||||
}
|
||||
```
|
||||
### ILowCodePluginConfig
|
||||
### IPublicTypePluginConfig
|
||||
**类型定义**
|
||||
```typescript
|
||||
export interface ILowCodePluginConfig {
|
||||
export interface IPublicTypePluginConfig {
|
||||
init?(): void;
|
||||
destroy?(): void;
|
||||
exports?(): any;
|
||||
@ -263,7 +267,7 @@ your-plugin/package.json
|
||||
```
|
||||
转换后的结构:
|
||||
```json
|
||||
const debug = (ctx: ILowCodePluginContext, options: any) => {
|
||||
const debug = (ctx: IPublicModelPluginContext, options: any) => {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@ -79,10 +79,10 @@ addPropsTransducer(transducer: PropsTransducer, stage: TransformStage)
|
||||
|
||||
**示例 1:在保存的时候删除每一个组件的 props.hidden**
|
||||
```typescript
|
||||
import { ILowCodePluginContext, project } from '@alilc/lowcode-engine';
|
||||
import { CompositeObject, TransformStage } from '@alilc/lowcode-types';
|
||||
import { project } from '@alilc/lowcode-engine';
|
||||
import { CompositeObject, TransformStage, IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
export const deleteHiddenTransducer = (ctx: ILowCodePluginContext) => {
|
||||
export const deleteHiddenTransducer = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
name: 'deleteHiddenTransducer',
|
||||
async init() {
|
||||
|
||||
@ -38,8 +38,9 @@ function registerSetter(
|
||||
```typescript
|
||||
import { setters, skeleton } from '@alilc/lowcode-engine';
|
||||
import { setterMap, pluginMap } from '@alilc/lowcode-engine-ext';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const setterRegistry = (ctx: ILowCodePluginContext) => {
|
||||
const setterRegistry = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
name: 'ext-setters-registry',
|
||||
async init() {
|
||||
@ -209,8 +210,9 @@ function registerSetter(
|
||||
```typescript
|
||||
import { setters, skeleton } from '@alilc/lowcode-engine';
|
||||
import { setterMap, pluginMap } from '@alilc/lowcode-engine-ext';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const setterRegistry = (ctx: ILowCodePluginContext) => {
|
||||
const setterRegistry = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
name: 'ext-setters-registry',
|
||||
async init() {
|
||||
|
||||
@ -130,12 +130,13 @@ npm publish
|
||||
2. 在引擎初始化侧引入插件
|
||||
```typescript
|
||||
import Inject, { injectAssets } from '@alilc/lowcode-plugin-inject';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
export default async () => {
|
||||
// 注意 Inject 插件必须在其他插件前注册,且所有插件的注册必须 await
|
||||
await plugins.register(Inject);
|
||||
await plugins.register(OtherPlugin);
|
||||
await plugins.register((ctx: ILowCodePluginContext) => {
|
||||
await plugins.register((ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
name: "editor-init",
|
||||
async init() {
|
||||
|
||||
@ -270,10 +270,11 @@ npm publish
|
||||
|
||||
### 在项目中引入资产包
|
||||
```typescript
|
||||
import { ILowCodePluginContext, material, plugins } from '@alilc/lowcode-engine';
|
||||
import { material, plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
// 动态加载 assets
|
||||
plugins.register((ctx: ILowCodePluginContext) => {
|
||||
plugins.register((ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
name: 'ext-assets',
|
||||
async init() {
|
||||
|
||||
@ -10,9 +10,10 @@ sidebar_position: 6
|
||||
|
||||
```typescript
|
||||
import { plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
import { Icon, Message } from '@alifd/next';
|
||||
|
||||
const addHelloAction = (ctx: ILowCodePluginContext) => {
|
||||
const addHelloAction = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
async init() {
|
||||
const { addBuiltinComponentAction } = ctx.material;
|
||||
@ -46,8 +47,9 @@ await plugins.register(addHelloAction);
|
||||
|
||||
```typescript
|
||||
import { plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const removeCopyAction = (ctx: ILowCodePluginContext) => {
|
||||
const removeCopyAction = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
async init() {
|
||||
const { removeBuiltinComponentAction } = ctx.material;
|
||||
|
||||
@ -17,9 +17,10 @@ sidebar_position: 5
|
||||
## 注册插件 API
|
||||
|
||||
```typescript
|
||||
import { plugins, ILowCodePluginContext } from '@alilc/lowcode-engine';
|
||||
import { plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const pluginA = (ctx: ILowCodePluginContext, options: any) => {
|
||||
const pluginA = (ctx: IPublicModelPluginContext, options: any) => {
|
||||
return {
|
||||
init() {
|
||||
console.log(options.key);
|
||||
|
||||
@ -34,10 +34,11 @@ material.setAssets(assets);
|
||||
|
||||
也可以通过异步加载物料中心上的物料。
|
||||
```typescript
|
||||
import { ILowCodePluginContext, material, plugins } from '@alilc/lowcode-engine';
|
||||
import { material, plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
// 动态加载 assets
|
||||
plugins.register((ctx: ILowCodePluginContext) => {
|
||||
plugins.register((ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
name: 'ext-assets',
|
||||
async init() {
|
||||
@ -57,7 +58,8 @@ plugins.register((ctx: ILowCodePluginContext) => {
|
||||
### 配置插件
|
||||
可以通过 npm 包的方式引入社区插件,配置如下所示:
|
||||
```typescript
|
||||
import { ILowCodePluginContext, plugins } from '@alilc/lowcode-engine';
|
||||
import { plugins } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
import PluginIssueTracker from '@alilc/lowcode-plugin-issue-tracker';
|
||||
|
||||
// 注册一个提 issue 组件到您的编辑器中,方位默认在左栏下侧
|
||||
|
||||
@ -125,9 +125,9 @@ Demo 根据**不同的设计器所需要的物料不同**,分为了下面的 8
|
||||
可以在 demo/sample-plugins 直接新增插件,这里我新增的插件目录是 plugin-demo。并且新增了 index.tsx 文件,将下面的代码粘贴到 index.tsx 中。
|
||||
```javascript
|
||||
import * as React from 'react';
|
||||
import { ILowCodePluginContext } from '@alilc/lowcode-engine';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
const LowcodePluginPluginDemo = (ctx: ILowCodePluginContext) => {
|
||||
const LowcodePluginPluginDemo = (ctx: IPublicModelPluginContext) => {
|
||||
return {
|
||||
// 插件对外暴露的数据和方法
|
||||
exports() {
|
||||
|
||||
22
modules/code-generator/babelTransform.js
Normal file
22
modules/code-generator/babelTransform.js
Normal file
@ -0,0 +1,22 @@
|
||||
const babelJest = require('babel-jest');
|
||||
const getBabelConfig = require('build-scripts-config/lib/config/babel/index.js');
|
||||
const formatWinPath = require('build-scripts-config/lib/config/jest/formatWinPath');
|
||||
const babelConfig = getBabelConfig();
|
||||
|
||||
babelConfig.plugins.push(['@babel/plugin-proposal-class-properties', { loose: true }]);
|
||||
|
||||
const jestBabelConfig = {
|
||||
...babelConfig,
|
||||
presets: babelConfig.presets.map((preset) => {
|
||||
if (Array.isArray(preset) && formatWinPath(preset[0]).indexOf('@babel/preset-env') > -1) {
|
||||
return [preset[0], {
|
||||
targets: {
|
||||
node: 'current',
|
||||
},
|
||||
}];
|
||||
}
|
||||
return preset;
|
||||
}),
|
||||
};
|
||||
|
||||
module.exports = babelJest.createTransformer(jestBabelConfig);
|
||||
@ -1,4 +1,8 @@
|
||||
module.exports = {
|
||||
transform: {
|
||||
'^.+\\.(js|jsx|ts|tsx)$': './babelTransform.js',
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': 'build-scripts-config/lib/config/jest/fileTransform.js',
|
||||
},
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
transformIgnorePatterns: ['/node_modules/(?!core-js)/'],
|
||||
|
||||
@ -98,6 +98,7 @@
|
||||
"qs": "^6.10.1",
|
||||
"semver": "^7.3.4",
|
||||
"short-uuid": "^3.1.1",
|
||||
"babel-jest": "^26.5.2",
|
||||
"tslib": "^2.3.1"
|
||||
},
|
||||
"browser": {
|
||||
@ -125,11 +126,11 @@
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-react": "^7.22.0",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"jest": "^27.4.7",
|
||||
"jest": "^26.5.2",
|
||||
"jest-util": "^27.4.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"standard-version": "^9.1.1",
|
||||
"ts-jest": "^27.1.3",
|
||||
"ts-jest": "^26.5.2",
|
||||
"ts-loader": "^6.2.2",
|
||||
"ts-node": "^8.10.2",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import type { NodeSchema, CompositeObject } from '@alilc/lowcode-types';
|
||||
import type { IPublicTypeNodeSchema, IPublicTypeCompositeObject } from '@alilc/lowcode-types';
|
||||
import type { TComponentAnalyzer } from '../types';
|
||||
|
||||
import { handleSubNodes } from '../utils/schema';
|
||||
|
||||
export const componentAnalyzer: TComponentAnalyzer = (container) => {
|
||||
let hasRefAttr = false;
|
||||
const nodeValidator = (n: NodeSchema) => {
|
||||
const nodeValidator = (n: IPublicTypeNodeSchema) => {
|
||||
if (n.props) {
|
||||
const props = n.props as CompositeObject;
|
||||
const props = n.props as IPublicTypeCompositeObject;
|
||||
if (props.ref) {
|
||||
hasRefAttr = true;
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import * as path from 'path';
|
||||
import { getErrorMessage } from '../utils/errors';
|
||||
import CodeGenerator from '..';
|
||||
import type { IProjectBuilder } from '..';
|
||||
import type { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
|
||||
/**
|
||||
* 执行出码 CLI 命令
|
||||
@ -131,7 +131,7 @@ function isLocalSolution(solution: string) {
|
||||
return solution.startsWith('.') || solution.startsWith('/') || solution.startsWith('~');
|
||||
}
|
||||
|
||||
async function loadSchemaFile(schemaFile: string): Promise<ProjectSchema> {
|
||||
async function loadSchemaFile(schemaFile: string): Promise<IPublicTypeProjectSchema> {
|
||||
if (!schemaFile) {
|
||||
throw new Error('invalid schema file name');
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ProjectSchema, ResultFile, ResultDir } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeProjectSchema, ResultFile, ResultDir } from '@alilc/lowcode-types';
|
||||
|
||||
import {
|
||||
BuilderComponentPlugin,
|
||||
@ -77,7 +77,7 @@ export function createModuleBuilder(
|
||||
};
|
||||
};
|
||||
|
||||
const generateModuleCode = async (schema: ProjectSchema | string): Promise<ResultDir> => {
|
||||
const generateModuleCode = async (schema: IPublicTypeProjectSchema | string): Promise<ResultDir> => {
|
||||
// Init
|
||||
const schemaParser: ISchemaParser = new SchemaParser();
|
||||
const parseResult: IParseResult = schemaParser.parse(schema);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ResultDir, ResultFile, ProjectSchema } from '@alilc/lowcode-types';
|
||||
import { ResultDir, ResultFile, IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
|
||||
import {
|
||||
IModuleBuilder,
|
||||
@ -87,13 +87,13 @@ export class ProjectBuilder implements IProjectBuilder {
|
||||
this.extraContextData = extraContextData;
|
||||
}
|
||||
|
||||
async generateProject(originalSchema: ProjectSchema | string): Promise<ResultDir> {
|
||||
async generateProject(originalSchema: IPublicTypeProjectSchema | string): Promise<ResultDir> {
|
||||
// Init
|
||||
const { schemaParser } = this;
|
||||
|
||||
const projectRoot = await this.template.generateTemplate();
|
||||
|
||||
let schema: ProjectSchema =
|
||||
let schema: IPublicTypeProjectSchema =
|
||||
typeof originalSchema === 'string' ? JSON.parse(originalSchema) : originalSchema;
|
||||
|
||||
// Parse / Format
|
||||
|
||||
@ -4,14 +4,14 @@
|
||||
*/
|
||||
import changeCase from 'change-case';
|
||||
import {
|
||||
UtilItem,
|
||||
IPublicTypeUtilItem,
|
||||
NodeDataType,
|
||||
NodeSchema,
|
||||
ContainerSchema,
|
||||
ProjectSchema,
|
||||
PropsMap,
|
||||
NodeData,
|
||||
NpmInfo,
|
||||
IPublicTypeNodeSchema,
|
||||
IPublicTypeContainerSchema,
|
||||
IPublicTypeProjectSchema,
|
||||
IPublicTypePropsMap,
|
||||
IPublicTypeNodeData,
|
||||
IPublicTypeNpmInfo,
|
||||
} from '@alilc/lowcode-types';
|
||||
import {
|
||||
IPageMeta,
|
||||
@ -72,18 +72,18 @@ function getRootComponentName(typeName: string, maps: Record<string, IExternalDe
|
||||
return typeName;
|
||||
}
|
||||
|
||||
function processChildren(schema: NodeSchema): void {
|
||||
function processChildren(schema: IPublicTypeNodeSchema): void {
|
||||
if (schema.props) {
|
||||
if (Array.isArray(schema.props)) {
|
||||
// FIXME: is array type props description
|
||||
} else {
|
||||
const nodeProps = schema.props as PropsMap;
|
||||
const nodeProps = schema.props as IPublicTypePropsMap;
|
||||
if (nodeProps.children) {
|
||||
if (!schema.children) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
schema.children = nodeProps.children as NodeDataType;
|
||||
} else {
|
||||
let _children: NodeData[] = [];
|
||||
let _children: IPublicTypeNodeData[] = [];
|
||||
|
||||
if (Array.isArray(schema.children)) {
|
||||
_children = _children.concat(schema.children);
|
||||
@ -92,9 +92,9 @@ function processChildren(schema: NodeSchema): void {
|
||||
}
|
||||
|
||||
if (Array.isArray(nodeProps.children)) {
|
||||
_children = _children.concat(nodeProps.children as NodeData[]);
|
||||
_children = _children.concat(nodeProps.children as IPublicTypeNodeData[]);
|
||||
} else {
|
||||
_children.push(nodeProps.children as NodeData);
|
||||
_children.push(nodeProps.children as IPublicTypeNodeData);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
@ -107,7 +107,7 @@ function processChildren(schema: NodeSchema): void {
|
||||
}
|
||||
|
||||
export class SchemaParser implements ISchemaParser {
|
||||
validate(schema: ProjectSchema): boolean {
|
||||
validate(schema: IPublicTypeProjectSchema): boolean {
|
||||
if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) {
|
||||
throw new CompatibilityError(`Not support schema with version [${schema.version}]`);
|
||||
}
|
||||
@ -115,7 +115,7 @@ export class SchemaParser implements ISchemaParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
parse(schemaSrc: ProjectSchema | string): IParseResult {
|
||||
parse(schemaSrc: IPublicTypeProjectSchema | string): IParseResult {
|
||||
// TODO: collect utils depends in JSExpression
|
||||
const compDeps: Record<string, IExternalDependency> = {};
|
||||
const internalDeps: Record<string, IInternalDependency> = {};
|
||||
@ -140,7 +140,7 @@ export class SchemaParser implements ISchemaParser {
|
||||
let containers: IContainerInfo[];
|
||||
// Test if this is a lowcode component without container
|
||||
if (schema.componentsTree.length > 0) {
|
||||
const firstRoot: ContainerSchema = schema.componentsTree[0] as ContainerSchema;
|
||||
const firstRoot: IPublicTypeContainerSchema = schema.componentsTree[0] as IPublicTypeContainerSchema;
|
||||
|
||||
if (!firstRoot.fileName && !isValidContainerType(firstRoot)) {
|
||||
// 整个 schema 描述一个容器,且无根节点定义
|
||||
@ -150,13 +150,13 @@ export class SchemaParser implements ISchemaParser {
|
||||
props: firstRoot.props || defaultContainer.props,
|
||||
css: firstRoot.css || defaultContainer.css,
|
||||
moduleName: (firstRoot as IContainerInfo).moduleName || defaultContainer.moduleName,
|
||||
children: schema.componentsTree as NodeSchema[],
|
||||
children: schema.componentsTree as IPublicTypeNodeSchema[],
|
||||
};
|
||||
containers = [container];
|
||||
} else {
|
||||
// 普通带 1 到多个容器的 schema
|
||||
containers = schema.componentsTree.map((n) => {
|
||||
const subRoot = n as ContainerSchema;
|
||||
const subRoot = n as IPublicTypeContainerSchema;
|
||||
const container: IContainerInfo = {
|
||||
...subRoot,
|
||||
componentName: getRootComponentName(subRoot.componentName, compDeps),
|
||||
@ -173,7 +173,7 @@ export class SchemaParser implements ISchemaParser {
|
||||
// 分析引用能力的依赖
|
||||
containers = containers.map((con) => ({
|
||||
...con,
|
||||
analyzeResult: componentAnalyzer(con as ContainerSchema),
|
||||
analyzeResult: componentAnalyzer(con as IPublicTypeContainerSchema),
|
||||
}));
|
||||
|
||||
// 建立所有容器的内部依赖索引
|
||||
@ -211,7 +211,7 @@ export class SchemaParser implements ISchemaParser {
|
||||
handleSubNodes<void>(
|
||||
container.children,
|
||||
{
|
||||
node: (i: NodeSchema) => processChildren(i),
|
||||
node: (i: IPublicTypeNodeSchema) => processChildren(i),
|
||||
},
|
||||
{
|
||||
rerun: true,
|
||||
@ -255,12 +255,12 @@ export class SchemaParser implements ISchemaParser {
|
||||
.filter((dep) => !!dep);
|
||||
|
||||
// 分析 Utils 依赖
|
||||
let utils: UtilItem[];
|
||||
let utils: IPublicTypeUtilItem[];
|
||||
if (schema.utils) {
|
||||
utils = schema.utils;
|
||||
utilsDeps = schema.utils
|
||||
.filter(
|
||||
(u): u is { name: string; type: 'npm' | 'tnpm'; content: NpmInfo } => u.type !== 'function',
|
||||
(u): u is { name: string; type: 'npm' | 'tnpm'; content: IPublicTypeNpmInfo } => u.type !== 'function',
|
||||
)
|
||||
.map(
|
||||
(u): IExternalDependency => ({
|
||||
@ -335,7 +335,7 @@ export class SchemaParser implements ISchemaParser {
|
||||
return handleSubNodes<string>(
|
||||
children,
|
||||
{
|
||||
node: (i: NodeSchema) => i.componentName,
|
||||
node: (i: IPublicTypeNodeSchema) => i.componentName,
|
||||
},
|
||||
{
|
||||
rerun: true,
|
||||
@ -343,8 +343,8 @@ export class SchemaParser implements ISchemaParser {
|
||||
);
|
||||
}
|
||||
|
||||
decodeSchema(schemaSrc: string | ProjectSchema): ProjectSchema {
|
||||
let schema: ProjectSchema;
|
||||
decodeSchema(schemaSrc: string | IPublicTypeProjectSchema): IPublicTypeProjectSchema {
|
||||
let schema: IPublicTypeProjectSchema;
|
||||
if (typeof schemaSrc === 'string') {
|
||||
try {
|
||||
schema = JSON.parse(schemaSrc);
|
||||
@ -359,7 +359,7 @@ export class SchemaParser implements ISchemaParser {
|
||||
return schema;
|
||||
}
|
||||
|
||||
private collectDataSourcesTypes(schema: ProjectSchema): string[] {
|
||||
private collectDataSourcesTypes(schema: IPublicTypeProjectSchema): string[] {
|
||||
const dataSourcesTypes = new Set<string>();
|
||||
|
||||
// 数据源的默认类型为 fetch
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/indent */
|
||||
|
||||
import {
|
||||
CompositeValue,
|
||||
JSExpression,
|
||||
IPublicTypeCompositeValue,
|
||||
IPublicTypeJSExpression,
|
||||
InterpretDataSourceConfig,
|
||||
isJSExpression,
|
||||
isJSFunction,
|
||||
@ -56,7 +56,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
||||
(dataSourceConfig && dataSourceConfig.list) || [];
|
||||
const dataSourceEngineOptions = { runtimeConfig: true };
|
||||
if (dataSourceItems.length > 0) {
|
||||
const requestHandlersMap: Record<string, JSExpression> = {};
|
||||
const requestHandlersMap: Record<string, IPublicTypeJSExpression> = {};
|
||||
|
||||
dataSourceItems.forEach((ds) => {
|
||||
const dsType = ds.type || 'fetch';
|
||||
@ -178,7 +178,7 @@ _defineDataSourceConfig() {
|
||||
|
||||
export default pluginFactory;
|
||||
|
||||
function wrapAsFunction(value: CompositeValue, scope: IScope): CompositeValue {
|
||||
function wrapAsFunction(value: IPublicTypeCompositeValue, scope: IScope): IPublicTypeCompositeValue {
|
||||
if (isJSExpression(value) || isJSFunction(value)) {
|
||||
return {
|
||||
type: 'JSExpression',
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import {
|
||||
NodeSchema,
|
||||
JSExpression,
|
||||
NpmInfo,
|
||||
CompositeValue,
|
||||
IPublicTypeNodeSchema,
|
||||
IPublicTypeJSExpression,
|
||||
IPublicTypeNpmInfo,
|
||||
IPublicTypeCompositeValue,
|
||||
isJSExpression,
|
||||
} from '@alilc/lowcode-types';
|
||||
|
||||
@ -86,7 +86,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
||||
// 2. 小程序出码的时候,很容易出现 Uncaught TypeError: Cannot read property 'avatar' of undefined 这样的异常(如下图的 50 行) -- 因为若直接出码,Rax 构建到小程序的时候会立即计算所有在视图中用到的变量
|
||||
// 3. 通过 this.xxx 能拿到的东西太多了,而且自定义的 methods 可能会无意间破坏 Rax 框架或小程序框架在页面 this 上的东东
|
||||
const customHandlers: HandlerSet<string> = {
|
||||
expression(input: JSExpression, scope: IScope) {
|
||||
expression(input: IPublicTypeJSExpression, scope: IScope) {
|
||||
return transformJsExpr(generateExpression(input, scope), scope, {
|
||||
dontWrapEval: !tolerateEvalErrors,
|
||||
});
|
||||
@ -171,7 +171,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
||||
return next;
|
||||
|
||||
function generateRaxLoopCtrl(
|
||||
nodeItem: NodeSchema,
|
||||
nodeItem: IPublicTypeNodeSchema,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
next?: NodePlugin,
|
||||
@ -218,7 +218,7 @@ function isImportAliasDefineChunk(chunk: ICodeChunk): chunk is ICodeChunk & {
|
||||
ext: {
|
||||
aliasName: string;
|
||||
originalName: string;
|
||||
dependency: NpmInfo;
|
||||
dependency: IPublicTypeNpmInfo;
|
||||
};
|
||||
} {
|
||||
return (
|
||||
@ -226,13 +226,13 @@ function isImportAliasDefineChunk(chunk: ICodeChunk): chunk is ICodeChunk & {
|
||||
!!chunk.ext &&
|
||||
typeof chunk.ext.aliasName === 'string' &&
|
||||
typeof chunk.ext.originalName === 'string' &&
|
||||
!!(chunk.ext.dependency as NpmInfo | null)?.componentName
|
||||
!!(chunk.ext.dependency as IPublicTypeNpmInfo | null)?.componentName
|
||||
);
|
||||
}
|
||||
|
||||
function generateNodeAttrForRax(
|
||||
this: { cfg: PluginConfig },
|
||||
attrData: { attrName: string; attrValue: CompositeValue },
|
||||
attrData: { attrName: string; attrValue: IPublicTypeCompositeValue },
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
next?: AttrPlugin,
|
||||
@ -257,7 +257,7 @@ function generateNodeAttrForRax(
|
||||
|
||||
function generateEventHandlerAttrForRax(
|
||||
attrName: string,
|
||||
attrValue: CompositeValue,
|
||||
attrValue: IPublicTypeCompositeValue,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
): CodePiece[] {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/indent */
|
||||
|
||||
import {
|
||||
CompositeValue,
|
||||
JSExpression,
|
||||
IPublicTypeCompositeValue,
|
||||
IPublicTypeJSExpression,
|
||||
InterpretDataSourceConfig,
|
||||
isJSExpression,
|
||||
isJSFunction,
|
||||
@ -72,7 +72,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
||||
(dataSourceConfig && dataSourceConfig.list) || [];
|
||||
const dataSourceEngineOptions = { runtimeConfig: true };
|
||||
if (dataSourceItems.length > 0) {
|
||||
const requestHandlersMap: Record<string, JSExpression> = {};
|
||||
const requestHandlersMap: Record<string, IPublicTypeJSExpression> = {};
|
||||
|
||||
dataSourceItems.forEach((ds) => {
|
||||
const dsType = ds.type || 'fetch';
|
||||
@ -187,7 +187,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
||||
|
||||
export default pluginFactory;
|
||||
|
||||
function wrapAsFunction(value: CompositeValue, scope: IScope): CompositeValue {
|
||||
function wrapAsFunction(value: IPublicTypeCompositeValue, scope: IScope): IPublicTypeCompositeValue {
|
||||
if (isJSExpression(value) || isJSFunction(value)) {
|
||||
return {
|
||||
type: 'JSExpression',
|
||||
|
||||
@ -16,7 +16,7 @@ import { COMMON_CHUNK_NAME } from '../../../const/generator';
|
||||
|
||||
import { createReactNodeGenerator } from '../../../utils/nodeToJSX';
|
||||
import { Scope } from '../../../utils/Scope';
|
||||
import { JSExpression } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeJSExpression } from '@alilc/lowcode-types';
|
||||
import { generateExpression } from '../../../utils/jsExpression';
|
||||
import { transformJsExpr } from '../../../core/jsx/handlers/transformJsExpression';
|
||||
import { transformThis2Context } from '../../../core/jsx/handlers/transformThis2Context';
|
||||
@ -47,7 +47,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
||||
// 这里会将内部的一些子上下文的访问(this.xxx)转换为 __$$context.xxx 的形式
|
||||
// 与 Rax 所不同的是,这里不会将最顶层的 this 转换掉
|
||||
const customHandlers: HandlerSet<string> = {
|
||||
expression(input: JSExpression, scope: IScope, config) {
|
||||
expression(input: IPublicTypeJSExpression, scope: IScope, config) {
|
||||
return transformJsExpr(generateExpression(input, scope), scope, {
|
||||
dontWrapEval: !(config?.tolerateEvalErrors ?? tolerateEvalErrors),
|
||||
dontTransformThis2ContextAtRootScope: true,
|
||||
@ -120,7 +120,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) =>
|
||||
function __$$eval(expr) {
|
||||
try {
|
||||
return expr();
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
${evalErrorsHandler}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { NpmInfo, PackageJSON } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeNpmInfo, PackageJSON } from '@alilc/lowcode-types';
|
||||
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||
|
||||
import {
|
||||
@ -84,9 +84,9 @@ const pluginFactory: BuilderComponentPluginFactory<RaxFrameworkOptions> = (cfg)
|
||||
|
||||
export default pluginFactory;
|
||||
|
||||
function getNpmDependencies(project: IProjectInfo): NpmInfo[] {
|
||||
const npmDeps: NpmInfo[] = [];
|
||||
const npmNameToPkgMap = new Map<string, NpmInfo>();
|
||||
function getNpmDependencies(project: IProjectInfo): IPublicTypeNpmInfo[] {
|
||||
const npmDeps: IPublicTypeNpmInfo[] = [];
|
||||
const npmNameToPkgMap = new Map<string, IPublicTypeNpmInfo>();
|
||||
|
||||
const allDeps = project.packages;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import fetch from 'node-fetch';
|
||||
import type { ProjectSchema, ResultDir } from '@alilc/lowcode-types';
|
||||
import type { IPublicTypeProjectSchema, ResultDir } from '@alilc/lowcode-types';
|
||||
import type { FlattenFile } from './types/file';
|
||||
|
||||
declare const Worker: any;
|
||||
@ -26,7 +26,7 @@ export type Result = ResultDir | FlattenFile[];
|
||||
|
||||
export async function generateCode(options: {
|
||||
solution: 'icejs' | 'rax';
|
||||
schema: ProjectSchema;
|
||||
schema: IPublicTypeProjectSchema;
|
||||
flattenResult?: boolean;
|
||||
workerJsUrl?: string;
|
||||
timeoutInMs?: number;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* eslint-disable no-console */
|
||||
import type { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
import CodeGen from './standalone';
|
||||
|
||||
declare const self: any;
|
||||
@ -13,7 +13,7 @@ self.onmessage = (event: any) => {
|
||||
|
||||
self.postMessage({ type: 'ready' });
|
||||
|
||||
async function run(msg: { solution: string; schema: ProjectSchema; flattenResult?: boolean }) {
|
||||
async function run(msg: { solution: string; schema: IPublicTypeProjectSchema; flattenResult?: boolean }) {
|
||||
try {
|
||||
print('begin run...');
|
||||
self.postMessage({ type: 'run:begin' });
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { ContainerSchema } from '@alilc/lowcode-types';
|
||||
import type { IPublicTypeContainerSchema } from '@alilc/lowcode-types';
|
||||
|
||||
export interface ICompAnalyzeResult {
|
||||
isUsingRef: boolean;
|
||||
}
|
||||
|
||||
export type TComponentAnalyzer = (container: ContainerSchema) => ICompAnalyzeResult;
|
||||
export type TComponentAnalyzer = (container: IPublicTypeContainerSchema) => ICompAnalyzeResult;
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import {
|
||||
JSONArray,
|
||||
JSONObject,
|
||||
CompositeArray,
|
||||
CompositeObject,
|
||||
IPublicTypeJSONArray,
|
||||
IPublicTypeJSONObject,
|
||||
IPublicTypeCompositeArray,
|
||||
IPublicTypeCompositeObject,
|
||||
ResultDir,
|
||||
ResultFile,
|
||||
NodeDataType,
|
||||
ProjectSchema,
|
||||
JSExpression,
|
||||
JSFunction,
|
||||
JSSlot,
|
||||
IPublicTypeProjectSchema,
|
||||
IPublicTypeJSExpression,
|
||||
IPublicTypeJSFunction,
|
||||
IPublicTypeJSSlot,
|
||||
} from '@alilc/lowcode-types';
|
||||
|
||||
import { IParseResult } from './intermediate';
|
||||
@ -96,7 +96,7 @@ export interface ICompiledModule {
|
||||
|
||||
export interface IModuleBuilder {
|
||||
generateModule: (input: unknown) => Promise<ICompiledModule>;
|
||||
generateModuleCode: (schema: ProjectSchema | string) => Promise<ResultDir>;
|
||||
generateModuleCode: (schema: IPublicTypeProjectSchema | string) => Promise<ResultDir>;
|
||||
linkCodeChunks: (chunks: Record<string, ICodeChunk[]>, fileName: string) => ResultFile[];
|
||||
addPlugin: (plugin: BuilderComponentPlugin) => void;
|
||||
}
|
||||
@ -111,16 +111,16 @@ export interface ICodeGenerator {
|
||||
/**
|
||||
* 出码接口,把 Schema 转换成代码文件系统描述
|
||||
*
|
||||
* @param {(ProjectSchema)} schema 传入的 Schema
|
||||
* @param {(IPublicTypeProjectSchema)} schema 传入的 Schema
|
||||
* @returns {ResultDir}
|
||||
* @memberof ICodeGenerator
|
||||
*/
|
||||
toCode: (schema: ProjectSchema) => Promise<ResultDir>;
|
||||
toCode: (schema: IPublicTypeProjectSchema) => Promise<ResultDir>;
|
||||
}
|
||||
|
||||
export interface ISchemaParser {
|
||||
validate: (schema: ProjectSchema) => boolean;
|
||||
parse: (schema: ProjectSchema | string) => IParseResult;
|
||||
validate: (schema: IPublicTypeProjectSchema) => boolean;
|
||||
parse: (schema: IPublicTypeProjectSchema | string) => IParseResult;
|
||||
}
|
||||
|
||||
export interface IProjectTemplate {
|
||||
@ -165,11 +165,11 @@ export interface IProjectBuilderOptions {
|
||||
}
|
||||
|
||||
export interface IProjectBuilder {
|
||||
generateProject: (schema: ProjectSchema | string) => Promise<ResultDir>;
|
||||
generateProject: (schema: IPublicTypeProjectSchema | string) => Promise<ResultDir>;
|
||||
}
|
||||
|
||||
/** 项目级别的前置处理器 */
|
||||
export type ProjectPreProcessor = (schema: ProjectSchema) => Promise<ProjectSchema> | ProjectSchema;
|
||||
export type ProjectPreProcessor = (schema: IPublicTypeProjectSchema) => Promise<IPublicTypeProjectSchema> | IPublicTypeProjectSchema;
|
||||
|
||||
export interface ProjectPostProcessorOptions {
|
||||
parseResult?: IParseResult;
|
||||
@ -179,8 +179,8 @@ export interface ProjectPostProcessorOptions {
|
||||
/** 项目级别的后置处理器 */
|
||||
export type ProjectPostProcessor = (
|
||||
result: ResultDir,
|
||||
schema: ProjectSchema,
|
||||
originalSchema: ProjectSchema | string,
|
||||
schema: IPublicTypeProjectSchema,
|
||||
originalSchema: IPublicTypeProjectSchema | string,
|
||||
options: ProjectPostProcessorOptions,
|
||||
) => Promise<ResultDir> | ResultDir;
|
||||
|
||||
@ -209,16 +209,16 @@ export type NodeGenerator<T> = (nodeItem: NodeDataType, scope: IScope) => T;
|
||||
|
||||
// FIXME: 在新的实现中,添加了第一参数 this: CustomHandlerSet 作为上下文。究其本质
|
||||
// scopeBindings?: IScopeBindings;
|
||||
// 这个组合只用来用来处理 CompositeValue 类型,不是这个类型的不要放在这里
|
||||
// 这个组合只用来用来处理 IPublicTypeCompositeValue 类型,不是这个类型的不要放在这里
|
||||
export interface HandlerSet<T> {
|
||||
string?: CompositeTypeGenerator<string, T>;
|
||||
boolean?: CompositeTypeGenerator<boolean, T>;
|
||||
number?: CompositeTypeGenerator<number, T>;
|
||||
expression?: CompositeTypeGenerator<JSExpression, T>;
|
||||
function?: CompositeTypeGenerator<JSFunction, T>;
|
||||
slot?: CompositeTypeGenerator<JSSlot, T>;
|
||||
array?: CompositeTypeGenerator<JSONArray | CompositeArray, T>;
|
||||
object?: CompositeTypeGenerator<JSONObject | CompositeObject, T>;
|
||||
expression?: CompositeTypeGenerator<IPublicTypeJSExpression, T>;
|
||||
function?: CompositeTypeGenerator<IPublicTypeJSFunction, T>;
|
||||
slot?: CompositeTypeGenerator<IPublicTypeJSSlot, T>;
|
||||
array?: CompositeTypeGenerator<IPublicTypeJSONArray | IPublicTypeCompositeArray, T>;
|
||||
object?: CompositeTypeGenerator<IPublicTypeJSONObject | IPublicTypeCompositeObject, T>;
|
||||
}
|
||||
|
||||
export interface CompositeValueGeneratorOptions {
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import { I18nMap, UtilsMap, ContainerSchema, JSONObject } from '@alilc/lowcode-types';
|
||||
import {
|
||||
IPublicTypeI18nMap,
|
||||
IPublicTypeUtilsMap,
|
||||
IPublicTypeContainerSchema,
|
||||
IPublicTypeJSONObject,
|
||||
} from '@alilc/lowcode-types';
|
||||
|
||||
import { IDependency, INpmPackage } from './deps';
|
||||
import { ICompAnalyzeResult } from './analyze';
|
||||
@ -6,7 +11,7 @@ import { ICompAnalyzeResult } from './analyze';
|
||||
export interface IParseResult {
|
||||
containers: IContainerInfo[];
|
||||
globalUtils?: IUtilInfo;
|
||||
globalI18n?: I18nMap;
|
||||
globalI18n?: IPublicTypeI18nMap;
|
||||
globalRouter?: IRouterInfo;
|
||||
project?: IProjectInfo;
|
||||
}
|
||||
@ -15,14 +20,14 @@ export interface IWithDependency {
|
||||
deps?: IDependency[];
|
||||
}
|
||||
|
||||
export interface IContainerInfo extends ContainerSchema, IWithDependency {
|
||||
export interface IContainerInfo extends IPublicTypeContainerSchema, IWithDependency {
|
||||
containerType: string;
|
||||
moduleName: string;
|
||||
analyzeResult?: ICompAnalyzeResult;
|
||||
}
|
||||
|
||||
export interface IUtilInfo extends IWithDependency {
|
||||
utils: UtilsMap;
|
||||
utils: IPublicTypeUtilsMap;
|
||||
}
|
||||
|
||||
export interface IRouterInfo extends IWithDependency {
|
||||
@ -45,8 +50,8 @@ export interface IProjectInfo {
|
||||
css?: string;
|
||||
containersDeps?: IDependency[];
|
||||
utilsDeps?: IDependency[];
|
||||
constants?: JSONObject;
|
||||
i18n?: I18nMap;
|
||||
constants?: IPublicTypeJSONObject;
|
||||
i18n?: IPublicTypeI18nMap;
|
||||
packages: INpmPackage[];
|
||||
meta?: { name?: string; title?: string } | Record<string, any>;
|
||||
config?: Record<string, any>;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { NodeSchema, CompositeValue } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeNodeSchema, IPublicTypeCompositeValue } from '@alilc/lowcode-types';
|
||||
import { HandlerSet, BaseGenerator, NodeGenerator } from './core';
|
||||
|
||||
export enum PIECE_TYPE {
|
||||
@ -17,11 +17,11 @@ export interface CodePiece {
|
||||
|
||||
export interface AttrData {
|
||||
attrName: string;
|
||||
attrValue: CompositeValue;
|
||||
attrValue: IPublicTypeCompositeValue;
|
||||
}
|
||||
// 对 JSX 出码的理解,目前定制点包含 【包装】【标签名】【属性】
|
||||
// 对 JSX 出码的理解,目前定制点包含【包装】【标签名】【属性】
|
||||
export type AttrPlugin = BaseGenerator<AttrData, CodePiece[], NodeGeneratorConfig>;
|
||||
export type NodePlugin = BaseGenerator<NodeSchema, CodePiece[], NodeGeneratorConfig>;
|
||||
export type NodePlugin = BaseGenerator<IPublicTypeNodeSchema, CodePiece[], NodeGeneratorConfig>;
|
||||
|
||||
export interface NodeGeneratorConfig {
|
||||
handlers?: HandlerSet<string>;
|
||||
@ -33,7 +33,7 @@ export interface NodeGeneratorConfig {
|
||||
/**
|
||||
* 是否要容忍对 JSExpression 求值时的异常
|
||||
* 默认:true
|
||||
* 注: 如果容忍异常,则会在求值时包裹 try-catch 块 -- 通过 __$$eval / __$$evalArray
|
||||
* 注:如果容忍异常,则会在求值时包裹 try-catch 块 -- 通过 __$$eval / __$$evalArray
|
||||
* catch 到异常时默认会抛出一个 CustomEvent 事件里面包含异常信息和求值的表达式
|
||||
*/
|
||||
tolerateEvalErrors?: boolean;
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import {
|
||||
CompositeArray,
|
||||
CompositeValue,
|
||||
CompositeObject,
|
||||
JSFunction,
|
||||
JSExpression,
|
||||
IPublicTypeCompositeArray,
|
||||
IPublicTypeCompositeValue,
|
||||
IPublicTypeCompositeObject,
|
||||
IPublicTypeJSFunction,
|
||||
IPublicTypeJSExpression,
|
||||
isJSExpression,
|
||||
isJSFunction,
|
||||
isJSSlot,
|
||||
JSSlot,
|
||||
IPublicTypeJSSlot,
|
||||
} from '@alilc/lowcode-types';
|
||||
import _ from 'lodash';
|
||||
|
||||
@ -43,7 +43,7 @@ function isDataSource(v: unknown): v is DataSource {
|
||||
}
|
||||
|
||||
function generateArray(
|
||||
value: CompositeArray,
|
||||
value: IPublicTypeCompositeArray,
|
||||
scope: IScope,
|
||||
options: CompositeValueGeneratorOptions = {},
|
||||
): string {
|
||||
@ -52,7 +52,7 @@ function generateArray(
|
||||
}
|
||||
|
||||
function generateObject(
|
||||
value: CompositeObject,
|
||||
value: IPublicTypeCompositeObject,
|
||||
scope: IScope,
|
||||
options: CompositeValueGeneratorOptions = {},
|
||||
): string {
|
||||
@ -88,7 +88,7 @@ function generateBool(value: boolean): string {
|
||||
return value ? 'true' : 'false';
|
||||
}
|
||||
|
||||
function genFunction(value: JSFunction): string {
|
||||
function genFunction(value: IPublicTypeJSFunction): string {
|
||||
const globalVars = parseExpressionGetKeywords(value.value);
|
||||
|
||||
if (globalVars.includes('arguments')) {
|
||||
@ -98,7 +98,7 @@ function genFunction(value: JSFunction): string {
|
||||
return generateFunction(value, { isArrow: true });
|
||||
}
|
||||
|
||||
function genJsSlot(value: JSSlot, scope: IScope, options: CompositeValueGeneratorOptions = {}) {
|
||||
function genJsSlot(value: IPublicTypeJSSlot, scope: IScope, options: CompositeValueGeneratorOptions = {}) {
|
||||
if (options.nodeGenerator) {
|
||||
return generateJsSlot(value, scope, options.nodeGenerator);
|
||||
}
|
||||
@ -106,7 +106,7 @@ function genJsSlot(value: JSSlot, scope: IScope, options: CompositeValueGenerato
|
||||
}
|
||||
|
||||
function generateUnknownType(
|
||||
value: CompositeValue,
|
||||
value: IPublicTypeCompositeValue,
|
||||
scope: IScope,
|
||||
options: CompositeValueGeneratorOptions = {},
|
||||
): string {
|
||||
@ -128,7 +128,7 @@ function generateUnknownType(
|
||||
// FIXME: 这个是临时方案
|
||||
// 在遇到 type variable 私有类型时,转换为 JSExpression
|
||||
if (isVariable(value)) {
|
||||
const transValue: JSExpression = {
|
||||
const transValue: IPublicTypeJSExpression = {
|
||||
type: 'JSExpression',
|
||||
value: value.variable,
|
||||
};
|
||||
@ -188,7 +188,7 @@ function generateUnknownType(
|
||||
if (options.handlers?.object) {
|
||||
return executeFunctionStack(value, scope, options.handlers.object, generateObject, options);
|
||||
}
|
||||
return generateObject(value as CompositeObject, scope, options);
|
||||
return generateObject(value as IPublicTypeCompositeObject, scope, options);
|
||||
}
|
||||
|
||||
if (_.isString(value)) {
|
||||
@ -218,7 +218,7 @@ function generateUnknownType(
|
||||
// 这一层曾经是对产出做最外层包装的,但其实包装逻辑不应该属于这一层
|
||||
// 这一层先不去掉,做冗余,方便后续重构
|
||||
export function generateCompositeType(
|
||||
value: CompositeValue,
|
||||
value: IPublicTypeCompositeValue,
|
||||
scope: IScope,
|
||||
options: CompositeValueGeneratorOptions = {},
|
||||
): string {
|
||||
|
||||
@ -2,7 +2,7 @@ import * as parser from '@babel/parser';
|
||||
import generate from '@babel/generator';
|
||||
import traverse from '@babel/traverse';
|
||||
import * as t from '@babel/types';
|
||||
import { JSExpression, JSFunction, isJSExpression, isJSFunction } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeJSExpression, IPublicTypeJSFunction, isJSExpression, isJSFunction } from '@alilc/lowcode-types';
|
||||
import { CodeGeneratorError, IScope } from '../types';
|
||||
import { transformExpressionLocalRef, ParseError } from './expressionParser';
|
||||
|
||||
@ -84,7 +84,7 @@ export function isJsCode(value: unknown): boolean {
|
||||
|
||||
export function generateExpression(value: any, scope: IScope): string {
|
||||
if (isJSExpression(value)) {
|
||||
const exprVal = (value as JSExpression).value.trim();
|
||||
const exprVal = (value as IPublicTypeJSExpression).value.trim();
|
||||
if (!exprVal) {
|
||||
return 'null';
|
||||
}
|
||||
@ -113,7 +113,7 @@ export function generateFunction(
|
||||
},
|
||||
) {
|
||||
if (isJsCode(value)) {
|
||||
const functionCfg = value as JSFunction;
|
||||
const functionCfg = value as IPublicTypeJSFunction;
|
||||
if (config.isMember) {
|
||||
return transformFuncExpr2MethodMember(config.name || '', functionCfg.value);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { JSSlot, isJSSlot, NodeData } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeJSSlot, isJSSlot, IPublicTypeNodeData } from '@alilc/lowcode-types';
|
||||
import { CodeGeneratorError, NodeGenerator, IScope } from '../types';
|
||||
import { unwrapJsExprQuoteInJsx } from './jsxHelpers';
|
||||
|
||||
@ -8,7 +8,7 @@ function generateSingleLineComment(commentText: string): string {
|
||||
|
||||
export function generateJsSlot(slot: any, scope: IScope, generator: NodeGenerator<string>): string {
|
||||
if (isJSSlot(slot)) {
|
||||
const { title, params, value } = slot as JSSlot;
|
||||
const { title, params, value } = slot as IPublicTypeJSSlot;
|
||||
|
||||
// slot 也是分有参数和无参数的
|
||||
// - 有参数的 slot 就是类似一个 render 函数,需要创建子作用域
|
||||
@ -39,7 +39,7 @@ export function generateJsSlot(slot: any, scope: IScope, generator: NodeGenerato
|
||||
}
|
||||
|
||||
function generateNodeDataOrArrayForJsSlot(
|
||||
value: NodeData | NodeData[],
|
||||
value: IPublicTypeNodeData | IPublicTypeNodeData[],
|
||||
generator: NodeGenerator<string>,
|
||||
scope: IScope,
|
||||
) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
import { pipe } from 'fp-ts/function';
|
||||
import { NodeSchema, isNodeSchema, NodeDataType, CompositeValue } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeNodeSchema, isNodeSchema, NodeDataType, IPublicTypeCompositeValue } from '@alilc/lowcode-types';
|
||||
|
||||
import {
|
||||
IScope,
|
||||
@ -57,7 +57,7 @@ export function isPureString(v: string) {
|
||||
}
|
||||
|
||||
function generateAttrValue(
|
||||
attrData: { attrName: string; attrValue: CompositeValue },
|
||||
attrData: { attrName: string; attrValue: IPublicTypeCompositeValue },
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
): CodePiece[] {
|
||||
@ -76,7 +76,7 @@ function generateAttrValue(
|
||||
|
||||
function generateAttr(
|
||||
attrName: string,
|
||||
attrValue: CompositeValue,
|
||||
attrValue: IPublicTypeCompositeValue,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
): CodePiece[] {
|
||||
@ -115,7 +115,7 @@ function generateAttr(
|
||||
}
|
||||
|
||||
function generateAttrs(
|
||||
nodeItem: NodeSchema,
|
||||
nodeItem: IPublicTypeNodeSchema,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
): CodePiece[] {
|
||||
@ -144,7 +144,7 @@ function generateAttrs(
|
||||
}
|
||||
|
||||
function generateBasicNode(
|
||||
nodeItem: NodeSchema,
|
||||
nodeItem: IPublicTypeNodeSchema,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
): CodePiece[] {
|
||||
@ -160,7 +160,7 @@ function generateBasicNode(
|
||||
}
|
||||
|
||||
function generateSimpleNode(
|
||||
nodeItem: NodeSchema,
|
||||
nodeItem: IPublicTypeNodeSchema,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
): CodePiece[] {
|
||||
@ -216,13 +216,13 @@ function linkPieces(pieces: CodePiece[]): string {
|
||||
}
|
||||
|
||||
function generateNodeSchema(
|
||||
nodeItem: NodeSchema,
|
||||
nodeItem: IPublicTypeNodeSchema,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
): string {
|
||||
const pieces: CodePiece[] = [];
|
||||
if (config?.nodePlugins) {
|
||||
const res = executeFunctionStack<NodeSchema, CodePiece[], NodeGeneratorConfig>(
|
||||
const res = executeFunctionStack<IPublicTypeNodeSchema, CodePiece[], NodeGeneratorConfig>(
|
||||
nodeItem,
|
||||
scope,
|
||||
config.nodePlugins,
|
||||
@ -247,11 +247,11 @@ function generateNodeSchema(
|
||||
* @type NodePlugin Extended
|
||||
*
|
||||
* @export
|
||||
* @param {NodeSchema} nodeItem 当前 UI 节点
|
||||
* @param {IPublicTypeNodeSchema} nodeItem 当前 UI 节点
|
||||
* @returns {CodePiece[]} 实现功能的相关代码片段
|
||||
*/
|
||||
export function generateReactLoopCtrl(
|
||||
nodeItem: NodeSchema,
|
||||
nodeItem: IPublicTypeNodeSchema,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
next?: NodePlugin,
|
||||
@ -301,11 +301,11 @@ export function generateReactLoopCtrl(
|
||||
* @type NodePlugin
|
||||
*
|
||||
* @export
|
||||
* @param {NodeSchema} nodeItem 当前 UI 节点
|
||||
* @param {IPublicTypeNodeSchema} nodeItem 当前 UI 节点
|
||||
* @returns {CodePiece[]} 实现功能的相关代码片段
|
||||
*/
|
||||
export function generateConditionReactCtrl(
|
||||
nodeItem: NodeSchema,
|
||||
nodeItem: IPublicTypeNodeSchema,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
next?: NodePlugin,
|
||||
@ -336,11 +336,11 @@ export function generateConditionReactCtrl(
|
||||
* @type NodePlugin
|
||||
*
|
||||
* @export
|
||||
* @param {NodeSchema} nodeItem 当前 UI 节点
|
||||
* @param {IPublicTypeNodeSchema} nodeItem 当前 UI 节点
|
||||
* @returns {CodePiece[]} 实现功能的相关代码片段
|
||||
*/
|
||||
export function generateReactExprInJS(
|
||||
nodeItem: NodeSchema,
|
||||
nodeItem: IPublicTypeNodeSchema,
|
||||
scope: IScope,
|
||||
config?: NodeGeneratorConfig,
|
||||
next?: NodePlugin,
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import * as _ from 'lodash';
|
||||
import {
|
||||
JSExpression,
|
||||
NodeData,
|
||||
NodeSchema,
|
||||
IPublicTypeJSExpression,
|
||||
IPublicTypeNodeData,
|
||||
IPublicTypeNodeSchema,
|
||||
isJSExpression,
|
||||
isJSSlot,
|
||||
isDOMText,
|
||||
ContainerSchema,
|
||||
NpmInfo,
|
||||
CompositeValue,
|
||||
IPublicTypeContainerSchema,
|
||||
IPublicTypeNpmInfo,
|
||||
IPublicTypeCompositeValue,
|
||||
isNodeSchema,
|
||||
isJSFunction,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { CodeGeneratorError } from '../types/error';
|
||||
|
||||
export function isContainerSchema(x: any): x is ContainerSchema {
|
||||
export function isContainerSchema(x: any): x is IPublicTypeContainerSchema {
|
||||
return (
|
||||
typeof x === 'object' &&
|
||||
x &&
|
||||
@ -23,7 +23,7 @@ export function isContainerSchema(x: any): x is ContainerSchema {
|
||||
);
|
||||
}
|
||||
|
||||
export function isNpmInfo(x: any): x is NpmInfo {
|
||||
export function isNpmInfo(x: any): x is IPublicTypeNpmInfo {
|
||||
return typeof x === 'object' && x && typeof x.package === 'string';
|
||||
}
|
||||
|
||||
@ -43,11 +43,11 @@ const DEFAULT_MAX_DEPTH = 100000;
|
||||
* @returns
|
||||
*/
|
||||
export function handleSubNodes<T>(
|
||||
children: NodeSchema['children'],
|
||||
children: IPublicTypeNodeSchema['children'],
|
||||
handlers: {
|
||||
string?: (i: string) => T;
|
||||
expression?: (i: JSExpression) => T;
|
||||
node?: (i: NodeSchema) => T;
|
||||
expression?: (i: IPublicTypeJSExpression) => T;
|
||||
node?: (i: IPublicTypeNodeSchema) => T;
|
||||
},
|
||||
options?: {
|
||||
rerun?: boolean;
|
||||
@ -64,7 +64,7 @@ export function handleSubNodes<T>(
|
||||
}
|
||||
|
||||
if (Array.isArray(children)) {
|
||||
const list: NodeData[] = children as NodeData[];
|
||||
const list: IPublicTypeNodeData[] = children as IPublicTypeNodeData[];
|
||||
return list
|
||||
.map((child) => handleSubNodes(child, handlers, { ...opt, maxDepth: maxDepth - 1 }))
|
||||
.reduce((p, c) => p.concat(c), []);
|
||||
@ -84,7 +84,7 @@ export function handleSubNodes<T>(
|
||||
return handleSubNodes(children.value, handlers, { ...opt, maxDepth: maxDepth - 1 });
|
||||
} else if (isNodeSchema(children)) {
|
||||
const handler = handlers.node || noop;
|
||||
const child = children as NodeSchema;
|
||||
const child = children as IPublicTypeNodeSchema;
|
||||
result = handler(child);
|
||||
|
||||
if (child.children) {
|
||||
@ -115,7 +115,7 @@ export function handleSubNodes<T>(
|
||||
|
||||
return childrenRes;
|
||||
|
||||
function handleCompositeValueInProps(value: CompositeValue): T[] {
|
||||
function handleCompositeValueInProps(value: IPublicTypeCompositeValue): T[] {
|
||||
if (isJSSlot(value)) {
|
||||
return handleSubNodes(value.value, handlers, { ...opt, maxDepth: maxDepth - 1 });
|
||||
}
|
||||
@ -125,7 +125,7 @@ export function handleSubNodes<T>(
|
||||
return _.flatMap(value, (v) => handleCompositeValueInProps(v));
|
||||
}
|
||||
|
||||
// CompositeObject
|
||||
// IPublicTypeCompositeObject
|
||||
if (
|
||||
!isJSExpression(value) &&
|
||||
!isJSFunction(value) &&
|
||||
@ -139,7 +139,7 @@ export function handleSubNodes<T>(
|
||||
}
|
||||
}
|
||||
|
||||
export function isValidContainerType(schema: NodeSchema) {
|
||||
export function isValidContainerType(schema: IPublicTypeNodeSchema) {
|
||||
return [
|
||||
'Page',
|
||||
'Component',
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import CodeGenerator from '../../src';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
import { createDiskPublisher } from '../helpers/solutionHelper';
|
||||
|
||||
const testCaseBaseName = path.basename(__filename, '.test.ts');
|
||||
@ -31,7 +31,7 @@ describe(testCaseBaseName, () => {
|
||||
function exportProject(
|
||||
importPath: string,
|
||||
outputPath: string,
|
||||
mergeSchema?: Partial<ProjectSchema>,
|
||||
mergeSchema?: Partial<IPublicTypeProjectSchema>,
|
||||
) {
|
||||
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
|
||||
const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import CodeGenerator from '../../src';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
import { createDiskPublisher } from '../helpers/solutionHelper';
|
||||
|
||||
const testCaseBaseName = path.basename(__filename, '.test.ts');
|
||||
@ -198,7 +198,7 @@ describe(testCaseBaseName, () => {
|
||||
function exportProject(
|
||||
importPath: string,
|
||||
outputPath: string,
|
||||
mergeSchema?: Partial<ProjectSchema>,
|
||||
mergeSchema?: Partial<IPublicTypeProjectSchema>,
|
||||
) {
|
||||
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
|
||||
const schema = { ...JSON.parse(schemaJsonStr), ...mergeSchema };
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import CodeGenerator from '../../src';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
import { createDiskPublisher } from '../helpers/solutionHelper';
|
||||
import { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';
|
||||
|
||||
@ -33,7 +33,7 @@ describe(testCaseBaseName, () => {
|
||||
function exportProject(
|
||||
importPath: string,
|
||||
outputPath: string,
|
||||
mergeSchema?: Partial<ProjectSchema>,
|
||||
mergeSchema?: Partial<IPublicTypeProjectSchema>,
|
||||
options?: IceJsProjectBuilderOptions,
|
||||
) {
|
||||
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import CodeGenerator from '../../src';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
import { createDiskPublisher } from '../helpers/solutionHelper';
|
||||
import { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';
|
||||
|
||||
@ -28,7 +28,7 @@ test('loop should be generated link __$$evalArray(xxx).map', async () => {
|
||||
function exportProject(
|
||||
importPath: string,
|
||||
outputPath: string,
|
||||
mergeSchema?: Partial<ProjectSchema>,
|
||||
mergeSchema?: Partial<IPublicTypeProjectSchema>,
|
||||
options?: IceJsProjectBuilderOptions,
|
||||
) {
|
||||
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import CodeGenerator from '../../src';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
import { createDiskPublisher } from '../helpers/solutionHelper';
|
||||
import { IceJsProjectBuilderOptions } from '../../src/solutions/icejs';
|
||||
|
||||
@ -32,7 +32,7 @@ test('loop should be generated link __$$evalArray(xxx).map', async () => {
|
||||
function exportProject(
|
||||
importPath: string,
|
||||
outputPath: string,
|
||||
mergeSchema?: Partial<ProjectSchema>,
|
||||
mergeSchema?: Partial<IPublicTypeProjectSchema>,
|
||||
options?: IceJsProjectBuilderOptions,
|
||||
) {
|
||||
const schemaJsonStr = fs.readFileSync(importPath, { encoding: 'utf8' });
|
||||
|
||||
@ -22,7 +22,7 @@ Object {
|
||||
function __$$eval(expr) {
|
||||
try {
|
||||
return expr();
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -97,7 +97,7 @@ Object {
|
||||
function __$$eval(expr) {
|
||||
try {
|
||||
return expr();
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -168,7 +168,7 @@ Object {
|
||||
function __$$eval(expr) {
|
||||
try {
|
||||
return expr();
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -236,7 +236,7 @@ Object {
|
||||
function __$$eval(expr) {
|
||||
try {
|
||||
return expr();
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
import { SchemaParser } from '../../../src';
|
||||
import SCHEMA_WITH_SLOT from './data/schema-with-slot.json';
|
||||
|
||||
describe('tests/public/SchemaParser/p0-basics', () => {
|
||||
it('should be able to get dependencies in slots', () => {
|
||||
const schemaParser = new SchemaParser();
|
||||
const result = schemaParser.parse(SCHEMA_WITH_SLOT as ProjectSchema);
|
||||
const result = schemaParser.parse(SCHEMA_WITH_SLOT as IPublicTypeProjectSchema);
|
||||
expect(result.containers.map((c) => c.deps)).toMatchSnapshot();
|
||||
expect(result.containers[0].deps?.some((dep) => dep.componentName === 'Tooltip')).toBeTruthy();
|
||||
expect(result.containers[0].deps?.some((dep) => dep.componentName === 'Icon')).toBeTruthy();
|
||||
|
||||
@ -13,7 +13,7 @@ import {
|
||||
|
||||
import CodeGenerator from '../../../src';
|
||||
|
||||
import type { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
|
||||
jest.setTimeout(15 * 1000);
|
||||
|
||||
@ -50,7 +50,7 @@ function defineTest(caseDirName: string) {
|
||||
});
|
||||
}
|
||||
|
||||
async function exportProject(schemaJson: ProjectSchema, targetPath: string, projectName: string) {
|
||||
async function exportProject(schemaJson: IPublicTypeProjectSchema, targetPath: string, projectName: string) {
|
||||
const raxAppBuilder = CodeGenerator.solutions.rax();
|
||||
const result = await raxAppBuilder.generateProject(schemaJson);
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
|
||||
import CodeGenerator from '../../../src';
|
||||
|
||||
import type { ProjectSchema } from '@alilc/lowcode-types';
|
||||
import type { IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
|
||||
jest.setTimeout(15 * 1000);
|
||||
|
||||
@ -49,7 +49,7 @@ function defineTest(caseDirName: string) {
|
||||
});
|
||||
}
|
||||
|
||||
async function exportProject(schemaJson: ProjectSchema, targetPath: string, projectName: string) {
|
||||
async function exportProject(schemaJson: IPublicTypeProjectSchema, targetPath: string, projectName: string) {
|
||||
const reactAppBuilder = CodeGenerator.solutions.icejs();
|
||||
const result = await reactAppBuilder.generateProject(schemaJson);
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { NodeData } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeNodeData } from '@alilc/lowcode-types';
|
||||
import { handleSubNodes } from '../../../src/utils/schema';
|
||||
import SCHEMA_WITH_SLOT from './data/schema-with-slot.json';
|
||||
|
||||
describe('utils/schema/handleSubNodes', () => {
|
||||
it('should be able to visit nodes in JSSlot(1)', () => {
|
||||
const nodes: NodeData[] = [
|
||||
const nodes: IPublicTypeNodeData[] = [
|
||||
{
|
||||
componentName: 'Foo',
|
||||
props: {
|
||||
@ -28,7 +28,7 @@ describe('utils/schema/handleSubNodes', () => {
|
||||
});
|
||||
|
||||
it('should be able to visit nodes in JSSlot(2)', () => {
|
||||
const nodes: NodeData[] = (SCHEMA_WITH_SLOT as any).componentsTree[0].children;
|
||||
const nodes: IPublicTypeNodeData[] = (SCHEMA_WITH_SLOT as any).componentsTree[0].children;
|
||||
|
||||
const result = handleSubNodes(nodes, {
|
||||
node: (node) => node.componentName,
|
||||
|
||||
@ -44,7 +44,6 @@
|
||||
"@alife/build-plugin-lowcode": "^1.0.17",
|
||||
"@iceworks/spec": "^1.0.0",
|
||||
"@types/rax": "^1.0.0",
|
||||
"build-plugin-component": "^1.0.0",
|
||||
"driver-universal": "^3.1.0",
|
||||
"eslint": "^6.8.0",
|
||||
"rax": "^1.1.0",
|
||||
|
||||
@ -34,7 +34,6 @@
|
||||
"@alife/build-plugin-lowcode": "^1.0.7",
|
||||
"@alib/build-scripts": "^0.1.3",
|
||||
"@alifd/adaptor-generate": "^0.1.3",
|
||||
"build-plugin-component": "^0.2.0",
|
||||
"build-plugin-fusion": "^0.1.0",
|
||||
"build-plugin-fusion-cool": "^0.1.0",
|
||||
"build-plugin-moment-locales": "^0.1.0",
|
||||
|
||||
@ -51,7 +51,10 @@
|
||||
"typescript": "4.6.2",
|
||||
"yarn": "^1.22.17",
|
||||
"rimraf": "^3.0.2",
|
||||
"@types/react-router": "5.1.18"
|
||||
"@types/react-router": "5.1.18",
|
||||
"build-plugin-component": "^1.12.0",
|
||||
"babel-jest": "^26.5.2",
|
||||
"@alilc/lowcode-test-mate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17.0 <18"
|
||||
@ -61,7 +64,6 @@
|
||||
"lockfile": "enable"
|
||||
},
|
||||
"resolutions": {
|
||||
"@builder/babel-preset-ice": "1.0.1",
|
||||
"typescript": "4.6.2"
|
||||
},
|
||||
"repository": "git@github.com:alibaba/lowcode-engine.git"
|
||||
|
||||
22
packages/designer/babelTransform.js
Normal file
22
packages/designer/babelTransform.js
Normal file
@ -0,0 +1,22 @@
|
||||
const babelJest = require('babel-jest');
|
||||
const getBabelConfig = require('build-scripts-config/lib/config/babel/index.js');
|
||||
const formatWinPath = require('build-scripts-config/lib/config/jest/formatWinPath');
|
||||
const babelConfig = getBabelConfig();
|
||||
|
||||
babelConfig.plugins.push(['@babel/plugin-proposal-class-properties', { loose: true }]);
|
||||
|
||||
const jestBabelConfig = {
|
||||
...babelConfig,
|
||||
presets: babelConfig.presets.map((preset) => {
|
||||
if (Array.isArray(preset) && formatWinPath(preset[0]).indexOf('@babel/preset-env') > -1) {
|
||||
return [preset[0], {
|
||||
targets: {
|
||||
node: 'current',
|
||||
},
|
||||
}];
|
||||
}
|
||||
return preset;
|
||||
}),
|
||||
};
|
||||
|
||||
module.exports = babelJest.createTransformer(jestBabelConfig);
|
||||
@ -1,9 +1,13 @@
|
||||
const fs = require('fs');
|
||||
const { join } = require('path');
|
||||
const esModules = ['zen-logger'].join('|');
|
||||
const esModules = [].join('|');
|
||||
const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));
|
||||
|
||||
const jestConfig = {
|
||||
transform: {
|
||||
'^.+\\.(js|jsx|ts|tsx)$': './babelTransform.js',
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': 'build-scripts-config/lib/config/jest/fileTransform.js',
|
||||
},
|
||||
// transform: {
|
||||
// '^.+\\.[jt]sx?$': 'babel-jest',
|
||||
// // '^.+\\.(ts|tsx)$': 'ts-jest',
|
||||
|
||||
@ -22,13 +22,10 @@
|
||||
"react": "^16",
|
||||
"react-dom": "^16.7.0",
|
||||
"ric-shim": "^1.0.1",
|
||||
"semver": "^7.3.5",
|
||||
"zen-logger": "^1.1.0"
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alib/build-scripts": "^0.1.29",
|
||||
"@alilc/lowcode-shell": "1.0.18",
|
||||
"@alilc/lowcode-test-mate": "^1.0.1",
|
||||
"@testing-library/react": "^11.2.2",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/enzyme": "^3.10.12",
|
||||
@ -40,9 +37,6 @@
|
||||
"@types/react": "^16",
|
||||
"@types/react-dom": "^16",
|
||||
"@types/semver": "7.3.9",
|
||||
"babel-jest": "^26.5.2",
|
||||
"build-plugin-component": "^1.0.0",
|
||||
"build-scripts-config": "^3.0.3",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.5",
|
||||
"jest": "^26.6.3",
|
||||
@ -54,9 +48,6 @@
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"resolutions": {
|
||||
"@builder/babel-preset-ice": "1.0.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "http",
|
||||
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/designer"
|
||||
|
||||
@ -2,14 +2,14 @@ import * as React from 'react';
|
||||
import { Component, Fragment, ReactElement, PureComponent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { computed, observer, Title, globalLocale } from '@alilc/lowcode-editor-core';
|
||||
import { I18nData, TitleContent } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeI18nData, IPublicTypeTitleContent } from '@alilc/lowcode-types';
|
||||
import { isI18nData } from '@alilc/lowcode-utils';
|
||||
import { DropLocation } from '../../designer';
|
||||
import { BuiltinSimulatorHost } from '../../builtin-simulator/host';
|
||||
import { ParentalNode } from '../../document/node';
|
||||
import { INode } from '../../document/node';
|
||||
|
||||
export class BorderContainerInstance extends PureComponent<{
|
||||
title: TitleContent;
|
||||
title: IPublicTypeTitleContent;
|
||||
rect: DOMRect | null;
|
||||
scale: number;
|
||||
scrollX: number;
|
||||
@ -37,7 +37,7 @@ export class BorderContainerInstance extends PureComponent<{
|
||||
}
|
||||
}
|
||||
|
||||
function getTitle(title: string | I18nData | ReactElement) {
|
||||
function getTitle(title: string | IPublicTypeI18nData | ReactElement) {
|
||||
if (typeof title === 'string') return title;
|
||||
if (isI18nData(title)) {
|
||||
const locale = globalLocale.getLocale() || 'zh-CN';
|
||||
@ -50,9 +50,8 @@ function getTitle(title: string | I18nData | ReactElement) {
|
||||
export class BorderContainer extends Component<{
|
||||
host: BuiltinSimulatorHost;
|
||||
}, {
|
||||
target?: ParentalNode;
|
||||
target?: INode;
|
||||
}> {
|
||||
|
||||
state = {} as any;
|
||||
|
||||
@computed get scale() {
|
||||
@ -70,7 +69,7 @@ export class BorderContainer extends Component<{
|
||||
componentDidMount() {
|
||||
const { host } = this.props;
|
||||
|
||||
host.designer.editor.on('designer.dropLocation.change', (loc: DropLocation) => {
|
||||
host.designer.editor.eventBus.on('designer.dropLocation.change', (loc: DropLocation) => {
|
||||
let { target } = this.state;
|
||||
if (target === loc?.target) return;
|
||||
this.setState({
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { Component, Fragment, PureComponent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { computed, observer, Title } from '@alilc/lowcode-editor-core';
|
||||
import { TitleContent } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeTitleContent } from '@alilc/lowcode-types';
|
||||
import { getClosestNode } from '@alilc/lowcode-utils';
|
||||
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
|
||||
|
||||
export class BorderDetectingInstance extends PureComponent<{
|
||||
title: TitleContent;
|
||||
title: IPublicTypeTitleContent;
|
||||
rect: DOMRect | null;
|
||||
scale: number;
|
||||
scrollX: number;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import DragResizeEngine from './drag-resize-engine';
|
||||
import { observer, computed, globalContext, Editor } from '@alilc/lowcode-editor-core';
|
||||
import { observer, computed, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import classNames from 'classnames';
|
||||
import { SimulatorContext } from '../context';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
@ -172,13 +172,14 @@ export class BoxResizingInstance extends Component<{
|
||||
metadata.configure.advanced.callbacks.onResizeEnd(e, cbNode);
|
||||
}
|
||||
|
||||
const editor = globalContext.get(Editor);
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.border.resize', {
|
||||
editor?.eventBus.emit('designer.border.resize', {
|
||||
selected,
|
||||
layout: node?.parent?.getPropValue('layout') || '',
|
||||
});
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
import classNames from 'classnames';
|
||||
import { observer, computed, Tip, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils';
|
||||
import { ActionContentObject } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeActionContentObject } from '@alilc/lowcode-types';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
import { OffsetObserver } from '../../designer';
|
||||
import { Node } from '../../document';
|
||||
@ -116,7 +116,7 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
|
||||
}
|
||||
}
|
||||
|
||||
function createAction(content: ReactNode | ComponentType<any> | ActionContentObject, key: string, node: Node) {
|
||||
function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject, key: string, node: Node) {
|
||||
if (isValidElement(content)) {
|
||||
return cloneElement(content, { key, node });
|
||||
}
|
||||
@ -131,13 +131,14 @@ function createAction(content: ReactNode | ComponentType<any> | ActionContentObj
|
||||
className="lc-borders-action"
|
||||
onClick={() => {
|
||||
action && action(node);
|
||||
const editor = globalContext.get('editor');
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.border.action', {
|
||||
editor?.eventBus.emit('designer.border.action', {
|
||||
name: key,
|
||||
selected,
|
||||
});
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { ISimulatorHost } from '../../simulator';
|
||||
import { Designer, Point } from '../../designer';
|
||||
import { cursor } from '@alilc/lowcode-utils';
|
||||
import { makeEventsHandler } from '../../utils/misc';
|
||||
import { createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
||||
|
||||
// 拖动缩放
|
||||
export default class DragResizeEngine {
|
||||
private emitter: EventEmitter;
|
||||
private emitter: IEventBus;
|
||||
|
||||
private dragResizing = false;
|
||||
|
||||
@ -14,7 +14,7 @@ export default class DragResizeEngine {
|
||||
|
||||
constructor(designer: Designer) {
|
||||
this.designer = designer;
|
||||
this.emitter = new EventEmitter();
|
||||
this.emitter = createModuleEventBus('DragResizeEngine');
|
||||
}
|
||||
|
||||
isDragResizing() {
|
||||
|
||||
@ -3,29 +3,27 @@ import { observer } from '@alilc/lowcode-editor-core';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
import {
|
||||
DropLocation,
|
||||
Rect,
|
||||
isLocationChildrenDetail,
|
||||
LocationChildrenDetail,
|
||||
isVertical,
|
||||
} from '../../designer';
|
||||
import { ISimulatorHost } from '../../simulator';
|
||||
import { ParentalNode } from '../../document';
|
||||
import { INode } from '../../document';
|
||||
import './insertion.less';
|
||||
import { NodeData, NodeSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicTypeLocationChildrenDetail, IPublicTypeRect } from '@alilc/lowcode-types';
|
||||
import { isLocationChildrenDetail } from '@alilc/lowcode-utils';
|
||||
|
||||
interface InsertionData {
|
||||
edge?: DOMRect;
|
||||
insertType?: string;
|
||||
vertical?: boolean;
|
||||
nearRect?: Rect;
|
||||
nearRect?: IPublicTypeRect;
|
||||
coverRect?: DOMRect;
|
||||
nearNode?: NodeData;
|
||||
nearNode?: IPublicTypeNodeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理拖拽子节点(INode)情况
|
||||
*/
|
||||
function processChildrenDetail(sim: ISimulatorHost, container: ParentalNode, detail: LocationChildrenDetail): InsertionData {
|
||||
function processChildrenDetail(sim: ISimulatorHost, container: INode, detail: IPublicTypeLocationChildrenDetail): InsertionData {
|
||||
let edge = detail.edge || null;
|
||||
|
||||
if (!edge) {
|
||||
@ -161,7 +159,7 @@ export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
y = ((insertType === 'before' ? nearRect.top : nearRect.bottom) + scrollY) * scale;
|
||||
style.width = nearRect.width * scale;
|
||||
}
|
||||
if (y === 0 && (nearNode as NodeSchema)?.componentMeta?.isTopFixed) {
|
||||
if (y === 0 && (nearNode as IPublicTypeNodeSchema)?.componentMeta?.isTopFixed) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ export function createSimulator(
|
||||
const doc = iframe.contentDocument!;
|
||||
|
||||
win.LCSimulatorHost = host;
|
||||
win._ = window._;
|
||||
|
||||
const styles: any = {};
|
||||
const scripts: any = {};
|
||||
|
||||
@ -6,7 +6,7 @@ import { Project } from '../project';
|
||||
import './host.less';
|
||||
|
||||
/*
|
||||
Simulator 模拟器,可替换部件,有协议约束, 包含画布的容器,使用场景:当 Canvas 大小变化时,用来居中处理 或 定位 Canvas
|
||||
Simulator 模拟器,可替换部件,有协议约束,包含画布的容器,使用场景:当 Canvas 大小变化时,用来居中处理 或 定位 Canvas
|
||||
Canvas(DeviceShell) 设备壳层,通过背景图片来模拟,通过设备预设样式改变宽度、高度及定位 CanvasViewport
|
||||
CanvasViewport 页面编排场景中宽高不可溢出 Canvas 区
|
||||
Content(Shell) 内容外层,宽高紧贴 CanvasViewport,禁用边框,禁用 margin
|
||||
@ -23,8 +23,8 @@ export class BuiltinSimulatorHostView extends Component<SimulatorHostProps> {
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
const { project, onMount } = this.props;
|
||||
this.host = (project.simulator as BuiltinSimulatorHost) || new BuiltinSimulatorHost(project);
|
||||
const { project, onMount, designer } = this.props;
|
||||
this.host = (project.simulator as BuiltinSimulatorHost) || new BuiltinSimulatorHost(project, designer);
|
||||
this.host.setProps(this.props);
|
||||
onMount?.(this.host);
|
||||
}
|
||||
@ -76,14 +76,15 @@ class Content extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
private dispose?: () => void;
|
||||
|
||||
componentDidMount() {
|
||||
const editor = globalContext.get('editor');
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
const onEnableEvents = (type: boolean) => {
|
||||
this.setState({
|
||||
disabledEvents: type,
|
||||
});
|
||||
};
|
||||
|
||||
editor.on('designer.builtinSimulator.disabledEvents', onEnableEvents);
|
||||
editor.eventBus.on('designer.builtinSimulator.disabledEvents', onEnableEvents);
|
||||
|
||||
this.dispose = () => {
|
||||
editor.removeListener('designer.builtinSimulator.disabledEvents', onEnableEvents);
|
||||
@ -97,7 +98,7 @@ class Content extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
render() {
|
||||
const sim = this.props.host;
|
||||
const { disabledEvents } = this.state;
|
||||
const { viewport } = sim;
|
||||
const { viewport, designer } = sim;
|
||||
const frameStyle: any = {
|
||||
transform: `scale(${viewport.scale})`,
|
||||
height: viewport.contentHeight,
|
||||
@ -107,10 +108,12 @@ class Content extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
frameStyle.pointerEvents = 'none';
|
||||
}
|
||||
|
||||
const { viewName } = designer;
|
||||
|
||||
return (
|
||||
<div className="lc-simulator-content">
|
||||
<iframe
|
||||
name="SimulatorRenderer"
|
||||
name={`${viewName}-SimulatorRenderer`}
|
||||
className="lc-simulator-content-frame"
|
||||
style={frameStyle}
|
||||
ref={(frame) => sim.mountContentFrame(frame)}
|
||||
|
||||
@ -4,25 +4,23 @@ import {
|
||||
reaction,
|
||||
computed,
|
||||
getPublicPath,
|
||||
hotkey,
|
||||
focusTracker,
|
||||
engineConfig,
|
||||
IReactionPublic,
|
||||
IReactionOptions,
|
||||
IReactionDisposer,
|
||||
makeObservable,
|
||||
createModuleEventBus,
|
||||
IEventBus,
|
||||
} from '@alilc/lowcode-editor-core';
|
||||
import { EventEmitter } from 'events';
|
||||
import {
|
||||
ISimulatorHost,
|
||||
Component,
|
||||
NodeInstance,
|
||||
ComponentInstance,
|
||||
DropContainer,
|
||||
} from '../simulator';
|
||||
import Viewport from './viewport';
|
||||
import { createSimulator } from './create-simulator';
|
||||
import { Node, ParentalNode, contains, isRootNode, isLowCodeComponent } from '../document';
|
||||
import { Node, INode, contains, isRootNode, isLowCodeComponent } from '../document';
|
||||
import ResourceConsumer from './resource-consumer';
|
||||
import {
|
||||
AssetLevel,
|
||||
@ -37,46 +35,48 @@ import {
|
||||
UtilsMetadata,
|
||||
getClosestNode,
|
||||
transactionManager,
|
||||
} from '@alilc/lowcode-utils';
|
||||
import {
|
||||
isShaken,
|
||||
LocateEvent,
|
||||
isDragAnyObject,
|
||||
isDragNodeObject,
|
||||
isLocationData,
|
||||
LocationChildrenDetail,
|
||||
LocationDetailType,
|
||||
} from '@alilc/lowcode-utils';
|
||||
import {
|
||||
isShaken,
|
||||
ILocateEvent,
|
||||
isChildInline,
|
||||
isRowContainer,
|
||||
getRectTarget,
|
||||
Rect,
|
||||
CanvasPoint,
|
||||
Designer,
|
||||
} from '../designer';
|
||||
import { parseMetadata } from './utils/parse-metadata';
|
||||
import { getClosestClickableNode } from './utils/clickable';
|
||||
import {
|
||||
ComponentMetadata,
|
||||
ComponentSchema,
|
||||
Package,
|
||||
TransitionType,
|
||||
DragObjectType,
|
||||
DragNodeObject,
|
||||
IPublicTypeComponentMetadata,
|
||||
IPublicTypeComponentSchema,
|
||||
IPublicTypePackage,
|
||||
IPublicEnumTransitionType,
|
||||
IPublicEnumDragObjectType,
|
||||
IPublicTypeDragNodeObject,
|
||||
NodeInstance,
|
||||
IPublicTypeComponentInstance,
|
||||
IPublicTypeLocationChildrenDetail,
|
||||
IPublicTypeLocationDetailType,
|
||||
IPublicTypeRect,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { BuiltinSimulatorRenderer } from './renderer';
|
||||
import clipboard from '../designer/clipboard';
|
||||
import { clipboard } from '../designer/clipboard';
|
||||
import { LiveEditing } from './live-editing/live-editing';
|
||||
import { Project } from '../project';
|
||||
import { Scroller } from '../designer/scroller';
|
||||
import { isElementNode, isDOMNodeVisible } from '../utils/misc';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
export interface LibraryItem extends Package{
|
||||
export type LibraryItem = IPublicTypePackage & {
|
||||
package: string;
|
||||
library: string;
|
||||
urls?: Asset;
|
||||
editUrls?: Asset;
|
||||
}
|
||||
};
|
||||
|
||||
export interface DeviceStyleProps {
|
||||
canvas?: object;
|
||||
@ -171,7 +171,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
readonly scroller: Scroller;
|
||||
|
||||
readonly emitter: EventEmitter = new EventEmitter();
|
||||
readonly emitter: IEventBus = createModuleEventBus('BuiltinSimulatorHost');
|
||||
|
||||
|
||||
readonly componentsConsumer: ResourceConsumer;
|
||||
|
||||
@ -192,10 +193,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
this.renderer?.enableAutoRepaintNode();
|
||||
}
|
||||
|
||||
constructor(project: Project) {
|
||||
constructor(project: Project, designer: Designer) {
|
||||
makeObservable(this);
|
||||
this.project = project;
|
||||
this.designer = project?.designer;
|
||||
this.designer = designer;
|
||||
this.scroller = this.designer.createScroller(this.viewport);
|
||||
this.autoRender = !engineConfig.get('disableAutoRender', false);
|
||||
this.componentsConsumer = new ResourceConsumer<Asset | undefined>(() => this.componentsAsset);
|
||||
@ -209,13 +210,13 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
transactionManager.onStartTransaction(() => {
|
||||
this.stopAutoRepaintNode();
|
||||
}, TransitionType.REPAINT);
|
||||
}, IPublicEnumTransitionType.REPAINT);
|
||||
// 防止批量调用 transaction 时,执行多次 rerender
|
||||
const rerender = debounce(this.rerender.bind(this), 28);
|
||||
transactionManager.onEndTransaction(() => {
|
||||
rerender();
|
||||
this.enableAutoRepaintNode();
|
||||
}, TransitionType.REPAINT);
|
||||
}, IPublicEnumTransitionType.REPAINT);
|
||||
}
|
||||
|
||||
get currentDocument() {
|
||||
@ -372,11 +373,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
* ],
|
||||
* "library":"BizCharts"
|
||||
* }
|
||||
* package:String 资源npm包名
|
||||
* exportName:String umd包导出名字,用于适配部分物料包define name不一致的问题,例如把BizCharts改成bizcharts,用来兼容物料用define声明的bizcharts
|
||||
* package:String 资源 npm 包名
|
||||
* exportName:String umd 包导出名字,用于适配部分物料包 define name 不一致的问题,例如把 BizCharts 改成 bizcharts,用来兼容物料用 define 声明的 bizcharts
|
||||
* version:String 版本号
|
||||
* urls:Array 资源cdn地址,必须是umd类型,可以是.js或者.css
|
||||
* library:String umd包直接导出的name
|
||||
* urls:Array 资源 cdn 地址,必须是 umd 类型,可以是.js 或者.css
|
||||
* library:String umd 包直接导出的 name
|
||||
*/
|
||||
buildLibrary(library?: LibraryItem[]) {
|
||||
const _library = library || (this.get('library') as LibraryItem[]);
|
||||
@ -418,7 +419,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
this.renderer?.rerender?.();
|
||||
}
|
||||
|
||||
async mountContentFrame(iframe: HTMLIFrameElement | null) {
|
||||
async mountContentFrame(iframe: HTMLIFrameElement | null): Promise<void> {
|
||||
if (!iframe || this._iframe === iframe) {
|
||||
return;
|
||||
}
|
||||
@ -463,7 +464,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
await this.injectionConsumer.waitFirstConsume();
|
||||
|
||||
if (Object.keys(this.asyncLibraryMap).length > 0) {
|
||||
// 加载异步Library
|
||||
// 加载异步 Library
|
||||
await renderer.loadAsyncLibrary(this.asyncLibraryMap);
|
||||
Object.keys(this.asyncLibraryMap).forEach(key => {
|
||||
delete this.asyncLibraryMap[key];
|
||||
@ -478,6 +479,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
this.setupEvents();
|
||||
|
||||
// bind hotkey & clipboard
|
||||
const hotkey = this.designer.editor.get('innerHotkey');
|
||||
hotkey.mount(this._contentWindow);
|
||||
focusTracker.mount(this._contentWindow);
|
||||
clipboard.injectCopyPaster(this._contentDocument);
|
||||
@ -489,7 +491,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
const libraryAsset: AssetList = this.buildLibrary(library);
|
||||
await this.renderer?.load(libraryAsset);
|
||||
if (Object.keys(this.asyncLibraryMap).length > 0) {
|
||||
// 加载异步Library
|
||||
// 加载异步 Library
|
||||
await this.renderer?.loadAsyncLibrary(this.asyncLibraryMap);
|
||||
Object.keys(this.asyncLibraryMap).forEach(key => {
|
||||
delete this.asyncLibraryMap[key];
|
||||
@ -536,9 +538,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
// FIXME: dirty fix remove label-for fro liveEditing
|
||||
(downEvent.target as HTMLElement).removeAttribute('for');
|
||||
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
|
||||
const focusNode = documentModel.focusNode;
|
||||
const { focusNode } = documentModel;
|
||||
const node = getClosestClickableNode(nodeInst?.node || focusNode, downEvent);
|
||||
// 如果找不到可点击的节点, 直接返回
|
||||
// 如果找不到可点击的节点,直接返回
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
@ -550,7 +552,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
const rglNode = node?.getParent();
|
||||
const isRGLNode = rglNode?.isRGLContainer;
|
||||
if (isRGLNode) {
|
||||
// 如果拖拽的是磁铁块的右下角handle,则直接跳过
|
||||
// 如果拖拽的是磁铁块的右下角 handle,则直接跳过
|
||||
if (downEvent.target.classList.contains('react-resizable-handle')) return;
|
||||
// 禁止多选
|
||||
isMulti = false;
|
||||
@ -576,7 +578,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
action: 'end',
|
||||
rglNode,
|
||||
});
|
||||
// 鼠标是否移动 ? - 鼠标抖动应该也需要支持选中事件,偶尔点击不能选中,磁帖块移除shaken检测
|
||||
// 鼠标是否移动 ? - 鼠标抖动应该也需要支持选中事件,偶尔点击不能选中,磁帖块移除 shaken 检测
|
||||
if (!isShaken(downEvent, e) || isRGLNode) {
|
||||
let { id } = node;
|
||||
designer.activeTracker.track({ node, instance: nodeInst?.instance });
|
||||
@ -597,7 +599,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.builtinSimulator.select', {
|
||||
editor?.eventBus.emit('designer.builtinSimulator.select', {
|
||||
selected,
|
||||
});
|
||||
}
|
||||
@ -624,7 +626,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
}
|
||||
designer.dragon.boost(
|
||||
{
|
||||
type: DragObjectType.Node,
|
||||
type: IPublicEnumDragObjectType.Node,
|
||||
nodes,
|
||||
},
|
||||
downEvent,
|
||||
@ -704,7 +706,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
}
|
||||
const nodeInst = this.getNodeInstanceFromElement(e.target as Element);
|
||||
if (nodeInst?.node) {
|
||||
let node = nodeInst.node;
|
||||
let { node } = nodeInst;
|
||||
const focusNode = node.document?.focusNode;
|
||||
if (node.contains(focusNode)) {
|
||||
node = focusNode;
|
||||
@ -828,7 +830,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.builtinSimulator.contextmenu', {
|
||||
editor?.eventBus.emit('designer.builtinSimulator.contextmenu', {
|
||||
selected,
|
||||
...nodeInst,
|
||||
instanceRect: this.computeComponentInstanceRect(nodeInst.instance),
|
||||
@ -840,7 +842,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* @see ISimulator
|
||||
*/
|
||||
generateComponentMetadata(componentName: string): ComponentMetadata {
|
||||
generateComponentMetadata(componentName: string): IPublicTypeComponentMetadata {
|
||||
// if html tags
|
||||
if (isHTMLTag(componentName)) {
|
||||
return {
|
||||
@ -874,15 +876,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
return this.renderer?.getComponent(componentName) || null;
|
||||
}
|
||||
|
||||
createComponent(schema: ComponentSchema): Component | null {
|
||||
createComponent(schema: IPublicTypeComponentSchema): Component | null {
|
||||
return null;
|
||||
// return this.renderer?.createComponent(schema) || null;
|
||||
}
|
||||
|
||||
@obx private instancesMap: {
|
||||
[docId: string]: Map<string, ComponentInstance[]>;
|
||||
[docId: string]: Map<string, IPublicTypeComponentInstance[]>;
|
||||
} = {};
|
||||
setInstance(docId: string, id: string, instances: ComponentInstance[] | null) {
|
||||
setInstance(docId: string, id: string, instances: IPublicTypeComponentInstance[] | null) {
|
||||
if (!hasOwnProperty(this.instancesMap, docId)) {
|
||||
this.instancesMap[docId] = new Map();
|
||||
}
|
||||
@ -896,7 +898,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* @see ISimulator
|
||||
*/
|
||||
getComponentInstances(node: Node, context?: NodeInstance): ComponentInstance[] | null {
|
||||
getComponentInstances(node: Node, context?: NodeInstance): IPublicTypeComponentInstance[] | null {
|
||||
const docId = node.document.id;
|
||||
|
||||
const instances = this.instancesMap[docId]?.get(node.id) || null;
|
||||
@ -921,16 +923,16 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
* @see ISimulator
|
||||
*/
|
||||
getClosestNodeInstance(
|
||||
from: ComponentInstance,
|
||||
from: IPublicTypeComponentInstance,
|
||||
specId?: string,
|
||||
): NodeInstance<ComponentInstance> | null {
|
||||
): NodeInstance<IPublicTypeComponentInstance> | null {
|
||||
return this.renderer?.getClosestNodeInstance(from, specId) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ISimulator
|
||||
*/
|
||||
computeRect(node: Node): Rect | null {
|
||||
computeRect(node: Node): IPublicTypeRect | null {
|
||||
const instances = this.getComponentInstances(node);
|
||||
if (!instances) {
|
||||
return null;
|
||||
@ -941,7 +943,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* @see ISimulator
|
||||
*/
|
||||
computeComponentInstanceRect(instance: ComponentInstance, selector?: string): Rect | null {
|
||||
computeComponentInstanceRect(instance: IPublicTypeComponentInstance, selector?: string): IPublicTypeRect | null {
|
||||
const renderer = this.renderer!;
|
||||
const elements = this.findDOMNodes(instance, selector);
|
||||
if (!elements) {
|
||||
@ -1007,7 +1009,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* @see ISimulator
|
||||
*/
|
||||
findDOMNodes(instance: ComponentInstance, selector?: string): Array<Element | Text> | null {
|
||||
findDOMNodes(instance: IPublicTypeComponentInstance, selector?: string): Array<Element | Text> | null {
|
||||
const elements = this._renderer?.findDOMNodes(instance);
|
||||
if (!elements) {
|
||||
return null;
|
||||
@ -1026,7 +1028,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* 通过 DOM 节点获取节点,依赖 simulator 的接口
|
||||
*/
|
||||
getNodeInstanceFromElement(target: Element | null): NodeInstance<ComponentInstance> | null {
|
||||
getNodeInstanceFromElement(target: Element | null): NodeInstance<IPublicTypeComponentInstance> | null {
|
||||
if (!target) {
|
||||
return null;
|
||||
}
|
||||
@ -1071,29 +1073,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
opt.top = top + scrollTop;
|
||||
scroll = true;
|
||||
}
|
||||
/*
|
||||
const rect = this.document.computeRect(node);
|
||||
if (!rect || rect.width === 0 || rect.height === 0) {
|
||||
if (!this.tryScrollAgain && tryTimes < 3) {
|
||||
this.tryScrollAgain = requestAnimationFrame(() => this.scrollToNode(node, null, tryTimes + 1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
const scrollTarget = this.viewport.scrollTarget!;
|
||||
const st = scrollTarget.top;
|
||||
const sl = scrollTarget.left;
|
||||
const { scrollHeight, scrollWidth } = scrollTarget;
|
||||
const { height, width, top, bottom, left, right } = this.viewport.contentBounds;
|
||||
|
||||
if (rect.height > height ? rect.top > bottom || rect.bottom < top : rect.top < top || rect.bottom > bottom) {
|
||||
opt.top = Math.min(rect.top + rect.height / 2 + st - top - height / 2, scrollHeight - height);
|
||||
scroll = true;
|
||||
}
|
||||
|
||||
if (rect.width > width ? rect.left > right || rect.right < left : rect.left < left || rect.right > right) {
|
||||
opt.left = Math.min(rect.left + rect.width / 2 + sl - left - width / 2, scrollWidth - width);
|
||||
scroll = true;
|
||||
} */
|
||||
|
||||
if (scroll && this.scroller) {
|
||||
this.scroller.scrollTo(opt);
|
||||
@ -1141,7 +1120,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* @see ISensor
|
||||
*/
|
||||
fixEvent(e: LocateEvent): LocateEvent {
|
||||
fixEvent(e: ILocateEvent): ILocateEvent {
|
||||
if (e.fixed) {
|
||||
return e;
|
||||
}
|
||||
@ -1172,7 +1151,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* @see ISensor
|
||||
*/
|
||||
isEnter(e: LocateEvent): boolean {
|
||||
isEnter(e: ILocateEvent): boolean {
|
||||
const rect = this.viewport.bounds;
|
||||
return (
|
||||
e.globalY >= rect.top &&
|
||||
@ -1197,9 +1176,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* @see ISensor
|
||||
*/
|
||||
locate(e: LocateEvent): any {
|
||||
locate(e: ILocateEvent): any {
|
||||
const { dragObject } = e;
|
||||
const { nodes } = dragObject as DragNodeObject;
|
||||
const { nodes } = dragObject as IPublicTypeDragNodeObject;
|
||||
|
||||
const operationalNodes = nodes?.filter((node) => {
|
||||
const onMoveHook = node.componentMeta?.getMetadata()?.configure.advanced?.callbacks?.onMoveHook;
|
||||
@ -1260,14 +1239,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
const { children } = container;
|
||||
|
||||
const detail: LocationChildrenDetail = {
|
||||
type: LocationDetailType.Children,
|
||||
const detail: IPublicTypeLocationChildrenDetail = {
|
||||
type: IPublicTypeLocationDetailType.Children,
|
||||
index: 0,
|
||||
edge,
|
||||
};
|
||||
|
||||
const locationData = {
|
||||
target: container as ParentalNode,
|
||||
target: container as INode,
|
||||
detail,
|
||||
source: `simulator${document.id}`,
|
||||
event: e,
|
||||
@ -1387,13 +1366,13 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* 查找合适的投放容器
|
||||
*/
|
||||
getDropContainer(e: LocateEvent): DropContainer | null {
|
||||
getDropContainer(e: ILocateEvent): DropContainer | null {
|
||||
const { target, dragObject } = e;
|
||||
const isAny = isDragAnyObject(dragObject);
|
||||
const document = this.project.currentDocument!;
|
||||
const { currentRoot } = document;
|
||||
let container: Node;
|
||||
let nodeInstance: NodeInstance<ComponentInstance> | undefined;
|
||||
let container: INode;
|
||||
let nodeInstance: NodeInstance<IPublicTypeComponentInstance> | undefined;
|
||||
|
||||
if (target) {
|
||||
const ref = this.getNodeInstanceFromElement(target);
|
||||
@ -1477,49 +1456,25 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
container = container.parent;
|
||||
instance = this.getClosestNodeInstance(dropContainer.instance, container.id)?.instance;
|
||||
dropContainer = {
|
||||
container: container as ParentalNode,
|
||||
container: container as INode,
|
||||
instance,
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} /* else if (res === DRILL_DOWN) {
|
||||
if (!upward) {
|
||||
container = container.parent;
|
||||
instance = this.getClosestNodeInstance(dropContainer.instance, container.id)?.instance;
|
||||
upward = {
|
||||
container,
|
||||
instance
|
||||
};
|
||||
}
|
||||
dropContainer = this.getNearByContainer(dropContainer, drillDownExcludes, e);
|
||||
if (!dropContainer) {
|
||||
dropContainer = upward;
|
||||
upward = null;
|
||||
}
|
||||
} else if (isNode(res)) {
|
||||
// TODO:
|
||||
} */
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
isAcceptable(/* container: ParentalNode */): boolean {
|
||||
isAcceptable(): boolean {
|
||||
return false;
|
||||
/*
|
||||
const meta = container.componentMeta;
|
||||
const instance: any = this.document.getView(container);
|
||||
if (instance && '$accept' in instance) {
|
||||
return true;
|
||||
}
|
||||
return meta.acceptable;
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制接受
|
||||
*/
|
||||
handleAccept({ container, instance }: DropContainer, e: LocateEvent): boolean {
|
||||
handleAccept({ container, instance }: DropContainer, e: ILocateEvent): boolean {
|
||||
const { dragObject } = e;
|
||||
const document = this.currentDocument!;
|
||||
const focusNode = document.focusNode;
|
||||
@ -1535,33 +1490,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
return false;
|
||||
}
|
||||
|
||||
// first use accept
|
||||
if (acceptable) {
|
||||
/*
|
||||
const view: any = this.document.getView(container);
|
||||
if (view && '$accept' in view) {
|
||||
if (view.$accept === false) {
|
||||
return false;
|
||||
}
|
||||
if (view.$accept === AT_CHILD || view.$accept === '@CHILD') {
|
||||
return AT_CHILD;
|
||||
}
|
||||
if (typeof view.$accept === 'function') {
|
||||
const ret = view.$accept(container, e);
|
||||
if (ret || ret === false) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (proto.acceptable) {
|
||||
const ret = proto.accept(container, e);
|
||||
if (ret || ret === false) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// check nesting
|
||||
return document.checkNesting(container, dragObject as any);
|
||||
}
|
||||
@ -1572,7 +1500,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
getNearByContainer(
|
||||
{ container, instance }: DropContainer,
|
||||
drillDownExcludes: Set<Node>,
|
||||
e: LocateEvent,
|
||||
e: ILocateEvent,
|
||||
) {
|
||||
const { children } = container;
|
||||
const document = this.project.currentDocument!;
|
||||
@ -1603,17 +1531,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
if (!rect) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
if (isPointInRect(e, rect)) {
|
||||
return child;
|
||||
}
|
||||
|
||||
const distance = distanceToRect(e, rect);
|
||||
if (nearDistance === null || distance < nearDistance) {
|
||||
nearDistance = distance;
|
||||
nearBy = child;
|
||||
} */
|
||||
}
|
||||
|
||||
return nearBy;
|
||||
@ -1625,7 +1542,7 @@ function isHTMLTag(name: string) {
|
||||
return /^[a-z]\w*$/.test(name);
|
||||
}
|
||||
|
||||
function isPointInRect(point: CanvasPoint, rect: Rect) {
|
||||
function isPointInRect(point: CanvasPoint, rect: IPublicTypeRect) {
|
||||
return (
|
||||
point.canvasY >= rect.top &&
|
||||
point.canvasY <= rect.bottom &&
|
||||
@ -1634,7 +1551,7 @@ function isPointInRect(point: CanvasPoint, rect: Rect) {
|
||||
);
|
||||
}
|
||||
|
||||
function distanceToRect(point: CanvasPoint, rect: Rect) {
|
||||
function distanceToRect(point: CanvasPoint, rect: IPublicTypeRect) {
|
||||
let minX = Math.min(Math.abs(point.canvasX - rect.left), Math.abs(point.canvasX - rect.right));
|
||||
let minY = Math.min(Math.abs(point.canvasY - rect.top), Math.abs(point.canvasY - rect.bottom));
|
||||
if (point.canvasX >= rect.left && point.canvasX <= rect.right) {
|
||||
@ -1647,7 +1564,7 @@ function distanceToRect(point: CanvasPoint, rect: Rect) {
|
||||
return Math.sqrt(minX ** 2 + minY ** 2);
|
||||
}
|
||||
|
||||
function distanceToEdge(point: CanvasPoint, rect: Rect) {
|
||||
function distanceToEdge(point: CanvasPoint, rect: IPublicTypeRect) {
|
||||
const distanceTop = Math.abs(point.canvasY - rect.top);
|
||||
const distanceBottom = Math.abs(point.canvasY - rect.bottom);
|
||||
|
||||
@ -1657,7 +1574,7 @@ function distanceToEdge(point: CanvasPoint, rect: Rect) {
|
||||
};
|
||||
}
|
||||
|
||||
function isNearAfter(point: CanvasPoint, rect: Rect, inline: boolean) {
|
||||
function isNearAfter(point: CanvasPoint, rect: IPublicTypeRect, inline: boolean) {
|
||||
if (inline) {
|
||||
return (
|
||||
Math.abs(point.canvasX - rect.left) + Math.abs(point.canvasY - rect.top) >
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { obx, globalContext, Editor } from '@alilc/lowcode-editor-core';
|
||||
import { LiveTextEditingConfig } from '@alilc/lowcode-types';
|
||||
import { obx, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import { IPublicTypePluginConfig, IPublicTypeLiveTextEditingConfig } from '@alilc/lowcode-types';
|
||||
import { Node, Prop } from '../../document';
|
||||
|
||||
const EDITOR_KEY = 'data-setter-prop';
|
||||
@ -52,17 +52,18 @@ export class LiveEditing {
|
||||
const targetElement = event.target as HTMLElement;
|
||||
const { liveTextEditing } = node.componentMeta;
|
||||
|
||||
const editor = globalContext.get(Editor);
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';
|
||||
editor?.emit('designer.builtinSimulator.liveEditing', {
|
||||
editor?.eventBus.emit('designer.builtinSimulator.liveEditing', {
|
||||
selected,
|
||||
});
|
||||
|
||||
let setterPropElement = getSetterPropElement(targetElement, rootElement);
|
||||
let propTarget = setterPropElement?.dataset.setterProp;
|
||||
let matched: (LiveTextEditingConfig & { propElement?: HTMLElement }) | undefined | null;
|
||||
let matched: (IPublicTypePluginConfig & { propElement?: HTMLElement }) | undefined | null;
|
||||
if (liveTextEditing) {
|
||||
if (propTarget) {
|
||||
// 已埋点命中 data-setter-prop="proptarget", 从 liveTextEditing 读取配置(mode|onSaveContent)
|
||||
@ -107,7 +108,7 @@ export class LiveEditing {
|
||||
}
|
||||
|
||||
// 进入编辑
|
||||
// 1. 设置contentEditable="plaintext|..."
|
||||
// 1. 设置 contentEditable="plaintext|..."
|
||||
// 2. 添加类名
|
||||
// 3. focus & cursor locate
|
||||
// 4. 监听 blur 事件
|
||||
@ -186,7 +187,7 @@ export class LiveEditing {
|
||||
}
|
||||
}
|
||||
|
||||
export type SpecificRule = (target: EditingTarget) => (LiveTextEditingConfig & {
|
||||
export type SpecificRule = (target: EditingTarget) => (IPublicTypeLiveTextEditingConfig & {
|
||||
propElement?: HTMLElement;
|
||||
}) | null;
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { Overlay } from '@alifd/next';
|
||||
import React from 'react';
|
||||
import { Title, globalContext, Editor } from '@alilc/lowcode-editor-core';
|
||||
import { Title, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import { canClickNode } from '@alilc/lowcode-utils';
|
||||
import './index.less';
|
||||
|
||||
import { Node, ParentalNode } from '@alilc/lowcode-designer';
|
||||
import { Node, INode } from '@alilc/lowcode-designer';
|
||||
|
||||
const { Popup } = Overlay;
|
||||
|
||||
@ -16,7 +16,7 @@ export interface IState {
|
||||
parentNodes: Node[];
|
||||
}
|
||||
|
||||
type UnionNode = Node | ParentalNode | null;
|
||||
type UnionNode = INode | null;
|
||||
|
||||
export default class InstanceNodeSelector extends React.Component<IProps, IState> {
|
||||
state: IState = {
|
||||
@ -30,7 +30,7 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState
|
||||
});
|
||||
}
|
||||
|
||||
// 获取节点的父级节点(最多获取5层)
|
||||
// 获取节点的父级节点(最多获取 5 层)
|
||||
getParentNodes = (node: Node) => {
|
||||
const parentNodes: any[] = [];
|
||||
const { focusNode } = node.document;
|
||||
@ -62,13 +62,14 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState
|
||||
|
||||
if (canClick && typeof node.select === 'function') {
|
||||
node.select();
|
||||
const editor = globalContext.get(Editor);
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.border.action', {
|
||||
editor?.eventBus.emit('designer.border.action', {
|
||||
name: 'select',
|
||||
selected,
|
||||
});
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
import { ComponentInstance, NodeInstance, Component } from '../simulator';
|
||||
import { NodeSchema } from '@alilc/lowcode-types';
|
||||
import { Component } from '../simulator';
|
||||
import { IPublicTypeNodeSchema, IPublicTypeComponentInstance, NodeInstance } from '@alilc/lowcode-types';
|
||||
|
||||
export interface BuiltinSimulatorRenderer {
|
||||
readonly isSimulatorRenderer: true;
|
||||
createComponent(schema: NodeSchema): Component | null;
|
||||
createComponent(schema: IPublicTypeNodeSchema): Component | null;
|
||||
getComponent(componentName: string): Component;
|
||||
getClosestNodeInstance(from: ComponentInstance, nodeId?: string): NodeInstance<ComponentInstance> | null;
|
||||
findDOMNodes(instance: ComponentInstance): Array<Element | Text> | null;
|
||||
getClosestNodeInstance(
|
||||
from: IPublicTypeComponentInstance,
|
||||
nodeId?: string,
|
||||
): NodeInstance<IPublicTypeComponentInstance> | null;
|
||||
findDOMNodes(instance: IPublicTypeComponentInstance): Array<Element | Text> | null;
|
||||
getClientRects(element: Element | Text): DOMRect[];
|
||||
setNativeSelection(enableFlag: boolean): void;
|
||||
setDraggingState(state: boolean): void;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { autorun, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||
import { autorun, makeObservable, obx, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { BuiltinSimulatorHost } from './host';
|
||||
import { EventEmitter } from 'events';
|
||||
import { BuiltinSimulatorRenderer, isSimulatorRenderer } from './renderer';
|
||||
|
||||
const UNSET = Symbol('unset');
|
||||
@ -20,7 +19,7 @@ export type RendererConsumer<T> = (renderer: BuiltinSimulatorRenderer, data: T)
|
||||
// 2. 消费机制(渲染进程自定 + 传递进入)
|
||||
|
||||
export default class ResourceConsumer<T = any> {
|
||||
private emitter = new EventEmitter();
|
||||
private emitter: IEventBus = createModuleEventBus('ResourceConsumer');
|
||||
|
||||
@obx.ref private _data: T | typeof UNSET = UNSET;
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ export const getClosestClickableNode = (
|
||||
if (canClick) {
|
||||
break;
|
||||
}
|
||||
// 对于不可点击的节点, 继续向上找
|
||||
// 对于不可点击的节点,继续向上找
|
||||
node = node.parent;
|
||||
}
|
||||
return node;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { isValidElement } from 'react';
|
||||
import { isElement } from '@alilc/lowcode-utils';
|
||||
import { PropConfig } from '@alilc/lowcode-types';
|
||||
import { IPublicTypePropConfig } from '@alilc/lowcode-types';
|
||||
|
||||
export const primitiveTypes = [
|
||||
'string',
|
||||
@ -55,7 +55,7 @@ const LowcodeTypes: any = {
|
||||
(window as any).React.PropTypes = LowcodeTypes;
|
||||
|
||||
// override primitive type checkers
|
||||
primitiveTypes.forEach(type => {
|
||||
primitiveTypes.forEach((type) => {
|
||||
const propType = (PropTypes as any)[type];
|
||||
if (!propType) {
|
||||
return;
|
||||
@ -91,7 +91,7 @@ LowcodeTypes.objectOf = (type: any) => {
|
||||
|
||||
// An object that could be one of many types
|
||||
LowcodeTypes.oneOfType = (types: any[]) => {
|
||||
const itemTypes = types.map(type => type.lowcodeType || 'any');
|
||||
const itemTypes = types.map((type) => type.lowcodeType || 'any');
|
||||
return define(PropTypes.oneOfType(types), {
|
||||
type: 'oneOfType',
|
||||
value: itemTypes,
|
||||
@ -100,7 +100,7 @@ LowcodeTypes.oneOfType = (types: any[]) => {
|
||||
|
||||
// An object with warnings on extra properties
|
||||
LowcodeTypes.exact = (typesMap: any) => {
|
||||
const configs = Object.keys(typesMap).map(key => {
|
||||
const configs = Object.keys(typesMap).map((key) => {
|
||||
return {
|
||||
name: key,
|
||||
propType: typesMap[key]?.lowcodeType || 'any',
|
||||
@ -114,7 +114,7 @@ LowcodeTypes.exact = (typesMap: any) => {
|
||||
|
||||
// An object taking on a particular shape
|
||||
LowcodeTypes.shape = (typesMap: any = {}) => {
|
||||
const configs = Object.keys(typesMap).map(key => {
|
||||
const configs = Object.keys(typesMap).map((key) => {
|
||||
return {
|
||||
name: key,
|
||||
propType: typesMap[key]?.lowcodeType || 'any',
|
||||
@ -127,7 +127,7 @@ LowcodeTypes.shape = (typesMap: any = {}) => {
|
||||
};
|
||||
|
||||
const BasicTypes = ['string', 'number', 'object'];
|
||||
export function parseProps(component: any): PropConfig[] {
|
||||
export function parseProps(component: any): IPublicTypePropConfig[] {
|
||||
if (!component) {
|
||||
return [];
|
||||
}
|
||||
@ -135,7 +135,7 @@ export function parseProps(component: any): PropConfig[] {
|
||||
const defaultProps = component.defaultProps || ({} as any);
|
||||
const result: any = {};
|
||||
if (!propTypes) return [];
|
||||
Object.keys(propTypes).forEach(key => {
|
||||
Object.keys(propTypes).forEach((key) => {
|
||||
const propTypeItem = propTypes[key];
|
||||
const defaultValue = defaultProps[key];
|
||||
const { lowcodeType } = propTypeItem;
|
||||
@ -173,7 +173,7 @@ export function parseProps(component: any): PropConfig[] {
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(defaultProps).forEach(key => {
|
||||
Object.keys(defaultProps).forEach((key) => {
|
||||
if (result[key]) return;
|
||||
const defaultValue = defaultProps[key];
|
||||
let type: string = typeof defaultValue;
|
||||
@ -198,7 +198,7 @@ export function parseProps(component: any): PropConfig[] {
|
||||
};
|
||||
});
|
||||
|
||||
return Object.keys(result).map(key => result[key]);
|
||||
return Object.keys(result).map((key) => result[key]);
|
||||
}
|
||||
|
||||
export function parseMetadata(component: any): any {
|
||||
|
||||
@ -13,7 +13,7 @@ export function isPackagePath(path: string): boolean {
|
||||
export function toTitleCase(s: string): string {
|
||||
return s
|
||||
.split(/[-_ .]+/)
|
||||
.map(token => token[0].toUpperCase() + token.substring(1))
|
||||
.map((token) => token[0].toUpperCase() + token.substring(1))
|
||||
.join('');
|
||||
}
|
||||
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
import { ReactElement } from 'react';
|
||||
import {
|
||||
ComponentMetadata,
|
||||
NpmInfo,
|
||||
NodeData,
|
||||
NodeSchema,
|
||||
ComponentAction,
|
||||
TitleContent,
|
||||
TransformedComponentMetadata,
|
||||
NestingFilter,
|
||||
I18nData,
|
||||
LiveTextEditingConfig,
|
||||
FieldConfig,
|
||||
MetadataTransducer,
|
||||
IPublicTypeComponentMetadata,
|
||||
IPublicTypeNpmInfo,
|
||||
IPublicTypeNodeData,
|
||||
IPublicTypeNodeSchema,
|
||||
IPublicTypeComponentAction,
|
||||
IPublicTypeTitleContent,
|
||||
IPublicTypeTransformedComponentMetadata,
|
||||
IPublicTypeNestingFilter,
|
||||
IPublicTypeI18nData,
|
||||
IPublicTypePluginConfig,
|
||||
IPublicTypeFieldConfig,
|
||||
IPublicTypeMetadataTransducer,
|
||||
IPublicModelComponentMeta,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { deprecate, isRegExp, isTitleConfig } from '@alilc/lowcode-utils';
|
||||
import { computed, engineConfig } from '@alilc/lowcode-editor-core';
|
||||
import EventEmitter from 'events';
|
||||
import { computed, engineConfig, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { componentDefaults, legacyIssues } from './transducers';
|
||||
import { isNode, Node, ParentalNode } from './document';
|
||||
import { isNode, Node, INode } from './document';
|
||||
import { Designer } from './designer';
|
||||
import { intlNode } from './locale';
|
||||
import {
|
||||
@ -47,7 +47,7 @@ export function ensureAList(list?: string | string[]): string[] | null {
|
||||
return list;
|
||||
}
|
||||
|
||||
export function buildFilter(rule?: string | string[] | RegExp | NestingFilter) {
|
||||
export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNestingFilter) {
|
||||
if (!rule) {
|
||||
return null;
|
||||
}
|
||||
@ -55,21 +55,25 @@ export function buildFilter(rule?: string | string[] | RegExp | NestingFilter) {
|
||||
return rule;
|
||||
}
|
||||
if (isRegExp(rule)) {
|
||||
return (testNode: Node | NodeSchema) => rule.test(testNode.componentName);
|
||||
return (testNode: Node | IPublicTypeNodeSchema) => rule.test(testNode.componentName);
|
||||
}
|
||||
const list = ensureAList(rule);
|
||||
if (!list) {
|
||||
return null;
|
||||
}
|
||||
return (testNode: Node | NodeSchema) => list.includes(testNode.componentName);
|
||||
return (testNode: Node | IPublicTypeNodeSchema) => list.includes(testNode.componentName);
|
||||
}
|
||||
|
||||
export class ComponentMeta {
|
||||
export interface IComponentMeta extends IPublicModelComponentMeta {
|
||||
|
||||
}
|
||||
|
||||
export class ComponentMeta implements IComponentMeta {
|
||||
readonly isComponentMeta = true;
|
||||
|
||||
private _npm?: NpmInfo;
|
||||
private _npm?: IPublicTypeNpmInfo;
|
||||
|
||||
private emitter: EventEmitter = new EventEmitter();
|
||||
private emitter: IEventBus = createModuleEventBus('ComponentMeta');
|
||||
|
||||
get npm() {
|
||||
return this._npm;
|
||||
@ -113,14 +117,14 @@ export class ComponentMeta {
|
||||
return this._rootSelector;
|
||||
}
|
||||
|
||||
private _transformedMetadata?: TransformedComponentMetadata;
|
||||
private _transformedMetadata?: IPublicTypeTransformedComponentMetadata;
|
||||
|
||||
get configure() {
|
||||
const config = this._transformedMetadata?.configure;
|
||||
return config?.combined || config?.props || [];
|
||||
}
|
||||
|
||||
private _liveTextEditing?: LiveTextEditingConfig[];
|
||||
private _liveTextEditing?: IPublicTypePluginConfig[];
|
||||
|
||||
get liveTextEditing() {
|
||||
return this._liveTextEditing;
|
||||
@ -132,15 +136,15 @@ export class ComponentMeta {
|
||||
return !!(this._isTopFixed);
|
||||
}
|
||||
|
||||
private parentWhitelist?: NestingFilter | null;
|
||||
private parentWhitelist?: IPublicTypeNestingFilter | null;
|
||||
|
||||
private childWhitelist?: NestingFilter | null;
|
||||
private childWhitelist?: IPublicTypeNestingFilter | null;
|
||||
|
||||
private _title?: TitleContent;
|
||||
private _title?: IPublicTypeTitleContent;
|
||||
|
||||
private _isMinimalRenderUnit?: boolean;
|
||||
|
||||
get title(): string | I18nData | ReactElement {
|
||||
get title(): string | IPublicTypeI18nData | ReactElement {
|
||||
// string | i18nData | ReactElement
|
||||
// TitleConfig title.label
|
||||
if (isTitleConfig(this._title)) {
|
||||
@ -165,19 +169,22 @@ export class ComponentMeta {
|
||||
return this._acceptable!;
|
||||
}
|
||||
|
||||
constructor(readonly designer: Designer, metadata: ComponentMetadata) {
|
||||
constructor(readonly designer: Designer, metadata: IPublicTypeComponentMetadata) {
|
||||
this.parseMetadata(metadata);
|
||||
}
|
||||
|
||||
setNpm(info: NpmInfo) {
|
||||
setNpm(info: IPublicTypeNpmInfo) {
|
||||
if (!this._npm) {
|
||||
this._npm = info;
|
||||
}
|
||||
}
|
||||
|
||||
private parseMetadata(metadata: ComponentMetadata) {
|
||||
private parseMetadata(metadata: IPublicTypeComponentMetadata) {
|
||||
const { componentName, npm, ...others } = metadata;
|
||||
let _metadata = metadata;
|
||||
if ((metadata as any).prototype) {
|
||||
this.prototype = (metadata as any).prototype;
|
||||
}
|
||||
if (!npm && !Object.keys(others).length) {
|
||||
// 没有注册的组件,只能删除,不支持复制、移动等操作
|
||||
_metadata = {
|
||||
@ -214,7 +221,7 @@ export class ComponentMeta {
|
||||
|
||||
const liveTextEditing = this._transformedMetadata.configure.advanced?.liveTextEditing || [];
|
||||
|
||||
function collectLiveTextEditing(items: FieldConfig[]) {
|
||||
function collectLiveTextEditing(items: IPublicTypeFieldConfig[]) {
|
||||
items.forEach((config) => {
|
||||
if (config?.items) {
|
||||
collectLiveTextEditing(config.items);
|
||||
@ -264,7 +271,7 @@ export class ComponentMeta {
|
||||
this.parseMetadata(this.getMetadata());
|
||||
}
|
||||
|
||||
private transformMetadata(metadta: ComponentMetadata): TransformedComponentMetadata {
|
||||
private transformMetadata(metadta: IPublicTypeComponentMetadata): IPublicTypeTransformedComponentMetadata {
|
||||
const result = getRegisteredMetadataTransducers().reduce((prevMetadata, current) => {
|
||||
return current(prevMetadata);
|
||||
}, preprocessMetadata(metadta));
|
||||
@ -307,15 +314,15 @@ export class ComponentMeta {
|
||||
return actions;
|
||||
}
|
||||
|
||||
setMetadata(metadata: ComponentMetadata) {
|
||||
setMetadata(metadata: IPublicTypeComponentMetadata) {
|
||||
this.parseMetadata(metadata);
|
||||
}
|
||||
|
||||
getMetadata(): TransformedComponentMetadata {
|
||||
getMetadata(): IPublicTypeTransformedComponentMetadata {
|
||||
return this._transformedMetadata!;
|
||||
}
|
||||
|
||||
checkNestingUp(my: Node | NodeData, parent: ParentalNode) {
|
||||
checkNestingUp(my: INode | IPublicTypeNodeData, parent: INode) {
|
||||
// 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器
|
||||
if (this.parentWhitelist) {
|
||||
return this.parentWhitelist(
|
||||
@ -326,11 +333,11 @@ export class ComponentMeta {
|
||||
return true;
|
||||
}
|
||||
|
||||
checkNestingDown(my: Node, target: Node | NodeSchema | NodeSchema[]): boolean {
|
||||
checkNestingDown(my: INode, target: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[]): boolean {
|
||||
// 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器
|
||||
if (this.childWhitelist) {
|
||||
const _target: any = !Array.isArray(target) ? [target] : target;
|
||||
return _target.every((item: Node | NodeSchema) => {
|
||||
return _target.every((item: Node | IPublicTypeNodeSchema) => {
|
||||
const _item = !isNode(item) ? new Node(my.document, item) : item;
|
||||
return (
|
||||
this.childWhitelist &&
|
||||
@ -356,7 +363,7 @@ export function isComponentMeta(obj: any): obj is ComponentMeta {
|
||||
return obj && obj.isComponentMeta;
|
||||
}
|
||||
|
||||
function preprocessMetadata(metadata: ComponentMetadata): TransformedComponentMetadata {
|
||||
function preprocessMetadata(metadata: IPublicTypeComponentMetadata): IPublicTypeTransformedComponentMetadata {
|
||||
if (metadata.configure) {
|
||||
if (Array.isArray(metadata.configure)) {
|
||||
return {
|
||||
@ -376,10 +383,10 @@ function preprocessMetadata(metadata: ComponentMetadata): TransformedComponentMe
|
||||
}
|
||||
|
||||
|
||||
const metadataTransducers: MetadataTransducer[] = [];
|
||||
const metadataTransducers: IPublicTypeMetadataTransducer[] = [];
|
||||
|
||||
export function registerMetadataTransducer(
|
||||
transducer: MetadataTransducer,
|
||||
transducer: IPublicTypeMetadataTransducer,
|
||||
level = 100,
|
||||
id?: string,
|
||||
) {
|
||||
@ -393,11 +400,11 @@ export function registerMetadataTransducer(
|
||||
}
|
||||
}
|
||||
|
||||
export function getRegisteredMetadataTransducers(): MetadataTransducer[] {
|
||||
export function getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[] {
|
||||
return metadataTransducers;
|
||||
}
|
||||
|
||||
const builtinComponentActions: ComponentAction[] = [
|
||||
const builtinComponentActions: IPublicTypeComponentAction[] = [
|
||||
{
|
||||
name: 'remove',
|
||||
content: {
|
||||
@ -440,7 +447,7 @@ const builtinComponentActions: ComponentAction[] = [
|
||||
newNode.select();
|
||||
const { isRGL, rglNode } = node.getRGL();
|
||||
if (isRGL) {
|
||||
// 复制layout信息
|
||||
// 复制 layout 信息
|
||||
let layout = rglNode.getPropValue('layout') || [];
|
||||
let curLayout = layout.filter((item) => item.i === node.getPropValue('fieldId'));
|
||||
if (curLayout && curLayout[0]) {
|
||||
@ -498,13 +505,13 @@ export function removeBuiltinComponentAction(name: string) {
|
||||
builtinComponentActions.splice(i, 1);
|
||||
}
|
||||
}
|
||||
export function addBuiltinComponentAction(action: ComponentAction) {
|
||||
export function addBuiltinComponentAction(action: IPublicTypeComponentAction) {
|
||||
builtinComponentActions.push(action);
|
||||
}
|
||||
|
||||
export function modifyBuiltinComponentAction(
|
||||
actionName: string,
|
||||
handle: (action: ComponentAction) => void,
|
||||
handle: (action: IPublicTypeComponentAction) => void,
|
||||
) {
|
||||
const builtinAction = builtinComponentActions.find((action) => action.name === actionName);
|
||||
if (builtinAction) {
|
||||
|
||||
@ -1,34 +1,34 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { LocationDetail } from './location';
|
||||
import { Node, isNode } from '../document/node/node';
|
||||
import { ComponentInstance } from '../simulator';
|
||||
import { obx } from '@alilc/lowcode-editor-core';
|
||||
import { INode } from '../document/node/node';
|
||||
import { obx, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
IPublicTypeActiveTarget,
|
||||
IPublicModelActiveTracker,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { isNode } from '@alilc/lowcode-utils';
|
||||
|
||||
export interface IActiveTracker extends IPublicModelActiveTracker {
|
||||
|
||||
export interface ActiveTarget {
|
||||
node: Node;
|
||||
detail?: LocationDetail;
|
||||
instance?: ComponentInstance;
|
||||
}
|
||||
export class ActiveTracker implements IActiveTracker {
|
||||
private emitter: IEventBus = createModuleEventBus('ActiveTracker');
|
||||
|
||||
export class ActiveTracker {
|
||||
private emitter = new EventEmitter();
|
||||
@obx.ref private _target?: IPublicTypeActiveTarget | INode;
|
||||
|
||||
@obx.ref private _target?: ActiveTarget;
|
||||
|
||||
track(target: ActiveTarget | Node) {
|
||||
if (isNode(target)) {
|
||||
target = { node: target };
|
||||
track(originalTarget: IPublicTypeActiveTarget | INode) {
|
||||
let target = originalTarget;
|
||||
if (isNode(originalTarget)) {
|
||||
target = { node: originalTarget as INode };
|
||||
}
|
||||
this._target = target;
|
||||
this.emitter.emit('change', target);
|
||||
}
|
||||
|
||||
get currentNode() {
|
||||
return this._target?.node;
|
||||
return (this._target as IPublicTypeActiveTarget)?.node;
|
||||
}
|
||||
|
||||
get detail() {
|
||||
return this._target?.detail;
|
||||
return (this._target as IPublicTypeActiveTarget)?.detail;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,10 +40,10 @@ export class ActiveTracker {
|
||||
}
|
||||
|
||||
get instance() {
|
||||
return this._target?.instance;
|
||||
return (this._target as IPublicTypeActiveTarget)?.instance;
|
||||
}
|
||||
|
||||
onChange(fn: (target: ActiveTarget) => void): () => void {
|
||||
onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void {
|
||||
this.emitter.addListener('change', fn);
|
||||
return () => {
|
||||
this.emitter.removeListener('change', fn);
|
||||
|
||||
@ -1,354 +0,0 @@
|
||||
import { hotkey, Editor, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import { isFormEvent } from '@alilc/lowcode-utils';
|
||||
import { focusing } from './focusing';
|
||||
import { insertChildren, TransformStage } from '../document';
|
||||
import clipboard from './clipboard';
|
||||
|
||||
export function isInLiveEditing() {
|
||||
if (globalContext.has(Editor)) {
|
||||
return Boolean(
|
||||
globalContext.get(Editor).get('designer')?.project?.simulator?.liveEditing?.editing,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
function getNextForSelect(next: any, head?: any, parent?: any): any {
|
||||
if (next) {
|
||||
if (!head) {
|
||||
return next;
|
||||
}
|
||||
|
||||
let ret;
|
||||
if (next.isContainer()) {
|
||||
const children = next.getChildren() || [];
|
||||
if (children && !children.isEmpty()) {
|
||||
ret = getNextForSelect(children.get(0));
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = getNextForSelect(next.nextSibling);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
return getNextForSelect(parent.nextSibling, false, parent.getParent());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
function getPrevForSelect(prev: any, head?: any, parent?: any): any {
|
||||
if (prev) {
|
||||
let ret;
|
||||
if (!head && prev.isContainer()) {
|
||||
const children = prev.getChildren() || [];
|
||||
const lastChild = children && !children.isEmpty() ? children.get(children.size - 1) : null;
|
||||
|
||||
ret = getPrevForSelect(lastChild);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!head) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
ret = getPrevForSelect(prev.prevSibling);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// hotkey binding
|
||||
hotkey.bind(['backspace', 'del'], (e: KeyboardEvent) => {
|
||||
if (isInLiveEditing()) return;
|
||||
// TODO: use focus-tracker
|
||||
const doc = focusing.focusDesigner?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
const sel = doc.selection;
|
||||
const topItems = sel.getTopNodes();
|
||||
// TODO: check can remove
|
||||
topItems.forEach((node) => {
|
||||
if (node.canPerformAction('remove')) {
|
||||
doc.removeNode(node);
|
||||
}
|
||||
});
|
||||
sel.clear();
|
||||
});
|
||||
|
||||
hotkey.bind('escape', (e: KeyboardEvent) => {
|
||||
// const currentFocus = focusing.current;
|
||||
if (isInLiveEditing()) return;
|
||||
const sel = focusing.focusDesigner?.currentDocument?.selection;
|
||||
if (isFormEvent(e) || !sel) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
sel.clear();
|
||||
// currentFocus.esc();
|
||||
});
|
||||
|
||||
// command + c copy command + x cut
|
||||
hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const doc = focusing.focusDesigner?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
let selected = doc.selection.getTopNodes(true);
|
||||
selected = selected.filter((node) => {
|
||||
return node.canPerformAction('copy');
|
||||
});
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const componentsMap = {};
|
||||
const componentsTree = selected.map((item) => item.export(TransformStage.Clone));
|
||||
|
||||
// FIXME: clear node.id
|
||||
|
||||
const data = { type: 'nodeSchema', componentsMap, componentsTree };
|
||||
|
||||
clipboard.setData(data);
|
||||
|
||||
const cutMode = action && action.indexOf('x') > 0;
|
||||
if (cutMode) {
|
||||
selected.forEach((node) => {
|
||||
const parentNode = node.getParent();
|
||||
parentNode?.select();
|
||||
node.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// command + v paste
|
||||
hotkey.bind(['command+v', 'ctrl+v'], (e) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !designer || !doc) {
|
||||
return;
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
clipboard.waitPasteData(e, ({ componentsTree }) => {
|
||||
if (componentsTree) {
|
||||
const { target, index } = designer.getSuitableInsertion(componentsTree) || {};
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
let canAddComponentsTree = componentsTree.filter((i) => {
|
||||
return doc.checkNestingUp(target, i);
|
||||
});
|
||||
if (canAddComponentsTree.length === 0) return;
|
||||
const nodes = insertChildren(target, canAddComponentsTree, index);
|
||||
if (nodes) {
|
||||
doc.selection.selectAll(nodes.map((o) => o.id));
|
||||
setTimeout(() => designer.activeTracker.track(nodes[0]), 10);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// command + z undo
|
||||
hotkey.bind(['command+z', 'ctrl+z'], (e) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const his = focusing.focusDesigner?.currentHistory;
|
||||
if (isFormEvent(e) || !his) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
const selection = focusing.focusDesigner?.currentSelection;
|
||||
const curSelected = Array.from(selection?.selected);
|
||||
his.back();
|
||||
selection?.selectAll(curSelected);
|
||||
});
|
||||
|
||||
// command + shift + z redo
|
||||
hotkey.bind(['command+y', 'ctrl+y', 'command+shift+z'], (e) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const his = focusing.focusDesigner?.currentHistory;
|
||||
if (isFormEvent(e) || !his) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selection = focusing.focusDesigner?.currentSelection;
|
||||
const curSelected = Array.from(selection?.selected);
|
||||
his.forward();
|
||||
selection?.selectAll(curSelected);
|
||||
});
|
||||
|
||||
// sibling selection
|
||||
hotkey.bind(['left', 'right'], (e, action) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
const firstNode = selected[0];
|
||||
const silbing = action === 'left' ? firstNode?.prevSibling : firstNode?.nextSibling;
|
||||
silbing?.select();
|
||||
});
|
||||
|
||||
hotkey.bind(['up', 'down'], (e, action) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
const firstNode = selected[0];
|
||||
|
||||
if (action === 'down') {
|
||||
const next = getNextForSelect(firstNode, true, firstNode.getParent());
|
||||
next?.select();
|
||||
} else if (action === 'up') {
|
||||
const prev = getPrevForSelect(firstNode, true, firstNode.getParent());
|
||||
prev?.select();
|
||||
}
|
||||
});
|
||||
|
||||
hotkey.bind(['option+left', 'option+right'], (e, action) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||
|
||||
const firstNode = selected[0];
|
||||
const parent = firstNode.getParent();
|
||||
if (!parent) return;
|
||||
|
||||
const isPrev = action && /(left)$/.test(action);
|
||||
|
||||
const silbing = isPrev ? firstNode.prevSibling : firstNode.nextSibling;
|
||||
if (silbing) {
|
||||
if (isPrev) {
|
||||
parent.insertBefore(firstNode, silbing);
|
||||
} else {
|
||||
parent.insertAfter(firstNode, silbing);
|
||||
}
|
||||
firstNode?.select();
|
||||
}
|
||||
});
|
||||
|
||||
hotkey.bind(['option+up'], (e) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||
|
||||
const firstNode = selected[0];
|
||||
const parent = firstNode.getParent();
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const silbing = firstNode.prevSibling;
|
||||
if (silbing) {
|
||||
if (silbing.isContainer()) {
|
||||
const place = silbing.getSuitablePlace(firstNode, null);
|
||||
place.container.insertAfter(firstNode, place.ref);
|
||||
} else {
|
||||
parent.insertBefore(firstNode, silbing);
|
||||
}
|
||||
firstNode?.select();
|
||||
} else {
|
||||
const place = parent.getSuitablePlace(firstNode, null); // upwards
|
||||
if (place) {
|
||||
place.container.insertBefore(firstNode, place.ref);
|
||||
firstNode?.select();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
hotkey.bind(['option+down'], (e) => {
|
||||
if (isInLiveEditing()) return;
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||
|
||||
const firstNode = selected[0];
|
||||
const parent = firstNode.getParent();
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const silbing = firstNode.nextSibling;
|
||||
if (silbing) {
|
||||
if (silbing.isContainer()) {
|
||||
// const place = silbing.getSuitablePlace(firstNode, null);
|
||||
silbing.insertBefore(firstNode, undefined);
|
||||
// place.container.insertBefore(firstNode, place.ref);
|
||||
} else {
|
||||
parent.insertAfter(firstNode, silbing);
|
||||
}
|
||||
firstNode?.select();
|
||||
} else {
|
||||
const place = parent.getSuitablePlace(firstNode, null); // upwards
|
||||
if (place) {
|
||||
place.container.insertAfter(firstNode, place.ref);
|
||||
firstNode?.select();
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -109,4 +109,4 @@ class Clipboard {
|
||||
}
|
||||
}
|
||||
|
||||
export default new Clipboard();
|
||||
export const clipboard = new Clipboard();
|
||||
|
||||
@ -4,16 +4,20 @@ import BuiltinDragGhostComponent from './drag-ghost';
|
||||
import { Designer, DesignerProps } from './designer';
|
||||
import { ProjectView } from '../project';
|
||||
import './designer.less';
|
||||
import clipboard from './clipboard';
|
||||
import { clipboard } from './clipboard';
|
||||
|
||||
export class DesignerView extends Component<DesignerProps & {
|
||||
type IProps = DesignerProps & {
|
||||
designer?: Designer;
|
||||
}> {
|
||||
readonly designer: Designer;
|
||||
};
|
||||
|
||||
constructor(props: any) {
|
||||
export class DesignerView extends Component<IProps> {
|
||||
readonly designer: Designer;
|
||||
readonly viewName: string | undefined;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
const { designer, ...designerProps } = props;
|
||||
this.viewName = designer?.viewName;
|
||||
if (designer) {
|
||||
this.designer = designer;
|
||||
designer.setProps(designerProps);
|
||||
|
||||
@ -1,53 +1,63 @@
|
||||
import { ComponentType } from 'react';
|
||||
import { obx, computed, autorun, makeObservable, IReactionPublic, IReactionOptions, IReactionDisposer } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
ProjectSchema,
|
||||
ComponentMetadata,
|
||||
ComponentAction,
|
||||
NpmInfo,
|
||||
IEditor,
|
||||
CompositeObject,
|
||||
PropsList,
|
||||
NodeSchema,
|
||||
PropsTransducer,
|
||||
IPublicTypeProjectSchema,
|
||||
IPublicTypeComponentMetadata,
|
||||
IPublicTypeComponentAction,
|
||||
IPublicTypeNpmInfo,
|
||||
IPublicModelEditor,
|
||||
IPublicTypeCompositeObject,
|
||||
IPublicTypePropsList,
|
||||
IPublicTypeNodeSchema,
|
||||
IPublicTypePropsTransducer,
|
||||
IShellModelFactory,
|
||||
IPublicModelDragObject,
|
||||
IPublicModelScrollable,
|
||||
IDesigner,
|
||||
IPublicModelScroller,
|
||||
IPublicTypeLocationData,
|
||||
IPublicEnumTransformStage,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { megreAssets, AssetsJson, isNodeSchema } from '@alilc/lowcode-utils';
|
||||
import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils';
|
||||
import { Project } from '../project';
|
||||
import { Node, DocumentModel, insertChildren, ParentalNode, TransformStage } from '../document';
|
||||
import { Node, DocumentModel, insertChildren, INode } from '../document';
|
||||
import { ComponentMeta } from '../component-meta';
|
||||
import { INodeSelector, Component } from '../simulator';
|
||||
import { Scroller, IScrollable } from './scroller';
|
||||
import { Dragon, isDragNodeObject, isDragNodeDataObject, LocateEvent, DragObject } from './dragon';
|
||||
import { Scroller } from './scroller';
|
||||
import { Dragon, ILocateEvent } from './dragon';
|
||||
import { ActiveTracker } from './active-tracker';
|
||||
import { Detecting } from './detecting';
|
||||
import { DropLocation, LocationData, isLocationChildrenDetail } from './location';
|
||||
import { DropLocation } from './location';
|
||||
import { OffsetObserver, createOffsetObserver } from './offset-observer';
|
||||
import { focusing } from './focusing';
|
||||
import { SettingTopEntry } from './setting';
|
||||
import { BemToolsManager } from '../builtin-simulator/bem-tools/manager';
|
||||
|
||||
const logger = new Logger({ level: 'warn', bizName: 'designer' });
|
||||
|
||||
export interface DesignerProps {
|
||||
editor: IEditor;
|
||||
editor: IPublicModelEditor;
|
||||
shellModelFactory: IShellModelFactory;
|
||||
className?: string;
|
||||
style?: object;
|
||||
defaultSchema?: ProjectSchema;
|
||||
defaultSchema?: IPublicTypeProjectSchema;
|
||||
hotkeys?: object;
|
||||
simulatorProps?: object | ((document: DocumentModel) => object);
|
||||
simulatorComponent?: ComponentType<any>;
|
||||
dragGhostComponent?: ComponentType<any>;
|
||||
suspensed?: boolean;
|
||||
componentMetadatas?: ComponentMetadata[];
|
||||
globalComponentActions?: ComponentAction[];
|
||||
componentMetadatas?: IPublicTypeComponentMetadata[];
|
||||
globalComponentActions?: IPublicTypeComponentAction[];
|
||||
onMount?: (designer: Designer) => void;
|
||||
onDragstart?: (e: LocateEvent) => void;
|
||||
onDrag?: (e: LocateEvent) => void;
|
||||
onDragend?: (e: { dragObject: DragObject; copy: boolean }, loc?: DropLocation) => void;
|
||||
onDragstart?: (e: ILocateEvent) => void;
|
||||
onDrag?: (e: ILocateEvent) => void;
|
||||
onDragend?: (e: { dragObject: IPublicModelDragObject; copy: boolean }, loc?: DropLocation) => void;
|
||||
viewName?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export class Designer {
|
||||
|
||||
export class Designer implements IDesigner {
|
||||
readonly dragon = new Dragon(this);
|
||||
|
||||
readonly activeTracker = new ActiveTracker();
|
||||
@ -56,7 +66,7 @@ export class Designer {
|
||||
|
||||
readonly project: Project;
|
||||
|
||||
readonly editor: IEditor;
|
||||
readonly editor: IPublicModelEditor;
|
||||
|
||||
readonly bemToolsManager = new BemToolsManager(this);
|
||||
|
||||
@ -74,14 +84,17 @@ export class Designer {
|
||||
return this.currentDocument?.selection;
|
||||
}
|
||||
|
||||
viewName: string | undefined;
|
||||
|
||||
constructor(props: DesignerProps) {
|
||||
makeObservable(this);
|
||||
const { editor, shellModelFactory } = props;
|
||||
const { editor, viewName, shellModelFactory } = props;
|
||||
this.editor = editor;
|
||||
this.viewName = viewName;
|
||||
this.shellModelFactory = shellModelFactory;
|
||||
this.setProps(props);
|
||||
|
||||
this.project = new Project(this, props.defaultSchema);
|
||||
this.project = new Project(this, props.defaultSchema, viewName);
|
||||
|
||||
this.dragon.onDragstart((e) => {
|
||||
this.detecting.enable = false;
|
||||
@ -113,6 +126,7 @@ export class Designer {
|
||||
|
||||
this.dragon.onDragend((e) => {
|
||||
const { dragObject, copy } = e;
|
||||
logger.debug('onDragend: dragObject ', dragObject, ' copy ', copy);
|
||||
const loc = this._dropLocation;
|
||||
if (loc) {
|
||||
if (isLocationChildrenDetail(loc.detail) && loc.detail.valid !== false) {
|
||||
@ -201,7 +215,7 @@ export class Designer {
|
||||
};
|
||||
|
||||
postEvent(event: string, ...args: any[]) {
|
||||
this.editor.emit(`designer.${event}`, ...args);
|
||||
this.editor.eventBus.emit(`designer.${event}`, ...args);
|
||||
}
|
||||
|
||||
private _dropLocation?: DropLocation;
|
||||
@ -213,14 +227,14 @@ export class Designer {
|
||||
/**
|
||||
* 创建插入位置,考虑放到 dragon 中
|
||||
*/
|
||||
createLocation(locationData: LocationData): DropLocation {
|
||||
createLocation(locationData: IPublicTypeLocationData): DropLocation {
|
||||
const loc = new DropLocation(locationData);
|
||||
if (this._dropLocation && this._dropLocation.document !== loc.document) {
|
||||
this._dropLocation.document.internalSetDropLocation(null);
|
||||
this._dropLocation.document.dropLocation = null;
|
||||
}
|
||||
this._dropLocation = loc;
|
||||
this.postEvent('dropLocation.change', loc);
|
||||
loc.document.internalSetDropLocation(loc);
|
||||
loc.document.dropLocation = loc;
|
||||
this.activeTracker.track({ node: loc.target, detail: loc.detail });
|
||||
return loc;
|
||||
}
|
||||
@ -230,13 +244,13 @@ export class Designer {
|
||||
*/
|
||||
clearLocation() {
|
||||
if (this._dropLocation) {
|
||||
this._dropLocation.document.internalSetDropLocation(null);
|
||||
this._dropLocation.document.dropLocation = null;
|
||||
}
|
||||
this.postEvent('dropLocation.change', undefined);
|
||||
this._dropLocation = undefined;
|
||||
}
|
||||
|
||||
createScroller(scrollable: IScrollable) {
|
||||
createScroller(scrollable: IPublicModelScrollable): IPublicModelScroller {
|
||||
return new Scroller(scrollable);
|
||||
}
|
||||
|
||||
@ -275,8 +289,8 @@ export class Designer {
|
||||
* 获得合适的插入位置
|
||||
*/
|
||||
getSuitableInsertion(
|
||||
insertNode?: Node | NodeSchema | NodeSchema[],
|
||||
): { target: ParentalNode; index?: number } | null {
|
||||
insertNode?: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[],
|
||||
): { target: INode; index?: number } | null {
|
||||
const activeDoc = this.project.currentDocument;
|
||||
if (!activeDoc) {
|
||||
return null;
|
||||
@ -287,12 +301,12 @@ export class Designer {
|
||||
this.getComponentMeta(insertNode[0].componentName).isModal
|
||||
) {
|
||||
return {
|
||||
target: activeDoc.rootNode as ParentalNode,
|
||||
target: activeDoc.rootNode as INode,
|
||||
};
|
||||
}
|
||||
const focusNode = activeDoc.focusNode!;
|
||||
const nodes = activeDoc.selection.getNodes();
|
||||
const refNode = nodes.find(item => focusNode.contains(item));
|
||||
const refNode = nodes.find((item) => focusNode.contains(item));
|
||||
let target;
|
||||
let index: number | undefined;
|
||||
if (!refNode || refNode === focusNode) {
|
||||
@ -360,16 +374,16 @@ export class Designer {
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
async loadIncrementalAssets(incrementalAssets: AssetsJson): Promise<void> {
|
||||
async loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise<void> {
|
||||
const { components, packages } = incrementalAssets;
|
||||
components && this.buildComponentMetasMap(components);
|
||||
if (packages) {
|
||||
await this.project.simulator!.setupComponents(packages);
|
||||
await this.project.simulator?.setupComponents(packages);
|
||||
}
|
||||
|
||||
if (components) {
|
||||
// 合并assets
|
||||
let assets = this.editor.get('assets');
|
||||
// 合并 assets
|
||||
let assets = this.editor.get('assets') || {};
|
||||
let newAssets = megreAssets(assets, incrementalAssets);
|
||||
// 对于 assets 存在需要二次网络下载的过程,必须 await 等待结束之后,再进行事件触发
|
||||
await this.editor.set('assets', newAssets);
|
||||
@ -377,7 +391,7 @@ export class Designer {
|
||||
// TODO: 因为涉及修改 prototype.view,之后在 renderer 里修改了 vc 的 view 获取逻辑后,可删除
|
||||
this.refreshComponentMetasMap();
|
||||
// 完成加载增量资源后发送事件,方便插件监听并处理相关逻辑
|
||||
this.editor.emit('designer.incrementalAssetsReady');
|
||||
this.editor.eventBus.emit('designer.incrementalAssetsReady');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -397,12 +411,30 @@ export class Designer {
|
||||
return this._simulatorComponent;
|
||||
}
|
||||
|
||||
@obx.ref private _simulatorProps?: object | ((document: DocumentModel) => object);
|
||||
@obx.ref private _simulatorProps?: object | ((project: Project) => object);
|
||||
|
||||
@computed get simulatorProps(): object | ((project: Project) => object) {
|
||||
@computed get simulatorProps(): object {
|
||||
if (typeof this._simulatorProps === 'function') {
|
||||
return this._simulatorProps(this.project);
|
||||
}
|
||||
return this._simulatorProps || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供给模拟器的参数
|
||||
*/
|
||||
@computed get projectSimulatorProps(): any {
|
||||
return {
|
||||
...this.simulatorProps,
|
||||
project: this.project,
|
||||
designer: this,
|
||||
onMount: (simulator: any) => {
|
||||
this.project.mountSimulator(simulator);
|
||||
this.editor.set('simulator', simulator);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@obx.ref private _suspensed = false;
|
||||
|
||||
get suspensed(): boolean {
|
||||
@ -417,11 +449,11 @@ export class Designer {
|
||||
}
|
||||
}
|
||||
|
||||
get schema(): ProjectSchema {
|
||||
get schema(): IPublicTypeProjectSchema {
|
||||
return this.project.getSchema();
|
||||
}
|
||||
|
||||
setSchema(schema?: ProjectSchema) {
|
||||
setSchema(schema?: IPublicTypeProjectSchema) {
|
||||
this.project.load(schema);
|
||||
}
|
||||
|
||||
@ -429,11 +461,11 @@ export class Designer {
|
||||
|
||||
private _lostComponentMetasMap = new Map<string, ComponentMeta>();
|
||||
|
||||
buildComponentMetasMap(metas: ComponentMetadata[]) {
|
||||
buildComponentMetasMap(metas: IPublicTypeComponentMetadata[]) {
|
||||
metas.forEach((data) => this.createComponentMeta(data));
|
||||
}
|
||||
|
||||
createComponentMeta(data: ComponentMetadata): ComponentMeta {
|
||||
createComponentMeta(data: IPublicTypeComponentMetadata): ComponentMeta {
|
||||
const key = data.componentName;
|
||||
let meta = this._componentMetasMap.get(key);
|
||||
if (meta) {
|
||||
@ -455,13 +487,13 @@ export class Designer {
|
||||
return meta;
|
||||
}
|
||||
|
||||
getGlobalComponentActions(): ComponentAction[] | null {
|
||||
getGlobalComponentActions(): IPublicTypeComponentAction[] | null {
|
||||
return this.props?.globalComponentActions || null;
|
||||
}
|
||||
|
||||
getComponentMeta(
|
||||
componentName: string,
|
||||
generateMetadata?: () => ComponentMetadata | null,
|
||||
generateMetadata?: () => IPublicTypeComponentMetadata | null,
|
||||
) {
|
||||
if (this._componentMetasMap.has(componentName)) {
|
||||
return this._componentMetasMap.get(componentName)!;
|
||||
@ -485,7 +517,7 @@ export class Designer {
|
||||
return this._componentMetasMap;
|
||||
}
|
||||
|
||||
@computed get componentsMap(): { [key: string]: NpmInfo | Component } {
|
||||
@computed get componentsMap(): { [key: string]: IPublicTypeNpmInfo | Component } {
|
||||
const maps: any = {};
|
||||
const designer = this;
|
||||
designer._componentMetasMap.forEach((config, key) => {
|
||||
@ -504,9 +536,9 @@ export class Designer {
|
||||
return maps;
|
||||
}
|
||||
|
||||
private propsReducers = new Map<TransformStage, PropsTransducer[]>();
|
||||
private propsReducers = new Map<IPublicEnumTransformStage, IPublicTypePropsTransducer[]>();
|
||||
|
||||
transformProps(props: CompositeObject | PropsList, node: Node, stage: TransformStage) {
|
||||
transformProps(props: IPublicTypeCompositeObject | IPublicTypePropsList, node: Node, stage: IPublicEnumTransformStage) {
|
||||
if (Array.isArray(props)) {
|
||||
// current not support, make this future
|
||||
return props;
|
||||
@ -528,7 +560,7 @@ export class Designer {
|
||||
}, props);
|
||||
}
|
||||
|
||||
addPropsReducer(reducer: PropsTransducer, stage: TransformStage) {
|
||||
addPropsReducer(reducer: IPublicTypePropsTransducer, stage: IPublicEnumTransformStage) {
|
||||
const reducers = this.propsReducers.get(stage);
|
||||
if (reducers) {
|
||||
reducers.push(reducer);
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||
import { EventEmitter } from 'events';
|
||||
import { Node, DocumentModel } from '../document';
|
||||
import { makeObservable, obx, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { IPublicModelDetecting, IPublicModelNode, IPublicModelDocumentModel } from '@alilc/lowcode-types';
|
||||
|
||||
const DETECTING_CHANGE_EVENT = 'detectingChange';
|
||||
export interface IDetecting extends IPublicModelDetecting {
|
||||
|
||||
export class Detecting {
|
||||
}
|
||||
|
||||
export class Detecting implements IDetecting {
|
||||
@obx.ref private _enable = true;
|
||||
|
||||
/**
|
||||
@ -24,9 +26,9 @@ export class Detecting {
|
||||
|
||||
@obx.ref xRayMode = false;
|
||||
|
||||
@obx.ref private _current: Node | null = null;
|
||||
@obx.ref private _current: IPublicModelNode | null = null;
|
||||
|
||||
private emitter: EventEmitter = new EventEmitter();
|
||||
private emitter: IEventBus = createModuleEventBus('Detecting');
|
||||
|
||||
constructor() {
|
||||
makeObservable(this);
|
||||
@ -36,27 +38,27 @@ export class Detecting {
|
||||
return this._current;
|
||||
}
|
||||
|
||||
capture(node: Node | null) {
|
||||
capture(node: IPublicModelNode | null) {
|
||||
if (this._current !== node) {
|
||||
this._current = node;
|
||||
this.emitter.emit(DETECTING_CHANGE_EVENT, this.current);
|
||||
}
|
||||
}
|
||||
|
||||
release(node: Node | null) {
|
||||
release(node: IPublicModelNode | null) {
|
||||
if (this._current === node) {
|
||||
this._current = null;
|
||||
this.emitter.emit(DETECTING_CHANGE_EVENT, this.current);
|
||||
}
|
||||
}
|
||||
|
||||
leave(document: DocumentModel | undefined) {
|
||||
leave(document: IPublicModelDocumentModel | undefined) {
|
||||
if (this.current && this.current.document === document) {
|
||||
this._current = null;
|
||||
}
|
||||
}
|
||||
|
||||
onDetectingChange(fn: (node: Node) => void) {
|
||||
onDetectingChange(fn: (node: IPublicModelNode) => void) {
|
||||
this.emitter.on(DETECTING_CHANGE_EVENT, fn);
|
||||
return () => {
|
||||
this.emitter.off(DETECTING_CHANGE_EVENT, fn);
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { Component, ReactElement } from 'react';
|
||||
import { observer, obx, Title, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { Designer } from '../designer';
|
||||
import { DragObject, isDragNodeObject } from '../dragon';
|
||||
import { isDragNodeObject } from '../dragon';
|
||||
import { isSimulatorHost } from '../../simulator';
|
||||
import './ghost.less';
|
||||
import { I18nData, NodeSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeI18nData, IPublicTypeNodeSchema, IPublicModelDragObject } from '@alilc/lowcode-types';
|
||||
|
||||
type offBinding = () => any;
|
||||
|
||||
@ -12,7 +12,7 @@ type offBinding = () => any;
|
||||
export default class DragGhost extends Component<{ designer: Designer }> {
|
||||
private dispose: offBinding[] = [];
|
||||
|
||||
@obx.ref private titles: (string | I18nData | ReactElement)[] | null = null;
|
||||
@obx.ref private titles: (string | IPublicTypeI18nData | ReactElement)[] | null = null;
|
||||
|
||||
@obx.ref private x = 0;
|
||||
|
||||
@ -54,14 +54,14 @@ export default class DragGhost extends Component<{ designer: Designer }> {
|
||||
];
|
||||
}
|
||||
|
||||
getTitles(dragObject: DragObject) {
|
||||
getTitles(dragObject: IPublicModelDragObject) {
|
||||
if (isDragNodeObject(dragObject)) {
|
||||
return dragObject.nodes.map((node) => node.title);
|
||||
}
|
||||
|
||||
const dataList = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||
|
||||
return dataList.map((item: NodeSchema, i) => (this.props.designer.getComponentMeta(item.componentName).title));
|
||||
return dataList.map((item: IPublicTypeNodeSchema, i) => (this.props.designer.getComponentMeta(item.componentName).title));
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
@ -1,97 +1,53 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { obx, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { DragNodeObject, DragAnyObject, DragObjectType, DragNodeDataObject, DragObject, IPublicModelNode } from '@alilc/lowcode-types';
|
||||
import { obx, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
IPublicTypeDragNodeObject,
|
||||
IPublicTypeDragAnyObject,
|
||||
IPublicEnumDragObjectType,
|
||||
IPublicTypeDragNodeDataObject,
|
||||
IPublicModelDragObject,
|
||||
IPublicModelNode,
|
||||
IPublicModelDragon,
|
||||
IPublicModelLocateEvent,
|
||||
ISensor,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { setNativeSelection, cursor } from '@alilc/lowcode-utils';
|
||||
import { DropLocation } from './location';
|
||||
import { Node, DocumentModel } from '../document';
|
||||
import { ISimulatorHost, isSimulatorHost, NodeInstance, ComponentInstance } from '../simulator';
|
||||
import { Node } from '../document';
|
||||
import { ISimulatorHost, isSimulatorHost } from '../simulator';
|
||||
import { Designer } from './designer';
|
||||
import { makeEventsHandler } from '../utils/misc';
|
||||
|
||||
export interface LocateEvent {
|
||||
export interface ILocateEvent extends IPublicModelLocateEvent {
|
||||
readonly type: 'LocateEvent';
|
||||
/**
|
||||
* 浏览器窗口坐标系
|
||||
*/
|
||||
readonly globalX: number;
|
||||
readonly globalY: number;
|
||||
/**
|
||||
* 原始事件
|
||||
*/
|
||||
readonly originalEvent: MouseEvent | DragEvent;
|
||||
/**
|
||||
* 拖拽对象
|
||||
*/
|
||||
readonly dragObject: DragObject;
|
||||
|
||||
/**
|
||||
* 激活的感应器
|
||||
*/
|
||||
sensor?: ISensor;
|
||||
|
||||
// ======= 以下是 激活的 sensor 将填充的值 ========
|
||||
/**
|
||||
* 浏览器事件响应目标
|
||||
*/
|
||||
target?: Element | null;
|
||||
/**
|
||||
* 当前激活文档画布坐标系
|
||||
*/
|
||||
canvasX?: number;
|
||||
canvasY?: number;
|
||||
/**
|
||||
* 激活或目标文档
|
||||
*/
|
||||
documentModel?: DocumentModel;
|
||||
/**
|
||||
* 事件订正标识,初始构造时,从发起端构造,缺少 canvasX,canvasY, 需要经过订正才有
|
||||
*/
|
||||
fixed?: true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拖拽敏感板
|
||||
* @deprecated use same function in @alilc/lowcode-utils
|
||||
*/
|
||||
export interface ISensor {
|
||||
/**
|
||||
* 是否可响应,比如面板被隐藏,可设置该值 false
|
||||
*/
|
||||
readonly sensorAvailable: boolean;
|
||||
/**
|
||||
* 给事件打补丁
|
||||
*/
|
||||
fixEvent(e: LocateEvent): LocateEvent;
|
||||
/**
|
||||
* 定位并激活
|
||||
*/
|
||||
locate(e: LocateEvent): DropLocation | undefined | null;
|
||||
/**
|
||||
* 是否进入敏感板区域
|
||||
*/
|
||||
isEnter(e: LocateEvent): boolean;
|
||||
/**
|
||||
* 取消激活
|
||||
*/
|
||||
deactiveSensor(): void;
|
||||
/**
|
||||
* 获取节点实例
|
||||
*/
|
||||
getNodeInstanceFromElement(e: Element | null): NodeInstance<ComponentInstance> | null;
|
||||
export function isDragNodeObject(obj: any): obj is IPublicTypeDragNodeObject {
|
||||
return obj && obj.type === IPublicEnumDragObjectType.Node;
|
||||
}
|
||||
|
||||
export function isDragNodeObject(obj: any): obj is DragNodeObject {
|
||||
return obj && obj.type === DragObjectType.Node;
|
||||
/**
|
||||
* @deprecated use same function in @alilc/lowcode-utils
|
||||
*/
|
||||
export function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataObject {
|
||||
return obj && obj.type === IPublicEnumDragObjectType.NodeData;
|
||||
}
|
||||
|
||||
export function isDragNodeDataObject(obj: any): obj is DragNodeDataObject {
|
||||
return obj && obj.type === DragObjectType.NodeData;
|
||||
/**
|
||||
* @deprecated use same function in @alilc/lowcode-utils
|
||||
*/
|
||||
export function isDragAnyObject(obj: any): obj is IPublicTypeDragAnyObject {
|
||||
return obj && obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node;
|
||||
}
|
||||
|
||||
export function isDragAnyObject(obj: any): obj is DragAnyObject {
|
||||
return obj && obj.type !== DragObjectType.NodeData && obj.type !== DragObjectType.Node;
|
||||
}
|
||||
|
||||
export function isLocateEvent(e: any): e is LocateEvent {
|
||||
export function isLocateEvent(e: any): e is ILocateEvent {
|
||||
return e && e.type === 'LocateEvent';
|
||||
}
|
||||
|
||||
@ -128,7 +84,7 @@ export function setShaken(e: any) {
|
||||
e.shaken = true;
|
||||
}
|
||||
|
||||
function getSourceSensor(dragObject: DragObject): ISimulatorHost | null {
|
||||
function getSourceSensor(dragObject: IPublicModelDragObject): ISimulatorHost | null {
|
||||
if (!isDragNodeObject(dragObject)) {
|
||||
return null;
|
||||
}
|
||||
@ -139,12 +95,18 @@ function isDragEvent(e: any): e is DragEvent {
|
||||
return e?.type?.startsWith('drag');
|
||||
}
|
||||
|
||||
export interface IDragon extends IPublicModelDragon {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag-on 拖拽引擎
|
||||
*/
|
||||
export class Dragon {
|
||||
export class Dragon implements IDragon {
|
||||
private sensors: ISensor[] = [];
|
||||
|
||||
key = Math.random();
|
||||
|
||||
/**
|
||||
* current active sensor, 可用于感应区高亮
|
||||
*/
|
||||
@ -162,10 +124,13 @@ export class Dragon {
|
||||
return this._dragging;
|
||||
}
|
||||
|
||||
private emitter = new EventEmitter();
|
||||
viewName: string | undefined;
|
||||
|
||||
private emitter: IEventBus = createModuleEventBus('Dragon');
|
||||
|
||||
constructor(readonly designer: Designer) {
|
||||
makeObservable(this);
|
||||
this.viewName = designer.viewName;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,7 +138,7 @@ export class Dragon {
|
||||
* @param shell container element
|
||||
* @param boost boost got a drag object
|
||||
*/
|
||||
from(shell: Element, boost: (e: MouseEvent) => DragObject | null) {
|
||||
from(shell: Element, boost: (e: MouseEvent) => IPublicModelDragObject | null) {
|
||||
const mousedown = (e: MouseEvent) => {
|
||||
// ESC or RightClick
|
||||
if (e.which === 3 || e.button === 2) {
|
||||
@ -200,7 +165,7 @@ export class Dragon {
|
||||
* @param dragObject 拖拽对象
|
||||
* @param boostEvent 拖拽初始时事件
|
||||
*/
|
||||
boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode) {
|
||||
boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode) {
|
||||
const { designer } = this;
|
||||
const masterSensors = this.getMasterSensors();
|
||||
const handleEvents = makeEventsHandler(boostEvent, masterSensors);
|
||||
@ -449,7 +414,7 @@ export class Dragon {
|
||||
};
|
||||
|
||||
// create drag locate event
|
||||
const createLocateEvent = (e: MouseEvent | DragEvent): LocateEvent => {
|
||||
const createLocateEvent = (e: MouseEvent | DragEvent): ILocateEvent => {
|
||||
const evt: any = {
|
||||
type: 'LocateEvent',
|
||||
dragObject,
|
||||
@ -495,7 +460,7 @@ export class Dragon {
|
||||
|
||||
const sourceSensor = getSourceSensor(dragObject);
|
||||
/* istanbul ignore next */
|
||||
const chooseSensor = (e: LocateEvent) => {
|
||||
const chooseSensor = (e: ILocateEvent) => {
|
||||
// this.sensors will change on dragstart
|
||||
const sensors: ISensor[] = this.sensors.concat(masterSensors as ISensor[]);
|
||||
let sensor =
|
||||
@ -646,21 +611,21 @@ export class Dragon {
|
||||
}
|
||||
}
|
||||
|
||||
onDragstart(func: (e: LocateEvent) => any) {
|
||||
onDragstart(func: (e: ILocateEvent) => any) {
|
||||
this.emitter.on('dragstart', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('dragstart', func);
|
||||
};
|
||||
}
|
||||
|
||||
onDrag(func: (e: LocateEvent) => any) {
|
||||
onDrag(func: (e: ILocateEvent) => any) {
|
||||
this.emitter.on('drag', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('drag', func);
|
||||
};
|
||||
}
|
||||
|
||||
onDragend(func: (x: { dragObject: DragObject; copy: boolean }) => any) {
|
||||
onDragend(func: (x: { dragObject: IPublicModelDragObject; copy: boolean }) => any) {
|
||||
this.emitter.on('dragend', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('dragend', func);
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import './builtin-hotkey';
|
||||
|
||||
export * from './designer';
|
||||
export * from './designer-view';
|
||||
export * from './dragon';
|
||||
@ -9,3 +7,6 @@ export * from './offset-observer';
|
||||
export * from './scroller';
|
||||
export * from './setting';
|
||||
export * from './active-tracker';
|
||||
export * from './focusing';
|
||||
export * from '../document';
|
||||
export * from './clipboard';
|
||||
|
||||
@ -1,43 +1,14 @@
|
||||
import { DocumentModel, Node as ComponentNode, ParentalNode } from '../document';
|
||||
import { LocateEvent } from './dragon';
|
||||
import { INode } from '../document';
|
||||
import { ILocateEvent } from './dragon';
|
||||
import {
|
||||
IPublicModelDocumentModel,
|
||||
IPublicModelDropLocation,
|
||||
IPublicTypeLocationDetailType,
|
||||
IPublicTypeRect,
|
||||
IPublicTypeLocationDetail,
|
||||
IPublicTypeLocationData,
|
||||
} from '@alilc/lowcode-types';
|
||||
|
||||
export interface LocationData {
|
||||
target: ParentalNode; // shadowNode | ConditionFlow | ElementNode | RootNode
|
||||
detail: LocationDetail;
|
||||
source: string;
|
||||
event: LocateEvent;
|
||||
}
|
||||
|
||||
export enum LocationDetailType {
|
||||
Children = 'Children',
|
||||
Prop = 'Prop',
|
||||
}
|
||||
|
||||
export interface LocationChildrenDetail {
|
||||
type: LocationDetailType.Children;
|
||||
index?: number | null;
|
||||
/**
|
||||
* 是否有效位置
|
||||
*/
|
||||
valid?: boolean;
|
||||
edge?: DOMRect;
|
||||
near?: {
|
||||
node: ComponentNode;
|
||||
pos: 'before' | 'after' | 'replace';
|
||||
rect?: Rect;
|
||||
align?: 'V' | 'H';
|
||||
};
|
||||
focus?: { type: 'slots' } | { type: 'node'; node: ParentalNode };
|
||||
}
|
||||
|
||||
export interface LocationPropDetail {
|
||||
// cover 形态,高亮 domNode,如果 domNode 为空,取 container 的值
|
||||
type: LocationDetailType.Prop;
|
||||
name: string;
|
||||
domNode?: HTMLElement;
|
||||
}
|
||||
|
||||
export type LocationDetail = LocationChildrenDetail | LocationPropDetail | { type: string; [key: string]: any };
|
||||
|
||||
export interface Point {
|
||||
clientX: number;
|
||||
@ -53,17 +24,18 @@ export type Rects = DOMRect[] & {
|
||||
elements: Array<Element | Text>;
|
||||
};
|
||||
|
||||
export type Rect = DOMRect & {
|
||||
elements: Array<Element | Text>;
|
||||
computed?: boolean;
|
||||
};
|
||||
|
||||
export function isLocationData(obj: any): obj is LocationData {
|
||||
/**
|
||||
* @deprecated use same function in @alilc/lowcode-utils
|
||||
*/
|
||||
export function isLocationData(obj: any): boolean {
|
||||
return obj && obj.target && obj.detail;
|
||||
}
|
||||
|
||||
export function isLocationChildrenDetail(obj: any): obj is LocationChildrenDetail {
|
||||
return obj && obj.type === LocationDetailType.Children;
|
||||
/**
|
||||
* @deprecated use same function in @alilc/lowcode-utils
|
||||
*/
|
||||
export function isLocationChildrenDetail(obj: any): boolean {
|
||||
return obj && obj.type === IPublicTypeLocationDetailType.Children;
|
||||
}
|
||||
|
||||
export function isRowContainer(container: Element | Text, win?: Window) {
|
||||
@ -92,7 +64,7 @@ export function isChildInline(child: Element | Text, win?: Window) {
|
||||
return /^inline/.test(style.getPropertyValue('display')) || /^(left|right)$/.test(style.getPropertyValue('float'));
|
||||
}
|
||||
|
||||
export function getRectTarget(rect: Rect | null) {
|
||||
export function getRectTarget(rect: IPublicTypeRect | null) {
|
||||
if (!rect || rect.computed) {
|
||||
return null;
|
||||
}
|
||||
@ -100,7 +72,7 @@ export function getRectTarget(rect: Rect | null) {
|
||||
return els && els.length > 0 ? els[0]! : null;
|
||||
}
|
||||
|
||||
export function isVerticalContainer(rect: Rect | null) {
|
||||
export function isVerticalContainer(rect: IPublicTypeRect | null) {
|
||||
const el = getRectTarget(rect);
|
||||
if (!el) {
|
||||
return false;
|
||||
@ -108,7 +80,7 @@ export function isVerticalContainer(rect: Rect | null) {
|
||||
return isRowContainer(el);
|
||||
}
|
||||
|
||||
export function isVertical(rect: Rect | null) {
|
||||
export function isVertical(rect: IPublicTypeRect | null) {
|
||||
const el = getRectTarget(rect);
|
||||
if (!el) {
|
||||
return false;
|
||||
@ -127,28 +99,42 @@ function isDocument(elem: any): elem is Document {
|
||||
export function getWindow(elem: Element | Document): Window {
|
||||
return (isDocument(elem) ? elem : elem.ownerDocument!).defaultView!;
|
||||
}
|
||||
export interface IDropLocation extends IPublicModelDropLocation {
|
||||
|
||||
export class DropLocation {
|
||||
readonly target: ParentalNode;
|
||||
readonly target: INode;
|
||||
|
||||
readonly detail: LocationDetail;
|
||||
readonly detail: IPublicTypeLocationDetail;
|
||||
|
||||
readonly event: LocateEvent;
|
||||
readonly event: ILocateEvent;
|
||||
|
||||
readonly source: string;
|
||||
|
||||
get document(): DocumentModel {
|
||||
get document(): IPublicModelDocumentModel;
|
||||
|
||||
clone(event: ILocateEvent): IDropLocation;
|
||||
}
|
||||
|
||||
export class DropLocation implements IDropLocation {
|
||||
readonly target: INode;
|
||||
|
||||
readonly detail: IPublicTypeLocationDetail;
|
||||
|
||||
readonly event: ILocateEvent;
|
||||
|
||||
readonly source: string;
|
||||
|
||||
get document(): IPublicModelDocumentModel {
|
||||
return this.target.document;
|
||||
}
|
||||
|
||||
constructor({ target, detail, source, event }: LocationData) {
|
||||
constructor({ target, detail, source, event }: IPublicTypeLocationData) {
|
||||
this.target = target;
|
||||
this.detail = detail;
|
||||
this.source = source;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
clone(event: LocateEvent): DropLocation {
|
||||
clone(event: ILocateEvent): DropLocation {
|
||||
return new DropLocation({
|
||||
target: this.target,
|
||||
detail: this.detail,
|
||||
|
||||
@ -2,7 +2,7 @@ import requestIdleCallback, { cancelIdleCallback } from 'ric-shim';
|
||||
import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { uniqueId } from '@alilc/lowcode-utils';
|
||||
import { INodeSelector, IViewport } from '../simulator';
|
||||
import { isRootNode, Node } from '../document';
|
||||
import { Node } from '../document';
|
||||
|
||||
export class OffsetObserver {
|
||||
readonly id = uniqueId('oobx');
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import { isElement } from '@alilc/lowcode-utils';
|
||||
import { IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller } from '@alilc/lowcode-types';
|
||||
|
||||
export class ScrollTarget {
|
||||
export interface IScrollTarget extends IPublicModelScrollTarget {
|
||||
}
|
||||
|
||||
export class ScrollTarget implements IScrollTarget {
|
||||
get left() {
|
||||
return 'scrollX' in this.target ? this.target.scrollX : this.target.scrollLeft;
|
||||
}
|
||||
@ -44,18 +48,18 @@ function easing(n: number) {
|
||||
|
||||
const SCROLL_ACCURCY = 30;
|
||||
|
||||
export interface IScrollable {
|
||||
scrollTarget?: ScrollTarget | Element;
|
||||
bounds?: DOMRect | null;
|
||||
scale?: number;
|
||||
export interface IScroller extends IPublicModelScroller {
|
||||
|
||||
}
|
||||
|
||||
export class Scroller {
|
||||
export class Scroller implements IScroller {
|
||||
private pid: number | undefined;
|
||||
scrollable: IPublicModelScrollable;
|
||||
|
||||
constructor(private scrollable: IScrollable) {}
|
||||
constructor(scrollable: IPublicModelScrollable) {
|
||||
this.scrollable = scrollable;
|
||||
}
|
||||
|
||||
get scrollTarget(): ScrollTarget | null {
|
||||
get scrollTarget(): IScrollTarget | null {
|
||||
let target = this.scrollable.scrollTarget;
|
||||
if (!target) {
|
||||
return null;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { SettingTarget } from '@alilc/lowcode-types';
|
||||
import { IPublicModelSettingTarget } from '@alilc/lowcode-types';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { Designer } from '../designer';
|
||||
import { Node } from '../../document';
|
||||
|
||||
export interface SettingEntry extends SettingTarget {
|
||||
export interface SettingEntry extends IPublicModelSettingTarget {
|
||||
readonly nodes: Node[];
|
||||
readonly componentMeta: ComponentMeta | null;
|
||||
readonly designer: Designer;
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { TitleContent, SetterType, DynamicSetter, FieldExtraProps, FieldConfig, CustomView, ISetValueOptions } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeTitleContent, IPublicTypeSetterType, IPublicTypeDynamicSetter, IPublicTypeFieldExtraProps, IPublicTypeFieldConfig, IPublicTypeCustomView, IPublicTypeSetValueOptions } from '@alilc/lowcode-types';
|
||||
import { Transducer } from './utils';
|
||||
import { SettingPropEntry } from './setting-prop-entry';
|
||||
import { SettingEntry } from './setting-entry';
|
||||
import { computed, obx, makeObservable, action } from '@alilc/lowcode-editor-core';
|
||||
import { cloneDeep, isCustomView, isDynamicSetter } from '@alilc/lowcode-utils';
|
||||
|
||||
function getSettingFieldCollectorKey(parent: SettingEntry, config: FieldConfig) {
|
||||
function getSettingFieldCollectorKey(parent: SettingEntry, config: IPublicTypeFieldConfig) {
|
||||
let cur = parent;
|
||||
const path = [config.name];
|
||||
while (cur !== parent.top) {
|
||||
@ -24,21 +24,21 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
|
||||
readonly transducer: Transducer;
|
||||
|
||||
private _config: FieldConfig;
|
||||
private _config: IPublicTypeFieldConfig;
|
||||
|
||||
extraProps: FieldExtraProps;
|
||||
extraProps: IPublicTypeFieldExtraProps;
|
||||
|
||||
// ==== dynamic properties ====
|
||||
private _title?: TitleContent;
|
||||
private _title?: IPublicTypeTitleContent;
|
||||
|
||||
get title() {
|
||||
// FIXME! intl
|
||||
return this._title || (typeof this.name === 'number' ? `项目 ${this.name}` : this.name);
|
||||
}
|
||||
|
||||
private _setter?: SetterType | DynamicSetter;
|
||||
private _setter?: IPublicTypeSetterType | IPublicTypeDynamicSetter;
|
||||
|
||||
@computed get setter(): SetterType | null {
|
||||
@computed get setter(): IPublicTypeSetterType | null {
|
||||
if (!this._setter) {
|
||||
return null;
|
||||
}
|
||||
@ -61,7 +61,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
|
||||
parent: SettingEntry;
|
||||
|
||||
constructor(parent: SettingEntry, config: FieldConfig, settingFieldCollector?: (name: string | number, field: SettingField) => void) {
|
||||
constructor(parent: SettingEntry, config: IPublicTypeFieldConfig, settingFieldCollector?: (name: string | number, field: SettingField) => void) {
|
||||
super(parent, config.name, config.type);
|
||||
makeObservable(this);
|
||||
const { title, items, setter, extraProps, ...rest } = config;
|
||||
@ -88,17 +88,17 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
this.transducer = new Transducer(this, { setter });
|
||||
}
|
||||
|
||||
private _items: Array<SettingField | CustomView> = [];
|
||||
private _items: Array<SettingField | IPublicTypeCustomView> = [];
|
||||
|
||||
get items(): Array<SettingField | CustomView> {
|
||||
get items(): Array<SettingField | IPublicTypeCustomView> {
|
||||
return this._items;
|
||||
}
|
||||
|
||||
get config(): FieldConfig {
|
||||
get config(): IPublicTypeFieldConfig {
|
||||
return this._config;
|
||||
}
|
||||
|
||||
private initItems(items: Array<FieldConfig | CustomView>, settingFieldCollector?: { (name: string | number, field: SettingField): void; (name: string, field: SettingField): void }) {
|
||||
private initItems(items: Array<IPublicTypeFieldConfig | IPublicTypeCustomView>, settingFieldCollector?: { (name: string | number, field: SettingField): void; (name: string, field: SettingField): void }) {
|
||||
this._items = items.map((item) => {
|
||||
if (isCustomView(item)) {
|
||||
return item;
|
||||
@ -113,7 +113,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
}
|
||||
|
||||
// 创建子配置项,通常用于 object/array 类型数据
|
||||
createField(config: FieldConfig): SettingField {
|
||||
createField(config: IPublicTypeFieldConfig): SettingField {
|
||||
return new SettingField(this, config);
|
||||
}
|
||||
|
||||
@ -123,14 +123,14 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
|
||||
// ======= compatibles for vision ======
|
||||
|
||||
getConfig<K extends keyof FieldConfig>(configName?: K): FieldConfig[K] | FieldConfig {
|
||||
getConfig<K extends keyof IPublicTypeFieldConfig>(configName?: K): IPublicTypeFieldConfig[K] | IPublicTypeFieldConfig {
|
||||
if (configName) {
|
||||
return this.config[configName];
|
||||
}
|
||||
return this._config;
|
||||
}
|
||||
|
||||
getItems(filter?: (item: SettingField | CustomView) => boolean): Array<SettingField | CustomView> {
|
||||
getItems(filter?: (item: SettingField | IPublicTypeCustomView) => boolean): Array<SettingField | IPublicTypeCustomView> {
|
||||
return this._items.filter(item => {
|
||||
if (filter) {
|
||||
return filter(item);
|
||||
@ -142,7 +142,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
private hotValue: any;
|
||||
|
||||
@action
|
||||
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: ISetValueOptions) {
|
||||
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions) {
|
||||
if (isHotValue) {
|
||||
this.setHotValue(val, extraOptions);
|
||||
return;
|
||||
@ -177,7 +177,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
}
|
||||
|
||||
@action
|
||||
setHotValue(data: any, options?: ISetValueOptions) {
|
||||
setHotValue(data: any, options?: IPublicTypeSetValueOptions) {
|
||||
this.hotValue = data;
|
||||
const value = this.transducer.toNative(data);
|
||||
if (options) {
|
||||
@ -208,7 +208,9 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
return this.designer.autorun(action, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use same function from '@alilc/lowcode-utils' instead
|
||||
*/
|
||||
export function isSettingField(obj: any): obj is SettingField {
|
||||
return obj && obj.isSettingField;
|
||||
}
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
import { obx, computed, makeObservable, runInAction } from '@alilc/lowcode-editor-core';
|
||||
import { GlobalEvent, IEditor, ISetValueOptions } from '@alilc/lowcode-types';
|
||||
import { uniqueId, isJSExpression } from '@alilc/lowcode-utils';
|
||||
import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { GlobalEvent, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types';
|
||||
import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils';
|
||||
import { SettingEntry } from './setting-entry';
|
||||
import { Node } from '../../document';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { Designer } from '../designer';
|
||||
import { EventEmitter } from 'events';
|
||||
import { isSettingField } from './setting-field';
|
||||
import { Setters } from '@alilc/lowcode-shell';
|
||||
|
||||
export class SettingPropEntry implements SettingEntry {
|
||||
// === static properties ===
|
||||
readonly editor: IEditor;
|
||||
readonly editor: IPublicModelEditor;
|
||||
|
||||
readonly isSameComponent: boolean;
|
||||
|
||||
@ -18,6 +17,8 @@ export class SettingPropEntry implements SettingEntry {
|
||||
|
||||
readonly isSingle: boolean;
|
||||
|
||||
readonly setters: Setters;
|
||||
|
||||
readonly nodes: Node[];
|
||||
|
||||
readonly componentMeta: ComponentMeta | null;
|
||||
@ -32,7 +33,7 @@ export class SettingPropEntry implements SettingEntry {
|
||||
|
||||
readonly id = uniqueId('entry');
|
||||
|
||||
readonly emitter = new EventEmitter();
|
||||
readonly emitter: IEventBus = createModuleEventBus('SettingPropEntry');
|
||||
|
||||
// ==== dynamic properties ====
|
||||
@obx.ref private _name: string | number;
|
||||
@ -70,6 +71,7 @@ export class SettingPropEntry implements SettingEntry {
|
||||
// copy parent static properties
|
||||
this.editor = parent.editor;
|
||||
this.nodes = parent.nodes;
|
||||
this.setters = parent.setters;
|
||||
this.componentMeta = parent.componentMeta;
|
||||
this.isSameComponent = parent.isSameComponent;
|
||||
this.isMultiple = parent.isMultiple;
|
||||
@ -173,7 +175,7 @@ export class SettingPropEntry implements SettingEntry {
|
||||
/**
|
||||
* 设置当前属性值
|
||||
*/
|
||||
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: ISetValueOptions) {
|
||||
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions) {
|
||||
const oldValue = this.getValue();
|
||||
if (this.type === 'field') {
|
||||
this.parent.setPropValue(this.name, val);
|
||||
@ -287,7 +289,7 @@ export class SettingPropEntry implements SettingEntry {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
valueChange(options: ISetValueOptions = {}) {
|
||||
valueChange(options: IPublicTypeSetValueOptions = {}) {
|
||||
this.emitter.emit('valuechange', options);
|
||||
|
||||
if (this.parent && isSettingField(this.parent)) {
|
||||
@ -296,7 +298,7 @@ export class SettingPropEntry implements SettingEntry {
|
||||
}
|
||||
|
||||
notifyValueChange(oldValue: any, newValue: any) {
|
||||
this.editor.emit(GlobalEvent.Node.Prop.Change, {
|
||||
this.editor.eventBus.emit(GlobalEvent.Node.Prop.Change, {
|
||||
node: this.getNode(),
|
||||
prop: this,
|
||||
oldValue,
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { CustomView, IEditor } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeCustomView, IPublicModelEditor } from '@alilc/lowcode-types';
|
||||
import { isCustomView } from '@alilc/lowcode-utils';
|
||||
import { computed } from '@alilc/lowcode-editor-core';
|
||||
import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { SettingEntry } from './setting-entry';
|
||||
import { SettingField } from './setting-field';
|
||||
import { SettingPropEntry } from './setting-prop-entry';
|
||||
import { Node } from '../../document';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { Designer } from '../designer';
|
||||
import { Setters } from '@alilc/lowcode-shell';
|
||||
|
||||
function generateSessionId(nodes: Node[]) {
|
||||
return nodes
|
||||
@ -17,9 +17,9 @@ function generateSessionId(nodes: Node[]) {
|
||||
}
|
||||
|
||||
export class SettingTopEntry implements SettingEntry {
|
||||
private emitter = new EventEmitter();
|
||||
private emitter: IEventBus = createModuleEventBus('SettingTopEntry');
|
||||
|
||||
private _items: Array<SettingField | CustomView> = [];
|
||||
private _items: Array<SettingField | IPublicTypeCustomView> = [];
|
||||
|
||||
private _componentMeta: ComponentMeta | null = null;
|
||||
|
||||
@ -72,15 +72,18 @@ export class SettingTopEntry implements SettingEntry {
|
||||
|
||||
readonly designer: Designer;
|
||||
|
||||
readonly setters: Setters;
|
||||
|
||||
disposeFunctions: any[] = [];
|
||||
|
||||
constructor(readonly editor: IEditor, readonly nodes: Node[]) {
|
||||
constructor(readonly editor: IPublicModelEditor, readonly nodes: Node[]) {
|
||||
if (!Array.isArray(nodes) || nodes.length < 1) {
|
||||
throw new ReferenceError('nodes should not be empty');
|
||||
}
|
||||
this.id = generateSessionId(nodes);
|
||||
this.first = nodes[0];
|
||||
this.designer = this.first.document.designer;
|
||||
this.setters = editor.get('setters') as Setters;
|
||||
|
||||
// setups
|
||||
this.setupComponentMeta();
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
// all this file for polyfill vision logic
|
||||
import { isValidElement } from 'react';
|
||||
import { FieldConfig, SetterConfig } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeFieldConfig, IPublicTypeSetterConfig } from '@alilc/lowcode-types';
|
||||
import { isSetterConfig, isDynamicSetter } from '@alilc/lowcode-utils';
|
||||
import { getSetter } from '@alilc/lowcode-editor-core';
|
||||
import { SettingField } from './setting-field';
|
||||
|
||||
function getHotterFromSetter(setter) {
|
||||
@ -36,12 +35,12 @@ export class Transducer {
|
||||
|
||||
context: any;
|
||||
|
||||
constructor(context: SettingField, config: { setter: FieldConfig['setter'] }) {
|
||||
constructor(context: SettingField, config: { setter: IPublicTypeFieldConfig['setter'] }) {
|
||||
let { setter } = config;
|
||||
|
||||
// 1. validElement
|
||||
// 2. SetterConfig
|
||||
// 3. SetterConfig[]
|
||||
// 2. IPublicTypeSetterConfig
|
||||
// 3. IPublicTypeSetterConfig[]
|
||||
if (Array.isArray(setter)) {
|
||||
setter = setter[0];
|
||||
} else if (isValidElement(setter) && setter.type.displayName === 'MixedSetter') {
|
||||
@ -59,12 +58,12 @@ export class Transducer {
|
||||
let isDynamic = true;
|
||||
|
||||
if (isSetterConfig(setter)) {
|
||||
const { componentName, isDynamic: dynamicFlag } = setter as SetterConfig;
|
||||
const { componentName, isDynamic: dynamicFlag } = setter as IPublicTypeSetterConfig;
|
||||
setter = componentName;
|
||||
isDynamic = dynamicFlag !== false;
|
||||
}
|
||||
if (typeof setter === 'string') {
|
||||
const { component, isDynamic: dynamicFlag } = getSetter(setter) || {};
|
||||
const { component, isDynamic: dynamicFlag } = context.setters.getSetter(setter) || {};
|
||||
setter = component;
|
||||
// 如果在物料配置中声明了,在 registerSetter 没有声明,取物料配置中的声明
|
||||
isDynamic = dynamicFlag === undefined ? isDynamic : dynamicFlag !== false;
|
||||
|
||||
@ -1,15 +1,31 @@
|
||||
import { makeObservable, obx, engineConfig, action, runWithGlobalEventOff, wrapWithEventSwitch } from '@alilc/lowcode-editor-core';
|
||||
import { NodeData, NodeSchema, RootSchema, PageSchema, ComponentsMap, DragNodeObject, DragNodeDataObject } from '@alilc/lowcode-types';
|
||||
import { EventEmitter } from 'events';
|
||||
import { makeObservable, obx, engineConfig, action, runWithGlobalEventOff, wrapWithEventSwitch, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
IPublicTypeNodeData,
|
||||
IPublicTypeNodeSchema,
|
||||
IPublicTypeRootSchema,
|
||||
IPublicTypePageSchema,
|
||||
IPublicTypeComponentsMap,
|
||||
IPublicTypeDragNodeObject,
|
||||
IPublicTypeDragNodeDataObject,
|
||||
IPublicModelDocumentModel,
|
||||
IPublicModelSelection,
|
||||
IPublicModelHistory,
|
||||
IPublicModelModalNodesManager,
|
||||
IPublicModelNode,
|
||||
IPublicApiProject,
|
||||
IPublicModelDropLocation,
|
||||
IPublicEnumEventNames,
|
||||
IPublicEnumTransformStage,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { Project } from '../project';
|
||||
import { ISimulatorHost } from '../simulator';
|
||||
import { ComponentMeta } from '../component-meta';
|
||||
import { isDragNodeDataObject, DropLocation, Designer, isDragNodeObject } from '../designer';
|
||||
import { Node, insertChildren, insertChild, isNode, RootNode, ParentalNode } from './node/node';
|
||||
import { IDropLocation, Designer } from '../designer';
|
||||
import { Node, insertChildren, insertChild, isNode, RootNode, INode } from './node/node';
|
||||
import { Selection } from './selection';
|
||||
import { History } from './history';
|
||||
import { TransformStage, ModalNodesManager } from './node';
|
||||
import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema } from '@alilc/lowcode-utils';
|
||||
import { ModalNodesManager } from './node';
|
||||
import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject } from '@alilc/lowcode-utils';
|
||||
|
||||
export type GetDataType<T, NodeType> = T extends undefined
|
||||
? NodeType extends {
|
||||
@ -18,8 +34,11 @@ export type GetDataType<T, NodeType> = T extends undefined
|
||||
? R
|
||||
: any
|
||||
: T;
|
||||
export interface IDocumentModel extends IPublicModelDocumentModel {
|
||||
|
||||
export class DocumentModel {
|
||||
}
|
||||
|
||||
export class DocumentModel implements IDocumentModel {
|
||||
/**
|
||||
* 根节点 类型有:Page/Component/Block
|
||||
*/
|
||||
@ -33,29 +52,29 @@ export class DocumentModel {
|
||||
/**
|
||||
* 选区控制
|
||||
*/
|
||||
readonly selection: Selection = new Selection(this);
|
||||
readonly selection: IPublicModelSelection = new Selection(this);
|
||||
|
||||
/**
|
||||
* 操作记录控制
|
||||
*/
|
||||
readonly history: History;
|
||||
readonly history: IPublicModelHistory;
|
||||
|
||||
/**
|
||||
* 模态节点管理
|
||||
*/
|
||||
readonly modalNodesManager: ModalNodesManager;
|
||||
readonly modalNodesManager: IPublicModelModalNodesManager;
|
||||
|
||||
private _nodesMap = new Map<string, Node>();
|
||||
private _nodesMap = new Map<string, IPublicModelNode>();
|
||||
|
||||
readonly project: Project;
|
||||
readonly project: IPublicApiProject;
|
||||
|
||||
readonly designer: Designer;
|
||||
|
||||
@obx.shallow private nodes = new Set<Node>();
|
||||
@obx.shallow private nodes = new Set<IPublicModelNode>();
|
||||
|
||||
private seqId = 0;
|
||||
|
||||
private emitter: EventEmitter;
|
||||
private emitter: IEventBus;
|
||||
|
||||
private rootNodeVisitorMap: { [visitorName: string]: any } = {};
|
||||
|
||||
@ -100,17 +119,17 @@ export class DocumentModel {
|
||||
this._drillDownNode = node;
|
||||
}
|
||||
|
||||
private _modalNode?: ParentalNode;
|
||||
private _modalNode?: INode;
|
||||
|
||||
private _blank?: boolean;
|
||||
|
||||
private inited = false;
|
||||
|
||||
constructor(project: Project, schema?: RootSchema) {
|
||||
constructor(project: Project, schema?: IPublicTypeRootSchema) {
|
||||
makeObservable(this);
|
||||
this.project = project;
|
||||
this.designer = this.project?.designer;
|
||||
this.emitter = new EventEmitter();
|
||||
this.emitter = createModuleEventBus('DocumentModel');
|
||||
|
||||
if (!schema) {
|
||||
this._blank = true;
|
||||
@ -128,9 +147,9 @@ export class DocumentModel {
|
||||
);
|
||||
|
||||
this.history = new History(
|
||||
() => this.export(TransformStage.Serilize),
|
||||
() => this.export(IPublicEnumTransformStage.Serilize),
|
||||
(schema) => {
|
||||
this.import(schema as RootSchema, true);
|
||||
this.import(schema as IPublicTypeRootSchema, true);
|
||||
this.simulator?.rerender();
|
||||
},
|
||||
);
|
||||
@ -255,14 +274,14 @@ export class DocumentModel {
|
||||
/**
|
||||
* 插入一个节点
|
||||
*/
|
||||
insertNode(parent: ParentalNode, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
insertNode(parent: INode, thing: Node | IPublicTypeNodeData, at?: number | null, copy?: boolean): Node {
|
||||
return insertChild(parent, thing, at, copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入多个节点
|
||||
*/
|
||||
insertNodes(parent: ParentalNode, thing: Node[] | NodeData[], at?: number | null, copy?: boolean) {
|
||||
insertNodes(parent: INode, thing: Node[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean) {
|
||||
return insertChildren(parent, thing, at, copy);
|
||||
}
|
||||
|
||||
@ -275,9 +294,9 @@ export class DocumentModel {
|
||||
if (typeof idOrNode === 'string') {
|
||||
id = idOrNode;
|
||||
node = this.getNode(id);
|
||||
} else {
|
||||
node = idOrNode;
|
||||
id = node.id;
|
||||
} else if (idOrNode.id) {
|
||||
id = idOrNode.id;
|
||||
node = this.getNode(id);
|
||||
}
|
||||
if (!node) {
|
||||
return;
|
||||
@ -300,13 +319,16 @@ export class DocumentModel {
|
||||
this._nodesMap.delete(node.id);
|
||||
}
|
||||
|
||||
@obx.ref private _dropLocation: DropLocation | null = null;
|
||||
@obx.ref private _dropLocation: IDropLocation | null = null;
|
||||
|
||||
/**
|
||||
* 内部方法,请勿调用
|
||||
*/
|
||||
internalSetDropLocation(loc: DropLocation | null) {
|
||||
|
||||
set dropLocation(loc: IPublicModelDropLocation | null) {
|
||||
this._dropLocation = loc;
|
||||
// pub event
|
||||
this.designer.editor.eventBus.emit(
|
||||
IPublicEnumEventNames.DOCUMENT_DROPLOCATION_CHANGED,
|
||||
{ document: this, location: loc },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -319,7 +341,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 包裹当前选区中的节点
|
||||
*/
|
||||
wrapWith(schema: NodeSchema): Node | null {
|
||||
wrapWith(schema: IPublicTypeNodeSchema): Node | null {
|
||||
const nodes = this.selection.getTopNodes();
|
||||
if (nodes.length < 1) {
|
||||
return null;
|
||||
@ -341,12 +363,12 @@ export class DocumentModel {
|
||||
/**
|
||||
* 导出 schema 数据
|
||||
*/
|
||||
get schema(): RootSchema {
|
||||
get schema(): IPublicTypeRootSchema {
|
||||
return this.rootNode?.schema as any;
|
||||
}
|
||||
|
||||
@action
|
||||
import(schema: RootSchema, checkId = false) {
|
||||
import(schema: IPublicTypeRootSchema, checkId = false) {
|
||||
const drillDownNodeId = this._drillDownNode?.id;
|
||||
runWithGlobalEventOff(() => {
|
||||
// TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除
|
||||
@ -363,14 +385,14 @@ export class DocumentModel {
|
||||
});
|
||||
}
|
||||
|
||||
export(stage: TransformStage = TransformStage.Serilize) {
|
||||
export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Serilize) {
|
||||
stage = compatStage(stage);
|
||||
// 置顶只作用于 Page 的第一级子节点,目前还用不到里层的置顶;如果后面有需要可以考虑将这段写到 node-children 中的 export
|
||||
const currentSchema = this.rootNode?.export(stage);
|
||||
if (Array.isArray(currentSchema?.children) && currentSchema?.children.length > 0) {
|
||||
const FixedTopNodeIndex = currentSchema.children
|
||||
.filter(i => isPlainObject(i))
|
||||
.findIndex((i => (i as NodeSchema).props?.__isTopFixed__));
|
||||
.findIndex((i => (i as IPublicTypeNodeSchema).props?.__isTopFixed__));
|
||||
if (FixedTopNodeIndex > 0) {
|
||||
const FixedTopNode = currentSchema.children.splice(FixedTopNodeIndex, 1);
|
||||
currentSchema.children.unshift(FixedTopNode[0]);
|
||||
@ -382,7 +404,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 导出节点数据
|
||||
*/
|
||||
getNodeSchema(id: string): NodeData | null {
|
||||
getNodeSchema(id: string): IPublicTypeNodeData | null {
|
||||
const node = this.getNode(id);
|
||||
if (node) {
|
||||
return node.schema;
|
||||
@ -505,8 +527,8 @@ export class DocumentModel {
|
||||
this.rootNode = null;
|
||||
}
|
||||
|
||||
checkNesting(dropTarget: ParentalNode, dragObject: DragNodeObject | NodeSchema | Node | DragNodeDataObject): boolean {
|
||||
let items: Array<Node | NodeSchema>;
|
||||
checkNesting(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | Node | IPublicTypeDragNodeDataObject): boolean {
|
||||
let items: Array<Node | IPublicTypeNodeSchema>;
|
||||
if (isDragNodeDataObject(dragObject)) {
|
||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||
} else if (isDragNodeObject(dragObject)) {
|
||||
@ -525,8 +547,8 @@ export class DocumentModel {
|
||||
* Will be deleted in version 2.0.0.
|
||||
* Use checkNesting method instead.
|
||||
*/
|
||||
checkDropTarget(dropTarget: ParentalNode, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
let items: Array<Node | NodeSchema>;
|
||||
checkDropTarget(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject): boolean {
|
||||
let items: Array<Node | IPublicTypeNodeSchema>;
|
||||
if (isDragNodeDataObject(dragObject)) {
|
||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||
} else {
|
||||
@ -538,7 +560,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 检查对象对父级的要求,涉及配置 parentWhitelist
|
||||
*/
|
||||
checkNestingUp(parent: ParentalNode, obj: NodeSchema | Node): boolean {
|
||||
checkNestingUp(parent: INode, obj: IPublicTypeNodeSchema | Node): boolean {
|
||||
if (isNode(obj) || isNodeSchema(obj)) {
|
||||
const config = isNode(obj) ? obj.componentMeta : this.getComponentMeta(obj.componentName);
|
||||
if (config) {
|
||||
@ -552,7 +574,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 检查投放位置对子级的要求,涉及配置 childWhitelist
|
||||
*/
|
||||
checkNestingDown(parent: ParentalNode, obj: NodeSchema | Node): boolean {
|
||||
checkNestingDown(parent: INode, obj: IPublicTypeNodeSchema | Node): boolean {
|
||||
const config = parent.componentMeta;
|
||||
return config.checkNestingDown(parent, obj);
|
||||
}
|
||||
@ -564,7 +586,7 @@ export class DocumentModel {
|
||||
|
||||
// add toData
|
||||
toData(extraComps?: string[]) {
|
||||
const node = this.export(TransformStage.Save);
|
||||
const node = this.export(IPublicEnumTransformStage.Save);
|
||||
const data = {
|
||||
componentsMap: this.getComponentsMap(extraComps),
|
||||
utils: this.getUtilsMap(),
|
||||
@ -653,7 +675,7 @@ export class DocumentModel {
|
||||
}
|
||||
|
||||
getComponentsMap(extraComps?: string[]) {
|
||||
const componentsMap: ComponentsMap = [];
|
||||
const componentsMap: IPublicTypeComponentsMap = [];
|
||||
// 组件去重
|
||||
const exsitingMap: { [componentName: string]: boolean } = {};
|
||||
for (const node of this._nodesMap.values()) {
|
||||
@ -735,7 +757,7 @@ export class DocumentModel {
|
||||
}
|
||||
|
||||
onReady(fn: Function) {
|
||||
this.designer.editor.on('document-open', fn);
|
||||
this.designer.editor.eventBus.on('document-open', fn);
|
||||
return () => {
|
||||
this.designer.editor.removeListener('document-open', fn);
|
||||
};
|
||||
@ -750,6 +772,6 @@ export function isDocumentModel(obj: any): obj is DocumentModel {
|
||||
return obj && obj.rootNode;
|
||||
}
|
||||
|
||||
export function isPageSchema(obj: any): obj is PageSchema {
|
||||
export function isPageSchema(obj: any): obj is IPublicTypePageSchema {
|
||||
return obj?.componentName === 'Page';
|
||||
}
|
||||
|
||||
@ -1,20 +1,23 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { reaction, untracked, globalContext, Editor } from '@alilc/lowcode-editor-core';
|
||||
import { NodeSchema } from '@alilc/lowcode-types';
|
||||
import { reaction, untracked, globalContext, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { IPublicTypeNodeSchema, IPublicModelHistory } from '@alilc/lowcode-types';
|
||||
|
||||
export interface Serialization<K = NodeSchema, T = string> {
|
||||
export interface Serialization<K = IPublicTypeNodeSchema, T = string> {
|
||||
serialize(data: K): T;
|
||||
unserialize(data: T): K;
|
||||
}
|
||||
|
||||
export class History<T = NodeSchema> {
|
||||
export interface IHistory extends IPublicModelHistory {
|
||||
|
||||
}
|
||||
|
||||
export class History<T = IPublicTypeNodeSchema> implements IHistory {
|
||||
private session: Session;
|
||||
|
||||
private records: Session[];
|
||||
|
||||
private point = 0;
|
||||
|
||||
private emitter = new EventEmitter();
|
||||
private emitter: IEventBus = createModuleEventBus('History');
|
||||
|
||||
private asleep = false;
|
||||
|
||||
@ -118,11 +121,12 @@ export class History<T = NodeSchema> {
|
||||
}
|
||||
const cursor = this.session.cursor - 1;
|
||||
this.go(cursor);
|
||||
const editor = globalContext.get(Editor);
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
editor.emit('history.back', cursor);
|
||||
editor.eventBus.emit('history.back', cursor);
|
||||
}
|
||||
|
||||
forward() {
|
||||
@ -131,11 +135,12 @@ export class History<T = NodeSchema> {
|
||||
}
|
||||
const cursor = this.session.cursor + 1;
|
||||
this.go(cursor);
|
||||
const editor = globalContext.get(Editor);
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
editor.emit('history.forward', cursor);
|
||||
editor.eventBus.emit('history.forward', cursor);
|
||||
}
|
||||
|
||||
savePoint() {
|
||||
@ -169,6 +174,14 @@ export class History<T = NodeSchema> {
|
||||
}
|
||||
return state;
|
||||
}
|
||||
/**
|
||||
* 监听 state 变更事件
|
||||
* @param func
|
||||
* @returns
|
||||
*/
|
||||
onChangeState(func: () => any): () => void {
|
||||
return this.onStateChange(func);
|
||||
}
|
||||
|
||||
onStateChange(func: () => any) {
|
||||
this.emitter.on('statechange', func);
|
||||
@ -177,6 +190,14 @@ export class History<T = NodeSchema> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听历史记录游标位置变更事件
|
||||
* @param func
|
||||
* @returns
|
||||
*/
|
||||
onChangeCursor(func: () => any): () => void {
|
||||
return this.onCursor(func);
|
||||
}
|
||||
onCursor(func: () => any) {
|
||||
this.emitter.on('cursor', func);
|
||||
return () => {
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { uniqueId } from '@alilc/lowcode-utils';
|
||||
import { TitleContent } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeTitleContent, IPublicModelExclusiveGroup } from '@alilc/lowcode-types';
|
||||
import { Node } from './node';
|
||||
import { intl } from '../../locale';
|
||||
|
||||
// modals assoc x-hide value, initial: check is Modal, yes will put it in modals, cross levels
|
||||
// if-else-if assoc conditionGroup value, should be the same level, and siblings, need renderEngine support
|
||||
export class ExclusiveGroup {
|
||||
// if-else-if assoc conditionGroup value, should be the same level,
|
||||
// and siblings, need renderEngine support
|
||||
export class ExclusiveGroup implements IPublicModelExclusiveGroup {
|
||||
readonly isExclusiveGroup = true;
|
||||
|
||||
readonly id = uniqueId('exclusive');
|
||||
@ -72,9 +73,9 @@ export class ExclusiveGroup {
|
||||
return i === this.visibleIndex;
|
||||
}
|
||||
|
||||
readonly title: TitleContent;
|
||||
readonly title: IPublicTypeTitleContent;
|
||||
|
||||
constructor(readonly name: string, title?: TitleContent) {
|
||||
constructor(readonly name: string, title?: IPublicTypeTitleContent) {
|
||||
makeObservable(this);
|
||||
this.title = title || {
|
||||
type: 'i18n',
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { Node } from './node';
|
||||
import { DocumentModel } from '../document-model';
|
||||
import { IPublicModelModalNodesManager } from '@alilc/lowcode-types';
|
||||
import { createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
||||
|
||||
export function getModalNodes(node: Node) {
|
||||
if (!node) return [];
|
||||
@ -17,7 +18,11 @@ export function getModalNodes(node: Node) {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export class ModalNodesManager {
|
||||
export interface IModalNodesManager extends IPublicModelModalNodesManager {
|
||||
|
||||
}
|
||||
|
||||
export class ModalNodesManager implements IModalNodesManager {
|
||||
public willDestroy: any;
|
||||
|
||||
private page: DocumentModel;
|
||||
@ -26,11 +31,11 @@ export class ModalNodesManager {
|
||||
|
||||
private nodeRemoveEvents: any;
|
||||
|
||||
private emitter: EventEmitter;
|
||||
private emitter: IEventBus;
|
||||
|
||||
constructor(page: DocumentModel) {
|
||||
this.page = page;
|
||||
this.emitter = new EventEmitter();
|
||||
this.emitter = createModuleEventBus('ModalNodesManager');
|
||||
this.nodeRemoveEvents = {};
|
||||
this.setNodes();
|
||||
this.hideModalNodes();
|
||||
|
||||
@ -1,21 +1,24 @@
|
||||
import { obx, computed, globalContext, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { Node, ParentalNode } from './node';
|
||||
import { TransformStage } from './transform-stage';
|
||||
import { NodeData } from '@alilc/lowcode-types';
|
||||
import { obx, computed, globalContext, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { Node, INode } from './node';
|
||||
import { IPublicTypeNodeData, IPublicModelNodeChildren, IPublicEnumTransformStage } from '@alilc/lowcode-types';
|
||||
import { shallowEqual, compatStage, isNodeSchema } from '@alilc/lowcode-utils';
|
||||
import { EventEmitter } from 'events';
|
||||
import { foreachReverse } from '../../utils/tree';
|
||||
import { NodeRemoveOptions } from '../../types';
|
||||
|
||||
export interface IOnChangeOptions {
|
||||
type: string;
|
||||
node: Node;
|
||||
}
|
||||
export class NodeChildren {
|
||||
@obx.shallow private children: Node[];
|
||||
|
||||
private emitter = new EventEmitter();
|
||||
export interface INodeChildren extends IPublicModelNodeChildren {
|
||||
|
||||
constructor(readonly owner: ParentalNode, data: NodeData | NodeData[], options: any = {}) {
|
||||
}
|
||||
export class NodeChildren implements INodeChildren {
|
||||
@obx.shallow private children: INode[];
|
||||
|
||||
private emitter: IEventBus = createModuleEventBus('NodeChildren');
|
||||
|
||||
constructor(readonly owner: INode, data: IPublicTypeNodeData | IPublicTypeNodeData[], options: any = {}) {
|
||||
makeObservable(this);
|
||||
this.children = (Array.isArray(data) ? data : [data]).map((child) => {
|
||||
return this.owner.document.createNode(child, options.checkId);
|
||||
@ -29,19 +32,19 @@ export class NodeChildren {
|
||||
/**
|
||||
* 导出 schema
|
||||
*/
|
||||
export(stage: TransformStage = TransformStage.Save): NodeData[] {
|
||||
export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save): IPublicTypeNodeData[] {
|
||||
stage = compatStage(stage);
|
||||
return this.children.map((node) => {
|
||||
const data = node.export(stage);
|
||||
if (node.isLeaf() && TransformStage.Save === stage) {
|
||||
if (node.isLeaf() && IPublicEnumTransformStage.Save === stage) {
|
||||
// FIXME: filter empty
|
||||
return data.children as NodeData;
|
||||
return data.children as IPublicTypeNodeData;
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
import(data?: NodeData | NodeData[], checkId = false) {
|
||||
import(data?: IPublicTypeNodeData | IPublicTypeNodeData[], checkId = false) {
|
||||
data = data ? (Array.isArray(data) ? data : [data]) : [];
|
||||
|
||||
const originChildren = this.children.slice();
|
||||
@ -73,7 +76,7 @@ export class NodeChildren {
|
||||
* @deprecated
|
||||
* @param nodes
|
||||
*/
|
||||
concat(nodes: Node[]) {
|
||||
concat(nodes: INode[]) {
|
||||
return this.children.concat(nodes);
|
||||
}
|
||||
|
||||
@ -114,8 +117,8 @@ export class NodeChildren {
|
||||
});
|
||||
}
|
||||
|
||||
unlinkChild(node: Node) {
|
||||
const i = this.children.indexOf(node);
|
||||
unlinkChild(node: INode) {
|
||||
const i = this.children.map(d => d.id).indexOf(node.id);
|
||||
if (i < 0) {
|
||||
return false;
|
||||
}
|
||||
@ -129,7 +132,7 @@ export class NodeChildren {
|
||||
/**
|
||||
* 删除一个节点
|
||||
*/
|
||||
delete(node: Node, purge = false, useMutator = true, options: NodeRemoveOptions = {}): boolean {
|
||||
delete(node: INode, purge = false, useMutator = true, options: NodeRemoveOptions = {}): boolean {
|
||||
node.internalPurgeStart();
|
||||
if (node.isParental()) {
|
||||
foreachReverse(
|
||||
@ -147,8 +150,8 @@ export class NodeChildren {
|
||||
(iterable, idx) => (iterable as [])[idx],
|
||||
);
|
||||
}
|
||||
// 需要在从 children 中删除 node 前记录下 index,internalSetParent 中会执行删除(unlink)操作
|
||||
const i = this.children.indexOf(node);
|
||||
// 需要在从 children 中删除 node 前记录下 index,internalSetParent 中会执行删除 (unlink) 操作
|
||||
const i = this.children.map(d => d.id).indexOf(node.id);
|
||||
if (purge) {
|
||||
// should set parent null
|
||||
node.internalSetParent(null, useMutator);
|
||||
@ -161,7 +164,9 @@ export class NodeChildren {
|
||||
const { document } = node;
|
||||
/* istanbul ignore next */
|
||||
if (globalContext.has('editor')) {
|
||||
globalContext.get('editor').emit('node.remove', { node, index: i });
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
editor.eventBus.emit('node.remove', { node, index: i });
|
||||
}
|
||||
document.unlinkNode(node);
|
||||
document.selection.remove(node.id);
|
||||
@ -189,19 +194,21 @@ export class NodeChildren {
|
||||
/**
|
||||
* 插入一个节点,返回新长度
|
||||
*/
|
||||
insert(node: Node, at?: number | null, useMutator = true): void {
|
||||
insert(node: INode, at?: number | null, useMutator = true): void {
|
||||
const { children } = this;
|
||||
let index = at == null || at === -1 ? children.length : at;
|
||||
|
||||
const i = children.indexOf(node);
|
||||
const i = children.map(d => d.id).indexOf(node.id);
|
||||
|
||||
if (node.parent) {
|
||||
/* istanbul ignore next */
|
||||
globalContext.has('editor') &&
|
||||
globalContext.get('editor').emit('node.remove.topLevel', {
|
||||
if (globalContext.has('editor')) {
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
editor.eventBus.emit('node.remove.topLevel', {
|
||||
node,
|
||||
index: node.index,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
@ -231,7 +238,9 @@ export class NodeChildren {
|
||||
this.emitter.emit('insert', node);
|
||||
/* istanbul ignore next */
|
||||
if (globalContext.has('editor')) {
|
||||
globalContext.get('editor').emit('node.add', { node });
|
||||
const workspace = globalContext.get('workspace');
|
||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
||||
editor.eventBus.emit('node.add', { node });
|
||||
}
|
||||
if (useMutator) {
|
||||
this.reportModified(node, this.owner, { type: 'insert' });
|
||||
@ -263,14 +272,14 @@ export class NodeChildren {
|
||||
/**
|
||||
* 取得节点索引编号
|
||||
*/
|
||||
indexOf(node: Node): number {
|
||||
return this.children.indexOf(node);
|
||||
indexOf(node: INode): number {
|
||||
return this.children.map(d => d.id).indexOf(node.id);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
splice(start: number, deleteCount: number, node?: Node): Node[] {
|
||||
splice(start: number, deleteCount: number, node?: INode): INode[] {
|
||||
if (node) {
|
||||
return this.children.splice(start, deleteCount, node);
|
||||
}
|
||||
@ -280,21 +289,21 @@ export class NodeChildren {
|
||||
/**
|
||||
* 根据索引获得节点
|
||||
*/
|
||||
get(index: number): Node | null {
|
||||
get(index: number): INode | null {
|
||||
return this.children.length > index ? this.children[index] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在节点
|
||||
*/
|
||||
has(node: Node) {
|
||||
has(node: INode) {
|
||||
return this.indexOf(node) > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代器
|
||||
*/
|
||||
[Symbol.iterator](): { next(): { value: Node } } {
|
||||
[Symbol.iterator](): { next(): { value: INode } } {
|
||||
let index = 0;
|
||||
const { children } = this;
|
||||
const length = children.length || 0;
|
||||
@ -317,7 +326,7 @@ export class NodeChildren {
|
||||
/**
|
||||
* 遍历
|
||||
*/
|
||||
forEach(fn: (item: Node, index: number) => void): void {
|
||||
forEach(fn: (item: INode, index: number) => void): void {
|
||||
this.children.forEach((child, index) => {
|
||||
return fn(child, index);
|
||||
});
|
||||
@ -326,43 +335,43 @@ export class NodeChildren {
|
||||
/**
|
||||
* 遍历
|
||||
*/
|
||||
map<T>(fn: (item: Node, index: number) => T): T[] | null {
|
||||
map<T>(fn: (item: INode, index: number) => T): T[] | null {
|
||||
return this.children.map((child, index) => {
|
||||
return fn(child, index);
|
||||
});
|
||||
}
|
||||
|
||||
every(fn: (item: Node, index: number) => any): boolean {
|
||||
every(fn: (item: INode, index: number) => any): boolean {
|
||||
return this.children.every((child, index) => fn(child, index));
|
||||
}
|
||||
|
||||
some(fn: (item: Node, index: number) => any): boolean {
|
||||
some(fn: (item: INode, index: number) => any): boolean {
|
||||
return this.children.some((child, index) => fn(child, index));
|
||||
}
|
||||
|
||||
filter(fn: (item: Node, index: number) => any) {
|
||||
filter(fn: (item: INode, index: number) => any) {
|
||||
return this.children.filter(fn);
|
||||
}
|
||||
|
||||
find(fn: (item: Node, index: number) => boolean) {
|
||||
find(fn: (item: INode, index: number) => boolean) {
|
||||
return this.children.find(fn);
|
||||
}
|
||||
|
||||
reduce(fn: (acc: any, cur: Node) => any, initialValue: any): void {
|
||||
reduce(fn: (acc: any, cur: INode) => any, initialValue: any): void {
|
||||
return this.children.reduce(fn, initialValue);
|
||||
}
|
||||
|
||||
mergeChildren(
|
||||
remover: (node: Node, idx: number) => boolean,
|
||||
adder: (children: Node[]) => NodeData[] | null,
|
||||
sorter: (firstNode: Node, secondNode: Node) => number,
|
||||
remover: (node: INode, idx: number) => boolean,
|
||||
adder: (children: INode[]) => IPublicTypeNodeData[] | null,
|
||||
sorter: (firstNode: INode, secondNode: INode) => number,
|
||||
): any {
|
||||
let changed = false;
|
||||
if (remover) {
|
||||
const willRemove = this.children.filter(remover);
|
||||
if (willRemove.length > 0) {
|
||||
willRemove.forEach((node) => {
|
||||
const i = this.children.indexOf(node);
|
||||
const i = this.children.map(d => d.id).indexOf(node.id);
|
||||
if (i > -1) {
|
||||
this.children.splice(i, 1);
|
||||
node.remove(false);
|
||||
@ -374,7 +383,7 @@ export class NodeChildren {
|
||||
if (adder) {
|
||||
const items = adder(this.children);
|
||||
if (items && items.length > 0) {
|
||||
items.forEach((child: NodeData) => {
|
||||
items.forEach((child: IPublicTypeNodeData) => {
|
||||
const node = this.owner.document.createNode(child);
|
||||
this.children.push(node);
|
||||
node.internalSetParent(this.owner);
|
||||
@ -398,7 +407,7 @@ export class NodeChildren {
|
||||
};
|
||||
}
|
||||
|
||||
onInsert(fn: (node: Node) => void) {
|
||||
onInsert(fn: (node: INode) => void) {
|
||||
this.emitter.on('insert', fn);
|
||||
return () => {
|
||||
this.emitter.removeListener('insert', fn);
|
||||
@ -410,7 +419,7 @@ export class NodeChildren {
|
||||
return 'Array';
|
||||
}
|
||||
|
||||
private reportModified(node: Node, owner: Node, options = {}) {
|
||||
private reportModified(node: INode, owner: INode, options = {}) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,20 +1,21 @@
|
||||
import { ReactElement } from 'react';
|
||||
import { EventEmitter } from 'events';
|
||||
import { obx, computed, autorun, makeObservable, runInAction, wrapWithEventSwitch, action } from '@alilc/lowcode-editor-core';
|
||||
import { obx, computed, autorun, makeObservable, runInAction, wrapWithEventSwitch, action, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
NodeSchema,
|
||||
PropsMap,
|
||||
PropsList,
|
||||
NodeData,
|
||||
I18nData,
|
||||
IPublicTypeNodeSchema,
|
||||
IPublicTypePropsMap,
|
||||
IPublicTypePropsList,
|
||||
IPublicTypeNodeData,
|
||||
IPublicTypeI18nData,
|
||||
SlotSchema,
|
||||
PageSchema,
|
||||
ComponentSchema,
|
||||
IPublicTypePageSchema,
|
||||
IPublicTypeComponentSchema,
|
||||
NodeStatus,
|
||||
CompositeValue,
|
||||
IPublicTypeCompositeValue,
|
||||
GlobalEvent,
|
||||
ComponentAction,
|
||||
IPublicTypeComponentAction,
|
||||
IPublicModelNode,
|
||||
IPublicModelExclusiveGroup,
|
||||
IPublicEnumTransformStage,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { compatStage, isDOMText, isJSExpression } from '@alilc/lowcode-utils';
|
||||
import { SettingTopEntry } from '@alilc/lowcode-designer';
|
||||
@ -24,11 +25,15 @@ import { NodeChildren } from './node-children';
|
||||
import { Prop } from './props/prop';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group';
|
||||
import { TransformStage } from './transform-stage';
|
||||
import { includeSlot, removeSlot } from '../../utils/slot';
|
||||
import { foreachReverse } from '../../utils/tree';
|
||||
import { NodeRemoveOptions } from '../../types';
|
||||
|
||||
|
||||
export interface INode extends IPublicModelNode {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础节点
|
||||
*
|
||||
@ -77,8 +82,8 @@ import { NodeRemoveOptions } from '../../types';
|
||||
* isLocked
|
||||
* hidden
|
||||
*/
|
||||
export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
private emitter: EventEmitter;
|
||||
export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> implements INode {
|
||||
private emitter: IEventBus;
|
||||
|
||||
/**
|
||||
* 是节点实例
|
||||
@ -114,12 +119,12 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
*/
|
||||
private _addons: { [key: string]: { exportData: () => any; isProp: boolean } } = {};
|
||||
|
||||
@obx.ref private _parent: ParentalNode | null = null;
|
||||
@obx.ref private _parent: INode | null = null;
|
||||
|
||||
/**
|
||||
* 父级节点
|
||||
*/
|
||||
get parent(): ParentalNode | null {
|
||||
get parent(): INode | null {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
@ -140,7 +145,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@computed get title(): string | I18nData | ReactElement {
|
||||
@computed get title(): string | IPublicTypeI18nData | ReactElement {
|
||||
let t = this.getExtraProp('title');
|
||||
// TODO: 暂时走不到这个分支
|
||||
// if (!t && this.componentMeta.descriptor) {
|
||||
@ -172,7 +177,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
});
|
||||
} else {
|
||||
this.props = new Props(this, props, extras);
|
||||
this._children = new NodeChildren(this as ParentalNode, this.initialChildren(children));
|
||||
this._children = new NodeChildren(this as INode, this.initialChildren(children));
|
||||
this._children.internalInitParent();
|
||||
this.props.merge(
|
||||
this.upgradeProps(this.initProps(props || {})),
|
||||
@ -184,7 +189,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
this.initBuiltinProps();
|
||||
|
||||
this.isInited = true;
|
||||
this.emitter = new EventEmitter();
|
||||
this.emitter = createModuleEventBus('Node');
|
||||
}
|
||||
|
||||
_settingEntry: SettingTopEntry;
|
||||
@ -210,12 +215,12 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
|
||||
@action
|
||||
private initProps(props: any): any {
|
||||
return this.document.designer.transformProps(props, this, TransformStage.Init);
|
||||
return this.document.designer.transformProps(props, this, IPublicEnumTransformStage.Init);
|
||||
}
|
||||
|
||||
@action
|
||||
private upgradeProps(props: any): any {
|
||||
return this.document.designer.transformProps(props, this, TransformStage.Upgrade);
|
||||
return this.document.designer.transformProps(props, this, IPublicEnumTransformStage.Upgrade);
|
||||
}
|
||||
|
||||
private autoruns?: Array<() => void>;
|
||||
@ -232,7 +237,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
});
|
||||
}
|
||||
|
||||
private initialChildren(children: any): NodeData[] {
|
||||
private initialChildren(children: any): IPublicTypeNodeData[] {
|
||||
// FIXME! this is dirty code
|
||||
if (children == null) {
|
||||
const initialChildren = this.componentMeta.getMetadata().configure.advanced?.initialChildren;
|
||||
@ -283,7 +288,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
/**
|
||||
* 是否一个父亲类节点
|
||||
*/
|
||||
isParental(): this is ParentalNode {
|
||||
isParental(): boolean {
|
||||
return !this.isLeaf();
|
||||
}
|
||||
|
||||
@ -325,7 +330,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
* 内部方法,请勿使用
|
||||
* @param useMutator 是否触发联动逻辑
|
||||
*/
|
||||
internalSetParent(parent: ParentalNode | null, useMutator = false) {
|
||||
internalSetParent(parent: INode | null, useMutator = false) {
|
||||
if (this._parent === parent) {
|
||||
return;
|
||||
}
|
||||
@ -387,7 +392,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
) {
|
||||
if (this.parent) {
|
||||
if (!options.suppressRemoveEvent) {
|
||||
this.document.designer.editor?.emit('node.remove.topLevel', {
|
||||
this.document.designer.editor?.eventBus.emit('node.remove.topLevel', {
|
||||
node: this,
|
||||
index: this.parent?.children?.indexOf(this),
|
||||
});
|
||||
@ -440,11 +445,11 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
return this.document.getComponentMeta(this.componentName);
|
||||
}
|
||||
|
||||
@computed get propsData(): PropsMap | PropsList | null {
|
||||
@computed get propsData(): IPublicTypePropsMap | IPublicTypePropsList | null {
|
||||
if (!this.isParental() || this.componentName === 'Fragment') {
|
||||
return null;
|
||||
}
|
||||
return this.props.export(TransformStage.Serilize).props || null;
|
||||
return this.props.export(IPublicEnumTransformStage.Serilize).props || null;
|
||||
}
|
||||
|
||||
@obx.shallow _slots: Node[] = [];
|
||||
@ -458,15 +463,15 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
@obx.ref private _conditionGroup: ExclusiveGroup | null = null;
|
||||
@obx.ref private _conditionGroup: IPublicModelExclusiveGroup | null = null;
|
||||
|
||||
/* istanbul ignore next */
|
||||
get conditionGroup(): ExclusiveGroup | null {
|
||||
get conditionGroup(): IPublicModelExclusiveGroup | null {
|
||||
return this._conditionGroup;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
setConditionGroup(grp: ExclusiveGroup | string | null) {
|
||||
setConditionGroup(grp: IPublicModelExclusiveGroup | string | null) {
|
||||
if (!grp) {
|
||||
this.getExtraProp('conditionGroup', false)?.remove();
|
||||
if (this._conditionGroup) {
|
||||
@ -589,7 +594,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
return this.props.get(getConvertedExtraKey(key), createIfNone) || null;
|
||||
}
|
||||
|
||||
setExtraProp(key: string, value: CompositeValue) {
|
||||
setExtraProp(key: string, value: IPublicTypeCompositeValue) {
|
||||
this.getProp(getConvertedExtraKey(key), true)?.setValue(value);
|
||||
}
|
||||
|
||||
@ -617,14 +622,14 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
/**
|
||||
* 设置多个属性值,和原有值合并
|
||||
*/
|
||||
mergeProps(props: PropsMap) {
|
||||
mergeProps(props: IPublicTypePropsMap) {
|
||||
this.props.merge(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置多个属性值,替换原有值
|
||||
*/
|
||||
setProps(props?: PropsMap | PropsList | Props | null) {
|
||||
setProps(props?: IPublicTypePropsMap | IPublicTypePropsList | Props | null) {
|
||||
if (props instanceof Props) {
|
||||
this.props = props;
|
||||
return;
|
||||
@ -674,7 +679,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
* 获取符合搭建协议-节点 schema 结构
|
||||
*/
|
||||
get schema(): Schema {
|
||||
return this.export(TransformStage.Save);
|
||||
return this.export(IPublicEnumTransformStage.Save);
|
||||
}
|
||||
|
||||
set schema(data: Schema) {
|
||||
@ -709,16 +714,16 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
/**
|
||||
* 导出 schema
|
||||
*/
|
||||
export(stage: TransformStage = TransformStage.Save, options: any = {}): Schema {
|
||||
export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, options: any = {}): Schema {
|
||||
stage = compatStage(stage);
|
||||
const baseSchema: any = {
|
||||
componentName: this.componentName,
|
||||
};
|
||||
|
||||
if (stage !== TransformStage.Clone) {
|
||||
if (stage !== IPublicEnumTransformStage.Clone) {
|
||||
baseSchema.id = this.id;
|
||||
}
|
||||
if (stage === TransformStage.Render) {
|
||||
if (stage === IPublicEnumTransformStage.Render) {
|
||||
baseSchema.docId = this.document.id;
|
||||
}
|
||||
|
||||
@ -817,7 +822,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
if (includeSlot(this, slotName)) {
|
||||
removeSlot(this, slotName);
|
||||
}
|
||||
slotNode.internalSetParent(this as ParentalNode, true);
|
||||
slotNode.internalSetParent(this as INode, true);
|
||||
this._slots.push(slotNode);
|
||||
}
|
||||
|
||||
@ -880,13 +885,13 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
*/
|
||||
canPerformAction(actionName: string): boolean {
|
||||
const availableActions =
|
||||
this.componentMeta?.availableActions?.filter((action: ComponentAction) => {
|
||||
this.componentMeta?.availableActions?.filter((action: IPublicTypeComponentAction) => {
|
||||
const { condition } = action;
|
||||
return typeof condition === 'function' ?
|
||||
condition(this) !== false :
|
||||
condition !== false;
|
||||
})
|
||||
.map((action: ComponentAction) => action.name) || [];
|
||||
.map((action: IPublicTypeComponentAction) => action.name) || [];
|
||||
|
||||
return availableActions.indexOf(actionName) >= 0;
|
||||
}
|
||||
@ -949,7 +954,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
|
||||
mergeChildren(
|
||||
remover: () => any,
|
||||
adder: (children: Node[]) => NodeData[] | null,
|
||||
adder: (children: Node[]) => IPublicTypeNodeData[] | null,
|
||||
sorter: () => any,
|
||||
) {
|
||||
this.children?.mergeChildren(remover, adder, sorter);
|
||||
@ -1018,7 +1023,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* TODO: replace non standard metas with standard ones.
|
||||
*/
|
||||
getSuitablePlace(node: Node, ref: any): any {
|
||||
const focusNode = this.document?.focusNode;
|
||||
@ -1137,11 +1142,11 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
emitPropChange(val: PropChangeOptions) {
|
||||
emitPropChange(val: IPublicTypePropChangeOptions) {
|
||||
this.emitter?.emit('propChange', val);
|
||||
}
|
||||
|
||||
onPropChange(func: (info: PropChangeOptions) => void): Function {
|
||||
onPropChange(func: (info: IPublicTypePropChangeOptions) => void): Function {
|
||||
const wrappedFunc = wrapWithEventSwitch(func);
|
||||
this.emitter.on('propChange', wrappedFunc);
|
||||
return () => {
|
||||
@ -1164,20 +1169,21 @@ function ensureNode(node: any, document: DocumentModel): Node {
|
||||
return nodeInstance;
|
||||
}
|
||||
|
||||
export interface ParentalNode<T extends NodeSchema = NodeSchema> extends Node<T> {
|
||||
readonly children: NodeChildren;
|
||||
}
|
||||
|
||||
export interface LeafNode extends Node {
|
||||
readonly children: null;
|
||||
}
|
||||
|
||||
export type PropChangeOptions = Omit<GlobalEvent.Node.Prop.ChangeOptions, 'node'>;
|
||||
export type IPublicTypePropChangeOptions = Omit<GlobalEvent.Node.Prop.ChangeOptions, 'node'>;
|
||||
|
||||
export type SlotNode = ParentalNode<SlotSchema>;
|
||||
export type PageNode = ParentalNode<PageSchema>;
|
||||
export type ComponentNode = ParentalNode<ComponentSchema>;
|
||||
export type SlotNode = Node<SlotSchema>;
|
||||
export type PageNode = Node<IPublicTypePageSchema>;
|
||||
export type ComponentNode = Node<IPublicTypeComponentSchema>;
|
||||
export type RootNode = PageNode | ComponentNode;
|
||||
|
||||
/**
|
||||
* @deprecated use same function from '@alilc/lowcode-utils' instead
|
||||
*/
|
||||
export function isNode(node: any): node is Node {
|
||||
return node && node.isNode;
|
||||
}
|
||||
@ -1266,14 +1272,14 @@ export function comparePosition(node1: Node, node2: Node): PositionNO {
|
||||
}
|
||||
|
||||
export function insertChild(
|
||||
container: ParentalNode,
|
||||
thing: Node | NodeData,
|
||||
container: INode,
|
||||
thing: Node | IPublicTypeNodeData,
|
||||
at?: number | null,
|
||||
copy?: boolean,
|
||||
): Node {
|
||||
let node: Node;
|
||||
if (isNode(thing) && (copy || thing.isSlot())) {
|
||||
thing = thing.export(TransformStage.Clone);
|
||||
thing = thing.export(IPublicEnumTransformStage.Clone);
|
||||
}
|
||||
if (isNode(thing)) {
|
||||
node = thing;
|
||||
@ -1287,8 +1293,8 @@ export function insertChild(
|
||||
}
|
||||
|
||||
export function insertChildren(
|
||||
container: ParentalNode,
|
||||
nodes: Node[] | NodeData[],
|
||||
container: INode,
|
||||
nodes: Node[] | IPublicTypeNodeData[],
|
||||
at?: number | null,
|
||||
copy?: boolean,
|
||||
): Node[] {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { untracked, computed, obx, engineConfig, action, makeObservable, mobx, runInAction } from '@alilc/lowcode-editor-core';
|
||||
import { CompositeValue, GlobalEvent, JSSlot, SlotSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeCompositeValue, GlobalEvent, IPublicTypeJSSlot, SlotSchema, IPublicEnumTransformStage } from '@alilc/lowcode-types';
|
||||
import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot } from '@alilc/lowcode-utils';
|
||||
import { valueToSource } from './value-to-source';
|
||||
import { Props } from './props';
|
||||
import { SlotNode, Node } from '../node';
|
||||
import { TransformStage } from '../transform-stage';
|
||||
// import { TransformStage } from '../transform-stage';
|
||||
|
||||
const { set: mobxSet, isObservableArray } = mobx;
|
||||
export const UNSET = Symbol.for('unset');
|
||||
@ -41,7 +41,7 @@ export class Prop implements IPropParent {
|
||||
|
||||
constructor(
|
||||
public parent: IPropParent,
|
||||
value: CompositeValue | UNSET = UNSET,
|
||||
value: IPublicTypeCompositeValue | UNSET = UNSET,
|
||||
key?: string | number,
|
||||
spread = false,
|
||||
options = {},
|
||||
@ -104,14 +104,14 @@ export class Prop implements IPropParent {
|
||||
/**
|
||||
* 属性值
|
||||
*/
|
||||
@computed get value(): CompositeValue | UNSET {
|
||||
return this.export(TransformStage.Serilize);
|
||||
@computed get value(): IPublicTypeCompositeValue | UNSET {
|
||||
return this.export(IPublicEnumTransformStage.Serilize);
|
||||
}
|
||||
|
||||
export(stage: TransformStage = TransformStage.Save): CompositeValue {
|
||||
export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save): IPublicTypeCompositeValue {
|
||||
stage = compatStage(stage);
|
||||
const type = this._type;
|
||||
if (stage === TransformStage.Render && this.key === '___condition___') {
|
||||
if (stage === IPublicEnumTransformStage.Render && this.key === '___condition___') {
|
||||
// 在设计器里,所有组件默认需要展示,除非开启了 enableCondition 配置
|
||||
if (engineConfig?.get('enableCondition') !== true) {
|
||||
return true;
|
||||
@ -125,7 +125,7 @@ export class Prop implements IPropParent {
|
||||
|
||||
if (type === 'literal' || type === 'expression') {
|
||||
// TODO 后端改造之后删除此逻辑
|
||||
if (this._value === null && stage === TransformStage.Save) {
|
||||
if (this._value === null && stage === IPublicEnumTransformStage.Save) {
|
||||
return '';
|
||||
}
|
||||
return this._value;
|
||||
@ -133,7 +133,7 @@ export class Prop implements IPropParent {
|
||||
|
||||
if (type === 'slot') {
|
||||
const schema = this._slotNode?.export(stage) || {} as any;
|
||||
if (stage === TransformStage.Render) {
|
||||
if (stage === IPublicEnumTransformStage.Render) {
|
||||
return {
|
||||
type: 'JSSlot',
|
||||
params: schema.params,
|
||||
@ -191,7 +191,7 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
// todo: JSFunction ...
|
||||
if (this.type === 'slot') {
|
||||
return JSON.stringify(this._slotNode!.export(TransformStage.Save));
|
||||
return JSON.stringify(this._slotNode!.export(IPublicEnumTransformStage.Save));
|
||||
}
|
||||
return this._code != null ? this._code : JSON.stringify(this.value);
|
||||
}
|
||||
@ -237,7 +237,7 @@ export class Prop implements IPropParent {
|
||||
* set value, val should be JSON Object
|
||||
*/
|
||||
@action
|
||||
setValue(val: CompositeValue) {
|
||||
setValue(val: IPublicTypeCompositeValue) {
|
||||
if (val === this._value) return;
|
||||
const editor = this.owner.document?.designer.editor;
|
||||
const oldValue = this._value;
|
||||
@ -277,7 +277,7 @@ export class Prop implements IPropParent {
|
||||
newValue: this._value,
|
||||
};
|
||||
|
||||
editor?.emit(GlobalEvent.Node.Prop.InnerChange, {
|
||||
editor?.eventBus.emit(GlobalEvent.Node.Prop.InnerChange, {
|
||||
node: this.owner as any,
|
||||
...propsInfo,
|
||||
});
|
||||
@ -286,8 +286,8 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
}
|
||||
|
||||
getValue(): CompositeValue {
|
||||
return this.export(TransformStage.Serilize);
|
||||
getValue(): IPublicTypeCompositeValue {
|
||||
return this.export(IPublicEnumTransformStage.Serilize);
|
||||
}
|
||||
|
||||
@action
|
||||
@ -312,7 +312,7 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
|
||||
@action
|
||||
setAsSlot(data: JSSlot) {
|
||||
setAsSlot(data: IPublicTypeJSSlot) {
|
||||
this._type = 'slot';
|
||||
let slotSchema: SlotSchema;
|
||||
// 当 data.value 的结构为 { componentName: 'Slot' } 时,复用部分 slotSchema 数据
|
||||
@ -557,7 +557,7 @@ export class Prop implements IPropParent {
|
||||
* @param force 强制
|
||||
*/
|
||||
@action
|
||||
add(value: CompositeValue, force = false): Prop | null {
|
||||
add(value: IPublicTypeCompositeValue, force = false): Prop | null {
|
||||
const type = this._type;
|
||||
if (type !== 'list' && type !== 'unset' && !force) {
|
||||
return null;
|
||||
@ -577,7 +577,7 @@ export class Prop implements IPropParent {
|
||||
* @param force 强制
|
||||
*/
|
||||
@action
|
||||
set(key: string | number, value: CompositeValue | Prop, force = false) {
|
||||
set(key: string | number, value: IPublicTypeCompositeValue | Prop, force = false) {
|
||||
const type = this._type;
|
||||
if (type !== 'map' && type !== 'list' && type !== 'unset' && !force) {
|
||||
return null;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { computed, makeObservable, obx, action } from '@alilc/lowcode-editor-core';
|
||||
import { PropsMap, PropsList, CompositeValue } from '@alilc/lowcode-types';
|
||||
import { IPublicTypePropsMap, IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage } from '@alilc/lowcode-types';
|
||||
import { uniqueId, compatStage } from '@alilc/lowcode-utils';
|
||||
import { Prop, IPropParent, UNSET } from './prop';
|
||||
import { Node } from '../node';
|
||||
import { TransformStage } from '../transform-stage';
|
||||
// import { TransformStage } from '../transform-stage';
|
||||
|
||||
interface ExtrasObject {
|
||||
[key: string]: any;
|
||||
@ -57,7 +57,7 @@ export class Props implements IPropParent {
|
||||
|
||||
@obx type: 'map' | 'list' = 'map';
|
||||
|
||||
constructor(owner: Node, value?: PropsMap | PropsList | null, extras?: ExtrasObject) {
|
||||
constructor(owner: Node, value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject) {
|
||||
makeObservable(this);
|
||||
this.owner = owner;
|
||||
if (Array.isArray(value)) {
|
||||
@ -76,7 +76,7 @@ export class Props implements IPropParent {
|
||||
}
|
||||
|
||||
@action
|
||||
import(value?: PropsMap | PropsList | null, extras?: ExtrasObject) {
|
||||
import(value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject) {
|
||||
const originItems = this.items;
|
||||
if (Array.isArray(value)) {
|
||||
this.type = 'list';
|
||||
@ -99,7 +99,7 @@ export class Props implements IPropParent {
|
||||
}
|
||||
|
||||
@action
|
||||
merge(value: PropsMap, extras?: PropsMap) {
|
||||
merge(value: IPublicTypePropsMap, extras?: IPublicTypePropsMap) {
|
||||
Object.keys(value).forEach((key) => {
|
||||
this.query(key, true)!.setValue(value[key]);
|
||||
this.query(key, true)!.setupItems();
|
||||
@ -112,8 +112,8 @@ export class Props implements IPropParent {
|
||||
}
|
||||
}
|
||||
|
||||
export(stage: TransformStage = TransformStage.Save): {
|
||||
props?: PropsMap | PropsList;
|
||||
export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save): {
|
||||
props?: IPublicTypePropsMap | IPublicTypePropsList;
|
||||
extras?: ExtrasObject;
|
||||
} {
|
||||
stage = compatStage(stage);
|
||||
@ -256,7 +256,7 @@ export class Props implements IPropParent {
|
||||
*/
|
||||
@action
|
||||
add(
|
||||
value: CompositeValue | null,
|
||||
value: IPublicTypeCompositeValue | null,
|
||||
key?: string | number,
|
||||
spread = false,
|
||||
options: any = {},
|
||||
|
||||
@ -212,6 +212,8 @@ export function valueToSource(
|
||||
}
|
||||
case 'undefined':
|
||||
return `${indentString.repeat(indentLevel)}undefined`;
|
||||
default:
|
||||
return `${indentString.repeat(indentLevel)}undefined`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { obx, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { obx, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import { Node, comparePosition, PositionNO } from './node/node';
|
||||
import { DocumentModel } from './document-model';
|
||||
import { IPublicModelSelection } from '@alilc/lowcode-types';
|
||||
|
||||
export class Selection {
|
||||
private emitter = new EventEmitter();
|
||||
export interface ISelection extends IPublicModelSelection {
|
||||
|
||||
}
|
||||
|
||||
export class Selection implements ISelection {
|
||||
private emitter: IEventBus = createModuleEventBus('Selection');
|
||||
|
||||
@obx.shallow private _selected: string[] = [];
|
||||
|
||||
@ -129,7 +133,7 @@ export class Selection {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶层选区节点, 场景:拖拽时,建立蒙层,只蒙在最上层
|
||||
* 获取顶层选区节点,场景:拖拽时,建立蒙层,只蒙在最上层
|
||||
*/
|
||||
getTopNodes(includeRoot = false) {
|
||||
const nodes = [];
|
||||
|
||||
@ -7,4 +7,3 @@ export * from './clone';
|
||||
export * from './page';
|
||||
export * from './container';
|
||||
export * from './unlock';
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
/* eslint-disable no-multi-assign */
|
||||
import { EngineConfig, engineConfig } from '@alilc/lowcode-editor-core';
|
||||
import { ILowCodePluginManager } from '@alilc/lowcode-designer';
|
||||
import { engineConfig, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
IPublicApiHotkey,
|
||||
IPublicApiProject,
|
||||
@ -9,43 +8,45 @@ import {
|
||||
IPublicApiMaterial,
|
||||
IPublicApiEvent,
|
||||
IPublicApiCommon,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { getLogger, Logger } from '@alilc/lowcode-utils';
|
||||
import {
|
||||
ILowCodePluginContext,
|
||||
IPluginContextOptions,
|
||||
ILowCodePluginPreferenceDeclaration,
|
||||
PreferenceValueType,
|
||||
IPublicModelPluginContext,
|
||||
IPluginPreferenceMananger,
|
||||
IPublicTypePreferenceValueType,
|
||||
IPublicModelEngineConfig,
|
||||
IPublicApiLogger,
|
||||
IPublicApiPlugins,
|
||||
IPublicTypePluginDeclaration,
|
||||
IPublicApiCanvas,
|
||||
} from '@alilc/lowcode-types';
|
||||
import {
|
||||
IPluginContextOptions,
|
||||
ILowCodePluginContextApiAssembler,
|
||||
ILowCodePluginContextPrivate,
|
||||
} from './plugin-types';
|
||||
import { isValidPreferenceKey } from './plugin-utils';
|
||||
|
||||
|
||||
export default class PluginContext implements ILowCodePluginContext, ILowCodePluginContextPrivate {
|
||||
export default class PluginContext implements IPublicModelPluginContext, ILowCodePluginContextPrivate {
|
||||
hotkey: IPublicApiHotkey;
|
||||
project: IPublicApiProject;
|
||||
skeleton: IPublicApiSkeleton;
|
||||
setters: IPublicApiSetters;
|
||||
material: IPublicApiMaterial;
|
||||
event: IPublicApiEvent;
|
||||
config: EngineConfig;
|
||||
config: IPublicModelEngineConfig;
|
||||
common: IPublicApiCommon;
|
||||
logger: Logger;
|
||||
plugins: ILowCodePluginManager;
|
||||
logger: IPublicApiLogger;
|
||||
plugins: IPublicApiPlugins;
|
||||
preference: IPluginPreferenceMananger;
|
||||
pluginEvent: IPublicApiEvent;
|
||||
canvas: IPublicApiCanvas;
|
||||
|
||||
constructor(
|
||||
plugins: ILowCodePluginManager,
|
||||
options: IPluginContextOptions,
|
||||
contextApiAssembler: ILowCodePluginContextApiAssembler,
|
||||
) {
|
||||
contextApiAssembler.assembleApis(this);
|
||||
this.plugins = plugins;
|
||||
const { pluginName = 'anonymous' } = options;
|
||||
this.logger = getLogger({ level: 'warn', bizName: `designer:plugin:${pluginName}` });
|
||||
|
||||
const { pluginName = 'anonymous', meta = {} } = options;
|
||||
contextApiAssembler.assembleApis(this, pluginName, meta);
|
||||
this.pluginEvent = createModuleEventBus(pluginName, 200);
|
||||
const enhancePluginContextHook = engineConfig.get('enhancePluginContextHook');
|
||||
if (enhancePluginContextHook) {
|
||||
enhancePluginContextHook(this);
|
||||
@ -54,12 +55,12 @@ export default class PluginContext implements ILowCodePluginContext, ILowCodePlu
|
||||
|
||||
setPreference(
|
||||
pluginName: string,
|
||||
preferenceDeclaration: ILowCodePluginPreferenceDeclaration,
|
||||
preferenceDeclaration: IPublicTypePluginDeclaration,
|
||||
): void {
|
||||
const getPreferenceValue = (
|
||||
key: string,
|
||||
defaultValue?: PreferenceValueType,
|
||||
): PreferenceValueType | undefined => {
|
||||
defaultValue?: IPublicTypePreferenceValueType,
|
||||
): IPublicTypePreferenceValueType | undefined => {
|
||||
if (!isValidPreferenceKey(key, preferenceDeclaration)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -1,45 +1,53 @@
|
||||
import { engineConfig } from '@alilc/lowcode-editor-core';
|
||||
import { getLogger } from '@alilc/lowcode-utils';
|
||||
import {
|
||||
ILowCodePlugin,
|
||||
ILowCodePluginConfig,
|
||||
ILowCodePluginRuntime,
|
||||
ILowCodePluginManager,
|
||||
ILowCodePluginContext,
|
||||
ILowCodeRegisterOptions,
|
||||
IPluginContextOptions,
|
||||
PreferenceValueType,
|
||||
ILowCodePluginConfigMeta,
|
||||
PluginPreference,
|
||||
ILowCodePluginPreferenceDeclaration,
|
||||
isLowCodeRegisterOptions,
|
||||
ILowCodePluginContextApiAssembler,
|
||||
} from './plugin-types';
|
||||
import { filterValidOptions } from './plugin-utils';
|
||||
import { LowCodePlugin } from './plugin';
|
||||
import { filterValidOptions, isLowCodeRegisterOptions } from './plugin-utils';
|
||||
import { LowCodePluginRuntime } from './plugin';
|
||||
// eslint-disable-next-line import/no-named-as-default
|
||||
import LowCodePluginContext from './plugin-context';
|
||||
import { invariant } from '../utils';
|
||||
import sequencify from './sequencify';
|
||||
import semverSatisfies from 'semver/functions/satisfies';
|
||||
import {
|
||||
ILowCodeRegisterOptions,
|
||||
IPublicTypePreferenceValueType,
|
||||
IPublicTypePlugin,
|
||||
} from '@alilc/lowcode-types';
|
||||
|
||||
const logger = getLogger({ level: 'warn', bizName: 'designer:pluginManager' });
|
||||
|
||||
export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
private plugins: ILowCodePlugin[] = [];
|
||||
// 保留的事件前缀
|
||||
const RESERVED_EVENT_PREFIX = ['designer', 'editor', 'skeleton', 'renderer', 'render', 'utils', 'plugin', 'engine', 'editor-core', 'engine-core', 'plugins', 'event', 'events', 'log', 'logger', 'ctx', 'context'];
|
||||
|
||||
private pluginsMap: Map<string, ILowCodePlugin> = new Map();
|
||||
export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
private plugins: ILowCodePluginRuntime[] = [];
|
||||
|
||||
pluginsMap: Map<string, ILowCodePluginRuntime> = new Map();
|
||||
pluginContextMap: Map<string, LowCodePluginContext> = new Map();
|
||||
|
||||
private pluginPreference?: PluginPreference = new Map();
|
||||
|
||||
contextApiAssembler: ILowCodePluginContextApiAssembler;
|
||||
|
||||
constructor(contextApiAssembler: ILowCodePluginContextApiAssembler) {
|
||||
constructor(contextApiAssembler: ILowCodePluginContextApiAssembler, readonly viewName = 'global') {
|
||||
this.contextApiAssembler = contextApiAssembler;
|
||||
}
|
||||
|
||||
private _getLowCodePluginContext(options: IPluginContextOptions) {
|
||||
return new LowCodePluginContext(this, options, this.contextApiAssembler);
|
||||
}
|
||||
_getLowCodePluginContext = (options: IPluginContextOptions) => {
|
||||
const { pluginName } = options;
|
||||
let context = this.pluginContextMap.get(pluginName);
|
||||
if (!context) {
|
||||
context = new LowCodePluginContext(options, this.contextApiAssembler);
|
||||
this.pluginContextMap.set(pluginName, context);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
isEngineVersionMatched(versionExp: string): boolean {
|
||||
const engineVersion = engineConfig.get('ENGINE_VERSION');
|
||||
@ -55,7 +63,7 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
* @param registerOptions - the plugin register options
|
||||
*/
|
||||
async register(
|
||||
pluginConfigCreator: (ctx: ILowCodePluginContext, options: any) => ILowCodePluginConfig,
|
||||
pluginModel: IPublicTypePlugin,
|
||||
options?: any,
|
||||
registerOptions?: ILowCodeRegisterOptions,
|
||||
): Promise<void> {
|
||||
@ -64,11 +72,18 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
registerOptions = options;
|
||||
options = {};
|
||||
}
|
||||
let { pluginName, meta = {} } = pluginConfigCreator as any;
|
||||
const { preferenceDeclaration, engines } = meta as ILowCodePluginConfigMeta;
|
||||
const ctx = this._getLowCodePluginContext({ pluginName });
|
||||
let { pluginName, meta = {} } = pluginModel;
|
||||
const { preferenceDeclaration, engines } = meta;
|
||||
// filter invalid eventPrefix
|
||||
const { eventPrefix } = meta;
|
||||
const isReservedPrefix = RESERVED_EVENT_PREFIX.find((item) => item === eventPrefix);
|
||||
if (isReservedPrefix) {
|
||||
meta.eventPrefix = undefined;
|
||||
logger.warn(`plugin ${pluginName} is trying to use ${eventPrefix} as event prefix, which is a reserved event prefix, please use another one`);
|
||||
}
|
||||
const ctx = this._getLowCodePluginContext({ pluginName, meta });
|
||||
const customFilterValidOptions = engineConfig.get('customPluginFilterOptions', filterValidOptions);
|
||||
const config = pluginConfigCreator(ctx, customFilterValidOptions(options, preferenceDeclaration!));
|
||||
const config = pluginModel(ctx, customFilterValidOptions(options, preferenceDeclaration!));
|
||||
// compat the legacy way to declare pluginName
|
||||
// @ts-ignore
|
||||
pluginName = pluginName || config.name;
|
||||
@ -78,7 +93,7 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
config,
|
||||
);
|
||||
|
||||
ctx.setPreference(pluginName, (preferenceDeclaration as ILowCodePluginPreferenceDeclaration));
|
||||
ctx.setPreference(pluginName, preferenceDeclaration);
|
||||
|
||||
const allowOverride = registerOptions?.override === true;
|
||||
|
||||
@ -104,21 +119,22 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
throw new Error(`plugin ${pluginName} skipped, engine check failed, current engine version is ${engineConfig.get('ENGINE_VERSION')}, meta.engines.lowcodeEngine is ${engineVersionExp}`);
|
||||
}
|
||||
|
||||
const plugin = new LowCodePlugin(pluginName, this, config, meta);
|
||||
// support initialization of those plugins which registered after normal initialization by plugin-manager
|
||||
const plugin = new LowCodePluginRuntime(pluginName, this, config, meta);
|
||||
// support initialization of those plugins which registered
|
||||
// after normal initialization by plugin-manager
|
||||
if (registerOptions?.autoInit) {
|
||||
await plugin.init();
|
||||
}
|
||||
this.plugins.push(plugin);
|
||||
this.pluginsMap.set(pluginName, plugin);
|
||||
logger.log(`plugin registered with pluginName: ${pluginName}, config: ${config}, meta: ${meta}`);
|
||||
logger.log(`plugin registered with pluginName: ${pluginName}, config: `, config, 'meta:', meta);
|
||||
}
|
||||
|
||||
get(pluginName: string): ILowCodePlugin | undefined {
|
||||
get(pluginName: string): ILowCodePluginRuntime | undefined {
|
||||
return this.pluginsMap.get(pluginName);
|
||||
}
|
||||
|
||||
getAll(): ILowCodePlugin[] {
|
||||
getAll(): ILowCodePluginRuntime[] {
|
||||
return this.plugins;
|
||||
}
|
||||
|
||||
@ -138,7 +154,7 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
|
||||
async init(pluginPreference?: PluginPreference) {
|
||||
const pluginNames: string[] = [];
|
||||
const pluginObj: { [name: string]: ILowCodePlugin } = {};
|
||||
const pluginObj: { [name: string]: ILowCodePluginRuntime } = {};
|
||||
this.pluginPreference = pluginPreference;
|
||||
this.plugins.forEach((plugin) => {
|
||||
pluginNames.push(plugin.name);
|
||||
@ -170,7 +186,7 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
return this.pluginsMap.size;
|
||||
}
|
||||
|
||||
getPluginPreference(pluginName: string): Record<string, PreferenceValueType> | null | undefined {
|
||||
getPluginPreference(pluginName: string): Record<string, IPublicTypePreferenceValueType> | null | undefined {
|
||||
if (!this.pluginPreference) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user