mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-06-23 18:39:20 +08:00
parent
f6b7e8dad8
commit
11e0e04cbd
32
packages/editor/src/layouts/workspace/Breadcrumb.vue
Normal file
32
packages/editor/src/layouts/workspace/Breadcrumb.vue
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="nodes.length === 1" class="m-editor-breadcrumb">
|
||||||
|
<template v-for="(item, index) in path" :key="item.id">
|
||||||
|
<TMagicButton text :disabled="item.id === node?.id" @click="select(item)">{{ item.name }}</TMagicButton
|
||||||
|
><span v-if="index < path.length - 1">/</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, inject } from 'vue';
|
||||||
|
|
||||||
|
import { TMagicButton } from '@tmagic/design';
|
||||||
|
import type { MApp, MNode } from '@tmagic/schema';
|
||||||
|
import type StageCore from '@tmagic/stage';
|
||||||
|
import { getNodePath } from '@tmagic/utils';
|
||||||
|
|
||||||
|
import type { Services } from '../../type';
|
||||||
|
|
||||||
|
const services = inject<Services>('services');
|
||||||
|
const editorService = services?.editorService;
|
||||||
|
|
||||||
|
const node = computed(() => editorService?.get<MNode>('node'));
|
||||||
|
const nodes = computed(() => editorService?.get<MNode[]>('nodes') || []);
|
||||||
|
const root = computed(() => editorService?.get<MApp>('root'));
|
||||||
|
const path = computed(() => getNodePath(node.value?.id || '', root.value?.items || []));
|
||||||
|
|
||||||
|
const select = async (node: MNode) => {
|
||||||
|
await editorService?.select(node);
|
||||||
|
editorService?.get<StageCore>('stage')?.select(node.id);
|
||||||
|
};
|
||||||
|
</script>
|
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="m-editor-workspace" tabindex="-1" ref="workspace">
|
<div class="m-editor-workspace" tabindex="-1" ref="workspace">
|
||||||
|
<Breadcrumb></Breadcrumb>
|
||||||
|
|
||||||
<slot name="stage">
|
<slot name="stage">
|
||||||
<MagicStage :key="page?.id"></MagicStage>
|
<MagicStage :key="page?.id"></MagicStage>
|
||||||
</slot>
|
</slot>
|
||||||
@ -22,6 +24,7 @@ import { isPage } from '@tmagic/utils';
|
|||||||
|
|
||||||
import type { Services } from '../../type';
|
import type { Services } from '../../type';
|
||||||
|
|
||||||
|
import Breadcrumb from './Breadcrumb.vue';
|
||||||
import PageBar from './PageBar.vue';
|
import PageBar from './PageBar.vue';
|
||||||
import MagicStage from './Stage.vue';
|
import MagicStage from './Stage.vue';
|
||||||
|
|
||||||
|
6
packages/editor/src/theme/breadcrumb.scss
Normal file
6
packages/editor/src/theme/breadcrumb.scss
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.m-editor-breadcrumb {
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
top: 5px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
@ -13,3 +13,4 @@
|
|||||||
@import "./icon.scss";
|
@import "./icon.scss";
|
||||||
@import "./code-block.scss";
|
@import "./code-block.scss";
|
||||||
@import "./layout.scss";
|
@import "./layout.scss";
|
||||||
|
@import "./breadcrumb.scss";
|
||||||
|
@ -73,6 +73,12 @@ export const useStage = (stageOptions: StageOptions) => {
|
|||||||
editorService.sort(ev.src, ev.dist);
|
editorService.sort(ev.src, ev.dist);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
stage.on('select-parent', () => {
|
||||||
|
const parent = editorService.get('parent');
|
||||||
|
editorService.select(parent);
|
||||||
|
editorService.get<StageCore>('stage').select(parent.id);
|
||||||
|
});
|
||||||
|
|
||||||
stage.on('changeGuides', (e) => {
|
stage.on('changeGuides', (e) => {
|
||||||
uiService.set('showGuides', true);
|
uiService.set('showGuides', true);
|
||||||
|
|
||||||
|
78
packages/stage/src/MoveableSelectParentAble.ts
Normal file
78
packages/stage/src/MoveableSelectParentAble.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { MoveableManagerInterface, Renderer } from 'moveable';
|
||||||
|
|
||||||
|
import type StageDragResize from './StageDragResize';
|
||||||
|
|
||||||
|
export default (dr: StageDragResize) => ({
|
||||||
|
name: 'selectParent',
|
||||||
|
props: {},
|
||||||
|
events: {},
|
||||||
|
render(moveable: MoveableManagerInterface<any, any>, React: Renderer) {
|
||||||
|
const rect = moveable.getRect();
|
||||||
|
const { pos2 } = moveable.state;
|
||||||
|
|
||||||
|
// use css for able
|
||||||
|
const editableViewer = moveable.useCSS(
|
||||||
|
'div',
|
||||||
|
`
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
will-change: transform;
|
||||||
|
transform-origin: 0px 0px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.moveable-button {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: #4af;
|
||||||
|
border-radius: 4px;
|
||||||
|
appearance: none;
|
||||||
|
border: 0;
|
||||||
|
color: white;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
// Add key (required)
|
||||||
|
// Add class prefix moveable-(required)
|
||||||
|
return React.createElement(
|
||||||
|
editableViewer,
|
||||||
|
{
|
||||||
|
className: 'moveable-editable',
|
||||||
|
style: {
|
||||||
|
transform: `translate(${pos2[0] - 25}px, ${pos2[1] - 30}px) rotate(${rect.rotation}deg) translate(10px)`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
React.createElement(
|
||||||
|
'button',
|
||||||
|
{
|
||||||
|
className: 'moveable-button',
|
||||||
|
title: '选中父组件',
|
||||||
|
onClick: () => {
|
||||||
|
dr.emit('select-parent');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
React.createElement(
|
||||||
|
'svg',
|
||||||
|
{
|
||||||
|
width: '1em',
|
||||||
|
height: '1em',
|
||||||
|
viewBox: '0 0 16 16',
|
||||||
|
fill: 'none',
|
||||||
|
xmlns: 'http://www.w3.org/2000/svg',
|
||||||
|
style: {
|
||||||
|
transform: 'rotate(90deg)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
React.createElement('path', {
|
||||||
|
d: 'M13.0001 4V10H4.20718L5.85363 8.35355L5.14652 7.64645L2.64652 10.1464C2.45126 10.3417 2.45126 10.6583 2.64652 10.8536L5.14652 13.3536L5.85363 12.6464L4.20718 11H13.0001C13.5524 11 14.0001 10.5523 14.0001 10V4H13.0001Z',
|
||||||
|
fill: 'currentColor',
|
||||||
|
fillOpacity: '0.9',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
@ -144,6 +144,9 @@ export default class StageCore extends EventEmitter {
|
|||||||
})
|
})
|
||||||
.on('sort', (data: UpdateEventData) => {
|
.on('sort', (data: UpdateEventData) => {
|
||||||
setTimeout(() => this.emit('sort', data));
|
setTimeout(() => this.emit('sort', data));
|
||||||
|
})
|
||||||
|
.on('select-parent', () => {
|
||||||
|
this.emit('select-parent');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.multiDr
|
this.multiDr
|
||||||
|
@ -27,6 +27,7 @@ import MoveableHelper from 'moveable-helper';
|
|||||||
import { removeClassNameByClassName } from '@tmagic/utils';
|
import { removeClassNameByClassName } from '@tmagic/utils';
|
||||||
|
|
||||||
import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
|
import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
|
||||||
|
import selectParentAbles from './MoveableSelectParentAble';
|
||||||
import StageCore from './StageCore';
|
import StageCore from './StageCore';
|
||||||
import StageMask from './StageMask';
|
import StageMask from './StageMask';
|
||||||
import type { StageDragResizeConfig } from './types';
|
import type { StageDragResizeConfig } from './types';
|
||||||
@ -593,6 +594,13 @@ export default class StageDragResize extends EventEmitter {
|
|||||||
bottom: isSortable ? undefined : this.container.clientHeight,
|
bottom: isSortable ? undefined : this.container.clientHeight,
|
||||||
...(moveableOptions.bounds || {}),
|
...(moveableOptions.bounds || {}),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
selectParent: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
ables: [selectParentAbles(this)],
|
||||||
|
|
||||||
...options,
|
...options,
|
||||||
...moveableOptions,
|
...moveableOptions,
|
||||||
};
|
};
|
||||||
|
@ -25,7 +25,7 @@ import { Mode, MouseButton, ZIndex } from './const';
|
|||||||
import Rule from './Rule';
|
import Rule from './Rule';
|
||||||
import type StageCore from './StageCore';
|
import type StageCore from './StageCore';
|
||||||
import type { StageMaskConfig } from './types';
|
import type { StageMaskConfig } from './types';
|
||||||
import { getScrollParent, isFixedParent } from './util';
|
import { getScrollParent, isFixedParent, isMoveableButton } from './util';
|
||||||
|
|
||||||
const wrapperClassName = 'editor-mask-wrapper';
|
const wrapperClassName = 'editor-mask-wrapper';
|
||||||
const throttleTime = 100;
|
const throttleTime = 100;
|
||||||
@ -315,13 +315,18 @@ export default class StageMask extends Rule {
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
||||||
|
if (!event.target) return;
|
||||||
|
|
||||||
|
const targetClassList = (event.target as HTMLDivElement).classList;
|
||||||
|
|
||||||
|
console.log(targetClassList);
|
||||||
|
|
||||||
// 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
|
// 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
|
||||||
if (!this.isMultiSelectStatus && (event.target as HTMLDivElement).className.indexOf('moveable-area') !== -1) {
|
if (!this.isMultiSelectStatus && targetClassList.contains('moveable-area')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 点击对象如果是边框锚点,则可能是resize
|
// 点击对象如果是边框锚点,则可能是resize; 点击对象是功能按钮
|
||||||
if ((event.target as HTMLDivElement).className.indexOf('moveable-control') !== -1) {
|
if (targetClassList.contains('moveable-control') || isMoveableButton(event.target as Element)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,3 +229,6 @@ export const up = (deltaTop: number, target: HTMLElement | SVGElement): SortEven
|
|||||||
dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id,
|
dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isMoveableButton = (target: Element) =>
|
||||||
|
target.classList.contains('moveable-button') || target.parentElement?.classList.contains('moveable-button');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user