11<template >
22 <div
3- class =" menu-head-wrapper"
4- :class =" {dragActive}"
3+ :class =" [{ dragActive }, 'menu-head-wrapper']"
54 :draggable =" !fixed"
65 :style =" style || getInitStyle"
76 @dragstart =" handleDragStart"
109 <div
1110 ref =" menuHead"
1211 tabindex =" 0"
13- class =" menu-head"
14- :class = " {menuActive, dragActive} "
12+ : class =" [{ menuActive, dragActive }, ' menu-head'] "
13+ :style = " getTheme "
1514 @mouseup =" toggleMenu"
1615 @mousedown =" handleMouseDown"
1716 @blur =" handleBlur"
2322 </div >
2423 <div
2524 ref =" menuContainer"
26- class =" menu-container"
27- :class =" {menuActive}"
25+ :class =" [{ menuActive }, 'menu-container']"
2826 :style =" menuStyle"
2927 @mousedown =" handleMenuClick"
3028 >
3937 :data =" menuData"
4038 :flip =" flipMenu"
4139 :on-selection =" handleMenuItemSelection"
40+ :theme =" theme"
4241 />
4342 </div >
4443 </div >
@@ -57,8 +56,7 @@ import {
5756import Menu , { MenuItem } from " ./Menu.vue" ;
5857import XIcon from " ./icons/XIcon.vue" ;
5958import BoxIcon from " ./icons/BoxIcon.vue" ;
60-
61- const MENU_SPACE = 10 ;
59+ import utils from " ../utils" ;
6260
6361export default defineComponent ({
6462 name: " FloatMenu" ,
@@ -107,6 +105,11 @@ export default defineComponent({
107105 type: Boolean ,
108106 default: false ,
109107 },
108+ theme: {
109+ type: Object as PropType <{ primary: string }>,
110+ required: false ,
111+ default: { primary: " #0080ff" },
112+ },
110113 },
111114 setup(props , { slots }) {
112115 // position of the circular menu head
@@ -138,32 +141,8 @@ export default defineComponent({
138141
139142 // sets the initial style
140143 const getInitStyle = computed (() => {
141- let left = 0 ,
142- top = 0 ;
143- switch (props .position ) {
144- case " top left" :
145- left = 20 ;
146- top = 20 ;
147- break ;
148- case " top right" :
149- left = window .innerWidth - props .dimension ;
150- top = 20 ;
151- break ;
152- case " bottom left" :
153- left = 20 ;
154- top = window .innerHeight - props .dimension ;
155- break ;
156- case " bottom right" :
157- left = window .innerWidth - props .dimension ;
158- top = window .innerHeight - props .dimension ;
159- }
160-
161- return {
162- left: ` ${left }px ` ,
163- top: ` ${top }px ` ,
164- width: ` ${props .dimension }px ` ,
165- height: ` ${props .dimension }px ` ,
166- };
144+ const position = utils .setupInitStyle (props .position , props .dimension );
145+ return position ;
167146 });
168147
169148 // compute the style
@@ -187,97 +166,39 @@ export default defineComponent({
187166 const setupMenuOrientation = () => {
188167 const menuContDOM = menuContainer .value as HTMLElement ;
189168 const menuHeadDOM = menuHead .value as HTMLElement ;
190-
191- const { top, bottom } = menuHeadDOM .getBoundingClientRect ();
192169 const { dimension } = props ;
193- const left = Math .round ((menuContDOM .clientWidth - dimension ) / 2 );
194170 const dir = unref (localMenuOrientation );
195- const menuHeight = menuContDOM .clientHeight ;
196-
197- let newMenuStyle = null ;
198-
199- // flip to bottom if there is not enough space on top
200- if (dir === " top" && menuHeight > top ) {
201- newMenuStyle = {
202- top: ` ${dimension + MENU_SPACE }px ` ,
203- left: ` -${left }px ` ,
204- };
205- localMenuOrientation .value = " top" ;
206- } else if (dir === " top" ) {
207- newMenuStyle = {
208- bottom: ` ${dimension + MENU_SPACE }px ` ,
209- left: ` -${left }px ` ,
210- };
211- // flip menu to top if there is no enough space at bottom
212- } else if (dir === " bottom" && window .innerHeight - bottom < menuHeight ) {
213- newMenuStyle = {
214- bottom: ` ${dimension + MENU_SPACE }px ` ,
215- left: ` -${left }px ` ,
216- };
217- localMenuOrientation .value = " bottom" ;
218- } else if (dir === " bottom" ) {
219- newMenuStyle = {
220- top: ` ${dimension + MENU_SPACE }px ` ,
221- left: ` -${left }px ` ,
222- };
223- }
224-
225- menuStyle .value = Object .assign ({}, newMenuStyle , {
226- " min-height" : ` ${props .menuDimension }px ` ,
227- width: ` ${props .menuDimension }px ` ,
228- });
171+ const newStyle = utils .setupMenuOrientation (
172+ menuHeadDOM ,
173+ menuContDOM ,
174+ dimension ,
175+ dir ,
176+ props .menuDimension
177+ );
178+
179+ localMenuOrientation .value = newStyle .newOrientation ;
180+ menuStyle .value = newStyle ;
229181 };
230182
231183 // this function repositions the menu head whenever it goes out of screen edges.
232184 const adjustFloatMenuPosition = (element : HTMLElement ) => {
233- const { top, bottom, left, right } = element .getBoundingClientRect ();
234- const { innerWidth : screenWidth, innerHeight : screenHeight } = window ;
235- const positionValue = unref (position );
236- const menuContWidth = ((menuContainer .value as unknown ) as HTMLElement )
237- .clientWidth ;
238- const menuContHalfWidth = Math .ceil (menuContWidth / 2 );
239-
240- if (! positionValue ) {
241- return ;
242- }
243-
244- if (props .flipOnEdges ) {
245- flipMenu .value = false ;
246- }
185+ const positionRef = unref (position );
247186
248- // resposition if the menuhead goes below the bottom of the viewport
249- if (bottom > screenHeight ) {
250- position .value = {
251- left: positionValue .left ,
252- top: positionValue .top - (bottom - screenHeight ),
253- };
254- }
255-
256- // resposition if the menuhead goes above the bottom of the viewport
257- if (top < 0 ) {
258- position .value = {
259- left: positionValue .left ,
260- top: positionValue .top + Math .abs (top ),
261- };
262- }
263-
264- // resposition if the menuhead goes beyond the leftside of the viewport
265- if (left < 0 || left < menuContHalfWidth ) {
266- position .value = {
267- left: menuContHalfWidth ,
268- top: positionValue .top ,
269- };
187+ if (! positionRef ) {
188+ return ;
270189 }
271190
272- // resposition if the menuhead goes beyond the rightside of the viewport
273- if (right > screenWidth || screenWidth - right < menuContWidth ) {
274- position .value = {
275- left: screenWidth - menuContWidth ,
276- top: positionValue .top ,
277- };
278-
279- if (props .flipOnEdges ) {
280- flipMenu .value = true ;
191+ if (menuContainer .value ) {
192+ const newPosition = utils .setupMenuPosition (
193+ element ,
194+ positionRef ,
195+ props .flipOnEdges ,
196+ menuContainer .value
197+ );
198+ flipMenu .value = newPosition .flip ;
199+
200+ if (newPosition .position ) {
201+ position .value = newPosition .position ;
281202 }
282203 }
283204 };
@@ -334,34 +255,33 @@ export default defineComponent({
334255 });
335256 };
336257
337- const handleMenuClose = () => {
338- menuActive .value = false ;
339- };
258+ const handleMenuClose = () => (menuActive .value = false );
259+ const handleBlur = () => (menuActive .value = false );
340260
341261 // close the menu while dragging
342262 const handleDragStart = () => {
343263 menuActive .value = false ;
344264 dragActive .value = true ;
345265 };
346266
347- const handleDragEnd = () => {
348- dragActive .value = false ;
349- };
267+ // set drag active to false
268+ const handleDragEnd = () => (dragActive .value = false );
350269
270+ // handler for selection
351271 const handleMenuItemSelection = (name : string ) => {
352272 menuActive .value = false ;
353273 props .onSelected && props .onSelected (name );
354274 };
355275
356- const handleBlur = () => {
357- menuActive .value = false ;
358- };
359-
360276 const handleMenuClick = (event : MouseEvent ) => {
361277 event .preventDefault ();
362278 event .stopPropagation ();
363279 };
364280
281+ const getTheme = computed (() => ({
282+ " --background" : props .theme .primary ,
283+ }));
284+
365285 return {
366286 flipMenu ,
367287 getInitStyle ,
@@ -380,6 +300,7 @@ export default defineComponent({
380300 style ,
381301 toggleMenu ,
382302 dragActive ,
303+ getTheme ,
383304 isSlotEmpty: slots && ! slots .default ,
384305 };
385306 },
0 commit comments