1 | import React, { useEffect, useId, useRef, useState } from "react";
|
2 |
|
3 | import { format, isValid, parse } from "date-fns";
|
4 | import { DayPicker } from "react-day-picker";
|
5 |
|
6 | export function Dialog() {
|
7 | const dialogRef = useRef<HTMLDialogElement>(null);
|
8 | const dialogId = useId();
|
9 | const headerId = useId();
|
10 |
|
11 |
|
12 | const [month, setMonth] = useState(new Date());
|
13 |
|
14 |
|
15 | const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
|
16 |
|
17 |
|
18 | const [inputValue, setInputValue] = useState("");
|
19 |
|
20 |
|
21 | const [isDialogOpen, setIsDialogOpen] = useState(false);
|
22 |
|
23 |
|
24 | const toggleDialog = () => setIsDialogOpen(!isDialogOpen);
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | useEffect(() => {
|
30 | if (!dialogRef.current) return;
|
31 | if (isDialogOpen) {
|
32 | dialogRef.current.showModal();
|
33 | } else {
|
34 | dialogRef.current.close();
|
35 | }
|
36 | }, [isDialogOpen]);
|
37 |
|
38 | |
39 |
|
40 |
|
41 |
|
42 | const handleDayPickerSelect = (date: Date | undefined) => {
|
43 | if (!date) {
|
44 | setInputValue("");
|
45 | setSelectedDate(undefined);
|
46 | } else {
|
47 | setSelectedDate(date);
|
48 | setInputValue(format(date, "MM/dd/yyyy"));
|
49 | }
|
50 | dialogRef.current?.close();
|
51 | };
|
52 | |
53 |
|
54 |
|
55 |
|
56 | const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
57 | setInputValue(e.target.value);
|
58 |
|
59 | const parsedDate = parse(e.target.value, "MM/dd/yyyy", new Date());
|
60 |
|
61 | if (isValid(parsedDate)) {
|
62 | setSelectedDate(parsedDate);
|
63 | setMonth(parsedDate);
|
64 | } else {
|
65 | setSelectedDate(undefined);
|
66 | }
|
67 | };
|
68 |
|
69 | return (
|
70 | <div>
|
71 | <label htmlFor="date-input">
|
72 | <strong>Pick a Date: </strong>
|
73 | </label>
|
74 | <input
|
75 | style={{ fontSize: "inherit" }}
|
76 | id="date-input"
|
77 | type="text"
|
78 | value={inputValue}
|
79 | placeholder={"MM/dd/yyyy"}
|
80 | onChange={handleInputChange}
|
81 | />{" "}
|
82 | <button
|
83 | style={{ fontSize: "inherit" }}
|
84 | onClick={toggleDialog}
|
85 | aria-controls="dialog"
|
86 | aria-haspopup="dialog"
|
87 | aria-expanded={isDialogOpen}
|
88 | aria-label="Open calendar to choose booking date"
|
89 | >
|
90 | 📆
|
91 | </button>
|
92 | <p aria-live="assertive" aria-atomic="true">
|
93 | {selectedDate !== undefined
|
94 | ? selectedDate.toDateString()
|
95 | : "Please type or pick a date"}
|
96 | </p>
|
97 | <dialog
|
98 | role="dialog"
|
99 | ref={dialogRef}
|
100 | id={dialogId}
|
101 | aria-modal
|
102 | aria-labelledby={headerId}
|
103 | onClose={() => setIsDialogOpen(false)}
|
104 | >
|
105 | {isDialogOpen && (
|
106 | <DayPicker
|
107 | defaultMonth={selectedDate || month}
|
108 | onMonthChange={setMonth}
|
109 | autoFocus
|
110 | mode="single"
|
111 | selected={selectedDate}
|
112 | onSelect={handleDayPickerSelect}
|
113 | footer={
|
114 | selectedDate !== undefined && (
|
115 | <>Selected: {selectedDate.toDateString()}</>
|
116 | )
|
117 | }
|
118 | />
|
119 | )}
|
120 | </dialog>
|
121 | </div>
|
122 | );
|
123 | }
|