Compare commits
18 Commits
v1.2.3
...
v1.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae00dd242d | ||
|
|
f70e0976f5 | ||
|
|
a27004bcba | ||
|
|
1f5ed8b066 | ||
|
|
cdea1f9be2 | ||
|
|
63b7ae9828 | ||
|
|
9fa55d9540 | ||
|
|
24ae886efe | ||
|
|
a9418eff02 | ||
|
|
6b63e85601 | ||
|
|
a78a1b8786 | ||
|
|
3ca9cbfae7 | ||
|
|
c263564bb6 | ||
|
|
19678f6452 | ||
|
|
699114af4a | ||
|
|
d25c32ea5d | ||
|
|
a6d009b435 | ||
|
|
75de2cadc1 |
@@ -75,4 +75,8 @@ playground 的示例项目,就是为开发者提供的基础应用示例。开
|
||||
|
||||
如果你有好的意见或建议,欢迎给我们提 Issues 或 Pull Requests,为提升魔方可视化编辑器开发体验贡献力量。<br>详见:[CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
|
||||
[腾讯开源激励计划](https://opensource.tencent.com/contribution) 鼓励开发者的参与和贡献,期待你的加入。
|
||||
[腾讯开源激励计划](https://opensource.tencent.com/contribution) 鼓励开发者的参与和贡献,期待你的加入。
|
||||
|
||||
### 欢迎入群交流
|
||||
|
||||
<img src="https://vfiles.gtimg.cn/vupload/20220412/b85d331649748582992.jpg" width=375>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"npmClient": "npm",
|
||||
"packages": [
|
||||
"packages/*",
|
||||
|
||||
15
package-lock.json
generated
15
package-lock.json
generated
@@ -14360,6 +14360,21 @@
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"keycode": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz",
|
||||
"integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg=="
|
||||
},
|
||||
"keycon": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/keycon/-/keycon-1.1.2.tgz",
|
||||
"integrity": "sha512-yCoUAfwqmQUWrtOFuZhicxasF/4ae+M0aH8yV1wEKKZCZql8v6jWhlVF9dT5i1TfuHSmgt/GNuCaWIHT8wk6eQ==",
|
||||
"requires": {
|
||||
"@daybrush/utils": "^1.0.0",
|
||||
"@scena/event-emitter": "^1.0.2",
|
||||
"keycode": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
|
||||
0
packages/core/README.md
Normal file
0
packages/core/README.md
Normal file
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"name": "@tmagic/core",
|
||||
"sideEffects": false,
|
||||
"main": "dist/tmagic-core.umd.js",
|
||||
@@ -25,8 +25,11 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||
},
|
||||
"keywords": [
|
||||
"vue"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tmagic/schema": "^1.0.0-beta.11",
|
||||
"@tmagic/schema": "^1.0.0-beta.12",
|
||||
"events": "^3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
1
packages/editor/README.md
Normal file
1
packages/editor/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# [文档](https://tencent.github.io/tmagic-editor/docs/)
|
||||
2
packages/editor/package-lock.json
generated
2
packages/editor/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tmagic/editor",
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"name": "@tmagic/editor",
|
||||
"sideEffects": false,
|
||||
"main": "dist/tmagic-editor.umd.js",
|
||||
@@ -26,16 +26,26 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||
},
|
||||
"homepage": "https://tencent.github.io/tmagic-editor/docs/",
|
||||
"keywords": [
|
||||
"editor",
|
||||
"drag",
|
||||
"resize",
|
||||
"vue",
|
||||
"vue3",
|
||||
"typescript"
|
||||
],
|
||||
"dependencies": {
|
||||
"@element-plus/icons": "0.0.11",
|
||||
"@tmagic/core": "^1.0.0-beta.11",
|
||||
"@tmagic/form": "^1.0.0-beta.11",
|
||||
"@tmagic/schema": "^1.0.0-beta.11",
|
||||
"@tmagic/stage": "^1.0.0-beta.11",
|
||||
"@tmagic/utils": "^1.0.0-beta.11",
|
||||
"@tmagic/core": "^1.0.0-beta.12",
|
||||
"@tmagic/form": "^1.0.0-beta.12",
|
||||
"@tmagic/schema": "^1.0.0-beta.12",
|
||||
"@tmagic/stage": "^1.0.0-beta.12",
|
||||
"@tmagic/utils": "^1.0.0-beta.12",
|
||||
"color": "^3.1.3",
|
||||
"element-plus": "^2.1.7",
|
||||
"events": "^3.3.0",
|
||||
"keycon": "^1.1.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"monaco-editor": "^0.32.1",
|
||||
"serialize-javascript": "^6.0.0",
|
||||
|
||||
@@ -39,9 +39,9 @@ export default defineComponent({
|
||||
return;
|
||||
}
|
||||
|
||||
values.value = node.value;
|
||||
const type = node.value.type || (node.value.items ? 'container' : 'text');
|
||||
curFormConfig.value = (await services?.propsService.getPropsConfig(type)) || [];
|
||||
values.value = node.value;
|
||||
};
|
||||
|
||||
watchEffect(init);
|
||||
|
||||
@@ -56,11 +56,11 @@ export default defineComponent({
|
||||
collapseValue,
|
||||
list,
|
||||
|
||||
appendComponent({ text, type, ...config }: ComponentItem): void {
|
||||
appendComponent({ text, type, data = {} }: ComponentItem): void {
|
||||
services?.editorService.add({
|
||||
name: text,
|
||||
type,
|
||||
...config,
|
||||
...data,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -72,6 +72,7 @@ export default defineComponent({
|
||||
services?.editorService.add({
|
||||
name: config.text,
|
||||
type: config.type,
|
||||
...(config.data || {}),
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="m-editor-workspace">
|
||||
<div class="m-editor-workspace" tabindex="1" ref="workspace">
|
||||
<magic-stage
|
||||
:key="page?.id"
|
||||
:runtime-url="runtimeUrl"
|
||||
@@ -18,9 +18,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, PropType } from 'vue';
|
||||
import { computed, defineComponent, inject, onMounted, onUnmounted, PropType, ref } from 'vue';
|
||||
import KeyController from 'keycon';
|
||||
|
||||
import type { MPage } from '@tmagic/schema';
|
||||
import type { MNode, MPage } from '@tmagic/schema';
|
||||
import type { MoveableOptions } from '@tmagic/stage';
|
||||
import StageCore from '@tmagic/stage';
|
||||
|
||||
@@ -55,8 +56,52 @@ export default defineComponent({
|
||||
|
||||
setup() {
|
||||
const services = inject<Services>('services');
|
||||
const workspace = ref<HTMLDivElement>();
|
||||
const node = computed(() => services?.editorService.get<MNode>('node'));
|
||||
let keycon: KeyController;
|
||||
|
||||
const mouseenterHandler = () => {
|
||||
workspace.value?.focus();
|
||||
};
|
||||
|
||||
const mouseleaveHandler = () => {
|
||||
workspace.value?.blur();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
workspace.value?.addEventListener('mouseenter', mouseenterHandler);
|
||||
|
||||
workspace.value?.addEventListener('mouseleave', mouseleaveHandler);
|
||||
|
||||
keycon = new KeyController(workspace.value);
|
||||
|
||||
keycon
|
||||
.keyup('delete', () => {
|
||||
node.value && services?.editorService.remove(node.value);
|
||||
})
|
||||
.keyup(['ctrl', 'c'], () => {
|
||||
node.value && services?.editorService.copy(node.value);
|
||||
})
|
||||
.keyup(['ctrl', 'v'], () => {
|
||||
node.value && services?.editorService.paste();
|
||||
})
|
||||
.keyup(['ctrl', 'x'], () => {
|
||||
if (node.value && services) {
|
||||
services.editorService.copy(node.value);
|
||||
services.editorService.remove(node.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
|
||||
workspace.value?.removeEventListener('mouseleave', mouseleaveHandler);
|
||||
keycon.destroy();
|
||||
});
|
||||
|
||||
return {
|
||||
workspace,
|
||||
|
||||
page: computed(() => services?.editorService.get<MPage>('page')),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -22,7 +22,7 @@ import serialize from 'serialize-javascript';
|
||||
|
||||
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
import type StageCore from '@tmagic/stage';
|
||||
import StageCore from '@tmagic/stage';
|
||||
import { getNodePath, isPop } from '@tmagic/utils';
|
||||
|
||||
import historyService, { StepValue } from '@editor/services/history';
|
||||
@@ -228,7 +228,12 @@ class Editor extends BaseService {
|
||||
if (!parentNode) throw new Error('未找到父元素');
|
||||
|
||||
const layout = await this.getLayout(parentNode);
|
||||
const newNode = initPosition({ ...toRaw(await propsService.getPropsValue(type)), ...config }, layout);
|
||||
const newNode = initPosition(
|
||||
{ ...toRaw(await propsService.getPropsValue(type, config)) },
|
||||
layout,
|
||||
parentNode,
|
||||
this.get<StageCore>('stage'),
|
||||
);
|
||||
|
||||
if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
|
||||
throw new Error('app下不能添加组件');
|
||||
|
||||
@@ -87,7 +87,7 @@ class Props extends BaseService {
|
||||
* @param type 组件类型
|
||||
* @returns 组件初始值
|
||||
*/
|
||||
public async getPropsValue(type: string) {
|
||||
public async getPropsValue(type: string, defaultValue = {}) {
|
||||
if (type === 'area') {
|
||||
const value = (await this.getPropsValue('button')) as MComponent;
|
||||
value.className = 'action-area';
|
||||
@@ -100,6 +100,7 @@ class Props extends BaseService {
|
||||
|
||||
return cloneDeep({
|
||||
...getDefaultPropsValue(type),
|
||||
...defaultValue,
|
||||
...(this.state.propsValueMap[type] || {}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -220,7 +220,9 @@ export interface ComponentItem {
|
||||
type: string;
|
||||
/** element-plus icon class */
|
||||
icon?: string | Component;
|
||||
[key: string]: any;
|
||||
data?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ComponentGroup {
|
||||
|
||||
@@ -20,7 +20,8 @@ import { random } from 'lodash-es';
|
||||
|
||||
import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
import { getNodePath, isPop } from '@tmagic/utils';
|
||||
import type StageCore from '@tmagic/stage';
|
||||
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
||||
|
||||
import { Layout } from '@editor/type';
|
||||
|
||||
@@ -105,7 +106,7 @@ const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
|
||||
export const setNewItemId = (config: MNode, parent?: MPage) => {
|
||||
const oldId = config.id;
|
||||
|
||||
config.id = generateId(config.type);
|
||||
config.id = generateId(config.type || 'component');
|
||||
config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`;
|
||||
|
||||
// 只有弹窗在页面下的一级子元素才有效
|
||||
@@ -139,11 +140,29 @@ export const toRelative = (node: MNode) => {
|
||||
return node;
|
||||
};
|
||||
|
||||
export const initPosition = (node: MNode, layout: Layout) => {
|
||||
const setTop2Middle = (node: MNode, parentNode: MNode, stage: StageCore) => {
|
||||
const style = node.style || {};
|
||||
const height = style.height || 0;
|
||||
|
||||
if (!stage || style.top || !parentNode.style || !isNumber(height)) return style;
|
||||
|
||||
const { height: parentHeight } = parentNode.style;
|
||||
|
||||
if (isPage(parentNode)) {
|
||||
const { scrollTop = 0, wrapperHeight } = stage.mask;
|
||||
style.top = (wrapperHeight - height) / 2 + scrollTop;
|
||||
} else {
|
||||
style.top = (parentHeight - height) / 2;
|
||||
}
|
||||
|
||||
return style;
|
||||
};
|
||||
|
||||
export const initPosition = (node: MNode, layout: Layout, parentNode: MNode, stage: StageCore) => {
|
||||
if (layout === Layout.ABSOLUTE) {
|
||||
node.style = {
|
||||
position: 'absolute',
|
||||
...(node.style || {}),
|
||||
...setTop2Middle(node, parentNode, stage),
|
||||
};
|
||||
return node;
|
||||
}
|
||||
@@ -200,6 +219,8 @@ export const Fixed2Other = async (node: MNode, root: MApp, getLayout: (node: MNo
|
||||
const offset = {
|
||||
left: cur?.style?.left || 0,
|
||||
top: cur?.style?.top || 0,
|
||||
right: '',
|
||||
bottom: '',
|
||||
};
|
||||
|
||||
path.forEach((value) => {
|
||||
|
||||
@@ -174,7 +174,7 @@ export const fillConfig = (config: FormConfig = []) => [
|
||||
type: 'select',
|
||||
options: (mForm: FormState, { model }: any) => {
|
||||
const node = editorService.getNodeById(model.to);
|
||||
if (!node) return [];
|
||||
if (!node?.type) return [];
|
||||
|
||||
return eventsService.getMethod(node.type).map((option) => ({
|
||||
text: option.label,
|
||||
|
||||
@@ -28,17 +28,21 @@ describe('events', () => {
|
||||
items: [
|
||||
{
|
||||
icon: 'el-icon-folder-opened',
|
||||
id: 0,
|
||||
reportType: 'module',
|
||||
text: '组',
|
||||
type: 'container',
|
||||
data: {
|
||||
id: 0,
|
||||
reportType: 'module',
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'el-icon-files',
|
||||
id: 0,
|
||||
reportType: 'module',
|
||||
text: '标签页(tab)',
|
||||
type: 'tabs',
|
||||
data: {
|
||||
id: 0,
|
||||
reportType: 'module',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
1
packages/form/README.md
Normal file
1
packages/form/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# [文档](https://tencent.github.io/tmagic-editor/docs/)
|
||||
2
packages/form/package-lock.json
generated
2
packages/form/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tmagic/form",
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"name": "@tmagic/form",
|
||||
"sideEffects": false,
|
||||
"main": "dist/tmagic-form.umd.js",
|
||||
@@ -28,7 +28,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons": "0.0.11",
|
||||
"@tmagic/utils": "^1.0.0-beta.11",
|
||||
"@tmagic/utils": "^1.0.0-beta.12",
|
||||
"element-plus": "^2.1.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment": "^2.29.1",
|
||||
|
||||
@@ -86,7 +86,7 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
size: {
|
||||
type: String,
|
||||
type: String as PropType<'small' | 'default' | 'large'>,
|
||||
},
|
||||
|
||||
inline: {
|
||||
|
||||
@@ -78,7 +78,7 @@ export default defineComponent({
|
||||
|
||||
labelWidth: [Number, String],
|
||||
|
||||
size: String as PropType<'mini' | 'small' | 'medium'>,
|
||||
size: String as PropType<'small' | 'default' | 'large'>,
|
||||
|
||||
confirmText: {
|
||||
type: String,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
:value-key="config.valueKey || 'value'"
|
||||
:allow-create="config.allowCreate"
|
||||
:disabled="disabled"
|
||||
:remote-method="remoteMethod"
|
||||
:remote-method="config.remote && remoteMethod"
|
||||
@change="changeHandler"
|
||||
@visible-change="visibleHandler"
|
||||
>
|
||||
@@ -354,8 +354,6 @@ export default defineComponent({
|
||||
return getConfig('request');
|
||||
},
|
||||
|
||||
async getInitOption() {},
|
||||
|
||||
changeHandler(value: any) {
|
||||
emit('change', value);
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<el-button
|
||||
v-if="typeof config.append === 'object' && config.append.type === 'button'"
|
||||
style="color: #409eff"
|
||||
:size="size"
|
||||
@click.prevent="buttonClickHandler"
|
||||
>
|
||||
{{ config.append.text }}
|
||||
@@ -43,6 +44,8 @@ export default defineComponent({
|
||||
emits: ['change', 'input'],
|
||||
|
||||
setup(props, { emit }) {
|
||||
const mForm = inject<FormState | undefined>('mForm');
|
||||
|
||||
useAddField(props.prop);
|
||||
|
||||
const modelName = computed(() => props.name || props.config.name || '');
|
||||
@@ -54,14 +57,11 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
inputHandler(v: string | number) {
|
||||
const mForm = inject<FormState | undefined>('mForm');
|
||||
emit('input', v);
|
||||
mForm?.$emit('field-input', props.prop, v);
|
||||
},
|
||||
|
||||
buttonClickHandler() {
|
||||
const mForm = inject<FormState | undefined>('mForm');
|
||||
|
||||
if (typeof props.config.append === 'string') return;
|
||||
|
||||
if (props.config.append?.handler) {
|
||||
|
||||
@@ -122,7 +122,11 @@ const initValueItem = function (
|
||||
// 这种情况比较多,提前结束
|
||||
if (name && !items && typeof initValue[name] !== 'undefined') {
|
||||
if (typeof value[name] === 'undefined') {
|
||||
value[name] = typeof initValue[name] === 'object' ? cloneDeep(initValue[name]) : initValue[name];
|
||||
if (type === 'number') {
|
||||
value[name] = Number(initValue[name]);
|
||||
} else {
|
||||
value[name] = typeof initValue[name] === 'object' ? cloneDeep(initValue[name]) : initValue[name];
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
1
packages/schema/README.md
Normal file
1
packages/schema/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# [文档](https://tencent.github.io/tmagic-editor/docs/)
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"name": "@tmagic/schema",
|
||||
"sideEffects": false,
|
||||
"main": "src/index.ts",
|
||||
|
||||
1
packages/stage/README.md
Normal file
1
packages/stage/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# [文档](https://tencent.github.io/tmagic-editor/docs/)
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"name": "@tmagic/stage",
|
||||
"sideEffects": false,
|
||||
"main": "dist/tmagic-stage.umd.js",
|
||||
@@ -23,8 +23,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@scena/guides": "^0.17.0",
|
||||
"@tmagic/schema": "^1.0.0-beta.11",
|
||||
"@tmagic/utils": "^1.0.0-beta.11",
|
||||
"@tmagic/schema": "^1.0.0-beta.12",
|
||||
"@tmagic/utils": "^1.0.0-beta.12",
|
||||
"events": "^3.3.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moveable": "^0.28.0",
|
||||
|
||||
@@ -169,10 +169,10 @@ export default class StageCore extends EventEmitter {
|
||||
* 更新选中的节点
|
||||
* @param data 更新的数据
|
||||
*/
|
||||
public update(data: UpdateData): void {
|
||||
public update(data: UpdateData): Promise<void> {
|
||||
const { config } = data;
|
||||
|
||||
this.renderer?.getRuntime().then((runtime) => {
|
||||
return this.renderer?.getRuntime().then((runtime) => {
|
||||
runtime?.update?.(data);
|
||||
// 更新配置后,需要等组件渲染更新
|
||||
setTimeout(() => {
|
||||
@@ -205,16 +205,16 @@ export default class StageCore extends EventEmitter {
|
||||
this.highlightedDom = el;
|
||||
}
|
||||
|
||||
public sortNode(data: SortEventData): void {
|
||||
this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
|
||||
public sortNode(data: SortEventData): Promise<void> {
|
||||
return this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
|
||||
}
|
||||
|
||||
public add(data: UpdateData): void {
|
||||
this.renderer?.getRuntime().then((runtime) => runtime?.add?.(data));
|
||||
public add(data: UpdateData): Promise<void> {
|
||||
return this.renderer?.getRuntime().then((runtime) => runtime?.add?.(data));
|
||||
}
|
||||
|
||||
public remove(data: RemoveData): void {
|
||||
this.renderer?.getRuntime().then((runtime) => runtime?.remove?.(data));
|
||||
public remove(data: RemoveData): Promise<void> {
|
||||
return this.renderer?.getRuntime().then((runtime) => runtime?.remove?.(data));
|
||||
}
|
||||
|
||||
public setZoom(zoom: number = DEFAULT_ZOOM): void {
|
||||
|
||||
@@ -367,6 +367,7 @@ export default class StageDragResize extends EventEmitter {
|
||||
if (!this.target) return {};
|
||||
|
||||
const isAbsolute = this.mode === Mode.ABSOLUTE;
|
||||
const isFixed = this.mode === Mode.FIXED;
|
||||
|
||||
let { moveableOptions = {} } = this.core.config;
|
||||
|
||||
@@ -381,8 +382,8 @@ export default class StageDragResize extends EventEmitter {
|
||||
dragArea: false,
|
||||
draggable: true,
|
||||
resizable: true,
|
||||
snappable: isAbsolute,
|
||||
snapGap: isAbsolute,
|
||||
snappable: isAbsolute || isFixed,
|
||||
snapGap: isAbsolute || isFixed,
|
||||
snapThreshold: 5,
|
||||
snapDigit: 0,
|
||||
throttleDrag: 0,
|
||||
|
||||
@@ -56,6 +56,7 @@ export default class StageHighlight extends EventEmitter {
|
||||
*/
|
||||
public clearHighlight(): void {
|
||||
if (!this.moveable) return;
|
||||
this.target = undefined;
|
||||
this.moveable.target = null;
|
||||
this.moveable.updateTarget();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import type { StageMaskConfig } from './types';
|
||||
import { createDiv, getScrollParent, isFixedParent } from './util';
|
||||
|
||||
const wrapperClassName = 'editor-mask-wrapper';
|
||||
const throttleTime = 300;
|
||||
const throttleTime = 100;
|
||||
|
||||
const hideScrollbar = () => {
|
||||
const style = globalThis.document.createElement('style');
|
||||
@@ -81,6 +81,8 @@ export default class StageMask extends Rule {
|
||||
public height = 0;
|
||||
public wrapperHeight = 0;
|
||||
public wrapperWidth = 0;
|
||||
public maxScrollTop = 0;
|
||||
public maxScrollLeft = 0;
|
||||
|
||||
private mode: Mode = Mode.ABSOLUTE;
|
||||
private pageResizeObserver: ResizeObserver | null = null;
|
||||
@@ -104,6 +106,7 @@ export default class StageMask extends Rule {
|
||||
this.wrapper.appendChild(this.content);
|
||||
this.content.addEventListener('wheel', this.mouseWheelHandler);
|
||||
this.content.addEventListener('mousemove', this.highlightHandler);
|
||||
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
||||
}
|
||||
|
||||
public setMode(mode: Mode) {
|
||||
@@ -136,6 +139,10 @@ export default class StageMask extends Rule {
|
||||
const { clientHeight, clientWidth } = entry.target;
|
||||
this.setHeight(clientHeight);
|
||||
this.setWidth(clientWidth);
|
||||
|
||||
this.fixScrollValue();
|
||||
this.scroll();
|
||||
this.core.dr.updateMoveable();
|
||||
});
|
||||
|
||||
this.pageResizeObserver.observe(page);
|
||||
@@ -145,6 +152,8 @@ export default class StageMask extends Rule {
|
||||
const { clientHeight, clientWidth } = entry.target;
|
||||
this.wrapperHeight = clientHeight;
|
||||
this.wrapperWidth = clientWidth;
|
||||
this.setMaxScrollLeft();
|
||||
this.setMaxScrollTop();
|
||||
});
|
||||
this.wrapperResizeObserver.observe(this.wrapper);
|
||||
}
|
||||
@@ -173,12 +182,21 @@ export default class StageMask extends Rule {
|
||||
this.pageScrollParent = null;
|
||||
this.pageResizeObserver?.disconnect();
|
||||
this.wrapperResizeObserver?.disconnect();
|
||||
|
||||
this.content.removeEventListener('mouseleave', this.mouseLeaveHandler);
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
private scroll() {
|
||||
let { scrollLeft, scrollTop } = this;
|
||||
|
||||
if (this.pageScrollParent) {
|
||||
this.pageScrollParent.scrollTo({
|
||||
top: scrollTop,
|
||||
left: scrollLeft,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.mode === Mode.FIXED) {
|
||||
scrollLeft = 0;
|
||||
scrollTop = 0;
|
||||
@@ -198,6 +216,7 @@ export default class StageMask extends Rule {
|
||||
*/
|
||||
private setHeight(height: number): void {
|
||||
this.height = height;
|
||||
this.setMaxScrollTop();
|
||||
this.content.style.height = `${height}px`;
|
||||
}
|
||||
|
||||
@@ -207,9 +226,35 @@ export default class StageMask extends Rule {
|
||||
*/
|
||||
private setWidth(width: number): void {
|
||||
this.width = width;
|
||||
this.setMaxScrollLeft();
|
||||
this.content.style.width = `${width}px`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算并设置最大滚动宽度
|
||||
*/
|
||||
private setMaxScrollLeft(): void {
|
||||
this.maxScrollLeft = this.width - this.wrapperWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算并设置最大滚动高度
|
||||
*/
|
||||
private setMaxScrollTop(): void {
|
||||
this.maxScrollTop = this.height - this.wrapperHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复滚动距离
|
||||
* 由于滚动容器变化等因素,会导致当前滚动的距离不正确
|
||||
*/
|
||||
private fixScrollValue(): void {
|
||||
if (this.scrollTop < 0) this.scrollTop = 0;
|
||||
if (this.scrollLeft < 0) this.scrollLeft = 0;
|
||||
if (this.maxScrollTop < this.scrollTop) this.scrollTop = this.maxScrollTop;
|
||||
if (this.maxScrollLeft < this.scrollLeft) this.scrollLeft = this.maxScrollLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击事件处理函数
|
||||
* @param event 事件对象
|
||||
@@ -246,39 +291,22 @@ export default class StageMask extends Rule {
|
||||
if (!this.page) throw new Error('page 未初始化');
|
||||
|
||||
const { deltaY, deltaX } = event;
|
||||
const { height, wrapperHeight, width, wrapperWidth } = this;
|
||||
|
||||
const maxScrollTop = height - wrapperHeight;
|
||||
const maxScrollLeft = width - wrapperWidth;
|
||||
|
||||
if (maxScrollTop > 0) {
|
||||
if (deltaY > 0) {
|
||||
this.scrollTop = this.scrollTop + Math.min(maxScrollTop - this.scrollTop, deltaY);
|
||||
} else {
|
||||
this.scrollTop = Math.max(this.scrollTop + deltaY, 0);
|
||||
}
|
||||
if (this.maxScrollTop > 0) {
|
||||
this.scrollTop = this.scrollTop + deltaY;
|
||||
}
|
||||
|
||||
if (width > wrapperWidth) {
|
||||
if (deltaX > 0) {
|
||||
this.scrollLeft = this.scrollLeft + Math.min(maxScrollLeft - this.scrollLeft, deltaX);
|
||||
} else {
|
||||
this.scrollLeft = Math.max(this.scrollLeft + deltaX, 0);
|
||||
}
|
||||
if (this.maxScrollLeft > 0) {
|
||||
this.scrollLeft = this.scrollLeft + deltaX;
|
||||
}
|
||||
|
||||
if (this.mode !== Mode.FIXED) {
|
||||
this.scrollTo(this.scrollLeft, this.scrollTop);
|
||||
}
|
||||
this.fixScrollValue();
|
||||
|
||||
if (this.pageScrollParent) {
|
||||
this.pageScrollParent.scrollTo({
|
||||
top: this.scrollTop,
|
||||
left: this.scrollLeft,
|
||||
});
|
||||
}
|
||||
this.scroll();
|
||||
|
||||
this.emit('scroll', event);
|
||||
};
|
||||
|
||||
private mouseLeaveHandler = () => {
|
||||
setTimeout(() => this.emit('clearHighlight'), throttleTime);
|
||||
};
|
||||
}
|
||||
|
||||
1
packages/table/README.md
Normal file
1
packages/table/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# [文档](https://tencent.github.io/tmagic-editor/docs/)
|
||||
2
packages/table/package-lock.json
generated
2
packages/table/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tmagic/table",
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"name": "@tmagic/table",
|
||||
"sideEffects": false,
|
||||
"main": "dist/tmagic-table.umd.js",
|
||||
@@ -26,7 +26,7 @@
|
||||
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tmagic/form": "^1.0.0-beta.11",
|
||||
"@tmagic/form": "^1.0.0-beta.12",
|
||||
"element-plus": "^2.1.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"vue": "^3.2.0"
|
||||
|
||||
2
packages/ui-react/package-lock.json
generated
2
packages/ui-react/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tmagic/ui-react",
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tmagic/ui-react",
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"main": "src/index.ts",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
@@ -13,7 +13,7 @@
|
||||
"react:build": "tsc && vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tmagic/schema": "^1.0.0-beta.11",
|
||||
"@tmagic/schema": "^1.0.0-beta.12",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
},
|
||||
|
||||
1
packages/ui/README.md
Normal file
1
packages/ui/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# [文档](https://tencent.github.io/tmagic-editor/docs/)
|
||||
2
packages/ui/package-lock.json
generated
2
packages/ui/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tmagic/ui",
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"name": "@tmagic/ui",
|
||||
"main": "src/index.ts",
|
||||
"engines": {
|
||||
@@ -10,7 +10,7 @@
|
||||
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tmagic/schema": "^1.0.0-beta.11",
|
||||
"@tmagic/schema": "^1.0.0-beta.12",
|
||||
"delegate": "^3.2.0",
|
||||
"tiny-emitter": "^2.1.0",
|
||||
"vue": "^3.2.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"name": "@tmagic/utils",
|
||||
"main": "dist/tmagic-utils.umd.js",
|
||||
"module": "dist/tmagic-utils.es.js",
|
||||
@@ -20,6 +20,10 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tmagic/schema": "^1.0.0-beta.12",
|
||||
"moment": "^2.29.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^15.12.4",
|
||||
"typescript": "^4.3.4",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
import { MNode } from '@tmagic/schema';
|
||||
import { MNode, NodeType } from '@tmagic/schema';
|
||||
|
||||
export const sleep = (ms: number): Promise<void> =>
|
||||
new Promise((resolve) => {
|
||||
@@ -204,3 +204,7 @@ export const getUrlParam = (param: string, url?: string) => {
|
||||
};
|
||||
|
||||
export const isPop = (node: MNode): boolean => Boolean(node.type?.toLowerCase().endsWith('pop'));
|
||||
|
||||
export const isPage = (node: MNode): boolean => Boolean(node.type?.toLowerCase() === NodeType.PAGE);
|
||||
|
||||
export const isNumber = (value: string) => /^(\d|\.)+$/.test(value);
|
||||
|
||||
2
playground/package-lock.json
generated
2
playground/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tmagic-playground",
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tmagic-playground",
|
||||
"version": "1.0.0-beta.11",
|
||||
"version": "1.0.0-beta.12",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -9,11 +9,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons": "0.0.11",
|
||||
"@tmagic/editor": "^1.0.0-beta.11",
|
||||
"@tmagic/form": "^1.0.0-beta.11",
|
||||
"@tmagic/schema": "^1.0.0-beta.11",
|
||||
"@tmagic/stage": "^1.0.0-beta.11",
|
||||
"@tmagic/utils": "^1.0.0-beta.11",
|
||||
"@tmagic/editor": "^1.0.0-beta.12",
|
||||
"@tmagic/form": "^1.0.0-beta.12",
|
||||
"@tmagic/schema": "^1.0.0-beta.12",
|
||||
"@tmagic/stage": "^1.0.0-beta.12",
|
||||
"@tmagic/utils": "^1.0.0-beta.12",
|
||||
"element-plus": "^2.1.7",
|
||||
"serialize-javascript": "^6.0.0",
|
||||
"vue": "^3.2.0",
|
||||
|
||||
Reference in New Issue
Block a user