|
1 | 1 | <script setup lang="ts"> |
| 2 | + /* eslint-disable no-console */ |
2 | 3 | import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'; |
3 | 4 | import { useEventListener } from '@vueuse/core'; |
4 | 5 | import { computePosition, flip, offset, platform, shift } from '@floating-ui/dom'; |
|
42 | 43 | const floatingReference = ref<HTMLElement | null>(null); |
43 | 44 | const scrollPosition = reactive({ x: 0, y: 0 }); |
44 | 45 |
|
| 46 | + const logPrefix = '[ContextMenuSurface]'; |
| 47 | +
|
45 | 48 | const updateFloatingPosition = async () => { |
46 | 49 | if ( |
47 | 50 | !(floatingReference.value instanceof HTMLElement) || |
48 | 51 | !(contextMenuPanel.value instanceof HTMLElement) |
49 | 52 | ) { |
| 53 | + console.debug(logPrefix, 'Skipping Floating UI computePosition; missing elements', { |
| 54 | + hasReference: floatingReference.value instanceof HTMLElement, |
| 55 | + hasPanel: contextMenuPanel.value instanceof HTMLElement, |
| 56 | + position: { ...contextMenuPosition }, |
| 57 | + }); |
50 | 58 | floatingStyles.left = `${contextMenuPosition.x}px`; |
51 | 59 | floatingStyles.top = `${contextMenuPosition.y}px`; |
52 | 60 | return; |
|
60 | 68 |
|
61 | 69 | floatingStyles.left = `${x}px`; |
62 | 70 | floatingStyles.top = `${y}px`; |
| 71 | + console.debug(logPrefix, 'Updated floating position', { x, y }); |
63 | 72 | }; |
64 | 73 |
|
65 | 74 | const closeMenu = () => { |
66 | 75 | if (!isOpen.value) return; |
| 76 | + console.debug(logPrefix, 'Closing menu'); |
67 | 77 | isOpen.value = false; |
68 | 78 | outsideEventsArmed.value = false; |
69 | 79 | floatingReference.value = null; |
|
97 | 107 |
|
98 | 108 | const wasOpen = isOpen.value; |
99 | 109 | outsideEventsArmed.value = false; |
| 110 | + console.debug(logPrefix, 'Opening menu', { |
| 111 | + wasOpen, |
| 112 | + origin, |
| 113 | + targetTag: (target as HTMLElement | null)?.tagName, |
| 114 | + }); |
100 | 115 | if (!wasOpen) { |
101 | 116 | isOpen.value = true; |
102 | 117 | emit('open'); |
|
107 | 122 |
|
108 | 123 | await nextTick(); |
109 | 124 | await updateFloatingPosition(); |
| 125 | + console.debug(logPrefix, 'Arming outside events'); |
110 | 126 | outsideEventsArmed.value = true; |
111 | 127 | }; |
112 | 128 |
|
|
118 | 134 | await nextTick(); |
119 | 135 | floatingReference.value = contextMenuAnchor.value; |
120 | 136 | await updateFloatingPosition(); |
| 137 | + console.debug(logPrefix, 'Menu opened; updated position after watcher'); |
121 | 138 | }, |
122 | 139 | ); |
123 | 140 |
|
|
172 | 189 | const isWithinPanelAttribute = targetElement?.closest(`[data-cy="${props.dataCy}"]`); |
173 | 190 |
|
174 | 191 | if (target && (isInsidePanel || isInsideButton || isWithinPanelAttribute)) { |
| 192 | + console.debug(logPrefix, 'Outside handler ignored (inside menu/button)', { |
| 193 | + targetTag: targetElement?.tagName, |
| 194 | + isInsidePanel, |
| 195 | + isInsideButton, |
| 196 | + isWithinPanelAttribute: Boolean(isWithinPanelAttribute), |
| 197 | + }); |
175 | 198 | return; |
176 | 199 | } |
| 200 | + console.debug(logPrefix, 'Outside pointer detected; closing', { |
| 201 | + targetTag: targetElement?.tagName, |
| 202 | + armed: outsideEventsArmed.value, |
| 203 | + closeOnOutside: props.closeOnOutsidePointer, |
| 204 | + }); |
177 | 205 | closeMenu(); |
178 | 206 | }; |
179 | 207 |
|
|
0 commit comments