Compare commits

...

33 Commits

Author SHA1 Message Date
roymondchen
5387a18024 chore: release vue-container/react-runtime-help/reate-iterator-conatiner 2025-10-14 15:49:20 +08:00
roymondchen
2b80ba3efd chore: update lockfile v1.6.1 2025-10-14 15:37:33 +08:00
roymondchen
6c3916c580 chore: release v1.6.1 2025-10-14 15:36:00 +08:00
roymondchen
4dfdc836f6 chore: update deps 2025-10-14 14:18:50 +08:00
roymondchen
fef1e2c2b4 style(editor): 组件列表标题样式调整 2025-10-14 14:14:48 +08:00
roymondchen
51f95aef6f feat(data-source, editor, schema, react-runtime-help, vue-components): 新增条件成立时隐藏的配置功能 2025-10-13 20:31:54 +08:00
roymondchen
81aa8f151d feat(editor): 属性配置中的样式面板样式优化 2025-10-13 19:32:29 +08:00
roymondchen
cae11dce12 fix(form): text与同行元素不对齐问题 2025-10-13 19:28:18 +08:00
roymondchen
83bf36d980 style(form): radio-group选项中icon大小根据size变化 2025-10-13 19:25:30 +08:00
roymondchen
2888004c17 chore: update deps 2025-10-13 15:57:48 +08:00
roymondchen
abab44ad24 chore: update deps 2025-09-16 19:49:48 +08:00
roymondchen
849b561933 feat(data-source): 数据源数据变化事件监听响应支持立即执行 2025-09-16 19:44:16 +08:00
roymondchen
1031595a97 fix(core): 异步加载数据源时,数据源事件配置失效 2025-09-16 19:34:15 +08:00
roymondchen
f5cb19dfa4 style(editor): 页面列表长度超过可视窗口时出现滚动条 2025-09-12 15:32:03 +08:00
roymondchen
e400175ffe fix: 组件声明周期函数配置中配置数据源自有方法生效 2025-09-10 16:24:44 +08:00
roymondchen
958c78d968 chore: update lockfile v1.6.0 2025-08-27 19:27:29 +08:00
roymondchen
9f81597596 chore: release v1.6.0 2025-08-27 19:26:01 +08:00
roymondchen
001f2b6c9e build(runtime): escape % if URI malformed 2025-08-27 19:18:17 +08:00
roymondchen
a56bb562d8 build: 构建playground失败 2025-08-27 19:08:57 +08:00
roymondchen
7695f005f6 style(runtime): 配置格式化 2025-08-27 17:01:08 +08:00
roymondchen
a10f9d230d fix(cli): 在pnpm工作空间中的项目,保持package.json不受配置中的packages影响 2025-08-27 16:48:51 +08:00
roymondchen
9f350541bf feat(cli): 支持tmagic.config.local配置文件,会与tmagic.config配置合并,可用于本地开发时的临时配置 2025-08-27 16:19:43 +08:00
roymondchen
0643699fac chore: 删除ui/ui-react 2025-08-27 15:43:28 +08:00
roymondchen
9f63dff49b build(runtime): 构建playground示例失败 2025-08-27 14:31:24 +08:00
roymondchen
7d3a2df793 chore: 删除vue2 runtime,后续vue-components里的组件不再考虑vue2的支持 2025-08-27 14:24:15 +08:00
roymondchen
0967c3449e build(runtime): 重构vue3 runtime的构建配置 2025-08-26 20:40:24 +08:00
roymondchen
f267643c42 chore: update deps 2025-08-26 17:27:37 +08:00
roymondchen
f3387ed5e9 chore: update lockfile v1.6.0-beta.6 2025-08-15 12:30:41 +08:00
roymondchen
71d1aab69e chore: release v1.6.0-beta.6 2025-08-15 12:29:06 +08:00
roymondchen
4c6118f50f feat(core): 事件支持关联数据源自身方法 2025-08-15 12:25:00 +08:00
roymondchen
77da3f9762 chore: update lockfile v1.6.0-beta.5 2025-08-08 16:00:48 +08:00
roymondchen
8b3cb63f77 chore: release v1.6.0-beta.5 2025-08-08 15:59:17 +08:00
roymondchen
fc1c9feafd fix(core): 事件行为应该为串行执行 2025-08-08 15:51:54 +08:00
129 changed files with 2427 additions and 2540 deletions

View File

@ -1,3 +1,53 @@
## [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) # [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)

View File

@ -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>
``` ```

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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 所需要的渲染器。
## 联动 ## 联动
页面搭建过程中,会涉及到两种联动形式 页面搭建过程中,会涉及到两种联动形式
- 在编辑器中,组件的表单配置项之间需要联动。 - 在编辑器中,组件的表单配置项之间需要联动。

View File

@ -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;
}); });
} }

View File

@ -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),与文档描述内容可以逐一对应上,希望文档内容可以为开发者带来比较好的开发体验。

View File

@ -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

View File

