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>
|
||||
<div class="m-editor-workspace" tabindex="-1" ref="workspace">
|
||||
<Breadcrumb></Breadcrumb>
|
||||
|
||||
<slot name="stage">
|
||||
<MagicStage :key="page?.id"></MagicStage>
|
||||
</slot>
|
||||
@ -22,6 +24,7 @@ import { isPage } from '@tmagic/utils';
|
||||
|
||||
import type { Services } from '../../type';
|
||||
|
||||
import Breadcrumb from './Breadcrumb.vue';
|
||||
import PageBar from './PageBar.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 "./code-block.scss";
|
||||
@import "./layout.scss";
|
||||
@import "./breadcrumb.scss";
|
||||
|
@ -73,6 +73,12 @@ export const useStage = (stageOptions: StageOptions) => {
|
||||
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) => {
|
||||
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) => {
|
||||
setTimeout(() => this.emit('sort', data));
|
||||
})
|
||||
.on('select-parent', () => {
|
||||
this.emit('select-parent');
|
||||
});
|
||||
|
||||
this.multiDr
|
||||
|
@ -27,6 +27,7 @@ import MoveableHelper from 'moveable-helper';
|
||||
import { removeClassNameByClassName } from '@tmagic/utils';
|
||||
|
||||
import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
|
||||
import selectParentAbles from './MoveableSelectParentAble';
|
||||
import StageCore from './StageCore';
|
||||
import StageMask from './StageMask';
|
||||
import type { StageDragResizeConfig } from './types';
|
||||
@ -593,6 +594,13 @@ export default class StageDragResize extends EventEmitter {
|
||||
bottom: isSortable ? undefined : this.container.clientHeight,
|
||||
...(moveableOptions.bounds || {}),
|
||||
},
|
||||
|
||||
props: {
|
||||
selectParent: true,
|
||||
},
|
||||
|
||||
ables: [selectParentAbles(this)],
|
||||
|
||||
...options,
|
||||
...moveableOptions,
|
||||
};
|
||||
|
@ -25,7 +25,7 @@ import { Mode, MouseButton, ZIndex } from './const';
|
||||
import Rule from './Rule';
|
||||
import type StageCore from './StageCore';
|
||||
import type { StageMaskConfig } from './types';
|
||||
import { getScrollParent, isFixedParent } from './util';
|
||||
import { getScrollParent, isFixedParent, isMoveableButton } from './util';
|
||||
|
||||
const wrapperClassName = 'editor-mask-wrapper';
|
||||
const throttleTime = 100;
|
||||
@ -315,13 +315,18 @@ export default class StageMask extends Rule {
|
||||
event.stopPropagation();
|
||||
|
||||
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;
|
||||
}
|
||||
// 点击对象如果是边框锚点,则可能是resize
|
||||
if ((event.target as HTMLDivElement).className.indexOf('moveable-control') !== -1) {
|
||||
// 点击对象如果是边框锚点,则可能是resize; 点击对象是功能按钮
|
||||
if (targetClassList.contains('moveable-control') || isMoveableButton(event.target as Element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -229,3 +229,6 @@ export const up = (deltaTop: number, target: HTMLElement | SVGElement): SortEven
|
||||
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