@@ -15,9 +15,9 @@ import { asNodeId } from '$/providers/openedProjects/graph/graphDatabase'
1515import { evaluationProgress } from ' $/providers/openedProjects/project/computedValueRegistry'
1616import { useNodeExecution } from ' $/providers/openedProjects/project/nodeExecution'
1717import { nodeEditBindings } from ' @/bindings'
18+ import ActionMenu from ' @/components/ActionMenu.vue'
1819import ComponentMenu from ' @/components/ComponentMenu.vue'
1920import ContextMenuTrigger from ' @/components/ContextMenuTrigger.vue'
20- import MenuButton from ' @/components/MenuButton.vue'
2121import ComponentWidgetTree , {
2222 GRAB_HANDLE_X_MARGIN_L ,
2323 GRAB_HANDLE_X_MARGIN_R ,
@@ -29,7 +29,7 @@ import GraphNodeComment from '@/components/GraphEditor/GraphNodeComment.vue'
2929import GraphNodeMessage from ' @/components/GraphEditor/GraphNodeMessage.vue'
3030import GraphVisualization from ' @/components/GraphEditor/GraphVisualization.vue'
3131import type { NodeCreationOptions } from ' @/components/GraphEditor/nodeCreation'
32- import ActionMenu from ' @/components/ActionMenu .vue'
32+ import MenuButton from ' @/components/MenuButton .vue'
3333import { useResizeHandles } from ' @/components/resizeHandles'
3434import ResizeHandles from ' @/components/ResizeHandles.vue'
3535import SvgIcon from ' @/components/SvgIcon.vue'
@@ -43,26 +43,18 @@ import { registerHandlers, toggledAction } from '@/providers/action'
4343import { injectGraphNavigator } from ' @/providers/graphNavigator'
4444import { injectNodeColors } from ' @/providers/graphNodeColors'
4545import { useGraphSelection } from ' @/providers/graphSelection'
46+ import { injectInteractionHandler , type Interaction } from ' @/providers/interactionHandler'
4647import { providePopoverRoot } from ' @/providers/popoverRoot'
4748import { provideWidgetControlledActions } from ' @/providers/widgetActions'
4849import { Ast } from ' @/util/ast'
4950import { prefixes } from ' @/util/ast/node'
50- import { onWindowBlur } from ' @/util/autoBlur'
51+ import { onWindowBlur , targetIsOutside } from ' @/util/autoBlur'
5152import type { Opt } from ' @/util/data/opt'
5253import { Rect } from ' @/util/data/rect'
5354import { Vec2 } from ' @/util/data/vec2'
54- import { Ok } from ' enso-common/src/utilities/data/result'
5555import { autoUpdate , flip , offset , shift , useFloating } from ' @floating-ui/vue'
56- import {
57- computed ,
58- nextTick ,
59- onUnmounted ,
60- ref ,
61- toRef ,
62- watch ,
63- watchEffect ,
64- type ComponentInstance ,
65- } from ' vue'
56+ import { Ok } from ' enso-common/src/utilities/data/result'
57+ import { computed , nextTick , onUnmounted , ref , toRef , watch , watchEffect } from ' vue'
6658import type { VisualizationIdentifier } from ' ydoc-shared/yjsModel'
6759
6860const contentNodeStyle = {
@@ -97,6 +89,7 @@ const projectStore = useProjectStore()
9789const graph = useGraphStore ()
9890const { module } = useCurrentProject ()
9991const navigator = injectGraphNavigator (true )
92+ const interaction = injectInteractionHandler ()
10093const nodeExecution = useNodeExecution ()
10194
10295const nodeId = computed (() => asNodeId (props .node .rootExpr .externalId ))
@@ -450,8 +443,10 @@ const alignmentMenuActions: DisplayableActionName[] = [
450443 ' components.alignBottom' ,
451444]
452445
446+ const hasMultiSelection = computed (() => (nodeSelection ?.selected .size ?? 0 ) > 1 )
447+
453448const contextMenuActions = computed <DisplayableActionName []>(() =>
454- nodeSelection . selected . size > 1 ? multiSelectionMenuActions : nodeMenuActions ,
449+ hasMultiSelection . value ? multiSelectionMenuActions : nodeMenuActions ,
455450)
456451
457452const alignmentMenu = useHoverMenu ()
@@ -473,14 +468,48 @@ const { floatingStyles: alignmentMenuStyles, update: updateAlignmentMenu } = use
473468watch (
474469 () => alignmentMenu .menuOpen ,
475470 (open ) => {
476- if (open ) nextTick (updateAlignmentMenu )
471+ if (open ) nextTick (updateAlignmentMenu )
472+ },
473+ )
474+
475+ const alignmentSubmenuInteraction: Interaction = {
476+ cancel : () => {
477+ alignmentMenu .menuOpen = false
478+ },
479+ end : () => {
480+ alignmentMenu .menuOpen = false
481+ },
482+ pointerdown : (event ) => {
483+ const outsideSubmenu =
484+ targetIsOutside (event , alignmentMenuTrigger .value ) &&
485+ targetIsOutside (event , alignmentMenuPanel .value )
486+ if (! outsideSubmenu ) return false
487+
488+ const parentInteraction = alignmentSubmenuInteraction .parentInteraction
489+ if (contextMenuTrigger .value ?.isTargetOutside (event ) && parentInteraction ) {
490+ interaction .end (parentInteraction )
491+ } else {
492+ interaction .end (alignmentSubmenuInteraction )
493+ }
494+ return false
495+ },
496+ }
497+
498+ interaction .setWhenWithParent (
499+ () => alignmentMenu .menuOpen ,
500+ (parentInteraction ) => {
501+ alignmentSubmenuInteraction .parentInteraction = parentInteraction
502+ return alignmentSubmenuInteraction
477503 },
478504)
479505
480506function closeAllMenus() {
481- // Close both menus
482- alignmentMenu .menuOpen = false
483- contextMenuTrigger .value ?.close ()
507+ const parentInteraction = alignmentSubmenuInteraction .parentInteraction
508+ if (parentInteraction ) {
509+ interaction .end (parentInteraction )
510+ } else {
511+ interaction .end (alignmentSubmenuInteraction )
512+ }
484513}
485514
486515onWindowBlur (() => {
@@ -544,10 +573,10 @@ resizeHandles.onResizeHeight((value) => emit('update:height', value))
544573 ref =" contextMenuTrigger"
545574 :actions =" contextMenuActions"
546575 @contextmenu =" ensureSelected"
547- @hidden =" ( alignmentMenu.menuOpen = false) "
576+ @hidden =" alignmentMenu.menuOpen = false"
548577 >
549578 <template #menuElements >
550- <div v-if =" nodeSelection.selected.size > 1 " >
579+ <div v-if =" hasMultiSelection " >
551580 <div
552581 ref =" alignmentMenuTrigger"
553582 class =" alignmentSubmenuTrigger"
@@ -568,7 +597,11 @@ resizeHandles.onResizeHeight((value) => emit('update:height', value))
568597 @pointerenter =" alignmentMenu.handleMenuEnter"
569598 @pointerleave =" alignmentMenu.handleMenuLeave"
570599 >
571- <ActionMenu class =" alignmentMenu" :actions =" alignmentMenuActions" @close =" closeAllMenus" />
600+ <ActionMenu
601+ class =" alignmentMenu"
602+ :actions =" alignmentMenuActions"
603+ @close =" closeAllMenus"
604+ />
572605 </div >
573606 </div >
574607 </template >
0 commit comments