@ -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)
### 页面发布 ### 页面发布

View File

@ -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)

View File

@ -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,

View File

@ -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",

View File

@ -1,9 +1,9 @@
{ {
"version": "1.6.0-beta.4", "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,7 +63,7 @@
"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",
@ -75,10 +73,10 @@
"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": {

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "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"

View File

@ -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

View File

@ -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);
} }
}; };

View 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]);
} }
}); });

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "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",

View File

@ -167,8 +167,13 @@ class App extends EventEmitter {
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();
});
}
} }
} }
@ -259,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;
} }
@ -281,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;
@ -288,21 +294,20 @@ 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;
}
} }
} }
} }

View File

@ -113,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[]) => {
@ -141,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[]) {
@ -152,20 +154,20 @@ 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();
} }
@ -200,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();

View File

@ -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';
@ -141,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);
} }
} }
} }

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "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",

View File

@ -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[] {

View File

@ -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>();

View File

@ -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;

View File

@ -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);
} }

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "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",

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "version": "1.6.1",
"name": "@tmagic/design", "name": "@tmagic/design",
"type": "module", "type": "module",
"sideEffects": [ "sideEffects": [

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "version": "1.6.1",
"name": "@tmagic/editor", "name": "@tmagic/editor",
"type": "module", "type": "module",
"sideEffects": [ "sideEffects": [

View File

@ -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"

View File

@ -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">

View File

@ -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>

View File

@ -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';
}>(), }>(),
{}, {},
); );

View File

@ -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;
}>(), }>(),
{}, {},

View File

@ -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';
}>(), }>(),
{}, {},
); );

View File

@ -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];

View File

@ -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];

View File

@ -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];

View File

@ -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<{

View File

@ -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];

View File

@ -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">

View File

@ -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,

View File

@ -13,4 +13,8 @@
flex: 2; flex: 2;
} }
} }
.tmagic-design-button {
margin-left: 5px;
padding: 5px 8px;
}
} }

View File

@ -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;

View File

@ -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 {

View File

@ -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;
} }
} }
} }

View File

