Skip to content

Commit 7f054ae

Browse files
authored
fix: Ensure tooltips are displayed behind modals (#22957)
1 parent ecad07e commit 7f054ae

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

packages/frontend-shared/src/components/StandardModal.cy.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import StandardModal from './StandardModal.vue'
2+
import Tooltip from './Tooltip.vue'
23
import { defaultMessages } from '@cy/i18n'
4+
import { DialogOverlay } from '@headlessui/vue'
35
import { ref } from 'vue'
46

57
const title = 'Test Title'
@@ -63,6 +65,42 @@ describe('<StandardModal />', { viewportWidth: 800, viewportHeight: 400 }, () =>
6365

6466
cy.percySnapshot()
6567
})
68+
69+
it('automatically closes tooltips on open', () => {
70+
const tooltipSlots = {
71+
default: () => <div data-cy="tooltip-trigger">Trigger</div>,
72+
popper: () => <div data-cy="tooltip-content">Tooltip Content</div>,
73+
}
74+
const modalSlots = {
75+
default: () => <div>Modal Content!</div>,
76+
overlay: ({ classes }) => <DialogOverlay class={[classes, 'bg-gray-800', 'opacity-90']} />,
77+
}
78+
const isOpen = ref(false)
79+
80+
cy.mount(() => (
81+
<div>
82+
<Tooltip v-slots={tooltipSlots} isInteractive />
83+
<StandardModal v-slots={modalSlots} modelValue={isOpen.value} />
84+
</div>
85+
))
86+
87+
// Open tooltip
88+
cy.findByTestId('tooltip-trigger').trigger('mouseenter')
89+
90+
// Wait for tooltip to be visible
91+
cy.findByTestId('tooltip-content')
92+
.should('be.visible')
93+
.then(() => {
94+
// Open modal
95+
isOpen.value = true
96+
})
97+
98+
// Verify tooltip is no longer open once modal was opened
99+
cy.findByTestId('tooltip-content')
100+
.should('not.be.visible')
101+
102+
cy.percySnapshot()
103+
})
66104
})
67105

68106
describe('mouse and keyboard behavior', () => {

packages/frontend-shared/src/components/StandardModal.vue

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ import StandardModalHeader from './StandardModalHeader.vue'
5252
import StandardModalBody from './StandardModalBody.vue'
5353
import StandardModalFooter from './StandardModalFooter.vue'
5454
55+
import { hideAllPoppers } from 'floating-vue'
56+
import { watch } from 'vue'
57+
5558
import {
5659
Dialog,
5760
DialogOverlay,
@@ -84,6 +87,18 @@ const setIsOpen = (val: boolean) => {
8487
emit('update:modelValue', val)
8588
}
8689
90+
// Ensure all tooltips are closed when the modal opens - this prevents tooltips from beneath that
91+
// are stuck open being rendered on top of the modal due to the use of a fixed z-index in `floating-vue`
92+
watch(
93+
() => props.modelValue,
94+
(value) => {
95+
if (value) {
96+
hideAllPoppers()
97+
}
98+
},
99+
{ immediate: true },
100+
)
101+
87102
const closeModal = () => {
88103
setIsOpen(false)
89104
}

packages/frontend-shared/src/gql-components/topnav/LoginModal.cy.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { LoginModalFragmentDoc } from '../../generated/graphql-test'
22
import LoginModal from './LoginModal.vue'
33
import { defaultMessages } from '@cy/i18n'
4+
import Tooltip from '../../components/Tooltip.vue'
5+
import { ref } from 'vue'
46

57
const text = defaultMessages.topNav
68

@@ -194,4 +196,42 @@ describe('<LoginModal />', { viewportWidth: 1000, viewportHeight: 750 }, () => {
194196
.and('be.disabled')
195197
})
196198
})
199+
200+
it('automatically closes tooltips on open', () => {
201+
const tooltipSlots = {
202+
default: () => <div data-cy="tooltip-trigger">Trigger</div>,
203+
popper: () => <div data-cy="tooltip-content">Tooltip Content</div>,
204+
}
205+
const isOpen = ref(false)
206+
207+
cy.mountFragment(LoginModalFragmentDoc, {
208+
render: (gqlVal) => {
209+
gqlVal.authState.browserOpened = true
210+
211+
return (
212+
<div>
213+
<Tooltip v-slots={tooltipSlots} isInteractive />
214+
<LoginModal gql={gqlVal} utmMedium="testing" modelValue={isOpen.value} />
215+
</div>
216+
)
217+
},
218+
})
219+
220+
// Open tooltip
221+
cy.findByTestId('tooltip-trigger').trigger('mouseenter')
222+
223+
// Wait for tooltip to be visible
224+
cy.findByTestId('tooltip-content')
225+
.should('be.visible')
226+
.then(() => {
227+
// Open modal
228+
isOpen.value = true
229+
})
230+
231+
// Verify tooltip is no longer open once modal was opened
232+
cy.findByTestId('tooltip-content')
233+
.should('not.be.visible')
234+
235+
cy.percySnapshot()
236+
})
197237
})

packages/frontend-shared/src/gql-components/topnav/LoginModal.vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,14 @@
9090
<script setup lang="ts">
9191
import { useI18n } from '@cy/i18n'
9292
import { gql } from '@urql/core'
93-
import { computed } from 'vue'
93+
import { computed, watch } from 'vue'
9494
import Auth from '../Auth.vue'
9595
import ExternalLink from '../ExternalLink.vue'
9696
import { useOnline } from '@vueuse/core'
9797
import NoInternetConnection from '../../components/NoInternetConnection.vue'
9898
import CopyText from '@cy/components/CopyText.vue'
9999
import StandardModalHeader from '@cy/components/StandardModalHeader.vue'
100+
import { hideAllPoppers } from 'floating-vue'
100101
101102
import {
102103
Dialog,
@@ -133,6 +134,18 @@ fragment LoginModal on Query {
133134
}
134135
`
135136
137+
// Ensure all tooltips are closed when the modal opens - this prevents tooltips from beneath that
138+
// are stuck open being rendered on top of the modal due to the use of a fixed z-index in `floating-vue`
139+
watch(
140+
() => props.modelValue,
141+
(value) => {
142+
if (value) {
143+
hideAllPoppers()
144+
}
145+
},
146+
{ immediate: true },
147+
)
148+
136149
const setIsOpen = (value: boolean) => {
137150
emit('update:modelValue', value)
138151
}

0 commit comments

Comments
 (0)