pipipi-pikachu 5 年之前
父节点
当前提交
8ff1500b53

+ 0 - 2
package.json

@@ -18,7 +18,6 @@
     "mitt": "^2.1.0",
     "store2": "^2.12.0",
     "vue": "^3.0.0",
-    "vue-router": "^4.0.0-0",
     "vuedraggable": "^4.0.1",
     "vuex": "^4.0.0-0"
   },
@@ -31,7 +30,6 @@
     "@typescript-eslint/parser": "^2.33.0",
     "@vue/cli-plugin-babel": "~4.5.0",
     "@vue/cli-plugin-eslint": "~4.5.0",
-    "@vue/cli-plugin-router": "~4.5.0",
     "@vue/cli-plugin-typescript": "~4.5.0",
     "@vue/cli-plugin-unit-jest": "~4.5.0",
     "@vue/cli-plugin-vuex": "~4.5.0",

+ 6 - 1
src/App.vue

@@ -1,5 +1,5 @@
 <template>
-  <router-view/>
+  <Editor />
 </template>
 
 <script lang="ts">
@@ -7,8 +7,13 @@ import { defineComponent, onMounted } from 'vue'
 import { useStore } from 'vuex'
 import { MutationTypes, ActionTypes, State } from '@/store'
 
+import Editor from './views/Editor/index.vue'
+
 export default defineComponent({
   name: 'app',
+  components: {
+    Editor,
+  },
   setup() {
     const store = useStore<State>()
 

+ 23 - 0
src/hooks/useScaleCanvas.ts

@@ -0,0 +1,23 @@
+import { computed } from 'vue'
+import { useStore } from 'vuex'
+import { MutationTypes, State } from '@/store'
+
+export default () => {
+  const store = useStore<State>()
+  const canvasPercentage = computed(() => store.state.canvasPercentage)
+
+  const scaleCanvas = (command: '+' | '-') => {
+    let percentage = canvasPercentage.value
+    const step = 5
+    const max = 120
+    const min = 60
+    if(command === '+' && percentage <= max) percentage += step
+    if(command === '-' && percentage >= min) percentage -= step
+    
+    store.commit(MutationTypes.SET_CANVAS_PERCENTAGE, percentage)
+  }
+  
+  return {
+    scaleCanvas,
+  }
+}

+ 0 - 2
src/main.ts

@@ -1,6 +1,5 @@
 import { createApp } from 'vue'
 import App from './App.vue'
-import router from './router'
 import store from './store'
 
 import '@/assets/styles/global.scss'
@@ -14,5 +13,4 @@ app.component('IconFont', IconFont)
 app.use(contextmenu)
 app.use(clickOutside)
 app.use(store)
-app.use(router)
 app.mount('#app')

+ 0 - 28
src/router/index.ts

@@ -1,28 +0,0 @@
-import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
-import Editor from '@/views/Editor/index.vue'
-
-const routes: Array<RouteRecordRaw> = [
-  {
-    path: '/',
-    name: 'Editor',
-    component: Editor,
-  },
-  {
-    path: '/player',
-    name: 'Player',
-    component: () => import(/* webpackChunkName: "Player" */ '@/views/Player/index.vue'),
-  },
-]
-
-const router = createRouter({
-  history: createWebHistory(process.env.BASE_URL),
-  routes,
-})
-
-router.beforeEach((to, from) => {
-  if(to.name === 'Player' && from.name !== 'Editor') {
-    return router.push({ path: '/' })
-  }
-})
-
-export default router

+ 3 - 1
src/store/constants.ts

@@ -3,10 +3,12 @@ export enum MutationTypes {
   // editor
   SET_ACTIVE_ELEMENT_ID_LIST = 'setActiveElementIdList',
   SET_HANDLE_ELEMENT_ID = 'setHandleElementId',
-  SET_EDITOR_AREA_SHOW_SCALE = 'setEditorAreaShowScale',
+  SET_CANVAS_PERCENTAGE = 'setCanvasPercentage',
+  SET_CANVAS_SCALE = 'setCanvasScale',
   SET_THUMBNAILS_FOCUS = 'setThumbnailsFocus',
   SET_EDITORAREA_FOCUS = 'setEditorAreaFocus',
   SET_DISABLE_HOTKEYS_STATE = 'setDisableHotkeysState',
+  SET_GRID_LINES_STATE = 'setGridLinesState',
   SET_AVAILABLE_FONTS = 'setAvailableFonts',
 
   // slides

+ 6 - 2
src/store/index.ts

@@ -13,10 +13,12 @@ export { MutationTypes, ActionTypes }
 export interface State {
   activeElementIdList: string[];
   handleElementId: string;
-  editorAreaShowScale: number;
+  canvasPercentage: number;
+  canvasScale: number;
   thumbnailsFocus: boolean;
   editorAreaFocus: boolean;
   disableHotkeys: boolean;
+  showGridLines: boolean;
   availableFonts: FontName[];
   slides: Slide[];
   slideIndex: number;
@@ -29,10 +31,12 @@ export interface State {
 const state: State = {
   activeElementIdList: [],
   handleElementId: '',
-  editorAreaShowScale: 90,
+  canvasPercentage: 90,
+  canvasScale: 1,
   thumbnailsFocus: false,
   editorAreaFocus: false,
   disableHotkeys: false,
+  showGridLines: false,
   availableFonts: [],
   slides: slides,
   slideIndex: 0,

+ 10 - 7
src/store/mutations.ts

@@ -5,11 +5,6 @@ import { Slide, PPTElement } from '@/types/slides'
 import { FONT_NAMES } from '@/configs/fontName'
 import { isSupportFontFamily } from '@/utils/fontFamily'
 
-interface AddSlideData {
-  index?: number;
-  slide: Slide | Slide[];
-}
-
 interface UpdateElementData {
   elId: string | string[];
   props: Partial<PPTElement>;
@@ -30,8 +25,12 @@ export const mutations: MutationTree<State> = {
     state.handleElementId = handleElementId
   },
 
-  [MutationTypes.SET_EDITOR_AREA_SHOW_SCALE](state, scale: number) {
-    state.editorAreaShowScale = scale
+  [MutationTypes.SET_CANVAS_PERCENTAGE](state, percentage: number) {
+    state.canvasPercentage = percentage
+  },
+
+  [MutationTypes.SET_CANVAS_SCALE](state, scale: number) {
+    state.canvasScale = scale
   },
 
   [MutationTypes.SET_THUMBNAILS_FOCUS](state, isFocus: boolean) {
@@ -46,6 +45,10 @@ export const mutations: MutationTree<State> = {
     state.disableHotkeys = disable
   },
 
+  [MutationTypes.SET_GRID_LINES_STATE](state, show: boolean) {
+    state.showGridLines = show
+  },
+
   [MutationTypes.SET_AVAILABLE_FONTS](state) {
     state.availableFonts = FONT_NAMES.filter(font => isSupportFontFamily(font.en))
   },

+ 3 - 6
src/views/Editor/Canvas/MultiSelectOperate.vue

@@ -39,10 +39,6 @@ export default defineComponent({
     BorderLine,
   },
   props: {
-    canvasScale: {
-      type: Number,
-      required: true,
-    },
     elementList: {
       type: Array as PropType<PPTElement[]>,
       required: true,
@@ -55,6 +51,7 @@ export default defineComponent({
   setup(props) {
     const store = useStore<State>()
     const activeElementIdList = computed(() => store.state.activeElementIdList)
+    const canvasScale = computed(() => store.state.canvasScale)
     const localActiveElementList = computed(() => props.elementList.filter(el => activeElementIdList.value.includes(el.elId)))
 
     const range = reactive({
@@ -64,8 +61,8 @@ export default defineComponent({
       maxY: 0,
     })
 
-    const width = computed(() => (range.maxX - range.minX) * props.canvasScale)
-    const height = computed(() => (range.maxY - range.minY) * props.canvasScale)
+    const width = computed(() => (range.maxX - range.minX) * canvasScale.value)
+    const height = computed(() => (range.maxY - range.minY) * canvasScale.value)
 
     const resizablePoints = computed(() => {
       return [

+ 15 - 16
src/views/Editor/Canvas/SlideBackground.vue

@@ -3,36 +3,34 @@
     class="slide-background"
     :style="backgroundStyle"
   >
-    <template v-if="isShowGridLines">
+    <template v-if="showGridLines">
       <GridLines />
       <GridLines :gridSize="100" gridColor="rgba(100, 100, 100, 0.3)" />
     </template>
   </div>
 </template>
 
-<script>
-import { computed, defineComponent } from 'vue'
-import GridLines from './GridLines'
+<script lang="ts">
+import { Ref, computed, defineComponent } from 'vue'
+import { useStore } from 'vuex'
+import { State } from '@/store'
+import { Slide } from '@/types/slides'
+import GridLines from './GridLines.vue'
 
 export default defineComponent({
   name: 'slide-background',
   components: {
     GridLines,
   },
-  props: {
-    background: {
-      type: Array,
-    },
-    isShowGridLines: {
-      type: Boolean,
-      default: false,
-    },
-  },
-  setup(props) {
+  setup() {
+    const store = useStore<State>()
+    const showGridLines = computed(() => store.state.showGridLines)
+    const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
+
     const backgroundStyle = computed(() => {
-      if(!props.background) return { backgroundColor: '#fff' }
+      if(!currentSlide.value.background) return { backgroundColor: '#fff' }
 
-      const [type, value] = props.background
+      const [type, value] = currentSlide.value.background
       if(type === 'solid') return { backgroundColor: value }
       else if(type === 'image') return { backgroundImage: `url(${value}` }
 
@@ -40,6 +38,7 @@ export default defineComponent({
     })
 
     return {
+      showGridLines,
       backgroundStyle,
     }
   },

+ 1 - 1
src/views/Editor/Canvas/hooks/useDragElement.ts

@@ -9,11 +9,11 @@ import { getRectRotatedRange, AlignLine, uniqAlignLines } from '@/utils/element'
 export default (
   elementList: Ref<PPTElement[]>,
   activeGroupElementId: Ref<string>,
-  canvasScale: Ref<number>,
   alignmentLines: Ref<AlignmentLineProps[]>,
 ) => {
   const store = useStore<State>()
   const activeElementIdList = computed(() => store.state.activeElementIdList)
+  const canvasScale = computed(() => store.state.canvasScale)
 
   const dragElement = (e: MouseEvent, element: PPTElement) => {
     if(!activeElementIdList.value.includes(element.elId)) return

+ 3 - 2
src/views/Editor/Canvas/hooks/useMouseSelection.ts

@@ -1,11 +1,12 @@
-import { Ref, reactive } from 'vue'
+import { Ref, reactive, computed } from 'vue'
 import { useStore } from 'vuex'
 import { State, MutationTypes } from '@/store'
 import { PPTElement } from '@/types/slides'
 import { getElementRange } from '@/utils/element'
 
-export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>, canvasScale: Ref<number>) => {
+export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>) => {
   const store = useStore<State>()
+  const canvasScale = computed(() => store.state.canvasScale)
 
   const mouseSelectionState = reactive({
     isShow: false,

+ 3 - 2
src/views/Editor/Canvas/hooks/useRotateElement.ts

@@ -1,4 +1,4 @@
-import { Ref } from 'vue'
+import { Ref, computed } from 'vue'
 import { useStore } from 'vuex'
 import { State, MutationTypes } from '@/store'
 import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides'
@@ -12,8 +12,9 @@ export const getAngleFromCoordinate = (x: number, y: number) => {
   return angle
 }
 
-export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>, canvasScale: Ref<number>) => {
+export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | null>) => {
   const store = useStore<State>()
+  const canvasScale = computed(() => store.state.canvasScale)
 
   const rotateElement = (element: PPTTextElement | PPTImageElement | PPTShapeElement) => {
     let isMouseDown = true

+ 1 - 1
src/views/Editor/Canvas/hooks/useScaleElement.ts

@@ -83,13 +83,13 @@ export const getOppositePoint = (direction: number, points: ReturnType<typeof ge
 
 export default (
   elementList: Ref<PPTElement[]>,
-  canvasScale: Ref<number>,
   activeGroupElementId: Ref<string>,
   alignmentLines: Ref<AlignmentLineProps[]>,
 ) => {
   const store = useStore<State>()
   const activeElementIdList = computed(() => store.state.activeElementIdList)
   const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
+  const canvasScale = computed(() => store.state.canvasScale)
 
   const scaleElement = (e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: ElementScaleHandler) => {
     let isMouseDown = true

+ 9 - 9
src/views/Editor/Canvas/hooks/useViewportSize.ts

@@ -1,15 +1,14 @@
-import { ref, computed, onMounted, onUnmounted, Ref } from 'vue'
+import { ref, computed, onMounted, onUnmounted, Ref, watch } from 'vue'
 import { useStore } from 'vuex'
-import { State } from '@/store'
+import { State, MutationTypes } from '@/store'
 import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
 
 export default (canvasRef: Ref<HTMLElement | null>) => {
-  const canvasScale = ref(1)
   const viewportLeft = ref(0)
   const viewportTop = ref(0)
 
   const store = useStore<State>()
-  const editorAreaShowScale = computed(() => store.state.editorAreaShowScale)
+  const canvasPercentage = computed(() => store.state.canvasPercentage)
 
   const setViewportSize = () => {
     if(!canvasRef.value) return
@@ -17,19 +16,21 @@ export default (canvasRef: Ref<HTMLElement | null>) => {
     const canvasHeight = canvasRef.value.clientHeight
 
     if(canvasHeight / canvasWidth > VIEWPORT_ASPECT_RATIO) {
-      const viewportActualWidth = canvasWidth * (editorAreaShowScale.value / 100)
-      canvasScale.value = viewportActualWidth / VIEWPORT_SIZE
+      const viewportActualWidth = canvasWidth * (canvasPercentage.value / 100)
+      store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualWidth / VIEWPORT_SIZE)
       viewportLeft.value = (canvasWidth - viewportActualWidth) / 2
       viewportTop.value = (canvasHeight - viewportActualWidth * VIEWPORT_ASPECT_RATIO) / 2
     }
     else {
-      const viewportActualHeight = canvasHeight * (editorAreaShowScale.value / 100)
-      canvasScale.value = viewportActualHeight / (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO)
+      const viewportActualHeight = canvasHeight * (canvasPercentage.value / 100)
+      store.commit(MutationTypes.SET_CANVAS_SCALE, viewportActualHeight / (VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO))
       viewportLeft.value = (canvasWidth - viewportActualHeight / VIEWPORT_ASPECT_RATIO) / 2
       viewportTop.value = (canvasHeight - viewportActualHeight) / 2
     }
   }
 
+  watch(canvasPercentage, setViewportSize)
+
   const viewportStyles = computed(() => ({
     width: VIEWPORT_SIZE,
     height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO,
@@ -47,7 +48,6 @@ export default (canvasRef: Ref<HTMLElement | null>) => {
   })
 
   return {
-    canvasScale,
     viewportStyles,
   }
 }

+ 24 - 12
src/views/Editor/Canvas/index.vue

@@ -2,6 +2,7 @@
   <div 
     class="canvas" 
     ref="canvasRef"
+    @mousewheel="$event => mousewheelScaleCanvas($event)"
     @mousedown="$event => handleClickBlankArea($event)"
     v-contextmenu="contextmenus"
     v-click-outside="removeEditorAreaFocus"
@@ -26,11 +27,6 @@
         :quadrant="mouseSelectionState.quadrant"
       />
 
-      <SlideBackground 
-        :background="currentSlide?.background"
-        :isShowGridLines="isShowGridLines"
-      />
-
       <AlignmentLine 
         v-for="(line, index) in alignmentLines" :key="index" 
         :type="line.type" :axis="line.axis" :length="line.length"
@@ -40,13 +36,13 @@
         v-if="activeElementIdList.length > 1"
         :elementList="elementList"
         :scaleMultiElement="scaleMultiElement"
-        :canvasScale="canvasScale"
       />
 
+      <SlideBackground />
+
       <EditableElement 
         v-for="(element, index) in elementList" 
         :key="element.elId"
-        :canvasScale="canvasScale"
         :elementInfo="element"
         :elementIndex="index + 1"
         :isActive="activeElementIdList.includes(element.elId)"
@@ -64,6 +60,7 @@
 <script lang="ts">
 import { computed, defineComponent, Ref, ref, watch, watchEffect } from 'vue'
 import { useStore } from 'vuex'
+import throttle from 'lodash/throttle'
 import { State, MutationTypes } from '@/store'
 import { ContextmenuItem } from '@/components/Contextmenu/types'
 import { PPTElement, Slide } from '@/types/slides'
@@ -80,6 +77,7 @@ import useDragElement from './hooks/useDragElement'
 import useDeleteElement from '@/hooks/useDeleteElement'
 import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement'
 import useSelectAllElement from '@/hooks/useSelectAllElement'
+import useScaleCanvas from '@/hooks/useScaleCanvas'
 
 import EditableElement from '@/views/_common/_element/EditableElement.vue'
 import MouseSelection from './MouseSelection.vue'
@@ -102,6 +100,7 @@ export default defineComponent({
     const activeElementIdList = computed(() => store.state.activeElementIdList)
     const handleElementId = computed(() => store.state.handleElementId)
     const editorAreaFocus = computed(() => store.state.editorAreaFocus)
+    const ctrlKeyState = computed(() => store.state.ctrlKeyState)
     const ctrlOrShiftKeyActive: Ref<boolean> = computed(() => store.getters.ctrlOrShiftKeyActive)
 
     const viewportRef = ref<HTMLElement | null>(null)
@@ -121,14 +120,15 @@ export default defineComponent({
     useDropImageElement(viewportRef)
 
     const canvasRef = ref<HTMLElement | null>(null)
-    const { canvasScale, viewportStyles } = useViewportSize(canvasRef)
+    const canvasScale = computed(() => store.state.canvasScale)
+    const { viewportStyles } = useViewportSize(canvasRef)
 
-    const { mouseSelectionState, updateMouseSelection } = useMouseSelection(elementList, viewportRef, canvasScale)
+    const { mouseSelectionState, updateMouseSelection } = useMouseSelection(elementList, viewportRef)
 
-    const { dragElement } = useDragElement(elementList, activeGroupElementId, canvasScale, alignmentLines)
+    const { dragElement } = useDragElement(elementList, activeGroupElementId, alignmentLines)
     const { selectElement } = useSelectElement(elementList, activeGroupElementId, dragElement)
-    const { scaleElement, scaleMultiElement } = useScaleElement(elementList, canvasScale, activeGroupElementId, alignmentLines)
-    const { rotateElement } = useRotateElement(elementList, viewportRef, canvasScale)
+    const { scaleElement, scaleMultiElement } = useScaleElement(elementList, activeGroupElementId, alignmentLines)
+    const { rotateElement } = useRotateElement(elementList, viewportRef)
 
     const { selectAllElement } = useSelectAllElement()
     const { deleteAllElements } = useDeleteElement()
@@ -144,6 +144,17 @@ export default defineComponent({
       if(editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, false)
     }
 
+    const { scaleCanvas } = useScaleCanvas()
+    const throttleScaleCanvas = throttle(scaleCanvas, 100, { leading: true, trailing: false })
+
+    const mousewheelScaleCanvas = (e: WheelEvent) => {
+      if(!ctrlKeyState.value) return
+
+      e.preventDefault()
+      if(e.deltaY > 0) throttleScaleCanvas('-')
+      else if(e.deltaY < 0) throttleScaleCanvas('+')
+    }
+
     const contextmenus = (): ContextmenuItem[] => {
       return [
         {
@@ -182,6 +193,7 @@ export default defineComponent({
       rotateElement,
       scaleElement,
       scaleMultiElement,
+      mousewheelScaleCanvas,
       contextmenus,
     }
   },

+ 33 - 5
src/views/Editor/CanvasTool/index.vue

@@ -15,19 +15,41 @@
     </div>
 
     <div class="right-handler">
-      <IconFont class="handler-item viewport-size" type="icon-minus" />
-      <span class="text">100%</span>
-      <IconFont class="handler-item viewport-size" type="icon-plus" />
-      <IconFont class="handler-item viewport-size" type="icon-number" />
+      <IconFont class="handler-item viewport-size" type="icon-minus" @click="scaleCanvas('-')" />
+      <span class="text">{{canvasScalePercentage}}</span>
+      <IconFont class="handler-item viewport-size" type="icon-plus" @click="scaleCanvas('+')" />
+      <IconFont class="handler-item viewport-size" type="icon-number" @click="toggleGridLines()" />
     </div>
   </div>
 </template>
 
 <script lang="ts">
-import { defineComponent } from 'vue'
+import { defineComponent, computed } from 'vue'
+import { useStore } from 'vuex'
+import { MutationTypes, State } from '@/store'
+import useScaleCanvas from '@/hooks/useScaleCanvas'
 
 export default defineComponent({
   name: 'canvas-tool',
+  setup() {
+    const store = useStore<State>()
+    const canvasScale = computed(() => store.state.canvasScale)
+    const showGridLines = computed(() => store.state.showGridLines)
+
+    const canvasScalePercentage = computed(() => parseInt(canvasScale.value * 100 + '') + '%')
+
+    const { scaleCanvas } = useScaleCanvas()
+
+    const toggleGridLines = () => {
+      store.commit(MutationTypes.SET_GRID_LINES_STATE, !showGridLines.value)
+    }
+
+    return {
+      scaleCanvas,
+      canvasScalePercentage,
+      toggleGridLines,
+    }
+  },
 })
 </script>
 
@@ -40,6 +62,7 @@ export default defineComponent({
   justify-content: space-between;
   padding: 0 10px;
   font-size: 13px;
+  user-select: none;
 }
 .left-handler {
   display: flex;
@@ -59,6 +82,11 @@ export default defineComponent({
   display: flex;
   align-items: center;
 
+  .text {
+    width: 40px;
+    text-align: center;
+  }
+
   .viewport-size {
     font-size: 12px;
     margin-top: -1px;

+ 2 - 1
src/views/Editor/Thumbnails/index.vue

@@ -5,7 +5,7 @@
     v-click-outside="() => setThumbnailsFocus(false)"
   >
     <div class="add-slide">
-      <span>+ 添加幻灯片</span>
+      <span @click="createSlide()">+ 添加幻灯片</span>
     </div>
     <draggable 
       class="thumbnail-list"
@@ -130,6 +130,7 @@ export default defineComponent({
       setThumbnailsFocus,
       slides,
       slideIndex,
+      createSlide,
       changSlideIndex,
       contextmenus,
       fillDigit,

+ 6 - 4
src/views/_common/_element/EditableElement.vue

@@ -24,6 +24,8 @@
 
 <script lang="ts">
 import { computed, defineComponent, PropType } from 'vue'
+import { useStore } from 'vuex'
+import { State } from '@/store'
 import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement, PPTLineElement } from '@/types/slides'
 import { ContextmenuItem } from '@/components/Contextmenu/types'
 
@@ -42,10 +44,6 @@ import TextElement from './TextElement/index.vue'
 export default defineComponent({
   name: 'editable-element',
   props: {
-    canvasScale: {
-      type: Number,
-      required: true,
-    },
     elementInfo: {
       type: Object as PropType<PPTElement>,
       required: true,
@@ -88,6 +86,9 @@ export default defineComponent({
     },
   },
   setup(props) {
+    const store = useStore<State>()
+    const canvasScale = computed(() => store.state.canvasScale)
+
     const currentElementComponent = computed(() => {
       const elementTypeMap = {
         'image': ImageElement,
@@ -180,6 +181,7 @@ export default defineComponent({
     }
 
     return {
+      canvasScale,
       currentElementComponent,
       contextmenus,
     }