feat : composable d'état du popover calendrier (#MUI-33)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
|||||||
|
import {describe, expect, it} from 'vitest'
|
||||||
|
import {defineComponent, h, ref} from 'vue'
|
||||||
|
import {mount} from '@vue/test-utils'
|
||||||
|
import {useCalendarPopover} from './useCalendarPopover'
|
||||||
|
|
||||||
|
const mountHost = () => {
|
||||||
|
const api: ReturnType<typeof useCalendarPopover> = {} as never
|
||||||
|
const Host = defineComponent({
|
||||||
|
setup() {
|
||||||
|
const root = ref<HTMLElement | null>(null)
|
||||||
|
Object.assign(api, useCalendarPopover(root))
|
||||||
|
return () => h('div', {ref: root}, 'host')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const wrapper = mount(Host, {attachTo: document.body})
|
||||||
|
return {wrapper, api}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('useCalendarPopover', () => {
|
||||||
|
it('starts closed in days view', () => {
|
||||||
|
const {api} = mountHost()
|
||||||
|
expect(api.isOpen.value).toBe(false)
|
||||||
|
expect(api.viewMode.value).toBe('days')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('open() opens in days view', () => {
|
||||||
|
const {api} = mountHost()
|
||||||
|
api.open()
|
||||||
|
expect(api.isOpen.value).toBe(true)
|
||||||
|
expect(api.viewMode.value).toBe('days')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toggleView() switches between days and months', () => {
|
||||||
|
const {api} = mountHost()
|
||||||
|
api.open()
|
||||||
|
api.toggleView()
|
||||||
|
expect(api.viewMode.value).toBe('months')
|
||||||
|
api.toggleView()
|
||||||
|
expect(api.viewMode.value).toBe('days')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('close() resets isOpen and viewMode', () => {
|
||||||
|
const {api} = mountHost()
|
||||||
|
api.open()
|
||||||
|
api.toggleView()
|
||||||
|
api.close()
|
||||||
|
expect(api.isOpen.value).toBe(false)
|
||||||
|
expect(api.viewMode.value).toBe('days')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('closes on outside mousedown', () => {
|
||||||
|
const {api} = mountHost()
|
||||||
|
api.open()
|
||||||
|
document.body.dispatchEvent(new MouseEvent('mousedown', {bubbles: true}))
|
||||||
|
expect(api.isOpen.value).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('stays open on inside mousedown', () => {
|
||||||
|
const {wrapper, api} = mountHost()
|
||||||
|
api.open()
|
||||||
|
wrapper.element.dispatchEvent(new MouseEvent('mousedown', {bubbles: true}))
|
||||||
|
expect(api.isOpen.value).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
28
app/components/malio/date/composables/useCalendarPopover.ts
Normal file
28
app/components/malio/date/composables/useCalendarPopover.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import {onBeforeUnmount, onMounted, ref, type Ref} from 'vue'
|
||||||
|
|
||||||
|
export function useCalendarPopover(rootRef: Ref<HTMLElement | null>) {
|
||||||
|
const isOpen = ref(false)
|
||||||
|
const viewMode = ref<'days' | 'months'>('days')
|
||||||
|
|
||||||
|
const open = () => {
|
||||||
|
isOpen.value = true
|
||||||
|
viewMode.value = 'days'
|
||||||
|
}
|
||||||
|
const close = () => {
|
||||||
|
isOpen.value = false
|
||||||
|
viewMode.value = 'days'
|
||||||
|
}
|
||||||
|
const toggleView = () => {
|
||||||
|
viewMode.value = viewMode.value === 'days' ? 'months' : 'days'
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseDown = (event: MouseEvent) => {
|
||||||
|
if (!isOpen.value || !rootRef.value) return
|
||||||
|
if (!rootRef.value.contains(event.target as Node)) close()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => document.addEventListener('mousedown', onMouseDown))
|
||||||
|
onBeforeUnmount(() => document.removeEventListener('mousedown', onMouseDown))
|
||||||
|
|
||||||
|
return {isOpen, viewMode, open, close, toggleView}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user