UNPKG

3.57 kBTypeScriptView Raw
1import React, { useEffect, useId, useRef, useState } from "react";
2
3import { format, isValid, parse } from "date-fns";
4import { DayPicker } from "react-day-picker";
5
6export function Dialog() {
7 const dialogRef = useRef<HTMLDialogElement>(null);
8 const dialogId = useId();
9 const headerId = useId();
10
11 // Hold the month in state to control the calendar when the input changes
12 const [month, setMonth] = useState(new Date());
13
14 // Hold the selected date in state
15 const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
16
17 // Hold the input value in state
18 const [inputValue, setInputValue] = useState("");
19
20 // Hold the dialog visibility in state
21 const [isDialogOpen, setIsDialogOpen] = useState(false);
22
23 // Function to toggle the dialog visibility
24 const toggleDialog = () => setIsDialogOpen(!isDialogOpen);
25
26 // Hook to handle the body scroll behavior and focus trapping. You may want to
27 // use your own trapping library as the body.style overflow will break the
28 // scroll position.
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 * Function to handle the DayPicker select event: update the input value and
40 * the selected date, and set the month.
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 * Handle the input change event: parse the input value to a date, update the
54 * selected date and set the month.
55 */
56 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
57 setInputValue(e.target.value); // keep the input value in sync
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}