Date input with calendar
Calendar input composed with @reactleaf/modal 2.0.
This example keeps a text input and a modal calendar picker synchronized to the same Temporal.PlainDate value.
Type a date directly or open the modal calendar.
Type a date and time directly or open the includeTime modal calendar.
import { Temporal } from '@js-temporal/polyfill'
import { Calendar } from '@reactleaf/calendar'
import { ModalManager, ModalProvider, type ModalComponent, useModalInstance } from '@reactleaf/modal'
import { useState } from 'react'
import '@reactleaf/calendar/index.css'
import '@reactleaf/modal/style.css'
const modal = new ModalManager()
type DatePickerModalProps = {
initialDate: Temporal.PlainDate | null
}
const DatePickerModal: ModalComponent<DatePickerModalProps, Temporal.PlainDate | null> = ({ initialDate }) => {
const { closeSelf } = useModalInstance<Temporal.PlainDate | null>()
const [draftDate, setDraftDate] = useState(initialDate ?? Temporal.Now.plainDateISO())
return (
<div>
<Calendar
mode="single"
value={draftDate}
onSelect={(next) => {
if (next) setDraftDate(next instanceof Temporal.PlainDateTime ? next.toPlainDate() : next)
}}
/>
<button type="button" onClick={() => void closeSelf(draftDate)}>
Apply
</button>
</div>
)
}
export function Example() {
const [date, setDate] = useState<Temporal.PlainDate | null>(null)
async function openCalendar() {
const result = await modal.open(DatePickerModal, { initialDate: date })
if (result !== undefined) setDate(result)
}
return (
<ModalProvider manager={modal} defaultLayerOptions={{ closeDelay: 180 }} rootOptions={{ preventScroll: true }}>
<input
value={date?.toString() ?? ''}
onChange={(event) => setDate(Temporal.PlainDate.from(event.target.value))}
/>
<button type="button" onClick={openCalendar}>
Calendar
</button>
</ModalProvider>
)
}