@ -1,4 +1,3 @@
/* 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.
* *
@ -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,

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "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",

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "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",

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "version": "1.6.1",
"name": "@tmagic/form", "name": "@tmagic/form",
"type": "module", "type": "module",
"sideEffects": [ "sideEffects": [

View File

@ -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>

View File

@ -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"

View File

@ -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;

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "version": "1.6.1",
"name": "@tmagic/schema", "name": "@tmagic/schema",
"type": "module", "type": "module",
"main": "dist/tmagic-schema.umd.cjs", "main": "dist/tmagic-schema.umd.cjs",

View File

@ -47,6 +47,8 @@ export enum NodeType {
} }
export const NODE_CONDS_KEY = 'displayConds'; export const NODE_CONDS_KEY = 'displayConds';
export const NODE_CONDS_RESULT_KEY = 'displayCondsResultReverse';
export const NODE_DISABLE_DATA_SOURCE_KEY = '_tmagic_node_disabled_data_source'; export const NODE_DISABLE_DATA_SOURCE_KEY = '_tmagic_node_disabled_data_source';
export const NODE_DISABLE_CODE_BLOCK_KEY = '_tmagic_node_disabled_code_block'; export const NODE_DISABLE_CODE_BLOCK_KEY = '_tmagic_node_disabled_code_block';
@ -130,6 +132,7 @@ export interface MComponent {
/** 组件根Dom的style */ /** 组件根Dom的style */
style?: StyleSchema; style?: StyleSchema;
[NODE_CONDS_KEY]?: DisplayCond[]; [NODE_CONDS_KEY]?: DisplayCond[];
[NODE_CONDS_RESULT_KEY]?: boolean;
[key: string]: any; [key: string]: any;
} }

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "version": "1.6.1",
"name": "@tmagic/stage", "name": "@tmagic/stage",
"type": "module", "type": "module",
"main": "dist/tmagic-stage.umd.cjs", "main": "dist/tmagic-stage.umd.cjs",

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "version": "1.6.1",
"name": "@tmagic/table", "name": "@tmagic/table",
"type": "module", "type": "module",
"sideEffects": [ "sideEffects": [

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "version": "1.6.1",
"name": "@tmagic/tdesign-vue-next-adapter", "name": "@tmagic/tdesign-vue-next-adapter",
"type": "module", "type": "module",
"main": "dist/tmagic-tdesign-vue-next-adapter.umd.cjs", "main": "dist/tmagic-tdesign-vue-next-adapter.umd.cjs",

View File

@ -1,5 +1,5 @@
{ {
"version": "1.6.0-beta.4", "version": "1.6.1",
"name": "@tmagic/utils", "name": "@tmagic/utils",
"type": "module", "type": "module",
"main": "dist/tmagic-utils.umd.cjs", "main": "dist/tmagic-utils.umd.cjs",

View File

@ -1,2 +0,0 @@
VITE_RUNTIME_PATH=/tmagic-editor/playground/runtime/vue2
VITE_ENTRY_PATH=./entry/vue2

View File

@ -1,2 +1,2 @@
VITE_RUNTIME_PATH=/tmagic-editor/playground/runtime/vue3 VITE_RUNTIME_PATH=/tmagic-editor/playground/runtime/vue
VITE_ENTRY_PATH=./entry/vue3 VITE_ENTRY_PATH=./entry/vue

View File

@ -1,27 +0,0 @@
# Vue 3 + Typescript + Vite
This template should help get you started developing with Vue 3 and Typescript in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur). Make sure to enable `vetur.experimental.templateInterpolationService` in settings!
### If Using `<script setup>`
[`<script setup>`](https://github.com/vuejs/rfcs/pull/227) is a feature that is currently in RFC stage. To get proper IDE support for the syntax, use [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) instead of Vetur (and disable Vetur).
## Type Support For `.vue` Imports in TS
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can use the following:
### If Using Volar
Run `Volar: Switch TS Plugin on/off` from VSCode command palette.
### If Using Vetur
1. Install and add `@vuedx/typescript-plugin-vue` to the [plugins section](https://www.typescriptlang.org/tsconfig#plugins) in `tsconfig.json`
2. Delete `src/shims-vue.d.ts` as it is no longer needed to provide module info to Typescript
3. Open `src/main.ts` in VSCode
4. Open the VSCode command palette
5. Search and run "Select TypeScript version" -> "Use workspace version"

View File

@ -1,23 +1,22 @@
{ {
"name": "tmagic-playground", "name": "tmagic-playground",
"version": "1.6.0-beta.4", "version": "1.6.1",
"type": "module", "type": "module",
"private": true, "private": true,
"scripts": { "scripts": {
"clean:top": "rimraf dist", "clean:top": "rimraf dist",
"dev": "vite --mode vue3", "dev": "vite --mode vue3",
"dev:vue2": "vite --mode vue2",
"dev:react": "vite --mode react", "dev:react": "vite --mode react",
"build": "npm run clean:top && node --max_old_space_size=8192 node_modules/vite/bin/vite.js build --mode vue3", "build": "npm run clean:top && node --max_old_space_size=8192 node_modules/vite/bin/vite.js build --mode vue3",
"serve": "vite preview" "serve": "vite preview"
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.2",
"@tmagic/core": "1.6.0-beta.4", "@tmagic/core": "1.6.1",
"@tmagic/editor": "1.6.0-beta.4", "@tmagic/editor": "1.6.1",
"@tmagic/element-plus-adapter": "1.6.0-beta.4", "@tmagic/element-plus-adapter": "1.6.1",
"@tmagic/tmagic-form-runtime": "1.1.3", "@tmagic/tmagic-form-runtime": "1.1.3",
"element-plus": "^2.9.11", "element-plus": "^2.11.4",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"monaco-editor": "^0.52.2", "monaco-editor": "^0.52.2",
"serialize-javascript": "^6.0.2", "serialize-javascript": "^6.0.2",
@ -28,15 +27,15 @@
"@types/lodash-es": "^4.17.4", "@types/lodash-es": "^4.17.4",
"@types/node": "^24.0.10", "@types/node": "^24.0.10",
"@types/serialize-javascript": "^5.0.4", "@types/serialize-javascript": "^5.0.4",
"@vitejs/plugin-legacy": "^7.0.0", "@vitejs/plugin-legacy": "^7.2.1",
"@vitejs/plugin-vue": "^6.0.0", "@vitejs/plugin-vue": "^6.0.1",
"@vitejs/plugin-vue-jsx": "^5.0.1", "@vitejs/plugin-vue-jsx": "^5.1.0",
"@vue/compiler-sfc": "catalog:", "@vue/compiler-sfc": "catalog:",
"sass": "^1.89.2", "lightningcss": "^1.30.2",
"terser": "^5.43.1", "terser": "^5.43.1",
"typescript": "catalog:", "typescript": "catalog:",
"unplugin-auto-import": "^19.3.0", "unplugin-auto-import": "^20.0.0",
"unplugin-vue-components": "^28.8.0", "unplugin-vue-components": "^29.0.0",
"vite": "catalog:" "vite": "catalog:"
} }
} }

View File

@ -116,5 +116,6 @@ export default defineConfig({
build: { build: {
sourcemap: true, sourcemap: true,
cssMinify: 'lightningcss'
}, },
}); });

2710
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -7,8 +7,8 @@ packages:
- 'eslint-config' - 'eslint-config'
catalog: catalog:
vue: ^3.5.17 vue: ^3.5.22
'@vue/compiler-sfc': ^3.5.17 '@vue/compiler-sfc': ^3.5.22
vite: ^7.0.3 vite: ^7.1.9
typescript: "^5.8.3" typescript: "^5.9.3"

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.0", "version": "0.1.1",
"name": "@tmagic/react-iterator-container", "name": "@tmagic/react-iterator-container",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",

View File

@ -56,11 +56,10 @@ const IteratorContainer: React.FC<IteratorContainerProps> = ({
const MagicUiComp = app?.resolveComponent('container'); const MagicUiComp = app?.resolveComponent('container');
const iteratorContainerNode = app?.getNode<TMagicIteratorContainer>( const iteratorContainerNode = app?.getNode<TMagicIteratorContainer>(id || config.id || '', {
id || config.id || '',
iteratorContainerId, iteratorContainerId,
iteratorIndex, iteratorIndex,
); });
iteratorContainerNode?.resetNodes(); iteratorContainerNode?.resetNodes();

View File

@ -30,7 +30,7 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@types/qrcode": "^1.4.2", "@types/qrcode": "^1.4.2",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0" "@types/react-dom": "^18.3.0"
} }

View File

@ -1,5 +1,5 @@
{ {
"version": "0.2.0", "version": "0.2.1",
"name": "@tmagic/react-runtime-help", "name": "@tmagic/react-runtime-help",
"type": "module", "type": "module",
"sideEffects": false, "sideEffects": false,

View File

@ -20,7 +20,7 @@ import { useContext, useEffect, useState } from 'react';
import type TMagicApp from '@tmagic/core'; import type TMagicApp from '@tmagic/core';
import type { Id, MNodeInstance, Node as TMagicNode } from '@tmagic/core'; import type { Id, MNodeInstance, Node as TMagicNode } from '@tmagic/core';
import { isDslNode } from '@tmagic/core'; import { isDslNode, NODE_CONDS_RESULT_KEY } from '@tmagic/core';
import AppContent from '../AppContent'; import AppContent from '../AppContent';
@ -96,8 +96,13 @@ export const useApp = ({ methods = {}, config, iteratorContainerId, iteratorInde
} }
const display = <T extends MNodeInstance>(config: T) => { const display = <T extends MNodeInstance>(config: T) => {
if (config.visible === false) return false; if (
if (config.condResult === false) return false; config.visible === false ||
config.condResult === false ||
(typeof config.condResult === 'undefined' && config[NODE_CONDS_RESULT_KEY])
) {
return false;
}
const displayCfg = config.display; const displayCfg = config.display;

View File

@ -1,2 +1,4 @@
.tmagic .tmagic
entry-dist dist
*.local
*.local.*

View File

@ -1,77 +0,0 @@
/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2025 Tencent. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';
import { defineConfig } from 'vite';
import legacy from '@vitejs/plugin-legacy';
import reactRefresh from '@vitejs/plugin-react-refresh';
export default defineConfig(({ mode }) => {
if (['value', 'config', 'event', 'ds:value', 'ds:config', 'ds:event'].includes(mode)) {
const capitalToken = mode
.split(':')
.map((word) => word[0].toUpperCase() + word.slice(1))
.join('');
const fileName = mode.replace(':', '-');
return {
publicDir: './.tmagic/public',
build: {
cssCodeSplit: false,
sourcemap: true,
minify: false,
target: 'esnext',
outDir: `../../playground/public/entry/react/${fileName}`,
lib: {
entry: `.tmagic/${fileName}-entry.ts`,
name: `magicPreset${capitalToken}s`,
fileName: 'index',
formats: ['umd'],
},
},
};
}
if (['page', 'playground'].includes(mode)) {
return {
plugins: [
reactRefresh(),
legacy({
targets: ['defaults', 'not IE 11'],
}),
],
root: `./${mode}/`,
publicDir: '../public',
base: `/tmagic-editor/playground/runtime/react/${mode}`,
build: {
emptyOutDir: true,
sourcemap: true,
outDir: path.resolve(process.cwd(), `../../playground/public/runtime/react/${mode}`),
},
};
}
return {};
});

View File

@ -1,39 +1,40 @@
{ {
"name": "runtime-react", "name": "runtime-react",
"version": "1.6.0-beta.4", "version": "1.6.1",
"type": "module", "type": "module",
"private": true, "private": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"scripts": { "scripts": {
"dev:react": "vite --config dev.vite.config.ts", "tmagic": "tmagic entry",
"dev:playground": "vite --config dev.vite.config.ts", "dev:react": "vite --force",
"build": "npm run build:libs && npm run build:page && npm run build:playground", "serve": "vite preview",
"build:page": "vite build --config build.vite.config.ts --mode page", "build": "rimraf ./dist && node scripts/build.mjs --type=all",
"build:playground": "vite build --config build.vite.config.ts --mode playground", "build:libs": "node scripts/build.mjs --type=res",
"build:libs": "tmagic entry && npm run build:config && npm run build:value && npm run build:event && npm run build:ds:libs", "build:page": "node scripts/build.mjs --type=page",
"build:ds:libs": "npm run build:ds:config && npm run build:ds:value && npm run build:ds:event", "build:playground": "node scripts/build.mjs --type=playground"
"build:config": "vite build --config build.vite.config.ts --mode config",
"build:value": "vite build --config build.vite.config.ts --mode value",
"build:event": "vite build --config build.vite.config.ts --mode event",
"build:ds:config": "vite build --config build.vite.config.ts --mode ds:config",
"build:ds:value": "vite build --config build.vite.config.ts --mode ds:value",
"build:ds:event": "vite build --config build.vite.config.ts --mode ds:event"
}, },
"dependencies": { "dependencies": {
"@tmagic/core": "1.6.0-beta.4", "@tmagic/core": "1.6.1",
"@tmagic/react-runtime-help": "0.2.0", "@tmagic/react-runtime-help": "0.2.0",
"@tmagic/stage": "1.6.0-beta.4", "@tmagic/stage": "1.6.1",
"axios": "^1.10.0", "axios": "^1.11.0",
"qrcode": "^1.5.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1" "react-dom": "^18.3.1"
}, },
"devDependencies": { "devDependencies": {
"@tmagic/cli": "1.6.0-beta.4", "@tmagic/cli": "1.6.1",
"@types/fs-extra": "^11.0.4",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@vitejs/plugin-legacy": "^7.0.0", "@vitejs/plugin-legacy": "^7.2.1",
"@vitejs/plugin-react-refresh": "^1.3.6", "@vitejs/plugin-react-refresh": "^1.3.6",
"fs-extra": "^11.3.1",
"typescript": "catalog:", "typescript": "catalog:",
"terser": "^5.43.1", "terser": "^5.43.1",
"vite": "catalog:" "vite": "catalog:",
"vite-plugin-commonjs": "^0.10.4"
} }
} }

View File

@ -0,0 +1,32 @@
import { defineConfig } from 'vite';
import baseConfig from '../vite.config';
const INVALID_CHAR_REGEX = /[\x00-\x1F\x7F<>*#"{}|^[\]`;?:&=+$,]/g;
const DRIVE_LETTER_REGEX = /^[a-z]:/i;
export default defineConfig({
...baseConfig,
root: './page',
publicDir: '../public',
base: `${baseConfig.base}/page`,
build: {
emptyOutDir: false,
sourcemap: true,
outDir: '../dist/page',
rollupOptions: {
output: {
// https://github.com/rollup/rollup/blob/master/src/utils/sanitizeFileName.ts
sanitizeFileName(name) {
const match = DRIVE_LETTER_REGEX.exec(name);
const driveLetter = match ? match[0] : '';
return driveLetter + name.slice(driveLetter.length).replace(INVALID_CHAR_REGEX, '');
},
},
},
},
});

View File

@ -0,0 +1,32 @@
import { defineConfig } from 'vite';
import baseConfig from '../vite.config';
const INVALID_CHAR_REGEX = /[\x00-\x1F\x7F<>*#"{}|^[\]`;?:&=+$,]/g;
const DRIVE_LETTER_REGEX = /^[a-z]:/i;
export default defineConfig({
...baseConfig,
root: './playground',
publicDir: '../public',
base: `${baseConfig.base}/playground`,
build: {
emptyOutDir: false,
sourcemap: true,
outDir: '../dist/playground',
rollupOptions: {
output: {
// https://github.com/rollup/rollup/blob/master/src/utils/sanitizeFileName.ts
sanitizeFileName(name) {
const match = DRIVE_LETTER_REGEX.exec(name);
const driveLetter = match ? match[0] : '';
return driveLetter + name.slice(driveLetter.length).replace(INVALID_CHAR_REGEX, '');
},
},
},
},
});

View File

@ -0,0 +1,60 @@
import { execSync } from 'node:child_process';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { build as buildVite } from 'vite';
import fse from 'fs-extra';
import minimist from 'minimist';
import resViteConfig from './vite.res.config.mjs';
const args = minimist(process.argv.slice(2));
const dirname = path.dirname(fileURLToPath(import.meta.url));
fse.removeSync(path.resolve(dirname, '../.tmagic'));
execSync('tmagic entry', {
stdio: 'inherit',
cwd: path.resolve(dirname, '../'),
});
if (args.type === 'res' || args.type === 'all') {
fse.removeSync(path.resolve(dirname, '../dist/entry'));
for (const mode of ['value', 'config', 'event', 'ds:value', 'ds:config', 'ds:event']) {
const fileName = mode.replace(':', '-');
buildVite({
root: path.resolve(dirname, '../'),
clearScreen: false,
configFile: false,
...resViteConfig(mode),
}).then(() => {
fse.copySync(
path.resolve(dirname, '../dist/entry', fileName),
path.resolve(dirname, '../../../playground/public/entry/vue/', fileName),
);
});
}
}
const buildRuntime = (type) => {
fse.removeSync(path.resolve(dirname, '../dist', type));
buildVite({
root: path.resolve(dirname, '../', type),
clearScreen: false,
configFile: path.resolve(dirname, '../', type, 'vite.config.ts'),
}).then(() => {
const clientFile = path.resolve(dirname, '../dist', type);
fse.copySync(clientFile, path.resolve(dirname, '../../../playground/public/runtime/react', type));
});
};
if (args.type === 'page' || args.type === 'all') {
buildRuntime('page');
}
if (args.type === 'playground' || args.type === 'all') {
buildRuntime('playground');
}

View File

@ -0,0 +1,28 @@
import { defineConfig } from 'vite';
export default defineConfig((mode) => {
const capitalToken = mode
.split(':')
.map((word) => word[0].toUpperCase() + word.slice(1))
.join('');
const fileName = mode.replace(':', '-');
return {
publicDir: './.tmagic/public',
build: {
cssCodeSplit: false,
sourcemap: true,
minify: false,
target: 'esnext',
outDir: `./dist/entry/${fileName}`,
lib: {
entry: `./.tmagic/${fileName}-entry.ts`,
name: `magicPreset${capitalToken}s`,
fileName: 'index',
formats: ['umd'],
},
},
};
});

View File

@ -1,8 +1,23 @@
import path from 'path';
import { defineConfig } from '@tmagic/cli'; import { defineConfig } from '@tmagic/cli';
export default defineConfig({ export default defineConfig({
packages: [path.join(__dirname, '../ui-react')],
componentFileAffix: '.tsx', componentFileAffix: '.tsx',
npmConfig: {
client: 'pnpm',
keepPackageJsonClean: true,
},
packages: [
{
button: '@tmagic/react-button',
container: '@tmagic/react-container',
img: '@tmagic/react-img',
'iterator-container': '@tmagic/react-iterator-container',
overlay: '@tmagic/react-overlay',
page: '@tmagic/react-page',
'page-fragment': '@tmagic/react-page-fragment',
'page-fragment-container': '@tmagic/react-page-fragment-container',
'qrcode': '@tmagic/react-qrcode',
'text': '@tmagic/react-text',
},
],
}); });

View File

@ -16,13 +16,28 @@
* limitations under the License. * limitations under the License.
*/ */
import path from 'path'; import path from 'node:path';
import { defineConfig } from 'vite'; import { defineConfig } from 'vite';
import legacy from '@vitejs/plugin-legacy';
import reactRefresh from '@vitejs/plugin-react-refresh'; import reactRefresh from '@vitejs/plugin-react-refresh';
import commonjs from 'vite-plugin-commonjs';
export default defineConfig({ export default defineConfig({
plugins: [reactRefresh()], plugins: [
commonjs({
filter: (id) => {
if (id.includes('qrcode')) {
return true;
}
return false;
},
}),
reactRefresh(),
legacy({
targets: ['defaults', 'not IE 11'],
})
],
resolve: { resolve: {
alias: [ alias: [
@ -34,17 +49,18 @@ export default defineConfig({
}, },
{ find: /^@tmagic\/utils/, replacement: path.join(__dirname, '../../packages/utils/src/index.ts') }, { find: /^@tmagic\/utils/, replacement: path.join(__dirname, '../../packages/utils/src/index.ts') },
{ find: /^@tmagic\/core/, replacement: path.join(__dirname, '../../packages/core/src/index.ts') }, { find: /^@tmagic\/core/, replacement: path.join(__dirname, '../../packages/core/src/index.ts') },
{ find: /^@tmagic\/schema/, replacement: path.join(__dirname, '../../packages/schema/src/index.ts') },
{ find: /^@data-source/, replacement: path.join(__dirname, '../../packages/data-source/src') },
{ find: /^@tmagic\/data-source/, replacement: path.join(__dirname, '../../packages/data-source/src/index.ts') }, { find: /^@tmagic\/data-source/, replacement: path.join(__dirname, '../../packages/data-source/src/index.ts') },
{ find: /^@tmagic\/dep/, replacement: path.join(__dirname, '../../packages/dep/src/index.ts') }, { find: /^@tmagic\/dep/, replacement: path.join(__dirname, '../../packages/dep/src/index.ts') },
{ find: /^@tmagic\/react-runtime-help/, replacement: path.join(__dirname, '../react-runtime-help/src/index.ts') }, { find: /^@data-source/, replacement: path.join(__dirname, '../../packages/data-source/src') },
{ find: /^@tmagic\/schema/, replacement: path.join(__dirname, '../../packages/schema/src/index.ts') },
{ find: /^@tmagic\/vue-runtime-help/, replacement: path.join(__dirname, '../vue-runtime-help/src/index.ts') },
{ find: /^qrcode/, replacement: path.join(__dirname, './node_modules/qrcode') },
], ],
}, },
root: './', root: './',
base: '/tmagic-editor/playground/runtime/react/', base: '/tmagic-editor/playground/runtime/react',
publicDir: 'public', publicDir: 'public',
@ -55,17 +71,10 @@ export default defineConfig({
}, },
build: { build: {
sourcemap: true,
cssCodeSplit: false,
rollupOptions: { rollupOptions: {
input: { input: {
page: './page/index.html', page: path.resolve(__dirname, './page/index.html'),
playground: './playground/index.html', playground: path.resolve(__dirname, './playground/index.html'),
},
output: {
entryFileNames: 'assets/[name].js',
}, },
}, },
}, },

View File

@ -1 +0,0 @@
# [文档](https://tencent.github.io/tmagic-editor/docs/)

View File

@ -1,38 +0,0 @@
{
"name": "@tmagic/ui-react",
"version": "1.5.18",
"type": "module",
"main": "dist/tmagic-ui-react.js",
"types": "types/index.d.ts",
"files": [
"src"
],
"engines": {
"node": ">=18"
},
"repository": {
"directory": "runtime/ui-react",
"type": "git",
"url": "https://github.com/Tencent/tmagic-editor.git"
},
"dependencies": {
"@tmagic/react-button": "workspace:*",
"@tmagic/react-container": "workspace:*",
"@tmagic/react-img": "workspace:*",
"@tmagic/react-iterator-container": "workspace:*",
"@tmagic/react-overlay": "workspace:*",
"@tmagic/react-page": "workspace:*",
"@tmagic/react-page-fragment": "workspace:*",
"@tmagic/react-page-fragment-container": "workspace:*",
"@tmagic/react-qrcode": "workspace:*",
"@tmagic/react-text": "workspace:*"
},
"peerDependencies": {
"typescript": "catalog:"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
}

View File

@ -1,54 +0,0 @@
/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2025 Tencent. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Button from '@tmagic/react-button';
import Container from '@tmagic/react-container';
import Img from '@tmagic/react-img';
import IteratorContainer from '@tmagic/react-iterator-container';
import Overlay from '@tmagic/react-overlay';
import Page from '@tmagic/react-page';
import PageFragment from '@tmagic/react-page-fragment';
import PageFragmentContainer from '@tmagic/react-page-fragment-container';
import QRcode from '@tmagic/react-qrcode';
import Text from '@tmagic/react-text';
export { default as TMagicUiButton } from '@tmagic/react-button';
export { default as TMagicUiContainer } from '@tmagic/react-container';
export { default as TMagicUiImg } from '@tmagic/react-img';
export { default as TMagicUiIteratorContainer } from '@tmagic/react-iterator-container';
export { default as TMagicUiOverlay } from '@tmagic/react-overlay';
export { default as TMagicUiPage } from '@tmagic/react-page';
export { default as TMagicUiPageFragment } from '@tmagic/react-page-fragment';
export { default as TMagicUiPageFragmentContainer } from '@tmagic/react-page-fragment-container';
export { default as TMagicUiQRcode } from '@tmagic/react-qrcode';
export { default as TMagicUiText } from '@tmagic/react-text';
const ui: Record<string, any> = {
page: Page,
container: Container,
button: Button,
text: Text,
img: Img,
qrcode: QRcode,
overlay: Overlay,
'page-fragment-container': PageFragmentContainer,
'page-fragment': PageFragment,
'iterator-container': IteratorContainer,
};
export default ui;

View File

@ -1 +0,0 @@
# [文档](https://tencent.github.io/tmagic-editor/docs/)

View File

@ -1,41 +0,0 @@
{
"version": "1.6.0-beta.0",
"name": "@tmagic/ui",
"type": "module",
"main": "dist/tmagic-ui.js",
"types": "types/index.d.ts",
"files": [
"src",
"dist",
"types"
],
"engines": {
"node": ">=18"
},
"license": "Apache-2.0",
"repository": {
"directory": "runtime/ui",
"type": "git",
"url": "https://github.com/Tencent/tmagic-editor.git"
},
"dependencies": {
"@tmagic/vue-button": "workspace:*",
"@tmagic/vue-container": "workspace:*",
"@tmagic/vue-img": "workspace:*",
"@tmagic/vue-iterator-container": "workspace:*",
"@tmagic/vue-overlay": "workspace:*",
"@tmagic/vue-page": "workspace:*",
"@tmagic/vue-page-fragment": "workspace:*",
"@tmagic/vue-page-fragment-container": "workspace:*",
"@tmagic/vue-qrcode": "workspace:*",
"@tmagic/vue-text": "workspace:*"
},
"peerDependencies": {
"typescript": "catalog:"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
}

View File

@ -1,54 +0,0 @@
/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2025 Tencent. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Button from '@tmagic/vue-button';
import Container from '@tmagic/vue-container';
import Img from '@tmagic/vue-img';
import IteratorContainer from '@tmagic/vue-iterator-container';
import Overlay from '@tmagic/vue-overlay';
import Page from '@tmagic/vue-page';
import PageFragment from '@tmagic/vue-page-fragment';
import PageFragmentContainer from '@tmagic/vue-page-fragment-container';
import QRcode from '@tmagic/vue-qrcode';
import Text from '@tmagic/vue-text';
export { default as TMagicUiButton } from '@tmagic/vue-button';
export { default as TMagicUiContainer } from '@tmagic/vue-container';
export { default as TMagicUiImg } from '@tmagic/vue-img';
export { default as TMagicUiIteratorContainer } from '@tmagic/vue-iterator-container';
export { default as TMagicUiOverlay } from '@tmagic/vue-overlay';
export { default as TMagicUiPage } from '@tmagic/vue-page';
export { default as TMagicUiPageFragment } from '@tmagic/vue-page-fragment';
export { default as TMagicUiPageFragmentContainer } from '@tmagic/vue-page-fragment-container';
export { default as TMagicUiQRcode } from '@tmagic/vue-qrcode';
export { default as TMagicUiText } from '@tmagic/vue-text';
const ui: Record<string, any> = {
page: Page,
container: Container,
button: Button,
text: Text,
img: Img,
qrcode: QRcode,
overlay: Overlay,
'page-fragment-container': PageFragmentContainer,
'page-fragment': PageFragment,
'iterator-container': IteratorContainer,
};
export default ui;

4
runtime/vue/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.tmagic
dist
*.local
*.local.*

43
runtime/vue/package.json Normal file
View File

@ -0,0 +1,43 @@
{
"name": "runtime-vue",
"version": "1.6.1",
"type": "module",
"private": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"scripts": {
"tmagic": "tmagic entry",
"dev": "vite --force",
"serve": "vite preview",
"build": "rimraf ./dist && node scripts/build.mjs --type=all",
"build:libs": "node scripts/build.mjs --type=res",
"build:page": "node scripts/build.mjs --type=page",
"build:playground": "node scripts/build.mjs --type=playground"
},
"dependencies": {
"@tmagic/core": "1.6.1",
"@tmagic/stage": "1.6.1",
"@tmagic/vue-runtime-help": "^1.2.0",
"axios": "^1.11.0",
"vue": "catalog:"
},
"devDependencies": {
"@tmagic/cli": "1.6.1",
"@types/fs-extra": "^11.0.4",
"@types/node": "^24.0.10",
"@vitejs/plugin-legacy": "^7.2.1",
"@vitejs/plugin-vue": "^6.0.1",
"@vitejs/plugin-vue-jsx": "^5.1.0",
"@vue/compiler-sfc": "catalog:",
"fs-extra": "^11.3.1",
"minimist": "^1.2.8",
"lightningcss": "^1.30.2",
"rimraf": "^3.0.2",
"rollup": "4.44.1",
"rollup-plugin-external-globals": "^0.13.0",
"terser": "^5.43.1",
"typescript": "catalog:",
"vite": "catalog:"
}
}

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.png" type="image/png"> <link rel="icon" href="/favicon.png" type="image/png">
<title>Vue2 Page</title> <title>Vue Page</title>
<style> <style>
html, html,
body, body,
@ -12,7 +12,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 0 padding: 0;
} }
#app { #app {
@ -25,9 +25,6 @@
display: none; display: none;
} }
</style> </style>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-demi"></script>
</head> </head>
<body style="font-size: 14px"> <body style="font-size: 14px">
<div id="app"></div> <div id="app"></div>

View File

@ -0,0 +1,30 @@
import { defineConfig } from 'vite';
import baseConfig from '../vite.config';
const INVALID_CHAR_REGEX = /[\x00-\x1F\x7F<>*#"{}|^[\]`;?:&=+$,]/g;
const DRIVE_LETTER_REGEX = /^[a-z]:/i;
export default defineConfig({
...baseConfig,
publicDir: '../public',
base: `${baseConfig.base}/page`,
build: {
emptyOutDir: false,
sourcemap: true,
outDir: '../dist/page',
rollupOptions: {
output: {
// https://github.com/rollup/rollup/blob/master/src/utils/sanitizeFileName.ts
sanitizeFileName(name) {
const match = DRIVE_LETTER_REGEX.exec(name);
const driveLetter = match ? match[0] : '';
return driveLetter + name.slice(driveLetter.length).replace(INVALID_CHAR_REGEX, '');
},
},
},
},
});

View File

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="/favicon.png" type="image/png"> <link rel="icon" href="/favicon.png" type="image/png">
<title>Vue2 Playground</title> <title>Vue Playground</title>
<style> <style>
.magic-ui-page { .magic-ui-page {
overflow: hidden; overflow: hidden;
@ -21,7 +21,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 0 padding: 0;
} }
#app { #app {
@ -37,12 +37,8 @@
background-color: rgba(51, 153, 255, 0.5) !important; background-color: rgba(51, 153, 255, 0.5) !important;
} }
</style> </style>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-demi"></script>
</head> </head>
<body style="font-size: 14px"> <body style="font-size: 14px">
<div id="app" class="in-editor"></div> <div id="app" class="in-editor"></div>
<script type="module" src="./main.ts"></script> <script type="module" src="./main.ts"></script>

Some files were not shown because too many files have changed in this diff Show More