Compare commits
8 Commits
v1.7.0-bet
...
v1.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6314078c10 | ||
|
|
b8f16eb3e1 | ||
|
|
4d2e42842f | ||
|
|
7b061ef8d3 | ||
|
|
67eab4a131 | ||
|
|
af61b10775 | ||
|
|
464d713b99 | ||
|
|
a24b57a129 |
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"npmClient": "npm",
|
||||
"packages": [
|
||||
"packages/*",
|
||||
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
@@ -15678,6 +15678,15 @@
|
||||
"react-simple-compat": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"moveable-helper": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/moveable-helper/-/moveable-helper-0.4.0.tgz",
|
||||
"integrity": "sha512-t1FK9PO187Gn0N6GVZcrQgePjiHmuj8eUhmJjH38LvTMnVVxiHzWYRx6ARFZvSFIIW4yb6BEAv4C99Bsx84nFw==",
|
||||
"requires": {
|
||||
"@daybrush/utils": "^1.0.0",
|
||||
"scenejs": "^1.4.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
@@ -16420,6 +16429,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"order-map": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/order-map/-/order-map-0.2.2.tgz",
|
||||
"integrity": "sha512-X//Db/lT11tdxxutWQfE+bmbTyieDJWrr/vSiwBwOf8RRw9yAgF7gqn1ihFmfX2E7l7gcPcucep3aWFjo5FpoA==",
|
||||
"requires": {
|
||||
"@daybrush/utils": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"os-browserify": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
|
||||
@@ -18067,6 +18084,17 @@
|
||||
"xmlchars": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"scenejs": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/scenejs/-/scenejs-1.5.0.tgz",
|
||||
"integrity": "sha512-Xo6LjUsaVcTbC+FGMMwUH1jthAQUj6bq2i55iEBBifrBn/nzm/++dGo8tqjCzMbm6KUPOpiry38N7r9QY2mWpQ==",
|
||||
"requires": {
|
||||
"@daybrush/utils": "^1.3.1",
|
||||
"@scena/event-emitter": "^1.0.3",
|
||||
"css-styled": "^1.0.0",
|
||||
"order-map": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"name": "@tmagic/core",
|
||||
"sideEffects": false,
|
||||
"main": "dist/tmagic-core.umd.js",
|
||||
@@ -26,7 +26,7 @@
|
||||
"url": "https://github.com/Tencent/tmagic-editor.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tmagic/schema": "^1.0.0-beta.8",
|
||||
"@tmagic/schema": "^1.0.0-beta.9",
|
||||
"events": "^3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
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.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"name": "@tmagic/editor",
|
||||
"sideEffects": false,
|
||||
"main": "dist/tmagic-editor.umd.js",
|
||||
@@ -28,10 +28,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons": "0.0.11",
|
||||
"@tmagic/core": "^1.0.0-beta.8",
|
||||
"@tmagic/core": "^1.0.0-beta.9",
|
||||
"@tmagic/form": "^1.0.0-beta.8",
|
||||
"@tmagic/schema": "^1.0.0-beta.8",
|
||||
"@tmagic/stage": "^1.0.0-beta.8",
|
||||
"@tmagic/schema": "^1.0.0-beta.9",
|
||||
"@tmagic/stage": "^1.0.0-beta.9",
|
||||
"@tmagic/utils": "^1.0.0-beta.8",
|
||||
"color": "^3.1.3",
|
||||
"element-plus": "^2.1.7",
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
import { computed, defineComponent, inject, PropType } from 'vue';
|
||||
import { ArrowDown, Back, Delete, Grid, Right, ScaleToOriginal, ZoomIn, ZoomOut } from '@element-plus/icons';
|
||||
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import MIcon from '@editor/components/Icon.vue';
|
||||
import type { MenuButton, MenuComponent, MenuItem, Services } from '@editor/type';
|
||||
|
||||
@@ -87,7 +89,7 @@ export default defineComponent({
|
||||
type: 'button',
|
||||
icon: Delete,
|
||||
tooltip: '刪除',
|
||||
disabled: () => services?.editorService.get('node')?.type === 'page',
|
||||
disabled: () => services?.editorService.get('node')?.type === NodeType.PAGE,
|
||||
handler: () => services?.editorService.remove(services?.editorService.get('node')),
|
||||
};
|
||||
case 'undo':
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
import { defineComponent, inject, toRaw } from 'vue';
|
||||
import { Plus } from '@element-plus/icons';
|
||||
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import { Services } from '@editor/type';
|
||||
import { generatePageNameByApp } from '@editor/utils';
|
||||
|
||||
@@ -31,7 +33,7 @@ export default defineComponent({
|
||||
if (!editorService) return;
|
||||
|
||||
editorService.add({
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
name: generatePageNameByApp(toRaw(editorService.get('root'))),
|
||||
});
|
||||
},
|
||||
|
||||
@@ -58,6 +58,7 @@ import type { ElTree } from 'element-plus';
|
||||
import { throttle } from 'lodash-es';
|
||||
|
||||
import type { MNode, MPage } from '@tmagic/schema';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import type { EditorService } from '@editor/services/editor';
|
||||
import type { Services } from '@editor/type';
|
||||
@@ -88,8 +89,8 @@ const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorServi
|
||||
|
||||
const { type: ingType } = ingData;
|
||||
|
||||
if (ingType !== 'page' && data.type === 'page') return false;
|
||||
if (ingType === 'page' && data.type !== 'page') return false;
|
||||
if (ingType !== NodeType.PAGE && data.type === NodeType.PAGE) return false;
|
||||
if (ingType === NodeType.PAGE && data.type !== NodeType.PAGE) return false;
|
||||
if (!data || !data.type) return false;
|
||||
if (['prev', 'next'].includes(type)) return true;
|
||||
if (data.items || data.type === 'container') return true;
|
||||
|
||||
@@ -11,9 +11,13 @@
|
||||
:class="{ active: page?.id === item.id }"
|
||||
@click="switchPage(item)"
|
||||
>
|
||||
<slot name="page-bar-title" :page="item">
|
||||
<span>{{ item.name }}</span>
|
||||
</slot>
|
||||
<div class="m-editor-page-bar-title">
|
||||
<slot name="page-bar-title" :page="item">
|
||||
<el-tooltip effect="dark" placement="top-start" :content="item.name">
|
||||
<span>{{ item.name }}</span>
|
||||
</el-tooltip>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<el-popover placement="top" :width="160" trigger="hover">
|
||||
<div>
|
||||
@@ -38,6 +42,7 @@ import { computed, defineComponent, inject, toRaw } from 'vue';
|
||||
import { CaretBottom, Plus } from '@element-plus/icons';
|
||||
|
||||
import type { MPage } from '@tmagic/schema';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import type { Services } from '@editor/type';
|
||||
import { generatePageNameByApp } from '@editor/utils/editor';
|
||||
@@ -60,7 +65,7 @@ export default defineComponent({
|
||||
addPage() {
|
||||
if (!editorService) return;
|
||||
const pageConfig = {
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
name: generatePageNameByApp(toRaw(editorService.get('root'))),
|
||||
};
|
||||
editorService.add(pageConfig);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, onMounted, ref, watch } from 'vue';
|
||||
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
import type StageCore from '@tmagic/stage';
|
||||
|
||||
import { LayerOffset, Layout, Services } from '@editor/type';
|
||||
@@ -53,7 +54,8 @@ export default defineComponent({
|
||||
if (!parent.value || !editorService) return (canCenter.value = false);
|
||||
const layout = await editorService.getLayout(parent.value);
|
||||
canCenter.value =
|
||||
[Layout.ABSOLUTE, Layout.FIXED].includes(layout) && !['app', 'page', 'pop'].includes(`${node.value?.type}`);
|
||||
[Layout.ABSOLUTE, Layout.FIXED].includes(layout) &&
|
||||
![NodeType.ROOT, NodeType.PAGE, 'pop'].includes(`${node.value?.type}`);
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
@@ -62,8 +64,8 @@ export default defineComponent({
|
||||
menu,
|
||||
canPaste,
|
||||
|
||||
canDelete: computed(() => node.value?.type !== 'page'),
|
||||
canMoveZPos: computed(() => node.value?.type !== 'page'),
|
||||
canDelete: computed(() => node.value?.type !== NodeType.PAGE),
|
||||
canMoveZPos: computed(() => node.value?.type !== NodeType.PAGE),
|
||||
canCenter,
|
||||
|
||||
center() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { cloneDeep, mergeWith } from 'lodash-es';
|
||||
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 { getNodePath, isPop } from '@tmagic/utils';
|
||||
|
||||
@@ -121,7 +122,7 @@ class Editor extends BaseService {
|
||||
info.parent = path[path.length - 2] as MContainer;
|
||||
|
||||
path.forEach((item) => {
|
||||
if (item.type === 'page') {
|
||||
if (item.type === NodeType.PAGE) {
|
||||
info.page = item as MPage;
|
||||
return;
|
||||
}
|
||||
@@ -209,7 +210,7 @@ class Editor extends BaseService {
|
||||
|
||||
let parentNode: MNode | undefined;
|
||||
|
||||
if (type === 'page') {
|
||||
if (type === NodeType.PAGE) {
|
||||
parentNode = this.get<MApp>('root');
|
||||
// 由于支持中间件扩展,在parent参数为undefined时,parent会变成next函数
|
||||
} else if (parent && typeof parent !== 'function') {
|
||||
@@ -225,7 +226,7 @@ class Editor extends BaseService {
|
||||
const layout = await this.getLayout(parentNode);
|
||||
const newNode = initPosition({ ...toRaw(await propsService.getPropsValue(type)), ...config }, layout);
|
||||
|
||||
if ((parentNode?.type === 'app' || curNode.type === 'app') && newNode.type !== 'page') {
|
||||
if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
|
||||
throw new Error('app下不能添加组件');
|
||||
}
|
||||
|
||||
@@ -236,7 +237,9 @@ class Editor extends BaseService {
|
||||
await this.select(newNode);
|
||||
|
||||
this.addModifiedNodeId(newNode.id);
|
||||
this.pushHistoryState();
|
||||
if (type !== NodeType.PAGE) {
|
||||
this.pushHistoryState();
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
@@ -264,7 +267,7 @@ class Editor extends BaseService {
|
||||
parent.items?.splice(index, 1);
|
||||
this.get<StageCore>('stage')?.remove({ id: node.id, root: this.get('root') });
|
||||
|
||||
if (node.type === 'page') {
|
||||
if (node.type === NodeType.PAGE) {
|
||||
await this.select(root.items[0] || root);
|
||||
} else {
|
||||
await this.select(parent);
|
||||
@@ -300,7 +303,7 @@ class Editor extends BaseService {
|
||||
|
||||
if (!newConfig.type) throw new Error('配置缺少type值');
|
||||
|
||||
if (newConfig.type === 'app') {
|
||||
if (newConfig.type === NodeType.ROOT) {
|
||||
this.set('root', newConfig);
|
||||
return newConfig;
|
||||
}
|
||||
@@ -327,7 +330,7 @@ class Editor extends BaseService {
|
||||
|
||||
this.get<StageCore>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
|
||||
|
||||
if (newConfig.type === 'page') {
|
||||
if (newConfig.type === NodeType.PAGE) {
|
||||
this.set('page', newConfig);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
color: $--font-color;
|
||||
border-top: 1px solid $--border-color;
|
||||
z-index: 2;
|
||||
overflow: hidden;
|
||||
|
||||
.m-editor-page-bar-item {
|
||||
padding: 0 10px;
|
||||
@@ -27,5 +28,12 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.m-editor-page-bar-title {
|
||||
max-width: 150px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
|
||||
import { random } from 'lodash-es';
|
||||
|
||||
import { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
||||
import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
import { getNodePath, isPop } from '@tmagic/utils';
|
||||
|
||||
import { Layout } from '@editor/type';
|
||||
@@ -34,7 +35,7 @@ export const generateId = (type: string | number): string => `${type}_${random(1
|
||||
*/
|
||||
export const getPageList = (app: MApp): MPage[] => {
|
||||
if (app.items && Array.isArray(app.items)) {
|
||||
return app.items.filter((item: MPage) => item.type === 'page');
|
||||
return app.items.filter((item: MPage) => item.type === NodeType.PAGE);
|
||||
}
|
||||
return [];
|
||||
};
|
||||
@@ -108,7 +109,7 @@ export const setNewItemId = (config: MNode, parent?: MPage) => {
|
||||
config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`;
|
||||
|
||||
// 只有弹窗在页面下的一级子元素才有效
|
||||
if (isPop(config) && parent?.type === 'page') {
|
||||
if (isPop(config) && parent?.type === NodeType.PAGE) {
|
||||
updatePopId(oldId, config.id, parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import { mount } from '@vue/test-utils';
|
||||
import ElementPlus from 'element-plus';
|
||||
|
||||
import MagicForm from '@tmagic/form';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import Editor from '@editor/Editor.vue';
|
||||
|
||||
@@ -47,14 +48,14 @@ describe('编辑器', () => {
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: 'app',
|
||||
type: NodeType.ROOT,
|
||||
id: 1,
|
||||
name: 'app',
|
||||
items: [
|
||||
{
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
id: 2,
|
||||
name: 'page',
|
||||
name: NodeType.PAGE,
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -19,13 +19,15 @@
|
||||
import { mount } from '@vue/test-utils';
|
||||
import ElementPlus from 'element-plus';
|
||||
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import PageBar from '@editor/layouts/workspace/PageBar.vue';
|
||||
|
||||
const editorState: Record<string, any> = {
|
||||
root: {
|
||||
items: [{ key: 0, id: 1, name: 'testName', type: 'page' }],
|
||||
items: [{ key: 0, id: 1, name: 'testName', type: NodeType.PAGE }],
|
||||
},
|
||||
page: { id: 1, type: 'page' },
|
||||
page: { id: 1, type: NodeType.PAGE },
|
||||
};
|
||||
|
||||
const editorService = {
|
||||
@@ -54,7 +56,7 @@ describe('PageBar', () => {
|
||||
await wrapper.find('i[class="el-icon m-editor-page-bar-menu-add-icon"]').trigger('click');
|
||||
|
||||
expect(editorService.add.mock.calls[0][0]).toEqual({
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
name: 'page_1',
|
||||
});
|
||||
done();
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
import { mount } from '@vue/test-utils';
|
||||
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import Stage from '@editor/layouts/workspace/Stage.vue';
|
||||
|
||||
globalThis.ResizeObserver =
|
||||
@@ -40,7 +42,7 @@ describe('Stage.vue', () => {
|
||||
);
|
||||
|
||||
const page = {
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
id: '2',
|
||||
items: [
|
||||
{
|
||||
@@ -55,7 +57,7 @@ describe('Stage.vue', () => {
|
||||
runtimeUrl: '',
|
||||
root: {
|
||||
id: '1',
|
||||
type: 'app',
|
||||
type: NodeType.ROOT,
|
||||
items: [page],
|
||||
},
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
||||
import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import editorService from '@editor/services/editor';
|
||||
import { COPY_STORAGE_KEY } from '@editor/utils';
|
||||
@@ -72,12 +73,12 @@ enum NodeId {
|
||||
// mock 页面数据,包含一个页面,两个组件
|
||||
const root: MNode = {
|
||||
id: NodeId.ROOT_ID,
|
||||
type: 'app',
|
||||
type: NodeType.ROOT,
|
||||
items: [
|
||||
{
|
||||
id: NodeId.PAGE_ID,
|
||||
layout: 'absolute',
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
style: {
|
||||
width: 375,
|
||||
},
|
||||
@@ -237,7 +238,7 @@ describe('add', () => {
|
||||
const rootNode = editorService.get<MApp>('root');
|
||||
const newNode = await editorService.add(
|
||||
{
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
},
|
||||
rootNode,
|
||||
);
|
||||
@@ -279,7 +280,7 @@ describe('remove', () => {
|
||||
// 先加一个页面
|
||||
const newPage = await editorService.add(
|
||||
{
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
},
|
||||
rootNode,
|
||||
);
|
||||
@@ -395,7 +396,7 @@ describe('alignCenter', () => {
|
||||
it('正常', async () => {
|
||||
// 设置当前编辑的页面
|
||||
await editorService.select(NodeId.PAGE_ID);
|
||||
await editorService.update({ id: NodeId.PAGE_ID, isAbsoluteLayout: true, type: 'page' });
|
||||
await editorService.update({ id: NodeId.PAGE_ID, isAbsoluteLayout: true, type: NodeType.PAGE });
|
||||
await editorService.select(NodeId.NODE_ID);
|
||||
const node = editorService.get<MNode>('node');
|
||||
await editorService.alignCenter(node);
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { MNode } from '@tmagic/schema';
|
||||
import type { MNode } from '@tmagic/schema';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
|
||||
import * as editor from '@editor/utils/editor';
|
||||
|
||||
@@ -30,12 +31,12 @@ describe('util form', () => {
|
||||
it('getPageList', () => {
|
||||
const pageList = editor.getPageList({
|
||||
id: 'app_1',
|
||||
type: 'app',
|
||||
type: NodeType.ROOT,
|
||||
items: [
|
||||
{
|
||||
id: 'page_1',
|
||||
name: 'index',
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
@@ -49,7 +50,7 @@ describe('util form', () => {
|
||||
{
|
||||
id: 'page_1',
|
||||
name: 'index',
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
items: [],
|
||||
},
|
||||
]);
|
||||
@@ -79,7 +80,7 @@ describe('setNewItemId', () => {
|
||||
it('items', () => {
|
||||
const config = {
|
||||
id: 1,
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
items: [
|
||||
{
|
||||
type: 'text',
|
||||
@@ -95,7 +96,7 @@ describe('setNewItemId', () => {
|
||||
it('pop', () => {
|
||||
const config = {
|
||||
id: 1,
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
items: [
|
||||
{
|
||||
type: 'button',
|
||||
@@ -158,7 +159,7 @@ describe('getNodeIndex', () => {
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
items: [
|
||||
{
|
||||
type: 'text',
|
||||
@@ -179,7 +180,7 @@ describe('getNodeIndex', () => {
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'page',
|
||||
type: NodeType.PAGE,
|
||||
items: [
|
||||
{
|
||||
type: 'text',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"name": "@tmagic/schema",
|
||||
"sideEffects": false,
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export enum NodeType {
|
||||
CONTAINER = 'container',
|
||||
PAGE = 'page',
|
||||
ROOT = 'app',
|
||||
}
|
||||
|
||||
export type Id = string | number;
|
||||
|
||||
export interface EventItemConfig {
|
||||
@@ -47,19 +53,19 @@ export interface MComponent {
|
||||
|
||||
export interface MContainer extends MComponent {
|
||||
/** 容器类型,默认为'container' */
|
||||
type: 'container' | string;
|
||||
type: NodeType.CONTAINER | string;
|
||||
/** 容器子元素 */
|
||||
items: (MComponent | MContainer)[];
|
||||
}
|
||||
|
||||
export interface MPage extends MContainer {
|
||||
/** 页面类型 */
|
||||
type: 'page';
|
||||
type: NodeType.PAGE;
|
||||
}
|
||||
|
||||
export interface MApp extends MComponent {
|
||||
/** App页面类型,app作为整个结构的根节点;有且只有一个 */
|
||||
type: 'app';
|
||||
type: NodeType.ROOT;
|
||||
/** */
|
||||
items: MPage[];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"name": "@tmagic/stage",
|
||||
"sideEffects": false,
|
||||
"main": "dist/tmagic-stage.umd.js",
|
||||
@@ -23,11 +23,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@scena/guides": "^0.17.0",
|
||||
"@tmagic/schema": "^1.0.0-beta.8",
|
||||
"@tmagic/schema": "^1.0.0-beta.9",
|
||||
"@tmagic/utils": "^1.0.0-beta.8",
|
||||
"events": "^3.3.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moveable": "^0.28.0"
|
||||
"moveable": "^0.28.0",
|
||||
"moveable-helper": "^0.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/events": "^3.0.0",
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
UpdateData,
|
||||
UpdateEventData,
|
||||
} from './types';
|
||||
import { addSelectedClassName, removeSelectedClassName } from './util';
|
||||
|
||||
export default class StageCore extends EventEmitter {
|
||||
public selectedDom: Element | undefined;
|
||||
@@ -46,6 +47,7 @@ export default class StageCore extends EventEmitter {
|
||||
public highlightLayer: StageHighlight;
|
||||
public config: StageCoreConfig;
|
||||
public zoom = DEFAULT_ZOOM;
|
||||
public container?: HTMLDivElement;
|
||||
private canSelect: CanSelect;
|
||||
|
||||
constructor(config: StageCoreConfig) {
|
||||
@@ -135,7 +137,8 @@ export default class StageCore extends EventEmitter {
|
||||
|
||||
if (el === this.selectedDom) return;
|
||||
|
||||
const runtime = await this.renderer?.getRuntime();
|
||||
const runtime = await this.renderer.getRuntime();
|
||||
|
||||
if (runtime?.beforeSelect) {
|
||||
await runtime.beforeSelect(el);
|
||||
}
|
||||
@@ -143,6 +146,13 @@ export default class StageCore extends EventEmitter {
|
||||
this.mask.setLayout(el);
|
||||
this.dr?.select(el, event);
|
||||
this.selectedDom = el;
|
||||
|
||||
if (this.renderer.contentWindow) {
|
||||
removeSelectedClassName(this.renderer.contentWindow.document);
|
||||
if (this.selectedDom) {
|
||||
addSelectedClassName(this.selectedDom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,6 +208,7 @@ export default class StageCore extends EventEmitter {
|
||||
* @param el 将stage挂载到该Dom节点上
|
||||
*/
|
||||
public mount(el: HTMLDivElement): void {
|
||||
this.container = el;
|
||||
const { mask, renderer } = this;
|
||||
|
||||
renderer.mount(el);
|
||||
@@ -226,6 +237,8 @@ export default class StageCore extends EventEmitter {
|
||||
highlightLayer.destroy();
|
||||
|
||||
this.removeAllListeners();
|
||||
|
||||
this.container = undefined;
|
||||
}
|
||||
|
||||
private async getTargetElement(idOrEl: Id | HTMLElement): Promise<HTMLElement> {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { EventEmitter } from 'events';
|
||||
|
||||
import type { MoveableOptions } from 'moveable';
|
||||
import Moveable from 'moveable';
|
||||
import MoveableHelper from 'moveable-helper';
|
||||
|
||||
import { GHOST_EL_ID_PREFIX, GuidesType, Mode } from './const';
|
||||
import StageCore from './StageCore';
|
||||
@@ -49,6 +50,7 @@ export default class StageDragResize extends EventEmitter {
|
||||
private dragStatus: ActionStatus = ActionStatus.END;
|
||||
private ghostEl: HTMLElement | undefined;
|
||||
private mode: Mode = Mode.ABSOLUTE;
|
||||
private moveableHelper?: MoveableHelper;
|
||||
|
||||
constructor(config: StageDragResizeConfig) {
|
||||
super();
|
||||
@@ -79,6 +81,12 @@ export default class StageDragResize extends EventEmitter {
|
||||
target: this.dragEl || this.target,
|
||||
});
|
||||
|
||||
this.moveableHelper = MoveableHelper.create({
|
||||
useBeforeRender: true,
|
||||
useRender: false,
|
||||
createAuto: true,
|
||||
});
|
||||
|
||||
this.initMoveable();
|
||||
|
||||
if (event) {
|
||||
@@ -188,34 +196,42 @@ export default class StageDragResize extends EventEmitter {
|
||||
private bindDragEvent(): void {
|
||||
if (!this.moveable) throw new Error('moveable 为初始化');
|
||||
|
||||
let offset = {
|
||||
left: 0,
|
||||
top: 0,
|
||||
};
|
||||
|
||||
this.moveable
|
||||
.on('dragStart', () => {
|
||||
.on('dragStart', (e) => {
|
||||
if (!this.target) throw new Error('未选中组件');
|
||||
|
||||
this.dragStatus = ActionStatus.START;
|
||||
|
||||
this.moveableHelper?.onDragStart(e);
|
||||
|
||||
offset = getAbsolutePosition(this.target, { left: 0, top: 0 });
|
||||
|
||||
if (this.mode === Mode.SORTABLE) {
|
||||
this.ghostEl = this.generateGhostEl(this.target);
|
||||
}
|
||||
})
|
||||
.on('drag', ({ left, top }) => {
|
||||
.on('drag', (e) => {
|
||||
if (!this.target || !this.dragEl) return;
|
||||
this.dragStatus = ActionStatus.ING;
|
||||
|
||||
const offset = getAbsolutePosition(this.target, { left, top });
|
||||
const { left, top } = e;
|
||||
|
||||
// 流式布局
|
||||
if (this.ghostEl) {
|
||||
this.dragEl.style.top = `${top}px`;
|
||||
this.ghostEl.style.top = `${offset.top}px`;
|
||||
this.ghostEl.style.top = `${top + offset.top}px`;
|
||||
return;
|
||||
}
|
||||
|
||||
this.dragEl.style.left = `${left}px`;
|
||||
this.dragEl.style.top = `${top}px`;
|
||||
this.moveableHelper?.onDrag(e);
|
||||
|
||||
this.target.style.left = `${offset.left}px`;
|
||||
this.target.style.top = `${offset.top}px`;
|
||||
this.target.style.left = `${left + offset.left}px`;
|
||||
this.target.style.top = `${top + offset.top}px`;
|
||||
})
|
||||
.on('dragEnd', () => {
|
||||
// 点击不拖动时会触发dragStart和dragEnd,但是不会有drag事件
|
||||
@@ -342,18 +358,26 @@ export default class StageDragResize extends EventEmitter {
|
||||
}
|
||||
|
||||
return {
|
||||
scrollable: true,
|
||||
origin: true,
|
||||
rootContainer: this.core.container,
|
||||
zoom: 1,
|
||||
dragArea: true,
|
||||
dragArea: false,
|
||||
draggable: true,
|
||||
resizable: true,
|
||||
snappable: isAbsolute,
|
||||
snapGap: isAbsolute,
|
||||
snapDirections: { center: isAbsolute, middle: isAbsolute },
|
||||
elementSnapDirections: { center: isAbsolute, middle: isAbsolute },
|
||||
|
||||
elementGuidelines: isAbsolute ? await this.getSnapElements(this.target) : [],
|
||||
snapThreshold: 5,
|
||||
snapDigit: 0,
|
||||
throttleDrag: 0,
|
||||
isDisplaySnapDigit: isAbsolute,
|
||||
snapDirections: {
|
||||
top: isAbsolute,
|
||||
right: isAbsolute,
|
||||
bottom: isAbsolute,
|
||||
left: isAbsolute,
|
||||
center: isAbsolute,
|
||||
middle: isAbsolute,
|
||||
},
|
||||
horizontalGuidelines: this.horizontalGuidelines,
|
||||
verticalGuidelines: this.verticalGuidelines,
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import { SELECTED_CLASS, ZIndex } from './const';
|
||||
import StageCore from './StageCore';
|
||||
import type { Runtime, RuntimeWindow, StageRenderConfig } from './types';
|
||||
import { getHost, isSameDomain } from './util';
|
||||
@@ -114,11 +115,23 @@ export default class StageRender extends EventEmitter {
|
||||
|
||||
private loadHandler = async () => {
|
||||
this.emit('onload');
|
||||
|
||||
if (this.render) {
|
||||
const el = await this.render(this.core);
|
||||
if (el) {
|
||||
this.iframe?.contentDocument?.body?.appendChild(el);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.contentWindow) {
|
||||
const style = this.contentWindow.document.createElement('style');
|
||||
style.id = 'tmagic-stage-render';
|
||||
style.innerHTML = `
|
||||
.${SELECTED_CLASS}, .${SELECTED_CLASS}-parent {
|
||||
z-index: ${ZIndex.SELECTED_EL};
|
||||
}
|
||||
`;
|
||||
this.contentWindow.document.head.appendChild(style);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ export enum GuidesType {
|
||||
|
||||
export enum ZIndex {
|
||||
MASK = '99999',
|
||||
SELECTED_EL = '666',
|
||||
}
|
||||
|
||||
export enum MouseButton {
|
||||
@@ -42,3 +43,5 @@ export enum Mode {
|
||||
FIXED = 'fixed',
|
||||
SORTABLE = 'sortable',
|
||||
}
|
||||
|
||||
export const SELECTED_CLASS = 'tmagic-stage-selected-area';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Mode } from './const';
|
||||
import { Mode, SELECTED_CLASS } from './const';
|
||||
import type { Offset } from './types';
|
||||
|
||||
export const getOffset = (el: HTMLElement): Offset => {
|
||||
@@ -154,3 +154,17 @@ export const createDiv = ({ className, cssText }: { className: string; cssText:
|
||||
el.style.cssText = cssText;
|
||||
return el;
|
||||
};
|
||||
|
||||
export const removeSelectedClassName = (doc: Document) => {
|
||||
const oldEl = doc.querySelector(`.${SELECTED_CLASS}`);
|
||||
|
||||
if (oldEl) {
|
||||
oldEl.classList.remove(SELECTED_CLASS);
|
||||
(oldEl.parentNode as HTMLDivElement)?.classList.remove(`${SELECTED_CLASS}-parent`);
|
||||
}
|
||||
};
|
||||
|
||||
export const addSelectedClassName = (el: Element) => {
|
||||
el.classList.add(SELECTED_CLASS);
|
||||
(el.parentNode as Element)?.classList.add(`${SELECTED_CLASS}-parent`);
|
||||
};
|
||||
|
||||
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.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tmagic/ui-react",
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"main": "src/index.ts",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
@@ -13,7 +13,7 @@
|
||||
"react:build": "tsc && vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tmagic/schema": "^1.0.0-beta.8",
|
||||
"@tmagic/schema": "^1.0.0-beta.9",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
},
|
||||
|
||||
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.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"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.8",
|
||||
"@tmagic/schema": "^1.0.0-beta.9",
|
||||
"delegate": "^3.2.0",
|
||||
"tiny-emitter": "^2.1.0",
|
||||
"vue": "^3.2.0"
|
||||
|
||||
2
playground/package-lock.json
generated
2
playground/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tmagic-playground",
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tmagic-playground",
|
||||
"version": "1.0.0-beta.8",
|
||||
"version": "1.0.0-beta.9",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -9,10 +9,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons": "0.0.11",
|
||||
"@tmagic/editor": "^1.0.0-beta.8",
|
||||
"@tmagic/editor": "^1.0.0-beta.9",
|
||||
"@tmagic/form": "^1.0.0-beta.8",
|
||||
"@tmagic/schema": "^1.0.0-beta.8",
|
||||
"@tmagic/stage": "^1.0.0-beta.8",
|
||||
"@tmagic/schema": "^1.0.0-beta.9",
|
||||
"@tmagic/stage": "^1.0.0-beta.9",
|
||||
"@tmagic/utils": "^1.0.0-beta.8",
|
||||
"element-plus": "^2.1.7",
|
||||
"serialize-javascript": "^6.0.0",
|
||||
|
||||
@@ -31,6 +31,7 @@ import { ElMessage } from 'element-plus';
|
||||
import serialize from 'serialize-javascript';
|
||||
|
||||
import type { MenuBarData, MoveableOptions, TMagicEditor } from '@tmagic/editor';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
import StageCore from '@tmagic/stage';
|
||||
import { asyncLoadJs } from '@tmagic/utils';
|
||||
|
||||
@@ -155,7 +156,7 @@ export default defineComponent({
|
||||
|
||||
if (!node) return options;
|
||||
|
||||
const isPage = node.type === 'page';
|
||||
const isPage = node.type === NodeType.PAGE;
|
||||
|
||||
options.draggable = !isPage;
|
||||
options.resizable = !isPage;
|
||||
|
||||
Reference in New Issue
Block a user