mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-06-03 06:29:18 +08:00
feat: 新增tmagic-form-runtime
This commit is contained in:
parent
a10ae0ddd1
commit
f8443ed316
@ -18,6 +18,7 @@
|
|||||||
"@tmagic/editor": "1.3.9",
|
"@tmagic/editor": "1.3.9",
|
||||||
"@tmagic/element-plus-adapter": "1.3.9",
|
"@tmagic/element-plus-adapter": "1.3.9",
|
||||||
"@tmagic/form": "1.3.9",
|
"@tmagic/form": "1.3.9",
|
||||||
|
"@tmagic/tmagic-form-runtime": "1.0.0",
|
||||||
"@tmagic/schema": "1.3.9",
|
"@tmagic/schema": "1.3.9",
|
||||||
"@tmagic/stage": "1.3.9",
|
"@tmagic/stage": "1.3.9",
|
||||||
"@tmagic/utils": "1.3.9",
|
"@tmagic/utils": "1.3.9",
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
import type { FormConfig } from '@tmagic/form';
|
|
||||||
|
|
||||||
export default [] as FormConfig;
|
|
@ -1,3 +0,0 @@
|
|||||||
import type { FormConfig } from '@tmagic/form';
|
|
||||||
|
|
||||||
export default [] as FormConfig;
|
|
@ -1,3 +0,0 @@
|
|||||||
import type { FormConfig } from '@tmagic/form';
|
|
||||||
|
|
||||||
export default [] as FormConfig;
|
|
@ -7,6 +7,7 @@
|
|||||||
:props-configs="propsConfigs"
|
:props-configs="propsConfigs"
|
||||||
:render="render"
|
:render="render"
|
||||||
:can-select="canSelect"
|
:can-select="canSelect"
|
||||||
|
:disabled-page-fragment="true"
|
||||||
:stage-rect="{ width: 'calc(100% - 70px)', height: '100%' }"
|
:stage-rect="{ width: 'calc(100% - 70px)', height: '100%' }"
|
||||||
:moveable-options="{ resizable: false }"
|
:moveable-options="{ resizable: false }"
|
||||||
>
|
>
|
||||||
@ -17,33 +18,26 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { createApp, onBeforeUnmount, ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { Document } from '@element-plus/icons-vue';
|
import { Document } from '@element-plus/icons-vue';
|
||||||
import cssStyle from 'element-plus/dist/index.css?raw';
|
|
||||||
|
|
||||||
|
import { MenuBarData, SideBarData, TMagicEditor, traverseNode } from '@tmagic/editor';
|
||||||
|
import { type MApp, NodeType } from '@tmagic/schema';
|
||||||
import {
|
import {
|
||||||
ComponentGroup,
|
canSelect,
|
||||||
MenuBarData,
|
COMPONENT_GROUP_LIST as componentGroupList,
|
||||||
propsService,
|
propsConfigs,
|
||||||
SideBarData,
|
useRuntime,
|
||||||
TMagicEditor,
|
} from '@tmagic/tmagic-form-runtime';
|
||||||
traverseNode,
|
import { guid } from '@tmagic/utils';
|
||||||
uiService,
|
|
||||||
} from '@tmagic/editor';
|
|
||||||
import MagicForm, { type FormConfig, MForm } from '@tmagic/form';
|
|
||||||
import { type MApp, type MNode, NodeType } from '@tmagic/schema';
|
|
||||||
import type StageCore from '@tmagic/stage';
|
|
||||||
import { guid, injectStyle } from '@tmagic/utils';
|
|
||||||
|
|
||||||
import propsConfigs from '../configs/form-config';
|
|
||||||
import commonConfig from '../configs/form-config/common';
|
|
||||||
import formDsl from '../configs/formDsl';
|
import formDsl from '../configs/formDsl';
|
||||||
|
|
||||||
formDsl.forEach((item) => {
|
formDsl.forEach((item) => {
|
||||||
traverseNode<any>(item, (item) => {
|
traverseNode<any>(item, (item) => {
|
||||||
item.id = `${item.type}_${guid()}`;
|
|
||||||
item.type = item.type || (item.items ? 'container' : 'text');
|
item.type = item.type || (item.items ? 'container' : 'text');
|
||||||
|
item.id = `${item.type}_${guid()}`;
|
||||||
item.style = {
|
item.style = {
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
@ -55,95 +49,10 @@ formDsl.forEach((item) => {
|
|||||||
const config = ref<MApp>({
|
const config = ref<MApp>({
|
||||||
type: NodeType.ROOT,
|
type: NodeType.ROOT,
|
||||||
id: 'app_form',
|
id: 'app_form',
|
||||||
items: [
|
items: [],
|
||||||
{
|
|
||||||
type: NodeType.PAGE,
|
|
||||||
id: 'page_form',
|
|
||||||
layout: 'relative',
|
|
||||||
items: formDsl as unknown as MNode[],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const render = (stage: StageCore) => {
|
const { render } = useRuntime();
|
||||||
injectStyle(stage.renderer.getDocument()!, cssStyle);
|
|
||||||
injectStyle(
|
|
||||||
stage.renderer.getDocument()!,
|
|
||||||
`
|
|
||||||
html,
|
|
||||||
body,
|
|
||||||
#app {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const el: HTMLDivElement = globalThis.document.createElement('div');
|
|
||||||
el.id = 'app';
|
|
||||||
el.style.overflow = 'auto';
|
|
||||||
createApp(MForm, {
|
|
||||||
config: config.value.items[0].items,
|
|
||||||
initValues: {},
|
|
||||||
})
|
|
||||||
.use(MagicForm)
|
|
||||||
.mount(el);
|
|
||||||
|
|
||||||
stage.renderer.contentWindow?.magic?.onRuntimeReady({});
|
|
||||||
setTimeout(() => {
|
|
||||||
stage.renderer.contentWindow?.magic.onPageElUpdate(el.children[0] as HTMLElement);
|
|
||||||
uiService.set('showRule', false);
|
|
||||||
});
|
|
||||||
|
|
||||||
return el;
|
|
||||||
};
|
|
||||||
|
|
||||||
const componentGroupList: ComponentGroup[] = [
|
|
||||||
{
|
|
||||||
title: '容器',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
text: '普通容器',
|
|
||||||
type: 'container',
|
|
||||||
data: {
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '表格',
|
|
||||||
type: 'table',
|
|
||||||
data: {
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '组列表',
|
|
||||||
type: 'group-list',
|
|
||||||
data: {
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '面板',
|
|
||||||
type: 'panel',
|
|
||||||
data: {
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '行',
|
|
||||||
type: 'row',
|
|
||||||
data: {
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@ -186,27 +95,4 @@ const sidebar: SideBarData = {
|
|||||||
status: '组件',
|
status: '组件',
|
||||||
items: ['component-list', 'layer'],
|
items: ['component-list', 'layer'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const canSelect = (el: HTMLElement) => Boolean(el.dataset.magicId);
|
|
||||||
|
|
||||||
propsService.usePlugin({
|
|
||||||
afterFillConfig(config: FormConfig, itemConfig: FormConfig) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
type: 'tab',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: '属性',
|
|
||||||
labelWidth: '80px',
|
|
||||||
items: [...commonConfig, ...itemConfig],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
propsService.removeAllPlugins();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -54,6 +54,10 @@ export default defineConfig({
|
|||||||
{ find: /^@tmagic\/editor/, replacement: path.join(__dirname, '../packages/editor/src/index.ts') },
|
{ find: /^@tmagic\/editor/, replacement: path.join(__dirname, '../packages/editor/src/index.ts') },
|
||||||
{ find: /^@tmagic\/schema/, replacement: path.join(__dirname, '../packages/schema/src/index.ts') },
|
{ find: /^@tmagic\/schema/, replacement: path.join(__dirname, '../packages/schema/src/index.ts') },
|
||||||
{ find: /^@tmagic\/form/, replacement: path.join(__dirname, '../packages/form/src/index.ts') },
|
{ find: /^@tmagic\/form/, replacement: path.join(__dirname, '../packages/form/src/index.ts') },
|
||||||
|
{
|
||||||
|
find: /^@tmagic\/tmagic-form-runtime/,
|
||||||
|
replacement: path.join(__dirname, '../runtime/tmagic-form/src/index.ts'),
|
||||||
|
},
|
||||||
{ find: /^@tmagic\/table/, replacement: path.join(__dirname, '../packages/table/src/index.ts') },
|
{ find: /^@tmagic\/table/, replacement: path.join(__dirname, '../packages/table/src/index.ts') },
|
||||||
{ find: /^@tmagic\/stage/, replacement: path.join(__dirname, '../packages/stage/src/index.ts') },
|
{ find: /^@tmagic\/stage/, replacement: path.join(__dirname, '../packages/stage/src/index.ts') },
|
||||||
{ find: /^@tmagic\/utils/, replacement: path.join(__dirname, '../packages/utils/src/index.ts') },
|
{ find: /^@tmagic\/utils/, replacement: path.join(__dirname, '../packages/utils/src/index.ts') },
|
||||||
|
54
pnpm-lock.yaml
generated
54
pnpm-lock.yaml
generated
@ -761,6 +761,9 @@ importers:
|
|||||||
'@tmagic/stage':
|
'@tmagic/stage':
|
||||||
specifier: 1.3.9
|
specifier: 1.3.9
|
||||||
version: link:../packages/stage
|
version: link:../packages/stage
|
||||||
|
'@tmagic/tmagic-form-runtime':
|
||||||
|
specifier: 1.0.0
|
||||||
|
version: link:../runtime/tmagic-form
|
||||||
'@tmagic/utils':
|
'@tmagic/utils':
|
||||||
specifier: 1.3.9
|
specifier: 1.3.9
|
||||||
version: link:../packages/utils
|
version: link:../packages/utils
|
||||||
@ -890,6 +893,55 @@ importers:
|
|||||||
specifier: ^5.0.7
|
specifier: ^5.0.7
|
||||||
version: 5.0.7(@types/node@18.19.3)(sass@1.35.1)(terser@5.14.2)
|
version: 5.0.7(@types/node@18.19.3)(sass@1.35.1)(terser@5.14.2)
|
||||||
|
|
||||||
|
runtime/tmagic-form:
|
||||||
|
dependencies:
|
||||||
|
'@tmagic/core':
|
||||||
|
specifier: ^1.3.9
|
||||||
|
version: link:../../packages/core
|
||||||
|
'@tmagic/editor':
|
||||||
|
specifier: ^1.3.9
|
||||||
|
version: link:../../packages/editor
|
||||||
|
'@tmagic/form':
|
||||||
|
specifier: ^1.3.9
|
||||||
|
version: link:../../packages/form
|
||||||
|
'@tmagic/schema':
|
||||||
|
specifier: ^1.3.9
|
||||||
|
version: link:../../packages/schema
|
||||||
|
'@tmagic/utils':
|
||||||
|
specifier: ^1.3.9
|
||||||
|
version: link:../../packages/utils
|
||||||
|
element-plus:
|
||||||
|
specifier: ^2.4.3
|
||||||
|
version: 2.4.3(vue@3.3.8)
|
||||||
|
vue:
|
||||||
|
specifier: ^3.3.8
|
||||||
|
version: 3.3.8(typescript@5.0.4)
|
||||||
|
devDependencies:
|
||||||
|
'@tmagic/stage':
|
||||||
|
specifier: ^1.3.9
|
||||||
|
version: link:../../packages/stage
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^18.19.0
|
||||||
|
version: 18.19.3
|
||||||
|
'@vitejs/plugin-vue':
|
||||||
|
specifier: ^4.5.2
|
||||||
|
version: 4.5.2(vite@5.0.7)(vue@3.3.8)
|
||||||
|
'@vue/compiler-sfc':
|
||||||
|
specifier: ^3.3.8
|
||||||
|
version: 3.3.8
|
||||||
|
rimraf:
|
||||||
|
specifier: ^3.0.2
|
||||||
|
version: 3.0.2
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.0.4
|
||||||
|
version: 5.0.4
|
||||||
|
vite:
|
||||||
|
specifier: ^5.0.7
|
||||||
|
version: 5.0.7(@types/node@18.19.3)(sass@1.35.1)(terser@5.14.2)
|
||||||
|
vue-tsc:
|
||||||
|
specifier: ^1.8.25
|
||||||
|
version: 1.8.25(typescript@5.0.4)
|
||||||
|
|
||||||
runtime/vue2:
|
runtime/vue2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tmagic/cli':
|
'@tmagic/cli':
|
||||||
@ -8936,7 +8988,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
hosted-git-info: 4.1.0
|
hosted-git-info: 4.1.0
|
||||||
is-core-module: 2.11.0
|
is-core-module: 2.11.0
|
||||||
semver: 7.5.1
|
semver: 7.5.4
|
||||||
validate-npm-package-license: 3.0.4
|
validate-npm-package-license: 3.0.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
38
runtime/tmagic-form/README.md
Normal file
38
runtime/tmagic-form/README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# TMagicFormRuntime
|
||||||
|
TMagicFormRuntime 基于@tmagic/form的编辑器runtime
|
||||||
|
|
||||||
|
## 环境准备
|
||||||
|
|
||||||
|
先基于[tmagic-editor](https://tencent.github.io/tmagic-editor/docs/guide/)将编辑器搭建起来
|
||||||
|
|
||||||
|
按住依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm add @tmagic/tmagic-form-runtime
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<TMagicEditor
|
||||||
|
:component-group-list="componentGroupList"
|
||||||
|
:props-configs="propsConfigs"
|
||||||
|
:render="render"
|
||||||
|
:can-select="canSelect"
|
||||||
|
:disabled-page-fragment="true"
|
||||||
|
:stage-rect="{ width: 'calc(100% - 70px)', height: '100%' }"
|
||||||
|
:moveable-options="{ resizable: false }"
|
||||||
|
|
||||||
|
...
|
||||||
|
>
|
||||||
|
</TMagicEditor>
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {
|
||||||
|
canSelect,
|
||||||
|
COMPONENT_GROUP_LIST as componentGroupList,
|
||||||
|
propsConfigs,
|
||||||
|
useRuntime,
|
||||||
|
} from '@tmagic/tmagic-form-runtime';
|
||||||
|
|
||||||
|
const { render } = useRuntime();
|
||||||
|
```
|
58
runtime/tmagic-form/package.json
Normal file
58
runtime/tmagic-form/package.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"name": "@tmagic/tmagic-form-runtime",
|
||||||
|
"type": "module",
|
||||||
|
"sideEffects": [
|
||||||
|
"dist/*",
|
||||||
|
"src/theme/*"
|
||||||
|
],
|
||||||
|
"main": "dist/tmagic-form-runtime.umd.cjs",
|
||||||
|
"module": "dist/tmagic-form-runtime.js",
|
||||||
|
"types": "types/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./types/index.d.ts",
|
||||||
|
"import": "./dist/tmagic-form-runtime.js",
|
||||||
|
"require": "./dist/tmagic-form.umd-runtime.cjs"
|
||||||
|
},
|
||||||
|
"./*": "./*"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "npm run build:type && vite build",
|
||||||
|
"build:type": "npm run clear:type && vue-tsc --declaration --emitDeclarationOnly --project tsconfig.build.json",
|
||||||
|
"clear:type": "rimraf ./types"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tmagic/core": "^1.3.9",
|
||||||
|
"@tmagic/editor": "^1.3.9",
|
||||||
|
"@tmagic/form": "^1.3.9",
|
||||||
|
"@tmagic/utils": "^1.3.9",
|
||||||
|
"@tmagic/schema": "^1.3.9",
|
||||||
|
"element-plus": "^2.4.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tmagic/editor": "^1.3.9",
|
||||||
|
"@tmagic/form": "^1.3.9",
|
||||||
|
"@tmagic/schema": "^1.3.9",
|
||||||
|
"element-plus": "^2.4.3",
|
||||||
|
"vue": "^3.3.8"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tmagic/stage": "^1.3.9",
|
||||||
|
"@types/node": "^18.19.0",
|
||||||
|
"@vitejs/plugin-vue": "^4.5.2",
|
||||||
|
"@vue/compiler-sfc": "^3.3.8",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"typescript": "^5.0.4",
|
||||||
|
"vite": "^5.0.7",
|
||||||
|
"vue-tsc": "^1.8.25"
|
||||||
|
}
|
||||||
|
}
|
25
runtime/tmagic-form/src/App.vue
Normal file
25
runtime/tmagic-form/src/App.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<MForm ref="mForm" :id="config?.id" :data-magic-id="config?.id" :config="formConfig" :init-values="values"></MForm>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { watch } from 'vue';
|
||||||
|
|
||||||
|
import { MForm } from '@tmagic/form';
|
||||||
|
import type StageCore from '@tmagic/stage';
|
||||||
|
|
||||||
|
import { useFormConfig } from './useFormConfig';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
stage: StageCore;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { mForm, formConfig, config, values } = useFormConfig(props.stage.renderer.contentWindow);
|
||||||
|
|
||||||
|
watch(formConfig, async () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const page = props.stage.renderer.getDocument()?.querySelector<HTMLElement>('.m-form');
|
||||||
|
page && props.stage.renderer.contentWindow?.magic.onPageElUpdate(page);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
161
runtime/tmagic-form/src/component-group-list.ts
Normal file
161
runtime/tmagic-form/src/component-group-list.ts
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import type { ComponentGroup } from '@tmagic/editor';
|
||||||
|
|
||||||
|
export const COMPONENT_GROUP_LIST: ComponentGroup[] = [
|
||||||
|
{
|
||||||
|
title: '容器',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
text: '普通容器',
|
||||||
|
type: 'container',
|
||||||
|
data: {
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '表格',
|
||||||
|
type: 'table',
|
||||||
|
data: {
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '组列表',
|
||||||
|
type: 'group-list',
|
||||||
|
data: {
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '面板',
|
||||||
|
type: 'panel',
|
||||||
|
data: {
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '行',
|
||||||
|
type: 'row',
|
||||||
|
data: {
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '表单组件',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
text: '输入框',
|
||||||
|
type: 'text',
|
||||||
|
data: {
|
||||||
|
text: '输入框',
|
||||||
|
name: 'text',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '数字输入框',
|
||||||
|
type: 'number',
|
||||||
|
data: {
|
||||||
|
text: '数字输入框',
|
||||||
|
name: 'number',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '文本域',
|
||||||
|
type: 'textarea',
|
||||||
|
data: {
|
||||||
|
text: '文本域',
|
||||||
|
name: 'textarea',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '链接',
|
||||||
|
type: 'link',
|
||||||
|
data: {
|
||||||
|
text: '链接',
|
||||||
|
name: 'link',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '日期',
|
||||||
|
type: 'datetime',
|
||||||
|
data: {
|
||||||
|
text: '日期',
|
||||||
|
name: 'datetime',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '时间',
|
||||||
|
type: 'time',
|
||||||
|
data: {
|
||||||
|
text: '时间',
|
||||||
|
name: 'time',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '选中器',
|
||||||
|
type: 'select',
|
||||||
|
data: {
|
||||||
|
text: '选中器',
|
||||||
|
name: 'select',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '级联选择器',
|
||||||
|
type: 'cascader',
|
||||||
|
data: {
|
||||||
|
text: '级联选择器',
|
||||||
|
name: 'cascader',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '开关',
|
||||||
|
type: 'switch',
|
||||||
|
data: {
|
||||||
|
text: '开关',
|
||||||
|
name: 'switch',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '多选框',
|
||||||
|
type: 'checkbox',
|
||||||
|
data: {
|
||||||
|
text: '多选框',
|
||||||
|
name: 'checkbox',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '多选组',
|
||||||
|
type: 'checkboxGroup',
|
||||||
|
data: {
|
||||||
|
text: '多选组',
|
||||||
|
name: 'checkboxGroup',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '单选框',
|
||||||
|
type: 'radio',
|
||||||
|
data: {
|
||||||
|
text: '单选框',
|
||||||
|
name: 'radio',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '单选组',
|
||||||
|
type: 'radioGroup',
|
||||||
|
data: {
|
||||||
|
text: '单选组',
|
||||||
|
name: 'radioGroup',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '取色器',
|
||||||
|
type: 'colorPicker',
|
||||||
|
data: {
|
||||||
|
text: '取色器',
|
||||||
|
name: 'colorPicker',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
14
runtime/tmagic-form/src/form-config/checkbox.ts
Normal file
14
runtime/tmagic-form/src/form-config/checkbox.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { createForm } from '@tmagic/form';
|
||||||
|
|
||||||
|
export default createForm([
|
||||||
|
{
|
||||||
|
name: 'activeValue',
|
||||||
|
text: '选中时的值',
|
||||||
|
defaultValue: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'inactiveValue',
|
||||||
|
text: '没有选中时的值',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
]);
|
@ -1,6 +1,6 @@
|
|||||||
import type { FormConfig } from '@tmagic/form';
|
import { createForm } from '@tmagic/form';
|
||||||
|
|
||||||
export default [
|
export default createForm([
|
||||||
{
|
{
|
||||||
name: 'id',
|
name: 'id',
|
||||||
type: 'hidden',
|
type: 'hidden',
|
||||||
@ -24,4 +24,10 @@ export default [
|
|||||||
text: '标签宽度',
|
text: '标签宽度',
|
||||||
extra: '表单域标签的的宽度,例如 "50px"。支持 auto。',
|
extra: '表单域标签的的宽度,例如 "50px"。支持 auto。',
|
||||||
},
|
},
|
||||||
] as FormConfig;
|
{
|
||||||
|
name: 'disabled',
|
||||||
|
text: '是否禁用',
|
||||||
|
type: 'switch',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
]);
|
3
runtime/tmagic-form/src/form-config/display.ts
Normal file
3
runtime/tmagic-form/src/form-config/display.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { createForm } from '@tmagic/form';
|
||||||
|
|
||||||
|
export default createForm([]);
|
@ -1,13 +1,17 @@
|
|||||||
|
import type { FormConfig } from '@tmagic/form';
|
||||||
|
|
||||||
import checkbox from './checkbox';
|
import checkbox from './checkbox';
|
||||||
import display from './display';
|
import display from './display';
|
||||||
import number from './number';
|
import number from './number';
|
||||||
import switchConfig from './switch';
|
import switchConfig from './switch';
|
||||||
import text from './text';
|
import text from './text';
|
||||||
|
|
||||||
export default {
|
const configs: Record<string, FormConfig> = {
|
||||||
text,
|
text,
|
||||||
checkbox,
|
checkbox,
|
||||||
display,
|
display,
|
||||||
number,
|
number,
|
||||||
switch: switchConfig,
|
switch: switchConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default configs;
|
@ -1,6 +1,6 @@
|
|||||||
import type { FormConfig } from '@tmagic/form';
|
import { createForm } from '@tmagic/form';
|
||||||
|
|
||||||
export default [
|
export default createForm([
|
||||||
{
|
{
|
||||||
type: 'number',
|
type: 'number',
|
||||||
name: 'min',
|
name: 'min',
|
||||||
@ -20,4 +20,4 @@ export default [
|
|||||||
name: 'placeholder',
|
name: 'placeholder',
|
||||||
text: 'placeholder',
|
text: 'placeholder',
|
||||||
},
|
},
|
||||||
] as FormConfig;
|
]);
|
3
runtime/tmagic-form/src/form-config/switch.ts
Normal file
3
runtime/tmagic-form/src/form-config/switch.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { createForm } from '@tmagic/form';
|
||||||
|
|
||||||
|
export default createForm([]);
|
@ -1,6 +1,6 @@
|
|||||||
import type { FormConfig } from '@tmagic/form';
|
import { createForm } from '@tmagic/form';
|
||||||
|
|
||||||
export default [
|
export default createForm([
|
||||||
{
|
{
|
||||||
name: 'placeholder',
|
name: 'placeholder',
|
||||||
text: 'placeholder',
|
text: 'placeholder',
|
||||||
@ -10,7 +10,14 @@ export default [
|
|||||||
legend: '后置按钮',
|
legend: '后置按钮',
|
||||||
type: 'fieldset',
|
type: 'fieldset',
|
||||||
labelWidth: '80px',
|
labelWidth: '80px',
|
||||||
|
checkbox: true,
|
||||||
|
expand: true,
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
type: 'hidden',
|
||||||
|
defaultValue: 'button',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'text',
|
name: 'text',
|
||||||
text: '按钮文案',
|
text: '按钮文案',
|
||||||
@ -23,4 +30,4 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
] as FormConfig;
|
]);
|
86
runtime/tmagic-form/src/index.ts
Normal file
86
runtime/tmagic-form/src/index.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { createApp, onBeforeUnmount } from 'vue';
|
||||||
|
import cssStyle from 'element-plus/dist/index.css?raw';
|
||||||
|
|
||||||
|
import { editorService, Layout, propsService, uiService } from '@tmagic/editor';
|
||||||
|
import MagicForm, { type FormConfig } from '@tmagic/form';
|
||||||
|
import type StageCore from '@tmagic/stage';
|
||||||
|
import { injectStyle } from '@tmagic/utils';
|
||||||
|
|
||||||
|
import commonConfig from './form-config/common';
|
||||||
|
import App from './App.vue';
|
||||||
|
import formConfigs from './form-config';
|
||||||
|
|
||||||
|
export * from './component-group-list';
|
||||||
|
|
||||||
|
export const propsConfigs = formConfigs;
|
||||||
|
|
||||||
|
export const canSelect = (el: HTMLElement) => Boolean(el.dataset.magicId);
|
||||||
|
|
||||||
|
export const useRuntime = () => {
|
||||||
|
const render = (stage: StageCore) => {
|
||||||
|
injectStyle(stage.renderer.getDocument()!, cssStyle);
|
||||||
|
injectStyle(
|
||||||
|
stage.renderer.getDocument()!,
|
||||||
|
`
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const el: HTMLDivElement = globalThis.document.createElement('div');
|
||||||
|
el.id = 'app';
|
||||||
|
el.style.overflow = 'auto';
|
||||||
|
|
||||||
|
createApp(App, {
|
||||||
|
stage,
|
||||||
|
})
|
||||||
|
.use(MagicForm)
|
||||||
|
.mount(el);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
uiService.set('showRule', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
|
||||||
|
propsService.usePlugin({
|
||||||
|
afterFillConfig(config: FormConfig, itemConfig: FormConfig) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'tab',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: '属性',
|
||||||
|
labelWidth: '80px',
|
||||||
|
items: [...commonConfig, ...itemConfig],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
editorService.usePlugin({
|
||||||
|
afterGetLayout() {
|
||||||
|
return Layout.RELATIVE;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
propsService.removeAllPlugins();
|
||||||
|
editorService.removeAllPlugins();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
render,
|
||||||
|
};
|
||||||
|
};
|
143
runtime/tmagic-form/src/useFormConfig.ts
Normal file
143
runtime/tmagic-form/src/useFormConfig.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { computed, nextTick, onBeforeUnmount, reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
import Core from '@tmagic/core';
|
||||||
|
import { type FormConfig, initValue, MForm } from '@tmagic/form';
|
||||||
|
import type { Id, MApp, MNode } from '@tmagic/schema';
|
||||||
|
import type { RemoveData, RuntimeWindow, UpdateData } from '@tmagic/stage';
|
||||||
|
import { getNodePath, replaceChildNode } from '@tmagic/utils';
|
||||||
|
|
||||||
|
export const useFormConfig = (contentWindow: RuntimeWindow | null) => {
|
||||||
|
const mForm = ref<InstanceType<typeof MForm>>();
|
||||||
|
|
||||||
|
const root = ref<MApp>();
|
||||||
|
const values = ref({});
|
||||||
|
const curPageId = ref<Id>();
|
||||||
|
const selectedId = ref<Id>();
|
||||||
|
|
||||||
|
const config = computed(
|
||||||
|
() => root.value?.items?.find((item: MNode) => item.id === curPageId.value) || root.value?.items?.[0],
|
||||||
|
);
|
||||||
|
|
||||||
|
const formConfig = computed(() => (config.value?.items || []) as FormConfig);
|
||||||
|
|
||||||
|
const app = new Core({
|
||||||
|
ua: contentWindow?.navigator.userAgent,
|
||||||
|
platform: 'editor',
|
||||||
|
});
|
||||||
|
|
||||||
|
const resetValues = () => {
|
||||||
|
initValue(mForm.value?.formState, {
|
||||||
|
initValues: {},
|
||||||
|
config: formConfig.value,
|
||||||
|
}).then((value) => {
|
||||||
|
values.value = value;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const runtimeReadyHandler = ({ data }: any) => {
|
||||||
|
if (!data.tmagicRuntimeReady) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
contentWindow?.magic?.onRuntimeReady({
|
||||||
|
getApp() {
|
||||||
|
return app;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateRootConfig(config: MApp) {
|
||||||
|
root.value = config;
|
||||||
|
app?.setConfig(config, curPageId.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePageId(id: Id) {
|
||||||
|
curPageId.value = id;
|
||||||
|
app?.setPage(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
select(id: Id) {
|
||||||
|
selectedId.value = id;
|
||||||
|
|
||||||
|
if (app?.getPage(id)) {
|
||||||
|
this.updatePageId?.(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const el = document.getElementById(`${id}`);
|
||||||
|
if (el) return el;
|
||||||
|
// 未在当前文档下找到目标元素,可能是还未渲染,等待渲染完成后再尝试获取
|
||||||
|
return nextTick().then(() => document.getElementById(`${id}`) as HTMLElement);
|
||||||
|
},
|
||||||
|
|
||||||
|
add({ config, parentId }: UpdateData) {
|
||||||
|
if (!root.value) throw new Error('error');
|
||||||
|
if (!selectedId.value) throw new Error('error');
|
||||||
|
if (!parentId) throw new Error('error');
|
||||||
|
|
||||||
|
const parent = getNodePath(parentId, [root.value]).pop();
|
||||||
|
if (!parent) throw new Error('未找到父节点');
|
||||||
|
|
||||||
|
if (config.type !== 'page') {
|
||||||
|
const parentNode = app?.page?.getNode(parent.id);
|
||||||
|
parentNode && app?.page?.initNode(config, parentNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.id !== selectedId.value) {
|
||||||
|
const index = parent.items?.findIndex((child: MNode) => child.id === selectedId.value);
|
||||||
|
parent.items?.splice(index + 1, 0, config);
|
||||||
|
} else {
|
||||||
|
// 新增节点添加到配置中
|
||||||
|
parent.items?.push(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetValues();
|
||||||
|
},
|
||||||
|
|
||||||
|
update({ config, parentId }: UpdateData) {
|
||||||
|
if (!root.value || !app) throw new Error('error');
|
||||||
|
|
||||||
|
const newNode = app.dataSourceManager?.compiledNode(config) || config;
|
||||||
|
replaceChildNode(reactive(newNode), [root.value], parentId);
|
||||||
|
|
||||||
|
const nodeInstance = app.page?.getNode(config.id);
|
||||||
|
if (nodeInstance) {
|
||||||
|
nodeInstance.setData(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetValues();
|
||||||
|
},
|
||||||
|
|
||||||
|
remove({ id, parentId }: RemoveData) {
|
||||||
|
if (!root.value) throw new Error('error');
|
||||||
|
|
||||||
|
const node = getNodePath(id, [root.value]).pop();
|
||||||
|
if (!node) throw new Error('未找到目标元素');
|
||||||
|
|
||||||
|
const parent = getNodePath(parentId, [root.value]).pop();
|
||||||
|
if (!parent) throw new Error('未找到父元素');
|
||||||
|
|
||||||
|
if (node.type === 'page') {
|
||||||
|
app?.deletePage();
|
||||||
|
} else {
|
||||||
|
app?.page?.deleteNode(node.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = parent.items?.findIndex((child: MNode) => child.id === node.id);
|
||||||
|
parent.items.splice(index, 1);
|
||||||
|
|
||||||
|
resetValues();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
contentWindow?.addEventListener('message', runtimeReadyHandler);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
contentWindow?.removeEventListener('message', runtimeReadyHandler);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
mForm,
|
||||||
|
config,
|
||||||
|
formConfig,
|
||||||
|
values,
|
||||||
|
};
|
||||||
|
};
|
13
runtime/tmagic-form/tsconfig.build.json
Normal file
13
runtime/tmagic-form/tsconfig.build.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"declaration": true,
|
||||||
|
"declarationDir": "types",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"paths": {},
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
}
|
6
runtime/tmagic-form/tsconfig.json
Normal file
6
runtime/tmagic-form/tsconfig.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "../..",
|
||||||
|
},
|
||||||
|
}
|
45
runtime/tmagic-form/vite.config.ts
Normal file
45
runtime/tmagic-form/vite.config.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 { defineConfig } from 'vite';
|
||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
|
||||||
|
import pkg from './package.json';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
|
||||||
|
build: {
|
||||||
|
cssCodeSplit: false,
|
||||||
|
sourcemap: true,
|
||||||
|
minify: false,
|
||||||
|
target: 'esnext',
|
||||||
|
|
||||||
|
lib: {
|
||||||
|
entry: 'src/index.ts',
|
||||||
|
name: 'TMagicFormRuntime',
|
||||||
|
fileName: 'tmagic-form-runtime',
|
||||||
|
},
|
||||||
|
|
||||||
|
rollupOptions: {
|
||||||
|
// 确保外部化处理那些你不想打包进库的依赖
|
||||||
|
external(id: string) {
|
||||||
|
return Object.keys(pkg.dependencies).some((k) => new RegExp(`^${k}`).test(id));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
@ -19,6 +19,7 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
// 内部模块都指向 src/index.ts, 会有更好的代码跳转体验.
|
// 内部模块都指向 src/index.ts, 会有更好的代码跳转体验.
|
||||||
"@tmagic/*": ["packages/*/src"],
|
"@tmagic/*": ["packages/*/src"],
|
||||||
|
"@tmagic/tmagic-form-runtime": ["runtime/tmagic-form/src"],
|
||||||
"@editor/*": ["packages/editor/src/*"],
|
"@editor/*": ["packages/editor/src/*"],
|
||||||
"@form/*": ["packages/form/src/*"],
|
"@form/*": ["packages/form/src/*"],
|
||||||
"@data-source/*": ["packages/data-source/src/*"],
|
"@data-source/*": ["packages/data-source/src/*"],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user