| | import { format, isValid, parse } from "date-fns"; |
| | import React, { useEffect, useId, useRef, useState } from "react"; |
| | import { DayPicker } from "react-day-picker"; |
| |
|
| | export function Dialog() { |
| | const dialogRef = useRef<HTMLDialogElement>(null); |
| | const dialogId = useId(); |
| | const headerId = useId(); |
| |
|
| | |
| | const [month, setMonth] = useState(new Date()); |
| |
|
| | |
| | const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined); |
| |
|
| | |
| | const [inputValue, setInputValue] = useState(""); |
| |
|
| | |
| | const [isDialogOpen, setIsDialogOpen] = useState(false); |
| |
|
| | |
| | const toggleDialog = () => setIsDialogOpen(!isDialogOpen); |
| | const calendarLabel = `Calendar, ${format(month, "MMMM yyyy")}`; |
| |
|
| | |
| | |
| | |
| | useEffect(() => { |
| | if (!dialogRef.current) return; |
| | if (isDialogOpen) { |
| | dialogRef.current.showModal(); |
| | } else { |
| | dialogRef.current.close(); |
| | } |
| | }, [isDialogOpen]); |
| |
|
| | |
| | |
| | |
| | |
| | const handleDayPickerSelect = (date: Date | undefined) => { |
| | if (!date) { |
| | setInputValue(""); |
| | setSelectedDate(undefined); |
| | } else { |
| | setSelectedDate(date); |
| | setInputValue(format(date, "MM/dd/yyyy")); |
| | } |
| | dialogRef.current?.close(); |
| | }; |
| | |
| | |
| | |
| | |
| | const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { |
| | setInputValue(e.target.value); |
| |
|
| | const parsedDate = parse(e.target.value, "MM/dd/yyyy", new Date()); |
| |
|
| | if (isValid(parsedDate)) { |
| | setSelectedDate(parsedDate); |
| | setMonth(parsedDate); |
| | } else { |
| | setSelectedDate(undefined); |
| | } |
| | }; |
| |
|
| | return ( |
| | <div> |
| | <label htmlFor="date-input"> |
| | <strong>Pick a Date: </strong> |
| | </label> |
| | <input |
| | style={{ fontSize: "inherit" }} |
| | id="date-input" |
| | type="text" |
| | value={inputValue} |
| | placeholder={"MM/dd/yyyy"} |
| | onChange={handleInputChange} |
| | />{" "} |
| | <button |
| | type="button" |
| | style={{ fontSize: "inherit" }} |
| | onClick={toggleDialog} |
| | aria-controls={dialogId} |
| | aria-haspopup="dialog" |
| | aria-expanded={isDialogOpen} |
| | aria-label="Open calendar to choose booking date" |
| | > |
| | 📆 |
| | </button> |
| | <p aria-live="assertive" aria-atomic="true"> |
| | {selectedDate !== undefined |
| | ? selectedDate.toDateString() |
| | : "Please type or pick a date"} |
| | </p> |
| | <dialog |
| | ref={dialogRef} |
| | id={dialogId} |
| | aria-modal |
| | aria-labelledby={headerId} |
| | onClose={() => setIsDialogOpen(false)} |
| | > |
| | {isDialogOpen && ( |
| | <> |
| | <h2 id={headerId}>Choose a date</h2> |
| | <DayPicker |
| | defaultMonth={selectedDate || month} |
| | onMonthChange={setMonth} |
| | autoFocus |
| | role="application" |
| | aria-label={calendarLabel} |
| | mode="single" |
| | selected={selectedDate} |
| | onSelect={handleDayPickerSelect} |
| | footer={ |
| | selectedDate !== undefined && ( |
| | <>Selected: {selectedDate.toDateString()}</> |
| | ) |
| | } |
| | /> |
| | </> |
| | )} |
| | </dialog> |
| | </div> |
| | ); |
| | } |
| |
|