143 lines
4.9 KiB
TypeScript
143 lines
4.9 KiB
TypeScript
import { describe, it, expect, vi, afterEach } from 'vitest'
|
|
import { nextTick, ref } from 'vue'
|
|
import { useDismissableLayer } from '../src/lib/use-dismissable-layer'
|
|
|
|
function firePointerDown(target: EventTarget) {
|
|
const event = new PointerEvent('pointerdown', { bubbles: true, cancelable: true })
|
|
target.dispatchEvent(event)
|
|
}
|
|
|
|
describe('useDismissableLayer', () => {
|
|
afterEach(() => {
|
|
document.body.replaceChildren()
|
|
})
|
|
|
|
it('calls onDismiss on Escape keydown while active', () => {
|
|
const containerRef = ref<HTMLElement | null>(document.createElement('div'))
|
|
const active = ref(true)
|
|
const onDismiss = vi.fn()
|
|
useDismissableLayer(containerRef, active, { onDismiss })
|
|
|
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
|
|
|
expect(onDismiss).toHaveBeenCalledOnce()
|
|
})
|
|
|
|
it('does not call onDismiss on Escape when inactive', () => {
|
|
const containerRef = ref<HTMLElement | null>(document.createElement('div'))
|
|
const active = ref(false)
|
|
const onDismiss = vi.fn()
|
|
useDismissableLayer(containerRef, active, { onDismiss })
|
|
|
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
|
|
|
expect(onDismiss).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('calls onDismiss on pointerdown outside the container', () => {
|
|
const container = document.createElement('div')
|
|
const outside = document.createElement('div')
|
|
document.body.append(container, outside)
|
|
const containerRef = ref<HTMLElement | null>(container)
|
|
const active = ref(true)
|
|
const onDismiss = vi.fn()
|
|
useDismissableLayer(containerRef, active, { onDismiss })
|
|
|
|
firePointerDown(outside)
|
|
|
|
expect(onDismiss).toHaveBeenCalledOnce()
|
|
})
|
|
|
|
it('does not call onDismiss on pointerdown inside the container', () => {
|
|
const container = document.createElement('div')
|
|
const inside = document.createElement('span')
|
|
container.append(inside)
|
|
document.body.append(container)
|
|
const containerRef = ref<HTMLElement | null>(container)
|
|
const active = ref(true)
|
|
const onDismiss = vi.fn()
|
|
useDismissableLayer(containerRef, active, { onDismiss })
|
|
|
|
firePointerDown(inside)
|
|
|
|
expect(onDismiss).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('skips onDismiss when onPointerDownOutside calls preventDefault', () => {
|
|
const container = document.createElement('div')
|
|
const outside = document.createElement('div')
|
|
document.body.append(container, outside)
|
|
const containerRef = ref<HTMLElement | null>(container)
|
|
const active = ref(true)
|
|
const onDismiss = vi.fn()
|
|
useDismissableLayer(containerRef, active, {
|
|
onDismiss,
|
|
onPointerDownOutside: (event) => event.preventDefault(),
|
|
})
|
|
|
|
firePointerDown(outside)
|
|
|
|
expect(onDismiss).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('only dismisses the topmost layer on Escape when layers are stacked', () => {
|
|
const container1 = document.createElement('div')
|
|
const container2 = document.createElement('div')
|
|
document.body.append(container1, container2)
|
|
const active1 = ref(true)
|
|
const active2 = ref(true)
|
|
const onDismiss1 = vi.fn()
|
|
const onDismiss2 = vi.fn()
|
|
useDismissableLayer(ref(container1), active1, { onDismiss: onDismiss1 })
|
|
useDismissableLayer(ref(container2), active2, { onDismiss: onDismiss2 })
|
|
|
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
|
|
|
expect(onDismiss2).toHaveBeenCalledOnce()
|
|
expect(onDismiss1).not.toHaveBeenCalled()
|
|
|
|
active1.value = false
|
|
active2.value = false
|
|
})
|
|
|
|
it('only dismisses the topmost layer on pointerdown outside it, even inside a lower layer', () => {
|
|
const container1 = document.createElement('div')
|
|
const container2 = document.createElement('div')
|
|
document.body.append(container1, container2)
|
|
const active1 = ref(true)
|
|
const active2 = ref(true)
|
|
const onDismiss1 = vi.fn()
|
|
const onDismiss2 = vi.fn()
|
|
useDismissableLayer(ref(container1), active1, { onDismiss: onDismiss1 })
|
|
useDismissableLayer(ref(container2), active2, { onDismiss: onDismiss2 })
|
|
|
|
firePointerDown(container1)
|
|
|
|
expect(onDismiss2).toHaveBeenCalledOnce()
|
|
expect(onDismiss1).not.toHaveBeenCalled()
|
|
|
|
active1.value = false
|
|
active2.value = false
|
|
})
|
|
|
|
it('promotes the next layer to topmost once the top layer deactivates', async () => {
|
|
const container1 = document.createElement('div')
|
|
const container2 = document.createElement('div')
|
|
document.body.append(container1, container2)
|
|
const active1 = ref(true)
|
|
const active2 = ref(true)
|
|
const onDismiss1 = vi.fn()
|
|
const onDismiss2 = vi.fn()
|
|
useDismissableLayer(ref(container1), active1, { onDismiss: onDismiss1 })
|
|
useDismissableLayer(ref(container2), active2, { onDismiss: onDismiss2 })
|
|
|
|
active2.value = false
|
|
await nextTick()
|
|
|
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
|
|
|
expect(onDismiss1).toHaveBeenCalledOnce()
|
|
|
|
active1.value = false
|
|
})
|
|
})
|