mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-10-14 17:33:01 +08:00
Compare commits
63 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5387a18024 | ||
|
2b80ba3efd | ||
|
6c3916c580 | ||
|
4dfdc836f6 | ||
|
fef1e2c2b4 | ||
|
51f95aef6f | ||
|
81aa8f151d | ||
|
cae11dce12 | ||
|
83bf36d980 | ||
|
2888004c17 | ||
|
abab44ad24 | ||
|
849b561933 | ||
|
1031595a97 | ||
|
f5cb19dfa4 | ||
|
e400175ffe | ||
|
958c78d968 | ||
|
9f81597596 | ||
|
001f2b6c9e | ||
|
a56bb562d8 | ||
|
7695f005f6 | ||
|
a10f9d230d | ||
|
9f350541bf | ||
|
0643699fac | ||
|
9f63dff49b | ||
|
7d3a2df793 | ||
|
0967c3449e | ||
|
f267643c42 | ||
|
f3387ed5e9 | ||
|
71d1aab69e | ||
|
4c6118f50f | ||
|
77da3f9762 | ||
|
8b3cb63f77 | ||
|
fc1c9feafd | ||
|
371be8aa27 | ||
|
7bb14e6c25 | ||
|
cdb07dfaea | ||
|
c2830fca6b | ||
|
bba67b5533 | ||
|
eda9924327 | ||
|
07b8f5fe83 | ||
|
d31a544a23 | ||
|
01b7b58065 | ||
|
870dd99e2c | ||
|
01b88dba25 | ||
|
2605011df4 | ||
|
00cf312a91 | ||
|
e3ed80b121 | ||
|
0752abc312 | ||
|
ded24c8b4f | ||
|
7799a5da61 | ||
|
6cb08cf458 | ||
|
305ea4619f | ||
|
291de2005d | ||
|
34bc223f02 | ||
|
bf9fad18b6 | ||
|
cebf3506d4 | ||
|
a43825caa2 | ||
|
1736d495fd | ||
|
44b592f36a | ||
|
6a54720068 | ||
|
aaf8046c63 | ||
|
5242585500 | ||
|
4637c80125 |
113
CHANGELOG.md
113
CHANGELOG.md
@ -1,3 +1,116 @@
|
|||||||
|
## [1.6.1](https://github.com/Tencent/tmagic-editor/compare/v1.6.0...v1.6.1) (2025-10-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **core:** 异步加载数据源时,数据源事件配置失效 ([1031595](https://github.com/Tencent/tmagic-editor/commit/1031595a976b33f8e5e3a71d8c00944d4777beb1))
|
||||||
|
* **form:** text与同行元素不对齐问题 ([cae11dc](https://github.com/Tencent/tmagic-editor/commit/cae11dce1290b9ea314c07daee30f1eb6f400681))
|
||||||
|
* 组件声明周期函数配置中配置数据源自有方法生效 ([e400175](https://github.com/Tencent/tmagic-editor/commit/e400175ffe89ab3105e50d2ffcd702d9d2a12970))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **data-source, editor, schema, react-runtime-help, vue-components:** 新增条件成立时隐藏的配置功能 ([51f95ae](https://github.com/Tencent/tmagic-editor/commit/51f95aef6f649851222e09e7234648f4985d1ad8))
|
||||||
|
* **data-source:** 数据源数据变化事件监听响应支持立即执行 ([849b561](https://github.com/Tencent/tmagic-editor/commit/849b561933d74bcc68f75f15d67e0d252c5a8468))
|
||||||
|
* **editor:** 属性配置中的样式面板样式优化 ([81aa8f1](https://github.com/Tencent/tmagic-editor/commit/81aa8f151d765bf08d2f88c334ff7c58b38aab56))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.6.0](https://github.com/Tencent/tmagic-editor/compare/v1.6.0-beta.6...v1.6.0) (2025-08-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **cli:** 在pnpm工作空间中的项目,保持package.json不受配置中的packages影响 ([a10f9d2](https://github.com/Tencent/tmagic-editor/commit/a10f9d230d93064c28ff82f2c3aba2679f8fe495))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **cli:** 支持tmagic.config.local配置文件,会与tmagic.config配置合并,可用于本地开发时的临时配置 ([9f35054](https://github.com/Tencent/tmagic-editor/commit/9f350541bf84a634499a9af53449015f34da26b5))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.6.0-beta.6](https://github.com/Tencent/tmagic-editor/compare/v1.6.0-beta.5...v1.6.0-beta.6) (2025-08-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **core:** 事件支持关联数据源自身方法 ([4c6118f](https://github.com/Tencent/tmagic-editor/commit/4c6118f50f8e78e8db157f9b32c49f5f068e3e9a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.6.0-beta.5](https://github.com/Tencent/tmagic-editor/compare/v1.6.0-beta.4...v1.6.0-beta.5) (2025-08-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **core:** 事件行为应该为串行执行 ([fc1c9fe](https://github.com/Tencent/tmagic-editor/commit/fc1c9feafd337ad8fa8a9b5b3501278779d32410))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.6.0-beta.4](https://github.com/Tencent/tmagic-editor/compare/v1.6.0-beta.3...v1.6.0-beta.4) (2025-07-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **editor:** runtime url更新后恢复当前选中状态 ([c2830fc](https://github.com/Tencent/tmagic-editor/commit/c2830fca6b21648b51a486650caba3f9eb753c91))
|
||||||
|
* **editor:** 避免services plugin重复添加 ([cdb07df](https://github.com/Tencent/tmagic-editor/commit/cdb07dfaea13a1813caddd59ba7e8efbdb374b3c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.6.0-beta.3](https://github.com/Tencent/tmagic-editor/compare/v1.6.0-beta.2...v1.6.0-beta.3) (2025-07-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **editor:** runtimeUrl更新后需要重新设置runtime的dsl ([d31a544](https://github.com/Tencent/tmagic-editor/commit/d31a544a2312b4d78ae74eb600760df450946db8))
|
||||||
|
* **editor:** 修复代码块编辑器的更新内容后按下ctrl+s光标会偏移的问题 ([07b8f5f](https://github.com/Tencent/tmagic-editor/commit/07b8f5fe8303bad57490c7dd0eba00e435fbfad5))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.6.0-beta.2](https://github.com/Tencent/tmagic-editor/compare/v1.6.0-beta.1...v1.6.0-beta.2) (2025-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **core:** 异步加载dsl片段下,事件触发时node可能不存在 ([01b88db](https://github.com/Tencent/tmagic-editor/commit/01b88dba251a1f7cc29947c2a80e15839e50fcca))
|
||||||
|
* **utile:** replaceChildNode找不多目标不报错 ([2605011](https://github.com/Tencent/tmagic-editor/commit/2605011df481d9edba5503d2ee3b3c9d4b76d0a3))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.6.0-beta.1](https://github.com/Tencent/tmagic-editor/compare/v1.6.0-beta.0...v1.6.0-beta.1) (2025-07-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **data-source:** 页面未初始化好之前,数据源数据变化后需要修改page.data ([305ea46](https://github.com/Tencent/tmagic-editor/commit/305ea4619fe15efbae069ef3f289c8742e8d51ee))
|
||||||
|
* **vue-components:** iterator-container 传递 page-fragment-contianer-id 参数 ([7799a5d](https://github.com/Tencent/tmagic-editor/commit/7799a5da618b0136f4b3c12315c69d21b27a5965))
|
||||||
|
* **vue-components:** page-fragment-container不标记为不是node节点 ([bf9fad1](https://github.com/Tencent/tmagic-editor/commit/bf9fad18b64521a9075a60f7e6e662b01d37f66f))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **core:** Node中的instance初始为null,用于判断是否与组件产生关联 ([291de20](https://github.com/Tencent/tmagic-editor/commit/291de2005de54b8eeba818de67ab3506885f5057))
|
||||||
|
* **editor:** 页面片容器内的组件不允许选中 ([ded24c8](https://github.com/Tencent/tmagic-editor/commit/ded24c8b4ff2c203260ec7633fc85325c98a565c))
|
||||||
|
* **vue-components:** page-fragment-container编辑器中不去除内部组件id,不然会导致无法从app中获取dsl ([34bc223](https://github.com/Tencent/tmagic-editor/commit/34bc223f0241d9eef39450ebcef8a92b23c63f37))
|
||||||
|
* **vue-components:** 添加页面片容器id prop ([a43825c](https://github.com/Tencent/tmagic-editor/commit/a43825caa27695fcd85cc4b5351a00080fefcec0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1.6.0-beta.0](https://github.com/Tencent/tmagic-editor/compare/v1.5.24...v1.6.0-beta.0) (2025-07-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **editor:** 依赖收集后没有同步到dsl中 ([aaf8046](https://github.com/Tencent/tmagic-editor/commit/aaf8046c63949ae733719409eb12109ef17b2cf1))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **core,data-source,utils,react-runtime-help,vue-runtime-help:** 新增对页面片节点的管理 ([6a54720](https://github.com/Tencent/tmagic-editor/commit/6a547200681991ae8abefd0e3d72a603d21f12d4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.5.24](https://github.com/Tencent/tmagic-editor/compare/v1.5.23...v1.5.24) (2025-07-03)
|
## [1.5.24](https://github.com/Tencent/tmagic-editor/compare/v1.5.23...v1.5.24) (2025-07-03)
|
||||||
|
|
||||||
|
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
Tencent is pleased to support the open source community by making TMagicEditor available.
|
Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
|
|
||||||
Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
|
|
||||||
TMagicEditor is licensed under the Apache License Version 2.0 except for the third-party components listed below.
|
TMagicEditor is licensed under the Apache License Version 2.0 except for the third-party components listed below.
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ export default defineConfig({
|
|||||||
|
|
||||||
footer: {
|
footer: {
|
||||||
message: 'Powered by 腾讯视频会员平台技术中心',
|
message: 'Powered by 腾讯视频会员平台技术中心',
|
||||||
copyright: 'Copyright (C) 2023 THL A29 Limited, a Tencent company.'
|
copyright: 'Copyright (C) 2025 Tencent.'
|
||||||
},
|
},
|
||||||
|
|
||||||
nav: [
|
nav: [
|
||||||
|
@ -375,7 +375,7 @@ const stageContentMenu = ref([
|
|||||||
```html
|
```html
|
||||||
<template>
|
<template>
|
||||||
<m-editor
|
<m-editor
|
||||||
runtime-url="https://tencent.github.io/tmagic-editor/playground/runtime/vue3/playground/index.html"
|
runtime-url="https://tencent.github.io/tmagic-editor/playground/runtime/vue/playground/index.html"
|
||||||
></m-editor>
|
></m-editor>
|
||||||
</template>
|
</template>
|
||||||
```
|
```
|
||||||
@ -675,7 +675,7 @@ const datasourceConfigs = {
|
|||||||
|
|
||||||
- **默认值:** `{}`
|
- **默认值:** `{}`
|
||||||
|
|
||||||
- **类型:** ((config?: [CustomizeMoveableOptionsCallbackConfig](https://github.com/Tencent/tmagic-editor/blob/239b5d3efeae916a8cf3e3566d88063ecccc0553/packages/stage/src/types.ts#L97-L109)) => MoveableOptions) | [MoveableOptions](https://daybrush.com/moveable/release/latest/doc/)
|
- **类型:** ((config: [CustomizeMoveableOptionsCallbackConfig](https://github.com/Tencent/tmagic-editor/blob/239b5d3efeae916a8cf3e3566d88063ecccc0553/packages/stage/src/types.ts#L97-L109)) => MoveableOptions) | [MoveableOptions](https://daybrush.com/moveable/release/latest/doc/)
|
||||||
|
|
||||||
- **示例:**
|
- **示例:**
|
||||||
|
|
||||||
|
@ -60,6 +60,5 @@ export default defineComponent({
|
|||||||
|
|
||||||
## 渲染器示例
|
## 渲染器示例
|
||||||
在tmagic-editor的示例项目中,我们提供了三个版本的 @tmagic/ui。可以参考对应前端框架的渲染器实现。
|
在tmagic-editor的示例项目中,我们提供了三个版本的 @tmagic/ui。可以参考对应前端框架的渲染器实现。
|
||||||
- [vue3 渲染器](https://github.com/Tencent/tmagic-editor/blob/master/packages/ui/src/container/src/Container.vue)
|
- [vue 渲染器](https://github.com/Tencent/tmagic-editor/blob/master/vue-components/container/src/Container.vue)
|
||||||
- [vue2 渲染器](https://github.com/Tencent/tmagic-editor/blob/master/packages/ui-vue2/src/container/Container.vue)
|
- [react 渲染器](https://github.com/Tencent/tmagic-editor/blob/master/react-components/container/src/Container.tsx)
|
||||||
- [react 渲染器](https://github.com/Tencent/tmagic-editor/blob/master/packages/ui-react/src/container/Container.tsx)
|
|
@ -5,15 +5,13 @@ tmagic-editor的设计是希望发布的页面支持多个前端框架,即各
|
|||||||
|
|
||||||
所以tmagic-editor的设计中,针对每个前端框架,都需要有一个对应的 @tmagic/ui 来承担渲染器职责。同时,也需要一个使用和 @tmagic/ui 相同前端框架的 runtime 来 @tmagic/ui 和业务组件的,具体 runtime 概念,可以参考[页面发布](../publish)。
|
所以tmagic-editor的设计中,针对每个前端框架,都需要有一个对应的 @tmagic/ui 来承担渲染器职责。同时,也需要一个使用和 @tmagic/ui 相同前端框架的 runtime 来 @tmagic/ui 和业务组件的,具体 runtime 概念,可以参考[页面发布](../publish)。
|
||||||
|
|
||||||
@tmagic/ui 在tmagic-editor设计中,承担的是业务逻辑无关的,基础组件渲染的功能。一切和业务相关的逻辑,都应该在 [runtime](../runtime.html) 中实现。这样 @tmagic/ui 就能保持其通用性。
|
我们以项目代码中提供的 vue 版本的 [vue-components](https://tencent.github.io/tmagic-editor/vue-components) 作为示例介绍其中包含的内容。
|
||||||
|
|
||||||
我们以项目代码中提供的 vue3 版本的 @tmagic/ui 作为示例介绍其中包含的内容。
|
|
||||||
|
|
||||||
## 渲染器
|
## 渲染器
|
||||||
在 vue3 中,实现渲染器的具体形式参考[页面渲染](../advanced/page)中描述的[容器渲染](../advanced/page.html#容器渲染)和[组件渲染](../advanced/page.html#容器渲染)。
|
在 vue 中,实现渲染器的具体形式参考[页面渲染](../advanced/page)中描述的[容器渲染](../advanced/page.html#容器渲染)和[组件渲染](../advanced/page.html#容器渲染)。
|
||||||
|
|
||||||
## 基础组件
|
## 基础组件
|
||||||
在 @tmagic/ui vue3 中,我们提供了几个基础组件,可以在项目源码中找到对应内容。
|
在 [vue-components](https://tencent.github.io/tmagic-editor/vue-components) 中,我们提供了几个基础组件,可以在项目源码中找到对应内容。
|
||||||
|
|
||||||
- page tmagic-editor的页面基础
|
- page tmagic-editor的页面基础
|
||||||
- container tmagic-editor的容器渲染器
|
- container tmagic-editor的容器渲染器
|
||||||
@ -23,8 +21,3 @@ tmagic-editor的设计是希望发布的页面支持多个前端框架,即各
|
|||||||
其中 page/container/Component 是 UI 的基础,是每个框架的 UI 都应该实现的。
|
其中 page/container/Component 是 UI 的基础,是每个框架的 UI 都应该实现的。
|
||||||
|
|
||||||
button/text 其实就是一个组件开发的示例,具体组件开发相关规范可以参考[组件开发](../component)。
|
button/text 其实就是一个组件开发的示例,具体组件开发相关规范可以参考[组件开发](../component)。
|
||||||
|
|
||||||
## @tmagic/ui 示例
|
|
||||||
- [vue3 渲染器](https://github.com/Tencent/tmagic-editor/blob/master/packages/ui)
|
|
||||||
- [vue2 渲染器](https://github.com/Tencent/tmagic-editor/blob/master/packages/ui-vue2)
|
|
||||||
- [react 渲染器](https://github.com/Tencent/tmagic-editor/blob/master/packages/ui-react)
|
|
@ -2,14 +2,14 @@
|
|||||||
tmagic-editor支持业务方进行自定义组件开发。在tmagic-editor中,组件是以 npm 包形式存在的,组件和插件只要按照规范开发,就可以在tmagic-editor的 runtime 中被加入并正确渲染组件。
|
tmagic-editor支持业务方进行自定义组件开发。在tmagic-editor中,组件是以 npm 包形式存在的,组件和插件只要按照规范开发,就可以在tmagic-editor的 runtime 中被加入并正确渲染组件。
|
||||||
|
|
||||||
## 组件开发
|
## 组件开发
|
||||||
以 vue3 的组件开发为例。运行项目中的 playground 示例,会自动加载 vue3 的 runtime。runtime会加载[@tmagic/ui](https://github.com/Tencent/tmagic-editor/tree/master/packages/ui)
|
以 vue 的组件开发为例。运行项目中的 playground 示例,会自动加载 vue 的 runtime。runtime会加载[@tmagic/ui](https://github.com/Tencent/tmagic-editor/tree/master/packages/ui)
|
||||||
|
|
||||||
## 组件注册
|
## 组件注册
|
||||||
在 [playground](https://tencent.github.io/tmagic-editor/playground/index.html#/) 中,我们可以尝试点击添加一个组件,在模拟器区域里,就会出现这个组件。其中就涉及到组件注册。
|
在 [playground](https://tencent.github.io/tmagic-editor/playground/index.html#/) 中,我们可以尝试点击添加一个组件,在模拟器区域里,就会出现这个组件。其中就涉及到组件注册。
|
||||||
|
|
||||||
这一步需要开发者基于tmagic-editor搭建了平台后,实现组件列表的注册、获取机制,tmagic-editor组件注册其实就是保存好组件 `type` 的映射关系。`type` 可以参考[组件介绍](../guide/conception.html#组件)。
|
这一步需要开发者基于tmagic-editor搭建了平台后,实现组件列表的注册、获取机制,tmagic-editor组件注册其实就是保存好组件 `type` 的映射关系。`type` 可以参考[组件介绍](../guide/conception.html#组件)。
|
||||||
|
|
||||||
可以参考 vue3 版本的 @tmagic/ui 中,[组件渲染](../guide/advanced/page.html#组件渲染)逻辑里,type 会作为组件名进入渲染。所以在 vue3 的组件开发中,我们也需要在为 vue 组件声明 name 字段时,和 type 值对应起来,才能正确渲染组件。
|
可以参考 vue 版本的 @tmagic/ui 中,[组件渲染](../guide/advanced/page.html#组件渲染)逻辑里,type 会作为组件名进入渲染。所以在 vue 的组件开发中,我们也需要在为 vue 组件声明 name 字段时,和 type 值对应起来,才能正确渲染组件。
|
||||||
|
|
||||||
### 组件规范
|
### 组件规范
|
||||||
组件的基础形式,需要有四个文件
|
组件的基础形式,需要有四个文件
|
||||||
@ -22,7 +22,7 @@ tmagic-editor支持业务方进行自定义组件开发。在tmagic-editor中,
|
|||||||
@tmagic/ui 中的 button/text 就是基础的组件示例。我们要求声明 index 入口,因为我们希望在后续的配套打包工具实现上,可以有一个统一规范入口。
|
@tmagic/ui 中的 button/text 就是基础的组件示例。我们要求声明 index 入口,因为我们希望在后续的配套打包工具实现上,可以有一个统一规范入口。
|
||||||
|
|
||||||
### 1. 创建组件
|
### 1. 创建组件
|
||||||
在项目中,如 runtime vue3 目录中,创建一个名为 test-component 的组件目录,其中包含上面四个规范文件。
|
在项目中,如 runtime 目录中,创建一个名为 test-component 的组件目录,其中包含上面四个规范文件。
|
||||||
```javascript
|
```javascript
|
||||||
// index.js
|
// index.js
|
||||||
// vue
|
// vue
|
||||||
@ -69,7 +69,7 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
vue3 版本的组件代码示例
|
版本的组件代码示例
|
||||||
```vue
|
```vue
|
||||||
<!-- Test.vue -->
|
<!-- Test.vue -->
|
||||||
<template>
|
<template>
|
||||||
@ -119,7 +119,7 @@ export default Test;
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 2. 使用tmagic-cli
|
### 2. 使用tmagic-cli
|
||||||
在 runtime vue3 中,我们已经提供好一份示例。在 tmagic.config.ts 文件中。只需要在 packages 加入你创建的组件的路径(如果是个 npm 包,则将路径替换为包名即可),打包工具就会自动识别到你的组件。
|
在 runtime vue 中,我们已经提供好一份示例。在 tmagic.config.ts 文件中。只需要在 packages 加入你创建的组件的路径(如果是个 npm 包,则将路径替换为包名即可),打包工具就会自动识别到你的组件。
|
||||||
|
|
||||||
### 3. 启动 playground
|
### 3. 启动 playground
|
||||||
在上面的步骤完成后,在 playground/src/configs/componentGroupList 中。找到组件栏的基础组件列表,在其中加入你的开发组件
|
在上面的步骤完成后,在 playground/src/configs/componentGroupList 中。找到组件栏的基础组件列表,在其中加入你的开发组件
|
||||||
@ -155,7 +155,7 @@ npm run playground
|
|||||||
<img src="https://image.video.qpic.cn/oa_fd3c9c-3_548108267_1636719045199471">
|
<img src="https://image.video.qpic.cn/oa_fd3c9c-3_548108267_1636719045199471">
|
||||||
|
|
||||||
### 4. 启动 runtime
|
### 4. 启动 runtime
|
||||||
在完成开发中组件在编辑器中的实现后,我们将编辑器中的 DSL 源码📄 打开,复制 DSL。并在 runtime/vue3/src/page 下。创建一个 page-config.js 文件。将 DSL 作为配置导出。
|
在完成开发中组件在编辑器中的实现后,我们将编辑器中的 DSL 源码📄 打开,复制 DSL。并在 runtime/vue/src/page 下。创建一个 page-config.js 文件。将 DSL 作为配置导出。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
window.magicDSL = [
|
window.magicDSL = [
|
||||||
@ -168,7 +168,7 @@ window.magicDSL = [
|
|||||||
import './page-config.js';
|
import './page-config.js';
|
||||||
```
|
```
|
||||||
|
|
||||||
然后执行在 runtime/vue3 目录下执行
|
然后执行在 runtime/ 目录下执行
|
||||||
```
|
```
|
||||||
npm run build:libs
|
npm run build:libs
|
||||||
npm run dev
|
npm run dev
|
||||||
|
@ -60,11 +60,6 @@ DSL 是编辑器搭建页面的最终产物(描述文件),其中包含了
|
|||||||
### runtime
|
### runtime
|
||||||
我们把页面统一称为 runtime,更具体的 runtime 概念可以查看[页面发布](./publish.html#runtime)。**runtime 是承载tmagic-editor项目页面的运行环境**。编辑器的工作区是 runtime 的一个具体实例,另一个就是我们发布上线后,用户访问的真实项目页面。
|
我们把页面统一称为 runtime,更具体的 runtime 概念可以查看[页面发布](./publish.html#runtime)。**runtime 是承载tmagic-editor项目页面的运行环境**。编辑器的工作区是 runtime 的一个具体实例,另一个就是我们发布上线后,用户访问的真实项目页面。
|
||||||
|
|
||||||
### @tmagic/ui
|
|
||||||
@tmagic/ui 包含了tmagic-editor的基础组件库,提供了容器、文本、按钮这样的基础组件。我们提供了不同语言框架的 @tmagic/ui,如 vue2 和 vue3。
|
|
||||||
|
|
||||||
@tmagic/ui 和 runtime 是配套出现的,runtime 必须基于 @tmagic/ui 才可以实现渲染。因为 @tmagic/ui 需要提供 runtime 所需要的渲染器。
|
|
||||||
|
|
||||||
## 联动
|
## 联动
|
||||||
页面搭建过程中,会涉及到两种联动形式
|
页面搭建过程中,会涉及到两种联动形式
|
||||||
- 在编辑器中,组件的表单配置项之间需要联动。
|
- 在编辑器中,组件的表单配置项之间需要联动。
|
||||||
|
@ -125,7 +125,7 @@ app.mount('#app');
|
|||||||
// 初始化页面数据
|
// 初始化页面数据
|
||||||
}),
|
}),
|
||||||
|
|
||||||
runtimeUrl: "/runtime/vue3/playground/index.html",
|
runtimeUrl: "/runtime/vue/playground/index.html",
|
||||||
|
|
||||||
propsConfigs: [
|
propsConfigs: [
|
||||||
// 组件属性列表
|
// 组件属性列表
|
||||||
@ -208,10 +208,10 @@ npm install sass -D
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
setup() {
|
setup() {
|
||||||
asyncLoadJs(`/runtime/vue3/assets/config.js`).then(() => {
|
asyncLoadJs(`/runtime/vue/assets/config.js`).then(() => {
|
||||||
propsConfigs.value = window.magicPresetConfigs;
|
propsConfigs.value = window.magicPresetConfigs;
|
||||||
});
|
});
|
||||||
asyncLoadJs(`/runtime/vue3/assets/value.js`).then(() => {
|
asyncLoadJs(`/runtime/vue/assets/value.js`).then(() => {
|
||||||
propsValues.value = window.magicPresetValues;
|
propsValues.value = window.magicPresetValues;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,6 @@ tmagic-editor可视化开源项目是从魔方平台演化而来的开源项目
|
|||||||
- **@tmagic/core** 实现对组件进行跨框架管理与一些通用复杂逻辑的实现。
|
- **@tmagic/core** 实现对组件进行跨框架管理与一些通用复杂逻辑的实现。
|
||||||
- **@tmagic/data-source** 实现数据源的管理与编译。
|
- **@tmagic/data-source** 实现数据源的管理与编译。
|
||||||
- **@tmagic/stage** 实现在编辑器中对组件的位置拖动与大小拖拉。
|
- **@tmagic/stage** 实现在编辑器中对组件的位置拖动与大小拖拉。
|
||||||
- **@tmagic/ui** 提供一些vue3基础组件。
|
|
||||||
- **@tmagic/ui-vue2** 提供一些vue2基础组件。
|
|
||||||
- **@tmagic/ui-react** 提供一些react基础组件。
|
|
||||||
- **runtime** 实现在编辑器中对使用不同框架的组件的渲染。
|
- **runtime** 实现在编辑器中对使用不同框架的组件的渲染。
|
||||||
|
|
||||||
可以查阅 tmagic 的[源代码](https://github.com/Tencent/tmagic-editor),与文档描述内容可以逐一对应上,希望文档内容可以为开发者带来比较好的开发体验。
|
可以查阅 tmagic 的[源代码](https://github.com/Tencent/tmagic-editor),与文档描述内容可以逐一对应上,希望文档内容可以为开发者带来比较好的开发体验。
|
||||||
|
@ -13,7 +13,7 @@ runtime 的概念,是理解tmagic-editor项目页运行的重要概念,runti
|
|||||||
|
|
||||||
所以更深入描述,runtime 是tmagic-editor页面的渲染环境,提供不同场景下的能力封装。如果理解了tmagic-editor的设计,阅读了tmagic-editor的源码,可以发现,runtime 只是对tmagic-editor的渲染器做了一层包装,在不同 runtime 中,tmagic-editor的渲染逻辑和组件代码都是相同的。
|
所以更深入描述,runtime 是tmagic-editor页面的渲染环境,提供不同场景下的能力封装。如果理解了tmagic-editor的设计,阅读了tmagic-editor的源码,可以发现,runtime 只是对tmagic-editor的渲染器做了一层包装,在不同 runtime 中,tmagic-editor的渲染逻辑和组件代码都是相同的。
|
||||||
|
|
||||||
并且,由于tmagic-editor在编辑器中的模拟器是通过 iframe 渲染的,和tmagic-editor平台本身可以做到框架解耦,所以 runtime 也可以用不同框架开发。目前tmagic-editor提供了 vue2/vue3 和 react 的 runtime 示例。
|
并且,由于tmagic-editor在编辑器中的模拟器是通过 iframe 渲染的,和tmagic-editor平台本身可以做到框架解耦,所以 runtime 也可以用不同框架开发。目前tmagic-editor提供了 vue 和 react 的 runtime 示例。
|
||||||
|
|
||||||
各个 runtime 的作用除了作为不同场景下的渲染环境,同时也是不同环境的打包构建载体。tmagic-editor示例代码中的打包就是基于 runtime 进行的。
|
各个 runtime 的作用除了作为不同场景下的渲染环境,同时也是不同环境的打包构建载体。tmagic-editor示例代码中的打包就是基于 runtime 进行的。
|
||||||
|
|
||||||
@ -21,8 +21,7 @@ runtime 的概念,是理解tmagic-editor项目页运行的重要概念,runti
|
|||||||
由于 runtime 是页面渲染的承载环境,其中会加载 @tmagic/ui 以及各个业务组件,业务发布项目页也是基于 runtime,所以在 runtime 中实现业务方的自定义逻辑是最合适的。runtime 可以提供一些全局 API,供业务组件调用。我们可以把下面的模拟器中的 runtime 视为一个业务方runtime。
|
由于 runtime 是页面渲染的承载环境,其中会加载 @tmagic/ui 以及各个业务组件,业务发布项目页也是基于 runtime,所以在 runtime 中实现业务方的自定义逻辑是最合适的。runtime 可以提供一些全局 API,供业务组件调用。我们可以把下面的模拟器中的 runtime 视为一个业务方runtime。
|
||||||
|
|
||||||
tmagic-editor提供了三个版本的 runtime 示例,可以参考:
|
tmagic-editor提供了三个版本的 runtime 示例,可以参考:
|
||||||
- [vue3 runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue3)
|
- [vue runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue)
|
||||||
- [vue2 runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue2)
|
|
||||||
- [react runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/react)
|
- [react runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/react)
|
||||||
|
|
||||||
### 真实页面渲染(Page)
|
### 真实页面渲染(Page)
|
||||||
|
@ -14,8 +14,7 @@ runtime 的 `page` 部分,就是真实项目页面的渲染环境。发布出
|
|||||||
- 加载第三方全局组件/插件等
|
- 加载第三方全局组件/插件等
|
||||||
|
|
||||||
具体的 page 实现示例,可以参考
|
具体的 page 实现示例,可以参考
|
||||||
- [vue3 runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue3/page)
|
- [vue runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue/page)
|
||||||
- [vue2 runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue2/page)
|
|
||||||
- [react runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/react/page)
|
- [react runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/react/page)
|
||||||
|
|
||||||
### playground
|
### playground
|
||||||
@ -45,8 +44,7 @@ window.magic.onPageElUpdate(document.querySelector('.magic-ui-page'));
|
|||||||
|sortNode| 组件在容器间排序 |{ `src` , `dist`, `root` }: `SortEventData` |
|
|sortNode| 组件在容器间排序 |{ `src` , `dist`, `root` }: `SortEventData` |
|
||||||
|
|
||||||
runtime 的实现示例,可以参考tmagic-editor提供的:
|
runtime 的实现示例,可以参考tmagic-editor提供的:
|
||||||
- [vue3 runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue3)
|
- [vue runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue)
|
||||||
- [vue2 runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/vue2)
|
|
||||||
- [react runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/react)
|
- [react runtime](https://github.com/Tencent/tmagic-editor/blob/master/runtime/react)
|
||||||
|
|
||||||
### 页面发布
|
### 页面发布
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# 3.[DSL](../conception.md#dsl) 解析渲染
|
# 3.[DSL](../conception.md#dsl) 解析渲染
|
||||||
|
|
||||||
tmagic 提供了 vue3/vue2/react 三个版本的解析渲染组件,可以直接使用
|
tmagic 提供了 vue/react 两个个版本的解析渲染组件,可以直接使用
|
||||||
|
|
||||||
[@tmagic/ui](https://www.npmjs.com/package/@tmagic/ui)
|
[@tmagic/ui](https://www.npmjs.com/package/@tmagic/ui)
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import js from '@eslint/js';
|
import js from '@eslint/js';
|
||||||
import stylistic from '@stylistic/eslint-plugin';
|
import stylistic from '@stylistic/eslint-plugin';
|
||||||
import stylisticTs from '@stylistic/eslint-plugin-ts';
|
|
||||||
import parserTs from '@typescript-eslint/parser';
|
import parserTs from '@typescript-eslint/parser';
|
||||||
import { defineConfig } from 'eslint/config';
|
import { defineConfig } from 'eslint/config';
|
||||||
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||||
@ -21,7 +20,6 @@ export default (tsconfigRootDir) =>
|
|||||||
...tseslint.config(tencentEslintBaseConfig, tencentEslintImportexport, tseslint.configs.base, {
|
...tseslint.config(tencentEslintBaseConfig, tencentEslintImportexport, tseslint.configs.base, {
|
||||||
plugins: {
|
plugins: {
|
||||||
'@stylistic': stylistic,
|
'@stylistic': stylistic,
|
||||||
'@stylistic/ts': stylisticTs,
|
|
||||||
},
|
},
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
parser: parserTs,
|
parser: parserTs,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tmagic/eslint-config",
|
"name": "@tmagic/eslint-config",
|
||||||
"version": "0.0.2",
|
"version": "0.0.3",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -9,18 +9,17 @@
|
|||||||
"url": "https://github.com/Tencent/tmagic-editor.git"
|
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/js": "^9.24.0",
|
"@eslint/js": "^9.34.0",
|
||||||
"@typescript-eslint/parser": "^8.30.1",
|
"@typescript-eslint/parser": "^8.41.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.30.1",
|
"@typescript-eslint/eslint-plugin": "^8.41.0 ",
|
||||||
"@stylistic/eslint-plugin": "^4.2.0",
|
"@stylistic/eslint-plugin": "^5.2.3",
|
||||||
"@stylistic/eslint-plugin-ts": "^4.2.0",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-config-prettier": "^10.1.2",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
"eslint-plugin-vue": "^10.0.0",
|
"eslint-plugin-vue": "^10.4.0",
|
||||||
"eslint-plugin-prettier": "^5.2.6",
|
"eslint-plugin-prettier": "^5.5.4 ",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.3.0",
|
||||||
"typescript-eslint": "^8.30.1"
|
"typescript-eslint": "^8.41.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": ">=9.24.0",
|
"eslint": ">=9.24.0",
|
||||||
|
28
package.json
28
package.json
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "tmagic",
|
"name": "tmagic",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "pnpm@10.11.1",
|
"packageManager": "pnpm@10.18.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bootstrap": "pnpm i && pnpm build",
|
"bootstrap": "pnpm i && pnpm build",
|
||||||
"clean:top": "rimraf */**/dist */**/types */dist coverage dwt* temp packages/cli/lib",
|
"clean:top": "rimraf */**/dist */**/types */dist coverage dwt* temp packages/cli/lib",
|
||||||
@ -11,16 +11,14 @@
|
|||||||
"clean:all": "pnpm clean:top && pnpm clean:modules",
|
"clean:all": "pnpm clean:top && pnpm clean:modules",
|
||||||
"lint": "eslint --cache .",
|
"lint": "eslint --cache .",
|
||||||
"lint-fix": "eslint --fix --cache .",
|
"lint-fix": "eslint --fix --cache .",
|
||||||
"playground": "pnpm --filter \"runtime-vue3\" build:libs && pnpm --filter \"runtime-vue3\" --filter \"tmagic-playground\" dev",
|
"playground": "pnpm --filter \"runtime-vue\" build:libs && pnpm --filter \"runtime-vue\" --filter \"tmagic-playground\" dev",
|
||||||
"pg": "pnpm playground",
|
"pg": "pnpm playground",
|
||||||
"playground:vue2": "pnpm --filter \"runtime-vue2\" build:libs && pnpm --filter \"runtime-vue2\" --filter \"tmagic-playground\" dev:vue2",
|
|
||||||
"pg:vue2": "pnpm playground:vue2",
|
|
||||||
"playground:react": "pnpm --filter \"runtime-react\" build:libs && pnpm --filter \"runtime-react\" --filter \"tmagic-playground\" dev:react",
|
"playground:react": "pnpm --filter \"runtime-react\" build:libs && pnpm --filter \"runtime-react\" --filter \"tmagic-playground\" dev:react",
|
||||||
"pg:react": "pnpm playground:react",
|
"pg:react": "pnpm playground:react",
|
||||||
"build": "pnpm build:dts && node scripts/build.mjs",
|
"build": "pnpm build:dts && node scripts/build.mjs",
|
||||||
"build:dts": "pnpm --filter \"@tmagic/cli\" build && tsc -p tsconfig.build-browser.json && vue-tsc --declaration --emitDeclarationOnly --project tsconfig.build-vue.json && rollup -c rollup.dts.config.js && rimraf temp",
|
"build:dts": "pnpm --filter \"@tmagic/cli\" build && tsc -p tsconfig.build-browser.json && vue-tsc --declaration --emitDeclarationOnly --project tsconfig.build-vue.json && rollup -c rollup.dts.config.js && rimraf temp",
|
||||||
"check:type": "tsc --incremental --noEmit -p tsconfig.check.json && vue-tsc --noEmit -p tsconfig.check-vue.json",
|
"check:type": "tsc --incremental --noEmit -p tsconfig.check.json && vue-tsc --noEmit -p tsconfig.check-vue.json",
|
||||||
"build:playground": "pnpm --filter \"runtime-vue3\" build && pnpm --filter \"tmagic-playground\" build",
|
"build:playground": "pnpm --filter \"runtime-vue\" build && pnpm --filter \"tmagic-playground\" build",
|
||||||
"docs:dev": "vitepress dev docs",
|
"docs:dev": "vitepress dev docs",
|
||||||
"docs:serve": "vitepress serve docs",
|
"docs:serve": "vitepress serve docs",
|
||||||
"docs:build": "vitepress build docs",
|
"docs:build": "vitepress build docs",
|
||||||
@ -32,7 +30,7 @@
|
|||||||
"release": "node scripts/release.mjs"
|
"release": "node scripts/release.mjs"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@ -49,15 +47,15 @@
|
|||||||
"@types/node": "24.0.10",
|
"@types/node": "24.0.10",
|
||||||
"@vitejs/plugin-vue": "^5.2.3",
|
"@vitejs/plugin-vue": "^5.2.3",
|
||||||
"@vitest/coverage-v8": "^2.1.9",
|
"@vitest/coverage-v8": "^2.1.9",
|
||||||
"@vue/compiler-sfc": "^3.5.13",
|
"@vue/compiler-sfc": "catalog:",
|
||||||
"c8": "^7.14.0",
|
"c8": "^7.14.0",
|
||||||
"commitizen": "^4.3.1",
|
"commitizen": "^4.3.1",
|
||||||
"conventional-changelog-cli": "^5.0.0",
|
"conventional-changelog-cli": "^5.0.0",
|
||||||
"cosmiconfig": "^8.3.6",
|
"cosmiconfig": "^8.3.6",
|
||||||
"cz-conventional-changelog": "^3.3.0",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"element-plus": "^2.9.11",
|
"element-plus": "^2.11.4",
|
||||||
"enquirer": "^2.4.1",
|
"enquirer": "^2.4.1",
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.37.0",
|
||||||
"execa": "^4.1.0",
|
"execa": "^4.1.0",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
@ -65,20 +63,20 @@
|
|||||||
"lint-staged": "^16.1.0",
|
"lint-staged": "^16.1.0",
|
||||||
"minimist": "^1.2.8",
|
"minimist": "^1.2.8",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.6.2",
|
||||||
"recast": "^0.23.11",
|
"recast": "^0.23.11",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rollup": "^4.44.1",
|
"rollup": "4.44.1",
|
||||||
"rollup-plugin-dts": "^6.2.1",
|
"rollup-plugin-dts": "^6.2.1",
|
||||||
"semver": "^7.7.1",
|
"semver": "^7.7.1",
|
||||||
"serialize-javascript": "^6.0.2",
|
"serialize-javascript": "^6.0.2",
|
||||||
"shx": "^0.3.4",
|
"shx": "^0.3.4",
|
||||||
"typescript": "catalog:",
|
"typescript": "catalog:",
|
||||||
"vite": "catalog:",
|
"vite": "catalog:",
|
||||||
"vitepress": "^1.6.3",
|
"vitepress": "^1.6.4",
|
||||||
"vitest": "^3.2.1",
|
"vitest": "^3.2.4",
|
||||||
"vue": "catalog:",
|
"vue": "catalog:",
|
||||||
"vue-tsc": "^3.0.0"
|
"vue-tsc": "^3.1.1"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"commitizen": {
|
"commitizen": {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/cli",
|
"name": "@tmagic/cli",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
@ -30,6 +30,7 @@
|
|||||||
"chokidar": "^3.6.0",
|
"chokidar": "^3.6.0",
|
||||||
"esbuild": "^0.21.5",
|
"esbuild": "^0.21.5",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
|
"merge-options": "^3.0.4",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"recast": "^0.23.11",
|
"recast": "^0.23.11",
|
||||||
"tslib": "^2.8.0"
|
"tslib": "^2.8.0"
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
|
// @ts-ignore
|
||||||
|
import mergeOptions from 'merge-options';
|
||||||
|
|
||||||
import App from '../Core';
|
import App from '../Core';
|
||||||
import { UserConfig } from '../types';
|
import { UserConfig } from '../types';
|
||||||
@ -22,18 +24,29 @@ export const scripts = (defaultAppConfig: UserConfig) => {
|
|||||||
path.resolve(defaultAppConfig.temp, 'config.cjs'),
|
path.resolve(defaultAppConfig.temp, 'config.cjs'),
|
||||||
].find((item) => fs.pathExistsSync(item));
|
].find((item) => fs.pathExistsSync(item));
|
||||||
|
|
||||||
const { npmConfig = {}, ...userConfig } = await loadUserConfig(userConfigPath);
|
const localUserConfigPath = [
|
||||||
|
path.resolve(defaultAppConfig.source, 'tmagic.config.local.ts'),
|
||||||
|
path.resolve(defaultAppConfig.source, 'tmagic.config.local.js'),
|
||||||
|
path.resolve(defaultAppConfig.source, 'tmagic.config.local.cjs'),
|
||||||
|
path.resolve(defaultAppConfig.temp, 'config.local.ts'),
|
||||||
|
path.resolve(defaultAppConfig.temp, 'config.local.js'),
|
||||||
|
path.resolve(defaultAppConfig.temp, 'config.local.cjs'),
|
||||||
|
].find((item) => fs.pathExistsSync(item));
|
||||||
|
|
||||||
|
let userConfig = await loadUserConfig(userConfigPath);
|
||||||
|
|
||||||
|
if (localUserConfigPath) {
|
||||||
|
const localUserConfig = await loadUserConfig(localUserConfigPath);
|
||||||
|
|
||||||
|
if (localUserConfig.packages?.length) {
|
||||||
|
localUserConfig.packages = [...(userConfig.packages || []), ...localUserConfig.packages];
|
||||||
|
}
|
||||||
|
|
||||||
|
userConfig = mergeOptions(userConfig, localUserConfig);
|
||||||
|
}
|
||||||
|
|
||||||
// resolve the final app config to use
|
// resolve the final app config to use
|
||||||
const appConfig = {
|
const appConfig = mergeOptions(defaultAppConfig, userConfig);
|
||||||
...defaultAppConfig,
|
|
||||||
...userConfig,
|
|
||||||
npmConfig: {
|
|
||||||
...(defaultAppConfig.npmConfig || {}),
|
|
||||||
...npmConfig,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const app = new App(appConfig);
|
const app = new App(appConfig);
|
||||||
|
|
||||||
// clean temp and cache
|
// clean temp and cache
|
||||||
|
@ -1,11 +1,35 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
import process from 'node:process';
|
||||||
|
|
||||||
|
const windowsPathRegex = /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/]+[^\\/]+)?[\\/]$/;
|
||||||
|
|
||||||
|
export const isRootPath = (path: string) => {
|
||||||
|
if (typeof path !== 'string') {
|
||||||
|
throw new TypeError('Expected a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
path = path.trim();
|
||||||
|
|
||||||
|
// While it's unclear how long a root path can be on Windows, it definitely cannot be longer than 100 characters.
|
||||||
|
if (path === '' || path.length > 100) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.platform === 'win32' ? windowsPathRegex.test(path) : path === '/';
|
||||||
|
};
|
||||||
|
|
||||||
export const backupFile = (runtimeSource: string, file: string) => {
|
export const backupFile = (runtimeSource: string, file: string) => {
|
||||||
|
if (isRootPath(runtimeSource)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const filePath = path.join(runtimeSource, file);
|
const filePath = path.join(runtimeSource, file);
|
||||||
|
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
fs.copyFileSync(filePath, `${filePath}.bak`);
|
fs.copyFileSync(filePath, `${filePath}.bak`);
|
||||||
|
} else {
|
||||||
|
backupFile(path.resolve(runtimeSource, '..'), file);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,11 +50,17 @@ export const backupLock = (runtimeSource: string, npmType: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const restoreFile = (runtimeSource: string, file: string) => {
|
export const restoreFile = (runtimeSource: string, file: string) => {
|
||||||
|
if (isRootPath(runtimeSource)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const filePath = path.join(runtimeSource, file);
|
const filePath = path.join(runtimeSource, file);
|
||||||
|
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
fs.unlinkSync(filePath);
|
fs.unlinkSync(filePath);
|
||||||
fs.renameSync(`${filePath}.bak`, filePath);
|
fs.renameSync(`${filePath}.bak`, filePath);
|
||||||
|
} else {
|
||||||
|
restoreFile(path.resolve(runtimeSource, '..'), file);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -601,10 +601,20 @@ const flattenPackagesConfig = (packages: (string | Record<string, string>)[]) =>
|
|||||||
const packagesConfig: ([string] | [string, string])[] = [];
|
const packagesConfig: ([string] | [string, string])[] = [];
|
||||||
packages.forEach((item) => {
|
packages.forEach((item) => {
|
||||||
if (typeof item === 'object') {
|
if (typeof item === 'object') {
|
||||||
Object.entries(item).forEach(([key, packagePath]) => {
|
for (const [key, packagePath] of Object.entries(item)) {
|
||||||
packagesConfig.push([packagePath, key]);
|
const index = packagesConfig.findIndex(([, k]) => {
|
||||||
});
|
return k === key;
|
||||||
|
});
|
||||||
|
if (index > -1) {
|
||||||
|
packagesConfig[index] = [packagePath, key];
|
||||||
|
} else {
|
||||||
|
packagesConfig.push([packagePath, key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (typeof item === 'string') {
|
} else if (typeof item === 'string') {
|
||||||
|
if (packagesConfig.find(([k]) => k === item)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
packagesConfig.push([item]);
|
packagesConfig.push([item]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/core",
|
"name": "@tmagic/core",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/tmagic-core.umd.cjs",
|
"main": "dist/tmagic-core.umd.cjs",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -29,7 +29,7 @@ import Flexible from './Flexible';
|
|||||||
import FlowState from './FlowState';
|
import FlowState from './FlowState';
|
||||||
import Node from './Node';
|
import Node from './Node';
|
||||||
import Page from './Page';
|
import Page from './Page';
|
||||||
import { AppOptionsConfig, ErrorHandler } from './type';
|
import { AppOptionsConfig, ErrorHandler, GetNodeOptions } from './type';
|
||||||
import { transformStyle as defaultTransformStyle } from './utils';
|
import { transformStyle as defaultTransformStyle } from './utils';
|
||||||
|
|
||||||
class App extends EventEmitter {
|
class App extends EventEmitter {
|
||||||
@ -45,6 +45,7 @@ class App extends EventEmitter {
|
|||||||
public codeDsl?: CodeBlockDSL;
|
public codeDsl?: CodeBlockDSL;
|
||||||
public dataSourceManager?: DataSourceManager;
|
public dataSourceManager?: DataSourceManager;
|
||||||
public page?: Page;
|
public page?: Page;
|
||||||
|
public pageFragments: Map<Id, Page> = new Map();
|
||||||
public useMock = false;
|
public useMock = false;
|
||||||
public platform = 'mobile';
|
public platform = 'mobile';
|
||||||
public jsEngine: JsEngine = 'browser';
|
public jsEngine: JsEngine = 'browser';
|
||||||
@ -159,11 +160,20 @@ class App extends EventEmitter {
|
|||||||
|
|
||||||
super.emit('dsl-change', { dsl: config, curPage: pageId });
|
super.emit('dsl-change', { dsl: config, curPage: pageId });
|
||||||
|
|
||||||
|
this.pageFragments.forEach((page) => {
|
||||||
|
page.destroy();
|
||||||
|
});
|
||||||
|
this.pageFragments.clear();
|
||||||
this.setPage(pageId);
|
this.setPage(pageId);
|
||||||
|
|
||||||
if (this.dataSourceManager) {
|
if (this.dataSourceManager) {
|
||||||
const dataSourceList = Array.from(this.dataSourceManager.dataSourceMap.values());
|
if (this.dataSourceManager.isAllDataSourceRegistered()) {
|
||||||
this.eventHelper?.bindDataSourceEvents(dataSourceList);
|
this.eventHelper?.bindDataSourceEvents();
|
||||||
|
} else {
|
||||||
|
this.dataSourceManager.once('registered-all', () => {
|
||||||
|
this.eventHelper?.bindDataSourceEvents();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,6 +202,11 @@ class App extends EventEmitter {
|
|||||||
for (const [, node] of this.page.nodes) {
|
for (const [, node] of this.page.nodes) {
|
||||||
this.eventHelper.bindNodeEvents(node);
|
this.eventHelper.bindNodeEvents(node);
|
||||||
}
|
}
|
||||||
|
for (const [, page] of this.pageFragments) {
|
||||||
|
for (const [, node] of page.nodes) {
|
||||||
|
this.eventHelper.bindNodeEvents(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.emit('page-change', this.page);
|
super.emit('page-change', this.page);
|
||||||
@ -215,8 +230,8 @@ class App extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNode<T extends Node = Node>(id: Id, iteratorContainerId?: Id[], iteratorIndex?: number[]) {
|
public getNode<T extends Node = Node>(id: Id, options?: GetNodeOptions) {
|
||||||
return this.page?.getNode<T>(id, iteratorContainerId, iteratorIndex);
|
return this.page?.getNode<T>(id, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerComponent(type: string, Component: any) {
|
public registerComponent(type: string, Component: any) {
|
||||||
@ -249,15 +264,15 @@ class App extends EventEmitter {
|
|||||||
* @param eventConfig 代码动作的配置
|
* @param eventConfig 代码动作的配置
|
||||||
* @returns void
|
* @returns void
|
||||||
*/
|
*/
|
||||||
public async runCode(codeId: Id, params: Record<string, any>, args: any[], flowState?: FlowState) {
|
public async runCode(codeId: Id, params: Record<string, any>, args: any[], flowState?: FlowState, node?: Node) {
|
||||||
if (!codeId || isEmpty(this.codeDsl)) return;
|
if (!codeId || isEmpty(this.codeDsl)) return;
|
||||||
const content = this.codeDsl?.[codeId]?.content;
|
const content = this.codeDsl?.[codeId]?.content;
|
||||||
if (typeof content === 'function') {
|
if (typeof content === 'function') {
|
||||||
try {
|
try {
|
||||||
await content({ app: this, params, eventParams: args, flowState });
|
await content({ app: this, params, eventParams: args, flowState, node });
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (this.errorHandler) {
|
if (this.errorHandler) {
|
||||||
this.errorHandler(e, undefined, { type: 'run-code', codeId, params, eventParams: args, flowState });
|
this.errorHandler(e, undefined, { type: 'run-code', codeId, params, eventParams: args, flowState, node });
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -271,6 +286,7 @@ class App extends EventEmitter {
|
|||||||
params: Record<string, any>,
|
params: Record<string, any>,
|
||||||
args: any[],
|
args: any[],
|
||||||
flowState?: FlowState,
|
flowState?: FlowState,
|
||||||
|
node?: Node,
|
||||||
) {
|
) {
|
||||||
if (!dsId || !methodName) return;
|
if (!dsId || !methodName) return;
|
||||||
|
|
||||||
@ -278,28 +294,32 @@ class App extends EventEmitter {
|
|||||||
|
|
||||||
if (!dataSource) return;
|
if (!dataSource) return;
|
||||||
|
|
||||||
const methods = dataSource.methods || [];
|
try {
|
||||||
|
const methods = dataSource.methods || [];
|
||||||
|
|
||||||
const method = methods.find((item) => item.name === methodName);
|
const method = methods.find((item) => item.name === methodName);
|
||||||
|
if (method && typeof method.content === 'function') {
|
||||||
if (!method) return;
|
await method.content({ app: this, params, dataSource, eventParams: args, flowState, node });
|
||||||
|
} else if (typeof dataSource[methodName] === 'function') {
|
||||||
if (typeof method.content === 'function') {
|
await dataSource[methodName]();
|
||||||
try {
|
}
|
||||||
await method.content({ app: this, params, dataSource, eventParams: args, flowState });
|
} catch (e: any) {
|
||||||
} catch (e: any) {
|
if (this.errorHandler) {
|
||||||
if (this.errorHandler) {
|
this.errorHandler(e, dataSource, { type: 'data-source-method', params, eventParams: args, flowState, node });
|
||||||
this.errorHandler(e, dataSource, { type: 'data-source-method', params, eventParams: args, flowState });
|
} else {
|
||||||
} else {
|
throw e;
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
|
this.page?.destroy();
|
||||||
this.page = undefined;
|
this.page = undefined;
|
||||||
|
this.pageFragments.forEach((page) => {
|
||||||
|
page.destroy();
|
||||||
|
});
|
||||||
|
this.pageFragments.clear();
|
||||||
|
|
||||||
this.flexible?.destroy();
|
this.flexible?.destroy();
|
||||||
this.flexible = undefined;
|
this.flexible = undefined;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -31,6 +31,7 @@ import {
|
|||||||
type DataSourceItemConfig,
|
type DataSourceItemConfig,
|
||||||
type EventActionItem,
|
type EventActionItem,
|
||||||
type EventConfig,
|
type EventConfig,
|
||||||
|
Id,
|
||||||
NODE_DISABLE_CODE_BLOCK_KEY,
|
NODE_DISABLE_CODE_BLOCK_KEY,
|
||||||
NODE_DISABLE_DATA_SOURCE_KEY,
|
NODE_DISABLE_DATA_SOURCE_KEY,
|
||||||
} from '@tmagic/schema';
|
} from '@tmagic/schema';
|
||||||
@ -41,8 +42,17 @@ import FlowState from './FlowState';
|
|||||||
import type { default as TMagicNode } from './Node';
|
import type { default as TMagicNode } from './Node';
|
||||||
import { AfterEventHandler, BeforeEventHandler } from './type';
|
import { AfterEventHandler, BeforeEventHandler } from './type';
|
||||||
|
|
||||||
|
interface EventCache {
|
||||||
|
toId: Id;
|
||||||
|
method: string;
|
||||||
|
fromCpt: any;
|
||||||
|
args: any[];
|
||||||
|
handled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export default class EventHelper extends EventEmitter {
|
export default class EventHelper extends EventEmitter {
|
||||||
public app: TMagicApp;
|
public app: TMagicApp;
|
||||||
|
public eventQueue: EventCache[] = [];
|
||||||
|
|
||||||
private nodeEventList = new Map<(fromCpt: TMagicNode, ...args: any[]) => void, symbol>();
|
private nodeEventList = new Map<(fromCpt: TMagicNode, ...args: any[]) => void, symbol>();
|
||||||
private dataSourceEventList = new Map<string, Map<string, (...args: any[]) => void>>();
|
private dataSourceEventList = new Map<string, Map<string, (...args: any[]) => void>>();
|
||||||
@ -103,21 +113,23 @@ export default class EventHelper extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public removeNodeEvents() {
|
public removeNodeEvents() {
|
||||||
Array.from(this.nodeEventList.keys()).forEach((handler) => {
|
for (const handler of Array.from(this.nodeEventList.keys())) {
|
||||||
const name = this.nodeEventList.get(handler);
|
const name = this.nodeEventList.get(handler);
|
||||||
name && this.off(name, handler);
|
name && this.off(name, handler);
|
||||||
});
|
}
|
||||||
|
|
||||||
this.nodeEventList.clear();
|
this.nodeEventList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bindDataSourceEvents(dataSourceList: DataSource[]) {
|
public bindDataSourceEvents() {
|
||||||
|
const dataSourceList = Array.from(this.app.dataSourceManager?.dataSourceMap.values() || []);
|
||||||
|
|
||||||
this.removeDataSourceEvents(dataSourceList);
|
this.removeDataSourceEvents(dataSourceList);
|
||||||
|
|
||||||
dataSourceList.forEach((dataSource) => {
|
for (const dataSource of dataSourceList) {
|
||||||
const dataSourceEvent = this.dataSourceEventList.get(dataSource.id) ?? new Map<string, (args: any) => void>();
|
const dataSourceEvent = this.dataSourceEventList.get(dataSource.id) ?? new Map<string, (args: any) => void>();
|
||||||
|
|
||||||
(dataSource.schema.events || []).forEach((event) => {
|
for (const event of dataSource.schema.events || []) {
|
||||||
const [prefix, ...path] = event.name?.split('.') || [];
|
const [prefix, ...path] = event.name?.split('.') || [];
|
||||||
if (!prefix) return;
|
if (!prefix) return;
|
||||||
const handler = (...args: any[]) => {
|
const handler = (...args: any[]) => {
|
||||||
@ -131,9 +143,9 @@ export default class EventHelper extends EventEmitter {
|
|||||||
// 数据源自定义事件
|
// 数据源自定义事件
|
||||||
dataSource.on(prefix, handler);
|
dataSource.on(prefix, handler);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
this.dataSourceEventList.set(dataSource.id, dataSourceEvent);
|
this.dataSourceEventList.set(dataSource.id, dataSourceEvent);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeDataSourceEvents(dataSourceList: DataSource[]) {
|
public removeDataSourceEvents(dataSourceList: DataSource[]) {
|
||||||
@ -142,24 +154,32 @@ export default class EventHelper extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 先清掉之前注册的事件,重新注册
|
// 先清掉之前注册的事件,重新注册
|
||||||
dataSourceList.forEach((dataSource) => {
|
for (const dataSource of dataSourceList) {
|
||||||
const dataSourceEvent = this.dataSourceEventList.get(dataSource.id)!;
|
const dataSourceEvent = this.dataSourceEventList.get(dataSource.id)!;
|
||||||
|
|
||||||
if (!dataSourceEvent) return;
|
if (!dataSourceEvent) return;
|
||||||
|
|
||||||
Array.from(dataSourceEvent.keys()).forEach((eventName) => {
|
for (const eventName of Array.from(dataSourceEvent.keys())) {
|
||||||
const [prefix, ...path] = eventName.split('.');
|
const [prefix, ...path] = eventName.split('.');
|
||||||
if (prefix === DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX) {
|
if (prefix === DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX) {
|
||||||
dataSource.offDataChange(path.join('.'), dataSourceEvent.get(eventName)!);
|
dataSource.offDataChange(path.join('.'), dataSourceEvent.get(eventName)!);
|
||||||
} else {
|
} else {
|
||||||
dataSource.off(prefix, dataSourceEvent.get(eventName)!);
|
dataSource.off(prefix, dataSourceEvent.get(eventName)!);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
this.dataSourceEventList.clear();
|
this.dataSourceEventList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getEventQueue() {
|
||||||
|
return this.eventQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addEventToQueue(event: EventCache) {
|
||||||
|
this.eventQueue.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件联动处理函数
|
* 事件联动处理函数
|
||||||
* @param eventsConfigIndex 事件配置索引,可以通过此索引从node.event中获取最新事件配置
|
* @param eventsConfigIndex 事件配置索引,可以通过此索引从node.event中获取最新事件配置
|
||||||
@ -182,9 +202,9 @@ export default class EventHelper extends EventEmitter {
|
|||||||
if (typeof config === 'number') {
|
if (typeof config === 'number') {
|
||||||
// 事件响应中可能会有修改数据源数据的,会更新dsl,所以这里需要重新获取
|
// 事件响应中可能会有修改数据源数据的,会更新dsl,所以这里需要重新获取
|
||||||
const actionItem = ((fromCpt as TMagicNode).events[config] as EventConfig).actions[i];
|
const actionItem = ((fromCpt as TMagicNode).events[config] as EventConfig).actions[i];
|
||||||
this.actionHandler(actionItem, fromCpt as TMagicNode, args, flowState);
|
await this.actionHandler(actionItem, fromCpt as TMagicNode, args, flowState);
|
||||||
} else {
|
} else {
|
||||||
this.actionHandler(actions[i], fromCpt as DataSource, args, flowState);
|
await this.actionHandler(actions[i], fromCpt as DataSource, args, flowState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flowState.reset();
|
flowState.reset();
|
||||||
@ -258,19 +278,44 @@ export default class EventHelper extends EventEmitter {
|
|||||||
[to, methodName] = methodName;
|
[to, methodName] = methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toNodes = [];
|
||||||
const toNode = this.app.getNode(to);
|
const toNode = this.app.getNode(to);
|
||||||
if (!toNode) throw new Error(`ID为${to}的组件不存在`);
|
if (toNode) {
|
||||||
|
toNodes.push(toNode);
|
||||||
|
}
|
||||||
|
|
||||||
if (toNode.instance) {
|
for (const [, page] of this.app.pageFragments) {
|
||||||
if (typeof toNode.instance[methodName] === 'function') {
|
const node = page.getNode(to);
|
||||||
await toNode.instance[methodName](fromCpt, ...args);
|
if (node) {
|
||||||
|
toNodes.push(node);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
toNode.addEventToQueue({
|
|
||||||
|
if (toNodes.length === 0) {
|
||||||
|
this.addEventToQueue({
|
||||||
|
toId: to,
|
||||||
method: methodName,
|
method: methodName,
|
||||||
fromCpt,
|
fromCpt,
|
||||||
args,
|
args,
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const instanceMethodPropmise = [];
|
||||||
|
for (const node of toNodes) {
|
||||||
|
if (node.instance) {
|
||||||
|
if (typeof node.instance[methodName] === 'function') {
|
||||||
|
instanceMethodPropmise.push(node.instance[methodName](fromCpt, ...args));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.addEventToQueue({
|
||||||
|
method: methodName,
|
||||||
|
fromCpt,
|
||||||
|
args,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(instanceMethodPropmise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
import { DataSource } from '@tmagic/data-source';
|
|
||||||
import type { EventConfig, MNode } from '@tmagic/schema';
|
import type { EventConfig, MNode } from '@tmagic/schema';
|
||||||
import { HookCodeType, HookType, NODE_DISABLE_CODE_BLOCK_KEY } from '@tmagic/schema';
|
import { HookCodeType, HookType, NODE_DISABLE_CODE_BLOCK_KEY } from '@tmagic/schema';
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ class Node extends EventEmitter {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
public events: EventConfig[] = [];
|
public events: EventConfig[] = [];
|
||||||
public instance?: any = {};
|
public instance?: any = null;
|
||||||
public page?: Page;
|
public page?: Page;
|
||||||
public parent?: Node;
|
public parent?: Node;
|
||||||
public app: TMagicApp;
|
public app: TMagicApp;
|
||||||
@ -75,7 +74,14 @@ class Node extends EventEmitter {
|
|||||||
this.events = events || [];
|
this.events = events || [];
|
||||||
this.style = style || {};
|
this.style = style || {};
|
||||||
try {
|
try {
|
||||||
this.instance.config = data;
|
if (
|
||||||
|
this.instance &&
|
||||||
|
!Object.isFrozen(this.instance) &&
|
||||||
|
Object.getOwnPropertyDescriptor(this.instance, 'config')?.writable !== false &&
|
||||||
|
!this.instance.__isVue
|
||||||
|
) {
|
||||||
|
this.instance.config = data;
|
||||||
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
} catch (e: any) {}
|
} catch (e: any) {}
|
||||||
|
|
||||||
@ -134,23 +140,10 @@ class Node extends EventEmitter {
|
|||||||
for (const item of hookData.hookData) {
|
for (const item of hookData.hookData) {
|
||||||
const { codeType = HookCodeType.CODE, codeId, params: itemParams = {} } = item;
|
const { codeType = HookCodeType.CODE, codeId, params: itemParams = {} } = item;
|
||||||
|
|
||||||
let functionContent: ((...args: any[]) => any) | string | undefined;
|
if (codeType === HookCodeType.CODE && typeof codeId === 'string') {
|
||||||
const functionParams: { app: TMagicApp; node: Node; params: Record<string, any>; dataSource?: DataSource } = {
|
await this.app.runCode(codeId, params || itemParams, [], undefined, this);
|
||||||
app: this.app,
|
|
||||||
node: this,
|
|
||||||
params: params || itemParams,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (codeType === HookCodeType.CODE && typeof codeId === 'string' && this.app.codeDsl?.[codeId]) {
|
|
||||||
functionContent = this.app.codeDsl[codeId].content;
|
|
||||||
} else if (codeType === HookCodeType.DATA_SOURCE_METHOD && Array.isArray(codeId) && codeId.length > 1) {
|
} else if (codeType === HookCodeType.DATA_SOURCE_METHOD && Array.isArray(codeId) && codeId.length > 1) {
|
||||||
const dataSource = this.app.dataSourceManager?.get(codeId[0]);
|
await this.app.runDataSourceMethod(codeId[0], codeId[1], params || itemParams, [], undefined, this);
|
||||||
functionContent = dataSource?.methods.find((method) => method.name === codeId[1])?.content;
|
|
||||||
functionParams.dataSource = dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (functionContent && typeof functionContent === 'function') {
|
|
||||||
await functionContent(functionParams);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,6 +188,25 @@ class Node extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.app.eventHelper) {
|
||||||
|
for (const eventConfig of this.app.eventHelper.getEventQueue()) {
|
||||||
|
for (const [, page] of this.app.pageFragments) {
|
||||||
|
const node = page.getNode(eventConfig.toId);
|
||||||
|
if (node && node === this) {
|
||||||
|
if (typeof instance[eventConfig.method] === 'function') {
|
||||||
|
await instance[eventConfig.method](eventConfig.fromCpt, ...eventConfig.args);
|
||||||
|
}
|
||||||
|
|
||||||
|
eventConfig.handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.app.eventHelper.eventQueue = this.app.eventHelper
|
||||||
|
.getEventQueue()
|
||||||
|
.filter((eventConfig) => !eventConfig.handled);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.data[NODE_DISABLE_CODE_BLOCK_KEY] !== true) {
|
if (this.data[NODE_DISABLE_CODE_BLOCK_KEY] !== true) {
|
||||||
this.runHookCode('mounted');
|
this.runHookCode('mounted');
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -22,6 +22,7 @@ import App from './App';
|
|||||||
import IteratorContainer from './IteratorContainer';
|
import IteratorContainer from './IteratorContainer';
|
||||||
import type { default as TMagicNode } from './Node';
|
import type { default as TMagicNode } from './Node';
|
||||||
import Node from './Node';
|
import Node from './Node';
|
||||||
|
import { GetNodeOptions } from './type';
|
||||||
interface ConfigOptions {
|
interface ConfigOptions {
|
||||||
config: MPage | MPageFragment;
|
config: MPage | MPageFragment;
|
||||||
app: App;
|
app: App;
|
||||||
@ -64,8 +65,15 @@ class Page extends Node {
|
|||||||
|
|
||||||
if (config.type && this.app.pageFragmentContainerType.has(config.type) && config.pageFragmentId) {
|
if (config.type && this.app.pageFragmentContainerType.has(config.type) && config.pageFragmentId) {
|
||||||
const pageFragment = this.app.dsl?.items?.find((page) => page.id === config.pageFragmentId);
|
const pageFragment = this.app.dsl?.items?.find((page) => page.id === config.pageFragmentId);
|
||||||
|
|
||||||
if (pageFragment) {
|
if (pageFragment) {
|
||||||
config.items = [pageFragment];
|
this.app.pageFragments.set(
|
||||||
|
config.id,
|
||||||
|
new Page({
|
||||||
|
config: pageFragment,
|
||||||
|
app: this.app,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,13 +84,16 @@ class Page extends Node {
|
|||||||
|
|
||||||
public getNode<T extends TMagicNode = TMagicNode>(
|
public getNode<T extends TMagicNode = TMagicNode>(
|
||||||
id: Id,
|
id: Id,
|
||||||
iteratorContainerId?: Id[],
|
{ iteratorContainerId, iteratorIndex, pageFragmentContainerId }: GetNodeOptions = {},
|
||||||
iteratorIndex?: number[],
|
|
||||||
): T | undefined {
|
): T | undefined {
|
||||||
if (this.nodes.has(id)) {
|
if (this.nodes.has(id)) {
|
||||||
return this.nodes.get(id) as T;
|
return this.nodes.get(id) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pageFragmentContainerId) {
|
||||||
|
return this.app.pageFragments.get(pageFragmentContainerId)?.getNode(id, { iteratorContainerId, iteratorIndex });
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(iteratorContainerId) && iteratorContainerId.length && Array.isArray(iteratorIndex)) {
|
if (Array.isArray(iteratorContainerId) && iteratorContainerId.length && Array.isArray(iteratorIndex)) {
|
||||||
let iteratorContainer = this.nodes.get(iteratorContainerId[0]) as IteratorContainer;
|
let iteratorContainer = this.nodes.get(iteratorContainerId[0]) as IteratorContainer;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -43,3 +43,9 @@ export type AfterEventHandler = (args: {
|
|||||||
source: TMagicNode | DataSource | undefined;
|
source: TMagicNode | DataSource | undefined;
|
||||||
args: any[];
|
args: any[];
|
||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
|
export interface GetNodeOptions {
|
||||||
|
iteratorContainerId?: Id[];
|
||||||
|
iteratorIndex?: number[];
|
||||||
|
pageFragmentContainerId?: Id;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -168,15 +168,21 @@ describe('App', () => {
|
|||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(app.getNode('text', ['iterator-container_1'], [0])?.data.text).toBe('1');
|
expect(app.getNode('text', { iteratorContainerId: ['iterator-container_1'], iteratorIndex: [0] })?.data.text).toBe(
|
||||||
expect(app.getNode('text', ['iterator-container_1'], [1])?.data.text).toBe('2');
|
'1',
|
||||||
expect(app.getNode('text_page_fragment', ['iterator-container_1'], [0])?.data.text).toBe('text_page_fragment');
|
);
|
||||||
|
expect(app.getNode('text', { iteratorContainerId: ['iterator-container_1'], iteratorIndex: [1] })?.data.text).toBe(
|
||||||
|
'2',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
app.getNode('text_page_fragment', { iteratorContainerId: ['iterator-container_1'], iteratorIndex: [0] })?.data
|
||||||
|
.text,
|
||||||
|
).toBe('text_page_fragment');
|
||||||
|
|
||||||
const ic1 = app.getNode(
|
const ic1 = app.getNode('iterator-container_11', {
|
||||||
'iterator-container_11',
|
iteratorContainerId: ['iterator-container_1'],
|
||||||
['iterator-container_1'],
|
iteratorIndex: [0],
|
||||||
[0],
|
}) as unknown as TMagicIteratorContainer;
|
||||||
) as unknown as TMagicIteratorContainer;
|
|
||||||
|
|
||||||
ic1?.setNodes(
|
ic1?.setNodes(
|
||||||
[
|
[
|
||||||
@ -200,11 +206,10 @@ describe('App', () => {
|
|||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
const ic2 = app.getNode(
|
const ic2 = app.getNode('iterator-container_11', {
|
||||||
'iterator-container_11',
|
iteratorContainerId: ['iterator-container_1'],
|
||||||
['iterator-container_1'],
|
iteratorIndex: [1],
|
||||||
[1],
|
}) as unknown as TMagicIteratorContainer;
|
||||||
) as unknown as TMagicIteratorContainer;
|
|
||||||
|
|
||||||
ic2?.setNodes(
|
ic2?.setNodes(
|
||||||
[
|
[
|
||||||
@ -228,10 +233,30 @@ describe('App', () => {
|
|||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(app.getNode('text', ['iterator-container_1', 'iterator-container_11'], [0, 0])?.data.text).toBe('111');
|
expect(
|
||||||
expect(app.getNode('text', ['iterator-container_1', 'iterator-container_11'], [0, 1])?.data.text).toBe('222');
|
app.getNode('text', {
|
||||||
expect(app.getNode('text', ['iterator-container_1', 'iterator-container_11'], [1, 0])?.data.text).toBe('11');
|
iteratorContainerId: ['iterator-container_1', 'iterator-container_11'],
|
||||||
expect(app.getNode('text', ['iterator-container_1', 'iterator-container_11'], [1, 1])?.data.text).toBe('22');
|
iteratorIndex: [0, 0],
|
||||||
|
})?.data.text,
|
||||||
|
).toBe('111');
|
||||||
|
expect(
|
||||||
|
app.getNode('text', {
|
||||||
|
iteratorContainerId: ['iterator-container_1', 'iterator-container_11'],
|
||||||
|
iteratorIndex: [0, 1],
|
||||||
|
})?.data.text,
|
||||||
|
).toBe('222');
|
||||||
|
expect(
|
||||||
|
app.getNode('text', {
|
||||||
|
iteratorContainerId: ['iterator-container_1', 'iterator-container_11'],
|
||||||
|
iteratorIndex: [1, 0],
|
||||||
|
})?.data.text,
|
||||||
|
).toBe('11');
|
||||||
|
expect(
|
||||||
|
app.getNode('text', {
|
||||||
|
iteratorContainerId: ['iterator-container_1', 'iterator-container_11'],
|
||||||
|
iteratorIndex: [1, 1],
|
||||||
|
})?.data.text,
|
||||||
|
).toBe('22');
|
||||||
|
|
||||||
ic.resetNodes();
|
ic.resetNodes();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/data-source",
|
"name": "@tmagic/data-source",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/tmagic-data-source.umd.cjs",
|
"main": "dist/tmagic-data-source.umd.cjs",
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -22,7 +22,13 @@ import EventEmitter from 'events';
|
|||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
import type { DataSourceSchema, default as TMagicApp, DisplayCond, Id, MNode } from '@tmagic/core';
|
import type { DataSourceSchema, default as TMagicApp, DisplayCond, Id, MNode } from '@tmagic/core';
|
||||||
import { compiledNode, getDefaultValueFromFields, NODE_CONDS_KEY, NODE_DISABLE_DATA_SOURCE_KEY } from '@tmagic/core';
|
import {
|
||||||
|
compiledNode,
|
||||||
|
getDefaultValueFromFields,
|
||||||
|
NODE_CONDS_KEY,
|
||||||
|
NODE_CONDS_RESULT_KEY,
|
||||||
|
NODE_DISABLE_DATA_SOURCE_KEY,
|
||||||
|
} from '@tmagic/core';
|
||||||
|
|
||||||
import { SimpleObservedData } from './observed-data/SimpleObservedData';
|
import { SimpleObservedData } from './observed-data/SimpleObservedData';
|
||||||
import { DataSource, HttpDataSource } from './data-sources';
|
import { DataSource, HttpDataSource } from './data-sources';
|
||||||
@ -238,8 +244,9 @@ class DataSourceManager extends EventEmitter {
|
|||||||
Array.isArray(items) && deep ? items.map((item) => this.compiledNode(item, sourceId, deep)) : items;
|
Array.isArray(items) && deep ? items.map((item) => this.compiledNode(item, sourceId, deep)) : items;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.condResult === false) return newNode;
|
if (node.condResult === false || (typeof node.condResult === 'undefined' && node[NODE_CONDS_RESULT_KEY])) {
|
||||||
if (node.visible === false) return newNode;
|
return newNode;
|
||||||
|
}
|
||||||
|
|
||||||
// 编译函数这里作为参数,方便后续支持自定义编译
|
// 编译函数这里作为参数,方便后续支持自定义编译
|
||||||
return compiledNode(
|
return compiledNode(
|
||||||
@ -255,11 +262,24 @@ class DataSourceManager extends EventEmitter {
|
|||||||
* @param {{ [NODE_CONDS_KEY]?: DisplayCond[] }} node 显示条件组配置
|
* @param {{ [NODE_CONDS_KEY]?: DisplayCond[] }} node 显示条件组配置
|
||||||
* @returns {boolean} 是否显示
|
* @returns {boolean} 是否显示
|
||||||
*/
|
*/
|
||||||
public compliedConds(node: { [NODE_CONDS_KEY]?: DisplayCond[]; [NODE_DISABLE_DATA_SOURCE_KEY]?: boolean }) {
|
public compliedConds(
|
||||||
|
node: {
|
||||||
|
[NODE_CONDS_KEY]?: DisplayCond[];
|
||||||
|
[NODE_CONDS_RESULT_KEY]?: boolean;
|
||||||
|
[NODE_DISABLE_DATA_SOURCE_KEY]?: boolean;
|
||||||
|
},
|
||||||
|
data = this.data,
|
||||||
|
) {
|
||||||
if (node[NODE_DISABLE_DATA_SOURCE_KEY]) {
|
if (node[NODE_DISABLE_DATA_SOURCE_KEY]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return compliedConditions(node, this.data);
|
|
||||||
|
const result = compliedConditions(node, data);
|
||||||
|
|
||||||
|
if (!node[NODE_CONDS_RESULT_KEY]) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return !result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -271,7 +291,11 @@ class DataSourceManager extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
public compliedIteratorItemConds(
|
public compliedIteratorItemConds(
|
||||||
itemData: any,
|
itemData: any,
|
||||||
node: { [NODE_CONDS_KEY]?: DisplayCond[] },
|
node: {
|
||||||
|
[NODE_CONDS_KEY]?: DisplayCond[];
|
||||||
|
[NODE_CONDS_RESULT_KEY]?: boolean;
|
||||||
|
[NODE_DISABLE_DATA_SOURCE_KEY]?: boolean;
|
||||||
|
},
|
||||||
dataSourceField: string[] = [],
|
dataSourceField: string[] = [],
|
||||||
) {
|
) {
|
||||||
const [dsId, ...keys] = dataSourceField;
|
const [dsId, ...keys] = dataSourceField;
|
||||||
@ -279,7 +303,7 @@ class DataSourceManager extends EventEmitter {
|
|||||||
if (!ds) return true;
|
if (!ds) return true;
|
||||||
|
|
||||||
const ctxData = createIteratorContentData(itemData, ds.id, keys, this.data);
|
const ctxData = createIteratorContentData(itemData, ds.id, keys, this.data);
|
||||||
return compliedConditions(node, ctxData);
|
return this.compliedConds(node, ctxData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public compliedIteratorItems(itemData: any, nodes: MNode[], dataSourceField: string[] = []): MNode[] {
|
public compliedIteratorItems(itemData: any, nodes: MNode[], dataSourceField: string[] = []): MNode[] {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -18,7 +18,7 @@
|
|||||||
import { union } from 'lodash-es';
|
import { union } from 'lodash-es';
|
||||||
|
|
||||||
import type { default as TMagicApp } from '@tmagic/core';
|
import type { default as TMagicApp } from '@tmagic/core';
|
||||||
import { getDepNodeIds, getNodes, isPage } from '@tmagic/core';
|
import { getDepNodeIds, getNodes, isPage, isPageFragment, replaceChildNode } from '@tmagic/core';
|
||||||
|
|
||||||
import DataSourceManager from './DataSourceManager';
|
import DataSourceManager from './DataSourceManager';
|
||||||
import type { ChangeEvent, DataSourceManagerData } from './types';
|
import type { ChangeEvent, DataSourceManagerData } from './types';
|
||||||
@ -52,18 +52,19 @@ export const createDataSourceManager = (app: TMagicApp, useMock?: boolean, initi
|
|||||||
|
|
||||||
// ssr环境下,数据应该是提前准备好的(放到initialData中),不应该发生变化,无需监听
|
// ssr环境下,数据应该是提前准备好的(放到initialData中),不应该发生变化,无需监听
|
||||||
// 有initialData不一定是在ssr环境下
|
// 有initialData不一定是在ssr环境下
|
||||||
if (app.jsEngine !== 'nodejs') {
|
if (app.jsEngine === 'nodejs') {
|
||||||
dataSourceManager.on('change', (sourceId: string, changeEvent: ChangeEvent) => {
|
return dataSourceManager;
|
||||||
const dep = dsl.dataSourceDeps?.[sourceId] || {};
|
}
|
||||||
const condDep = dsl.dataSourceCondDeps?.[sourceId] || {};
|
|
||||||
|
|
||||||
const nodeIds = union([...Object.keys(condDep), ...Object.keys(dep)]);
|
dataSourceManager.on('change', (sourceId: string, changeEvent: ChangeEvent) => {
|
||||||
|
const dep = dsl.dataSourceDeps?.[sourceId] || {};
|
||||||
|
const condDep = dsl.dataSourceCondDeps?.[sourceId] || {};
|
||||||
|
|
||||||
const pages = app.page?.data && app.platform !== 'editor' ? [app.page.data] : dsl.items;
|
const nodeIds = union([...Object.keys(condDep), ...Object.keys(dep)]);
|
||||||
|
|
||||||
dataSourceManager.emit(
|
for (const page of dsl.items) {
|
||||||
'update-data',
|
if (app.platform === 'editor' || (isPage(page) && page.id === app.page?.data.id) || isPageFragment(page)) {
|
||||||
getNodes(nodeIds, pages).map((node) => {
|
const newNodes = getNodes(nodeIds, [page]).map((node) => {
|
||||||
if (app.platform !== 'editor') {
|
if (app.platform !== 'editor') {
|
||||||
node.condResult = dataSourceManager.compliedConds(node);
|
node.condResult = dataSourceManager.compliedConds(node);
|
||||||
}
|
}
|
||||||
@ -73,19 +74,33 @@ export const createDataSourceManager = (app: TMagicApp, useMock?: boolean, initi
|
|||||||
if (typeof app.page?.setData === 'function') {
|
if (typeof app.page?.setData === 'function') {
|
||||||
if (isPage(newNode)) {
|
if (isPage(newNode)) {
|
||||||
app.page.setData(newNode);
|
app.page.setData(newNode);
|
||||||
} else {
|
} else if (page.id === app.page.data.id && !app.page.instance) {
|
||||||
const n = app.page.getNode(node.id);
|
replaceChildNode(newNode, [app.page.data]);
|
||||||
n?.setData(newNode);
|
}
|
||||||
|
|
||||||
|
app.getNode(node.id)?.setData(newNode);
|
||||||
|
|
||||||
|
for (const [, pageFragment] of app.pageFragments) {
|
||||||
|
if (pageFragment.data.id === newNode.id) {
|
||||||
|
pageFragment.setData(newNode);
|
||||||
|
} else if (pageFragment.data.id === page.id) {
|
||||||
|
pageFragment.getNode(newNode.id)?.setData(newNode);
|
||||||
|
if (!pageFragment.instance) {
|
||||||
|
replaceChildNode(newNode, [pageFragment.data]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newNode;
|
return newNode;
|
||||||
}),
|
});
|
||||||
sourceId,
|
|
||||||
changeEvent,
|
if (newNodes.length) {
|
||||||
);
|
dataSourceManager.emit('update-data', newNodes, sourceId, changeEvent, page.id);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return dataSourceManager;
|
return dataSourceManager;
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -23,9 +23,9 @@ export class DeepObservedData extends ObservedData {
|
|||||||
update = (data: any, path?: string) => {
|
update = (data: any, path?: string) => {
|
||||||
this.state?.update(path ?? '', data);
|
this.state?.update(path ?? '', data);
|
||||||
};
|
};
|
||||||
on = (path: string, callback: (newVal: any) => void) => {
|
on = (path: string, callback: (newVal: any) => void, options?: { immediate?: boolean }) => {
|
||||||
// subscribe 会立即执行一次,ignoreFirstCall 会忽略第一次执行
|
// subscribe 会立即执行一次,ignoreFirstCall 会忽略第一次执行
|
||||||
const unsubscribe = this.state!.subscribe(path, ignoreFirstCall(callback));
|
const unsubscribe = this.state!.subscribe(path, options?.immediate ? callback : ignoreFirstCall(callback));
|
||||||
|
|
||||||
// 把取消监听的函数保存下来,供 off 时调用
|
// 把取消监听的函数保存下来,供 off 时调用
|
||||||
const pathSubscribers = this.subscribers.get(path) ?? new Map<Function, () => void>();
|
const pathSubscribers = this.subscribers.get(path) ?? new Map<Function, () => void>();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export abstract class ObservedData {
|
export abstract class ObservedData {
|
||||||
abstract update(data: any, path?: string): void;
|
abstract update(data: any, path?: string): void;
|
||||||
|
|
||||||
abstract on(path: string, callback: (newVal: any) => void): void;
|
abstract on(path: string, callback: (newVal: any) => void, options?: { immediate?: boolean }): void;
|
||||||
|
|
||||||
abstract off(path: string, callback: (newVal: any) => void): void;
|
abstract off(path: string, callback: (newVal: any) => void): void;
|
||||||
|
|
||||||
|
@ -32,7 +32,10 @@ export class SimpleObservedData extends ObservedData {
|
|||||||
this.event.emit('', changeEvent);
|
this.event.emit('', changeEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
on(path: string, callback: (newVal: any) => void): void {
|
on(path: string, callback: (newVal: any) => void, options?: { immediate?: boolean }): void {
|
||||||
|
if (options?.immediate) {
|
||||||
|
callback(this.getData(path));
|
||||||
|
}
|
||||||
this.event.on(path, callback);
|
this.event.on(path, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/dep",
|
"name": "@tmagic/dep",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/tmagic-dep.umd.cjs",
|
"main": "dist/tmagic-dep.umd.cjs",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/design",
|
"name": "@tmagic/design",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": [
|
"sideEffects": [
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/editor",
|
"name": "@tmagic/editor",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": [
|
"sideEffects": [
|
||||||
|
@ -129,7 +129,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
import { provide, watch } from 'vue';
|
import { provide } from 'vue';
|
||||||
|
|
||||||
import type { MApp } from '@tmagic/core';
|
import type { MApp } from '@tmagic/core';
|
||||||
|
|
||||||
@ -211,22 +211,6 @@ const stageOptions: StageOptions = {
|
|||||||
|
|
||||||
stageOverlayService.set('stageOptions', stageOptions);
|
stageOverlayService.set('stageOptions', stageOptions);
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.runtimeUrl,
|
|
||||||
(url) => {
|
|
||||||
if (!url) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stage = editorService.get('stage');
|
|
||||||
if (!stage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stage.reloadIframe(url);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
provide('services', services);
|
provide('services', services);
|
||||||
|
|
||||||
provide('codeOptions', props.codeOptions);
|
provide('codeOptions', props.codeOptions);
|
||||||
|
@ -3,9 +3,8 @@ import type { FormConfig, FormState } from '@tmagic/form';
|
|||||||
import StageCore, {
|
import StageCore, {
|
||||||
CONTAINER_HIGHLIGHT_CLASS_NAME,
|
CONTAINER_HIGHLIGHT_CLASS_NAME,
|
||||||
ContainerHighlightType,
|
ContainerHighlightType,
|
||||||
type CustomizeMoveableOptionsCallbackConfig,
|
type CustomizeMoveableOptions,
|
||||||
type GuidesOptions,
|
type GuidesOptions,
|
||||||
type MoveableOptions,
|
|
||||||
RenderType,
|
RenderType,
|
||||||
type UpdateDragEl,
|
type UpdateDragEl,
|
||||||
} from '@tmagic/stage';
|
} from '@tmagic/stage';
|
||||||
@ -56,7 +55,7 @@ export interface EditorProps {
|
|||||||
datasourceConfigs?: Record<string, FormConfig>;
|
datasourceConfigs?: Record<string, FormConfig>;
|
||||||
datasourceEventMethodList?: Record<string, { events: EventOption[]; methods: EventOption[] }>;
|
datasourceEventMethodList?: Record<string, { events: EventOption[]; methods: EventOption[] }>;
|
||||||
/** 画布中组件选中框的移动范围 */
|
/** 画布中组件选中框的移动范围 */
|
||||||
moveableOptions?: MoveableOptions | ((config?: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions);
|
moveableOptions?: CustomizeMoveableOptions;
|
||||||
/** 编辑器初始化时默认选中的组件ID */
|
/** 编辑器初始化时默认选中的组件ID */
|
||||||
defaultSelected?: Id;
|
defaultSelected?: Id;
|
||||||
/** 拖入画布中容器时,识别到容器后给容器根dom加上的class */
|
/** 拖入画布中容器时,识别到容器后给容器根dom加上的class */
|
||||||
@ -127,7 +126,7 @@ export const defaultEditorProps = {
|
|||||||
eventMethodList: () => ({}),
|
eventMethodList: () => ({}),
|
||||||
datasourceValues: () => ({}),
|
datasourceValues: () => ({}),
|
||||||
datasourceConfigs: () => ({}),
|
datasourceConfigs: () => ({}),
|
||||||
canSelect: (el: HTMLElement) => Boolean(getIdFromEl()(el)),
|
canSelect: (el: HTMLElement) => Boolean(getIdFromEl()(el) && !el.dataset.tmagicPageFragmentContainerId),
|
||||||
isContainer: (el: HTMLElement) => el.classList.contains('magic-ui-container'),
|
isContainer: (el: HTMLElement) => el.classList.contains('magic-ui-container'),
|
||||||
codeOptions: () => ({}),
|
codeOptions: () => ({}),
|
||||||
customContentMenu: (menus: (MenuButton | MenuComponent)[]) => menus,
|
customContentMenu: (menus: (MenuButton | MenuComponent)[]) => menus,
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
content="选择数据源"
|
content="选择数据源"
|
||||||
>
|
>
|
||||||
<TMagicButton
|
<TMagicButton
|
||||||
style="margin-left: 5px"
|
|
||||||
:type="showDataSourceFieldSelect ? 'primary' : 'default'"
|
:type="showDataSourceFieldSelect ? 'primary' : 'default'"
|
||||||
:size="size"
|
:size="size"
|
||||||
@click="showDataSourceFieldSelect = !showDataSourceFieldSelect"
|
@click="showDataSourceFieldSelect = !showDataSourceFieldSelect"
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="m-fields-style-setter">
|
<TMagicCollapse class="m-fields-style-setter" :model-value="collapseValue">
|
||||||
<TMagicCollapse :model-value="collapseValue">
|
<template v-for="(item, index) in list" :key="index">
|
||||||
<template v-for="(item, index) in list" :key="index">
|
<TMagicCollapseItem :name="`${index}`">
|
||||||
<TMagicCollapseItem :name="`${index}`">
|
<template #title><MIcon :icon="Grid"></MIcon>{{ item.title }}</template>
|
||||||
<template #title><MIcon :icon="Grid"></MIcon>{{ item.title }}</template>
|
<component
|
||||||
<component v-if="item.component" :is="item.component" :values="model[name]" @change="change"></component>
|
v-if="item.component"
|
||||||
</TMagicCollapseItem>
|
:is="item.component"
|
||||||
</template>
|
:values="model[name]"
|
||||||
</TMagicCollapse>
|
:size="size"
|
||||||
</div>
|
:disabled="disabled"
|
||||||
|
@change="change"
|
||||||
|
></component>
|
||||||
|
</TMagicCollapseItem>
|
||||||
|
</template>
|
||||||
|
</TMagicCollapse>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -6,13 +6,21 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
link
|
link
|
||||||
:class="model[name] === item.value && 'btn-active'"
|
:class="model[name] === item.value && 'btn-active'"
|
||||||
|
:disabled="disabled"
|
||||||
@click="changeHandler(item.value)"
|
@click="changeHandler(item.value)"
|
||||||
>
|
>
|
||||||
<div :class="['position-icon', item.class, model[name] === item.value && 'active']"></div>
|
<div :class="['position-icon', item.class, model[name] === item.value && 'active']"></div>
|
||||||
</TMagicButton>
|
</TMagicButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="custom-value">
|
<div class="custom-value">
|
||||||
<TMagicInput v-model="model[name]" size="small" placeholder="自定义背景位置" clearable @change="changeHandler">
|
<TMagicInput
|
||||||
|
v-model="model[name]"
|
||||||
|
placeholder="自定义背景位置"
|
||||||
|
clearable
|
||||||
|
:size="size"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="changeHandler"
|
||||||
|
>
|
||||||
</TMagicInput>
|
</TMagicInput>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-value-container">
|
<div class="border-value-container">
|
||||||
<MContainer :config="config" :model="model" @change="change"></MContainer>
|
<MContainer :config="config" :model="model" :size="size" :disabled="disabled" @change="change"></MContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -67,7 +67,6 @@ const config = computed(() => ({
|
|||||||
{
|
{
|
||||||
name: `border${direction.value}Style`,
|
name: `border${direction.value}Style`,
|
||||||
text: '边框样式',
|
text: '边框样式',
|
||||||
|
|
||||||
labelWidth: '68px',
|
labelWidth: '68px',
|
||||||
type: 'data-source-field-select',
|
type: 'data-source-field-select',
|
||||||
fieldConfig: {
|
fieldConfig: {
|
||||||
@ -90,6 +89,8 @@ const emit = defineEmits<{
|
|||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
model: FormValue;
|
model: FormValue;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
}>(),
|
}>(),
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
<span class="next-input">
|
<span class="next-input">
|
||||||
<input
|
<input
|
||||||
v-model="model[item.name]"
|
v-model="model[item.name]"
|
||||||
:title="model[item.name]"
|
|
||||||
@change="change($event, item.name)"
|
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
|
:title="model[item.name]"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="change($event, item.name)"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -60,6 +61,8 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
model: FormValue;
|
model: FormValue;
|
||||||
}>(),
|
}>(),
|
||||||
{},
|
{},
|
||||||
|
@ -4,9 +4,10 @@
|
|||||||
<span class="next-input">
|
<span class="next-input">
|
||||||
<input
|
<input
|
||||||
v-model="model[item.name]"
|
v-model="model[item.name]"
|
||||||
:title="model[item.name]"
|
|
||||||
@change="change($event, item.name)"
|
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
|
:title="model[item.name]"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="change($event, item.name)"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -42,6 +43,8 @@ const emit = defineEmits<{
|
|||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
model: FormValue;
|
model: FormValue;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
}>(),
|
}>(),
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<MContainer :config="config" :model="values" @change="change"></MContainer>
|
<MContainer :config="config" :model="values" :size="size" :disabled="disabled" @change="change"></MContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -11,7 +11,11 @@ import type { StyleSchema } from '@tmagic/schema';
|
|||||||
import BackgroundPosition from '../components/BackgroundPosition.vue';
|
import BackgroundPosition from '../components/BackgroundPosition.vue';
|
||||||
import { BackgroundNoRepeat, BackgroundRepeat, BackgroundRepeatX, BackgroundRepeatY } from '../icons/background-repeat';
|
import { BackgroundNoRepeat, BackgroundRepeat, BackgroundRepeatX, BackgroundRepeatY } from '../icons/background-repeat';
|
||||||
|
|
||||||
defineProps<{ values: Partial<StyleSchema> }>();
|
defineProps<{
|
||||||
|
values: Partial<StyleSchema>;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
change: [v: StyleSchema, eventData: ContainerChangeEventData];
|
change: [v: StyleSchema, eventData: ContainerChangeEventData];
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MContainer :config="config" :model="values" @change="change"></MContainer>
|
<MContainer :config="config" :model="values" :size="size" :disabled="disabled" @change="change"></MContainer>
|
||||||
<Border :model="values" @change="change"></Border>
|
<Border :model="values" :size="size" :disabled="disabled" @change="change"></Border>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -9,7 +9,11 @@ import type { StyleSchema } from '@tmagic/schema';
|
|||||||
|
|
||||||
import Border from '../components/Border.vue';
|
import Border from '../components/Border.vue';
|
||||||
|
|
||||||
defineProps<{ values: Partial<StyleSchema> }>();
|
defineProps<{
|
||||||
|
values: Partial<StyleSchema>;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
change: [v: StyleSchema, eventData: ContainerChangeEventData];
|
change: [v: StyleSchema, eventData: ContainerChangeEventData];
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<MContainer :config="config" :model="values" @change="change"></MContainer>
|
<MContainer :config="config" :model="values" :size="size" :disabled="disabled" @change="change"></MContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -10,7 +10,11 @@ import type { StyleSchema } from '@tmagic/schema';
|
|||||||
|
|
||||||
import { AlignCenter, AlignLeft, AlignRight } from '../icons/text-align';
|
import { AlignCenter, AlignLeft, AlignRight } from '../icons/text-align';
|
||||||
|
|
||||||
defineProps<{ values: Partial<StyleSchema> }>();
|
defineProps<{
|
||||||
|
values: Partial<StyleSchema>;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
change: [v: StyleSchema, eventData: ContainerChangeEventData];
|
change: [v: StyleSchema, eventData: ContainerChangeEventData];
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<MContainer :config="config" :model="values" @change="change"></MContainer>
|
<MContainer :config="config" :model="values" :size="size" :disabled="disabled" @change="change"></MContainer>
|
||||||
<Box v-show="!['fixed', 'absolute'].includes(values.position)" :model="values" @change="change"></Box>
|
<Box
|
||||||
|
v-show="!['fixed', 'absolute'].includes(values.position)"
|
||||||
|
:model="values"
|
||||||
|
:size="size"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="change"
|
||||||
|
></Box>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -28,6 +34,8 @@ import {
|
|||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
values: Partial<StyleSchema>;
|
values: Partial<StyleSchema>;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<MContainer :config="config" :model="values" @change="change"></MContainer>
|
<MContainer :config="config" :model="values" :size="size" :disabled="disabled" @change="change"></MContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ContainerChangeEventData, MContainer } from '@tmagic/form';
|
import { ContainerChangeEventData, MContainer } from '@tmagic/form';
|
||||||
import type { StyleSchema } from '@tmagic/schema';
|
import type { StyleSchema } from '@tmagic/schema';
|
||||||
|
|
||||||
const props = defineProps<{ values: Partial<StyleSchema> }>();
|
const props = defineProps<{
|
||||||
|
values: Partial<StyleSchema>;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
change: [v: string | StyleSchema, eventData: ContainerChangeEventData];
|
change: [v: string | StyleSchema, eventData: ContainerChangeEventData];
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -347,6 +347,32 @@ export const initServiceEvents = (
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.runtimeUrl,
|
||||||
|
(url) => {
|
||||||
|
if (!url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stage = editorService.get('stage');
|
||||||
|
if (!stage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stage.reloadIframe(url);
|
||||||
|
|
||||||
|
stage.renderer?.once('runtime-ready', (runtime) => {
|
||||||
|
runtime.updateRootConfig?.(cloneDeep(toRaw(editorService.get('root')))!);
|
||||||
|
const page = editorService.get('page');
|
||||||
|
const node = editorService.get('node');
|
||||||
|
page?.id && runtime?.updatePageId?.(page.id);
|
||||||
|
setTimeout(() => {
|
||||||
|
node && stage?.select(toRaw(node.id));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const getStage = (): Promise<StageCore> => {
|
const getStage = (): Promise<StageCore> => {
|
||||||
const stage = editorService.get('stage');
|
const stage = editorService.get('stage');
|
||||||
if (stage) {
|
if (stage) {
|
||||||
@ -388,10 +414,9 @@ export const initServiceEvents = (
|
|||||||
if (value) {
|
if (value) {
|
||||||
depService.clearIdleTasks();
|
depService.clearIdleTasks();
|
||||||
|
|
||||||
|
await (typeof Worker === 'undefined' ? collectIdle(value.items, true) : depService.collectByWorker(value));
|
||||||
|
|
||||||
const dsl = cloneDeep(toRaw(value));
|
const dsl = cloneDeep(toRaw(value));
|
||||||
|
|
||||||
await (typeof Worker === 'undefined' ? collectIdle(dsl.items, true) : depService.collectByWorker(dsl));
|
|
||||||
|
|
||||||
if (dsl.dataSources && dsl.dataSourceDeps && app?.dataSourceManager) {
|
if (dsl.dataSources && dsl.dataSourceDeps && app?.dataSourceManager) {
|
||||||
for (const node of getNodes(getDepNodeIds(dsl.dataSourceDeps), dsl.items)) {
|
for (const node of getNodes(getDepNodeIds(dsl.dataSourceDeps), dsl.items)) {
|
||||||
updateNode(app.dataSourceManager.compiledNode(node), dsl);
|
updateNode(app.dataSourceManager.compiledNode(node), dsl);
|
||||||
@ -435,7 +460,7 @@ export const initServiceEvents = (
|
|||||||
delete value.dataSourceCondDeps;
|
delete value.dataSourceCondDeps;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handler = async () => {
|
(async () => {
|
||||||
const nodeId = editorService.get('node')?.id || props.defaultSelected;
|
const nodeId = editorService.get('node')?.id || props.defaultSelected;
|
||||||
let node;
|
let node;
|
||||||
if (nodeId) {
|
if (nodeId) {
|
||||||
@ -454,9 +479,7 @@ export const initServiceEvents = (
|
|||||||
if (toRaw(value) !== toRaw(preValue)) {
|
if (toRaw(value) !== toRaw(preValue)) {
|
||||||
emit('update:modelValue', value);
|
emit('update:modelValue', value);
|
||||||
}
|
}
|
||||||
};
|
})();
|
||||||
|
|
||||||
handler();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 新增节点,收集依赖
|
// 新增节点,收集依赖
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue';
|
import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
import { FullScreen } from '@element-plus/icons-vue';
|
import { FullScreen } from '@element-plus/icons-vue';
|
||||||
import { throttle } from 'lodash-es';
|
import { throttle } from 'lodash-es';
|
||||||
import serialize from 'serialize-javascript';
|
import serialize from 'serialize-javascript';
|
||||||
@ -62,7 +62,7 @@ const props = withDefaults(
|
|||||||
const emit = defineEmits(['initd', 'save']);
|
const emit = defineEmits(['initd', 'save']);
|
||||||
|
|
||||||
const toString = (v: string | any, language: string): string => {
|
const toString = (v: string | any, language: string): string => {
|
||||||
let value = '';
|
let value: string;
|
||||||
if (typeof v !== 'string') {
|
if (typeof v !== 'string') {
|
||||||
if (language === 'json') {
|
if (language === 'json') {
|
||||||
value = JSON.stringify(v, null, 2);
|
value = JSON.stringify(v, null, 2);
|
||||||
@ -113,19 +113,40 @@ const setEditorValue = (v: string | any, m: string | any) => {
|
|||||||
if (props.type === 'diff') {
|
if (props.type === 'diff') {
|
||||||
const originalModel = monaco.editor.createModel(values.value, 'text/javascript');
|
const originalModel = monaco.editor.createModel(values.value, 'text/javascript');
|
||||||
const modifiedModel = monaco.editor.createModel(toString(m, props.language), 'text/javascript');
|
const modifiedModel = monaco.editor.createModel(toString(m, props.language), 'text/javascript');
|
||||||
|
const position = vsDiffEditor?.getPosition();
|
||||||
return vsDiffEditor?.setModel({
|
const result = vsDiffEditor?.setModel({
|
||||||
original: originalModel,
|
original: originalModel,
|
||||||
modified: modifiedModel,
|
modified: modifiedModel,
|
||||||
});
|
});
|
||||||
|
if (position) {
|
||||||
|
vsDiffEditor?.setPosition(position);
|
||||||
|
vsDiffEditor?.focus();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
// 保存当前光标位置
|
||||||
return vsEditor?.setValue(values.value);
|
const position = vsEditor?.getPosition();
|
||||||
|
const result = vsEditor?.setValue(values.value);
|
||||||
|
// 恢复光标位置
|
||||||
|
if (position) {
|
||||||
|
vsEditor?.setPosition(position);
|
||||||
|
vsEditor?.focus();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEditorValue = () =>
|
const getEditorValue = () =>
|
||||||
(props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue()) || '';
|
(props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue()) || '';
|
||||||
|
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
const newValue = getEditorValue();
|
||||||
|
values.value = newValue;
|
||||||
|
emit('save', props.parse ? parseCode(newValue, props.language) : newValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
if (!codeEditorEl.value) return;
|
if (!codeEditorEl.value) return;
|
||||||
|
|
||||||
@ -149,16 +170,7 @@ const init = async () => {
|
|||||||
setEditorValue(props.initValues, props.modifiedValues);
|
setEditorValue(props.initValues, props.modifiedValues);
|
||||||
|
|
||||||
emit('initd', vsEditor);
|
emit('initd', vsEditor);
|
||||||
|
codeEditorEl.value.addEventListener('keydown', handleKeyDown);
|
||||||
codeEditorEl.value.addEventListener('keydown', (e) => {
|
|
||||||
if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
const newValue = getEditorValue();
|
|
||||||
values.value = newValue;
|
|
||||||
emit('save', props.parse ? parseCode(newValue, props.language) : newValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (props.type !== 'diff' && props.autoSave) {
|
if (props.type !== 'diff' && props.autoSave) {
|
||||||
vsEditor?.onDidBlurEditorWidget(() => {
|
vsEditor?.onDidBlurEditorWidget(() => {
|
||||||
@ -214,7 +226,9 @@ onBeforeUnmount(() => {
|
|||||||
vsEditor = null;
|
vsEditor = null;
|
||||||
vsDiffEditor = null;
|
vsDiffEditor = null;
|
||||||
});
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
codeEditorEl.value?.removeEventListener('keydown', handleKeyDown);
|
||||||
|
});
|
||||||
const fullScreen = ref(false);
|
const fullScreen = ref(false);
|
||||||
const fullScreenHandler = () => {
|
const fullScreenHandler = () => {
|
||||||
fullScreen.value = !fullScreen.value;
|
fullScreen.value = !fullScreen.value;
|
||||||
|
@ -11,19 +11,21 @@
|
|||||||
:width="160"
|
:width="160"
|
||||||
:destroy-on-close="true"
|
:destroy-on-close="true"
|
||||||
>
|
>
|
||||||
<div>
|
<div class="page-bar-popover-wrapper">
|
||||||
<slot name="page-list-popover" :list="list">
|
<div class="page-bar-popover-inner">
|
||||||
<ToolButton
|
<slot name="page-list-popover" :list="list">
|
||||||
v-for="(item, index) in list"
|
<ToolButton
|
||||||
:data="{
|
v-for="(item, index) in list"
|
||||||
type: 'button',
|
:data="{
|
||||||
text: item.devconfig?.tabName || item.name || item.id,
|
type: 'button',
|
||||||
className: item.id === page?.id ? 'active' : '',
|
text: item.devconfig?.tabName || item.name || item.id,
|
||||||
handler: () => switchPage(item.id),
|
className: item.id === page?.id ? 'active' : '',
|
||||||
}"
|
handler: () => switchPage(item.id),
|
||||||
:key="index"
|
}"
|
||||||
></ToolButton>
|
:key="index"
|
||||||
</slot>
|
></ToolButton>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<TMagicIcon class="m-editor-page-list-menu-icon">
|
<TMagicIcon class="m-editor-page-list-menu-icon">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -206,7 +206,9 @@ export default class extends EventEmitter {
|
|||||||
|
|
||||||
public usePlugin(options: Record<string, Function>) {
|
public usePlugin(options: Record<string, Function>) {
|
||||||
for (const [methodName, method] of Object.entries(options)) {
|
for (const [methodName, method] of Object.entries(options)) {
|
||||||
if (typeof method === 'function') this.pluginOptionsList[methodName].push(method);
|
if (typeof method === 'function' && !this.pluginOptionsList[methodName].includes(method)) {
|
||||||
|
this.pluginOptionsList[methodName].push(method);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -11,6 +11,17 @@
|
|||||||
border-bottom: 1px solid $border-color;
|
border-bottom: 1px solid $border-color;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .el-collapse-item__header {
|
||||||
|
padding: 0 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-collapse-item__title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-collapse-item__header,
|
.el-collapse-item__header,
|
||||||
|
@ -13,4 +13,8 @@
|
|||||||
flex: 2;
|
flex: 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.tmagic-design-button {
|
||||||
|
margin-left: 5px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,11 @@
|
|||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-bar-popover-wrapper {
|
||||||
|
max-height: calc(100vh - $page-bar-height - 20px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s ease 0s;
|
transition: all 0.2s ease 0s;
|
||||||
|
@ -72,11 +72,6 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 2px solid $border-color;
|
border-bottom: 2px solid $border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tmagic-design-form {
|
|
||||||
padding-right: 10px;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.m-editor-props-panel-src-icon {
|
.m-editor-props-panel-src-icon {
|
||||||
|
@ -8,12 +8,25 @@
|
|||||||
.tmagic-design-collapse-item {
|
.tmagic-design-collapse-item {
|
||||||
> .el-collapse-item__header {
|
> .el-collapse-item__header {
|
||||||
background-color: #f2f3f7;
|
background-color: #f2f3f7;
|
||||||
height: 36px;
|
height: 26px;
|
||||||
padding: 10px;
|
min-height: 26px;
|
||||||
|
line-height: 26px;
|
||||||
|
padding: 0 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-collapse-item__wrap {
|
.el-collapse-item__wrap {
|
||||||
padding: 0 10px;
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-collapse-item__title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-collapse-item__content {
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -26,9 +26,8 @@ import type { FormConfig, TableColumnConfig } from '@tmagic/form';
|
|||||||
import type StageCore from '@tmagic/stage';
|
import type StageCore from '@tmagic/stage';
|
||||||
import type {
|
import type {
|
||||||
ContainerHighlightType,
|
ContainerHighlightType,
|
||||||
CustomizeMoveableOptionsCallbackConfig,
|
CustomizeMoveableOptions,
|
||||||
GuidesOptions,
|
GuidesOptions,
|
||||||
MoveableOptions,
|
|
||||||
RenderType,
|
RenderType,
|
||||||
UpdateDragEl,
|
UpdateDragEl,
|
||||||
} from '@tmagic/stage';
|
} from '@tmagic/stage';
|
||||||
@ -157,7 +156,7 @@ export interface StageOptions {
|
|||||||
containerHighlightType?: ContainerHighlightType;
|
containerHighlightType?: ContainerHighlightType;
|
||||||
disabledDragStart?: boolean;
|
disabledDragStart?: boolean;
|
||||||
render?: (stage: StageCore) => HTMLDivElement | void | Promise<HTMLDivElement | void>;
|
render?: (stage: StageCore) => HTMLDivElement | void | Promise<HTMLDivElement | void>;
|
||||||
moveableOptions?: MoveableOptions | ((config?: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions);
|
moveableOptions?: CustomizeMoveableOptions;
|
||||||
canSelect?: (el: HTMLElement) => boolean | Promise<boolean>;
|
canSelect?: (el: HTMLElement) => boolean | Promise<boolean>;
|
||||||
isContainer?: (el: HTMLElement) => boolean | Promise<boolean>;
|
isContainer?: (el: HTMLElement) => boolean | Promise<boolean>;
|
||||||
updateDragEl?: UpdateDragEl;
|
updateDragEl?: UpdateDragEl;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
|
||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -17,7 +16,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { NODE_CONDS_KEY, NODE_DISABLE_CODE_BLOCK_KEY, NODE_DISABLE_DATA_SOURCE_KEY } from '@tmagic/core';
|
import {
|
||||||
|
NODE_CONDS_KEY,
|
||||||
|
NODE_CONDS_RESULT_KEY,
|
||||||
|
NODE_DISABLE_CODE_BLOCK_KEY,
|
||||||
|
NODE_DISABLE_DATA_SOURCE_KEY,
|
||||||
|
} from '@tmagic/core';
|
||||||
import { tMagicMessage } from '@tmagic/design';
|
import { tMagicMessage } from '@tmagic/design';
|
||||||
import type { FormConfig, FormState, TabConfig, TabPaneConfig } from '@tmagic/form';
|
import type { FormConfig, FormState, TabConfig, TabPaneConfig } from '@tmagic/form';
|
||||||
|
|
||||||
@ -163,8 +167,20 @@ export const advancedTabConfig: TabPaneConfig = {
|
|||||||
|
|
||||||
export const displayTabConfig: TabPaneConfig = {
|
export const displayTabConfig: TabPaneConfig = {
|
||||||
title: '显示条件',
|
title: '显示条件',
|
||||||
display: (_vm: FormState, { model }: any) => model.type !== 'page',
|
display: (_state: FormState, { model }: any) => model.type !== 'page',
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
name: NODE_CONDS_RESULT_KEY,
|
||||||
|
type: 'select',
|
||||||
|
text: '条件成立时',
|
||||||
|
defaultValue: false,
|
||||||
|
options: [
|
||||||
|
{ text: '显示', value: false },
|
||||||
|
{ text: '隐藏', value: true },
|
||||||
|
],
|
||||||
|
extra: (_state, { model }) =>
|
||||||
|
`条件成立时${model[NODE_CONDS_RESULT_KEY] ? '隐藏' : '显示'},不成立时${model[NODE_CONDS_RESULT_KEY] ? '显示' : '隐藏'};<br />同一条件组内的所有条件配置同时成立时表示该条件组成立,任意一个条件组成立时表示条件成立(条件组内为且的关系,条件组间为或的关系);<br />条件为空时表示成立;`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'display-conds',
|
type: 'display-conds',
|
||||||
name: NODE_CONDS_KEY,
|
name: NODE_CONDS_KEY,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/element-plus-adapter",
|
"name": "@tmagic/element-plus-adapter",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/tmagic-element-plus-adapter.umd.cjs",
|
"main": "dist/tmagic-element-plus-adapter.umd.cjs",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/form-schema",
|
"name": "@tmagic/form-schema",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/tmagic-form-schema.umd.cjs",
|
"main": "dist/tmagic-form-schema.umd.cjs",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.5.24",
|
"version": "1.6.1",
|
||||||
"name": "@tmagic/form",
|
"name": "@tmagic/form",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": [
|
"sideEffects": [
|
||||||
|
@ -9,12 +9,12 @@
|
|||||||
>
|
>
|
||||||
<TMagicTooltip v-if="option.tooltip" placement="top-start" :content="option.tooltip">
|
<TMagicTooltip v-if="option.tooltip" placement="top-start" :content="option.tooltip">
|
||||||
<div>
|
<div>
|
||||||
<TMagicIcon v-if="option.icon" :size="'16'"><component :is="option.icon"></component></TMagicIcon>
|
<TMagicIcon v-if="option.icon" :size="iconSize"><component :is="option.icon"></component></TMagicIcon>
|
||||||
<span>{{ option.text }}</span>
|
<span>{{ option.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
</TMagicTooltip>
|
</TMagicTooltip>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<TMagicIcon v-if="option.icon" :size="'16'"><component :is="option.icon"></component></TMagicIcon>
|
<TMagicIcon v-if="option.icon" :size="iconSize"><component :is="option.icon"></component></TMagicIcon>
|
||||||
<span>{{ option.text }}</span>
|
<span>{{ option.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
</component>
|
</component>
|
||||||
@ -49,4 +49,14 @@ const clickHandler = (item: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useAddField(props.prop);
|
useAddField(props.prop);
|
||||||
|
|
||||||
|
const iconSize = computed(() => {
|
||||||
|
if (props.size === 'small') {
|
||||||
|
return '12';
|
||||||
|
}
|
||||||
|
if (props.size === 'large') {
|
||||||
|
return '16';
|
||||||
|
}
|
||||||
|
return '14';
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width: 100%">
|
<div class="m-fields-text">
|
||||||
<TMagicInput
|
<TMagicInput
|
||||||
v-model="model[name]"
|
v-model="model[name]"
|
||||||
ref="input"
|
ref="input"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
.m-fields-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.m-form-validate__warning {
|
.m-form-validate__warning {
|
||||||
color: var(--el-color-warning);
|
color: var(--el-color-warning);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
* Copyright (C) 2025 Tencent. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
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