Improve time inputs
Split into multiple inputs. Intercept pastes to fill out all fields.
This commit is contained in:
		@@ -1,8 +1,8 @@
 | 
			
		||||
import { useEffect, useRef, useState } from "preact/hooks";
 | 
			
		||||
import { DateTime } from "luxon";
 | 
			
		||||
import { useFlash } from "../App/FlashContext";
 | 
			
		||||
 | 
			
		||||
export const TimeInput = ({ defaultValue, onInput }) => {
 | 
			
		||||
    const format = "yyyy-LL-dd, HH:mm:ss";
 | 
			
		||||
    const ref = useRef(null);
 | 
			
		||||
 | 
			
		||||
    const [time, setTime] = useState(defaultValue);
 | 
			
		||||
@@ -11,23 +11,144 @@ export const TimeInput = ({ defaultValue, onInput }) => {
 | 
			
		||||
        onInput(time);
 | 
			
		||||
    }, [time]);
 | 
			
		||||
 | 
			
		||||
    const flash = useFlash();
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
            <div class={"input"}>
 | 
			
		||||
                <input
 | 
			
		||||
                    placeholder={"YYYY-MM-DD, hh:mm:ss"}
 | 
			
		||||
                    style={{
 | 
			
		||||
                        border: "none",
 | 
			
		||||
                        fontSize: "16px",
 | 
			
		||||
                    }}
 | 
			
		||||
                    value={time && time.toFormat(format)}
 | 
			
		||||
                    onBlur={(ev) => {
 | 
			
		||||
                        const dt = DateTime.fromFormat(ev.currentTarget.value, format);
 | 
			
		||||
                        if (dt.isValid) {
 | 
			
		||||
                            setTime(dt);
 | 
			
		||||
                        }
 | 
			
		||||
                    }}
 | 
			
		||||
                ></input>
 | 
			
		||||
            <div
 | 
			
		||||
                class={"input"}
 | 
			
		||||
                onPaste={(ev) => {
 | 
			
		||||
                    ev.preventDefault();
 | 
			
		||||
                    const pasteValue = ev.clipboardData.getData("text/plain");
 | 
			
		||||
                    let dt = DateTime.fromISO(pasteValue);
 | 
			
		||||
 | 
			
		||||
                    if (dt.isValid) {
 | 
			
		||||
                        setTime(dt);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    dt = DateTime.fromSQL(pasteValue);
 | 
			
		||||
 | 
			
		||||
                    if (dt.isValid) {
 | 
			
		||||
                        setTime(dt);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    flash({
 | 
			
		||||
                        message: `Couldn't parse your clipboard data as a valid date-time`,
 | 
			
		||||
                        type: "error",
 | 
			
		||||
                    });
 | 
			
		||||
                }}
 | 
			
		||||
            >
 | 
			
		||||
                <div style={{ flexGrow: "1" }}>
 | 
			
		||||
                    <label>
 | 
			
		||||
                        <span class="is-sr-only">Years input</span>
 | 
			
		||||
                        <input
 | 
			
		||||
                            style={{
 | 
			
		||||
                                borderStyle: "none",
 | 
			
		||||
                                fontFamily: "monospace",
 | 
			
		||||
                                width: "calc(4ch + 4px)",
 | 
			
		||||
                                fontSize: "1rem",
 | 
			
		||||
                            }}
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            pattern="\d*"
 | 
			
		||||
                            maxlength={4}
 | 
			
		||||
                            placeholder="2023"
 | 
			
		||||
                            value={time?.year.toLocaleString("en-US", {
 | 
			
		||||
                                minimumIntegerDigits: 4,
 | 
			
		||||
                                useGrouping: false,
 | 
			
		||||
                            })}
 | 
			
		||||
                        ></input>{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    -
 | 
			
		||||
                    <label>
 | 
			
		||||
                        <span class="is-sr-only">Months input</span>
 | 
			
		||||
                        <input
 | 
			
		||||
                            style={{
 | 
			
		||||
                                borderStyle: "none",
 | 
			
		||||
                                fontFamily: "monospace",
 | 
			
		||||
                                width: "calc(2ch + 4px)",
 | 
			
		||||
                                fontSize: "1rem",
 | 
			
		||||
                            }}
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            pattern="\d*"
 | 
			
		||||
                            maxlength={2}
 | 
			
		||||
                            placeholder="12"
 | 
			
		||||
                            value={time?.month.toLocaleString("en-US", { minimumIntegerDigits: 2 })}
 | 
			
		||||
                        ></input>{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    -
 | 
			
		||||
                    <label>
 | 
			
		||||
                        <span class="is-sr-only">Days input</span>
 | 
			
		||||
                        <input
 | 
			
		||||
                            style={{
 | 
			
		||||
                                borderStyle: "none",
 | 
			
		||||
                                fontFamily: "monospace",
 | 
			
		||||
                                width: "calc(2ch + 4px)",
 | 
			
		||||
                                fontSize: "1rem",
 | 
			
		||||
                            }}
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            pattern="\d*"
 | 
			
		||||
                            maxlength={2}
 | 
			
		||||
                            placeholder="25"
 | 
			
		||||
                            value={time?.day.toLocaleString("en-US", { minimumIntegerDigits: 2 })}
 | 
			
		||||
                        ></input>{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <label style={{ marginLeft: "8px" }}>
 | 
			
		||||
                        <span class="is-sr-only">Hours input</span>
 | 
			
		||||
                        <input
 | 
			
		||||
                            style={{
 | 
			
		||||
                                borderStyle: "none",
 | 
			
		||||
                                fontFamily: "monospace",
 | 
			
		||||
                                width: "calc(2ch + 4px)",
 | 
			
		||||
                                fontSize: "1rem",
 | 
			
		||||
                            }}
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            pattern="\d*"
 | 
			
		||||
                            maxlength={2}
 | 
			
		||||
                            placeholder="12"
 | 
			
		||||
                            value={time?.hour.toLocaleString("en-US", { minimumIntegerDigits: 2 })}
 | 
			
		||||
                        ></input>{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    :
 | 
			
		||||
                    <label>
 | 
			
		||||
                        <span class="is-sr-only">Minutes input</span>
 | 
			
		||||
                        <input
 | 
			
		||||
                            style={{
 | 
			
		||||
                                borderStyle: "none",
 | 
			
		||||
                                fontFamily: "monospace",
 | 
			
		||||
                                width: "calc(2ch + 4px)",
 | 
			
		||||
                                fontSize: "1rem",
 | 
			
		||||
                            }}
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            pattern="\d*"
 | 
			
		||||
                            maxlength={2}
 | 
			
		||||
                            placeholder="30"
 | 
			
		||||
                            value={time?.minute.toLocaleString("en-US", {
 | 
			
		||||
                                minimumIntegerDigits: 2,
 | 
			
		||||
                            })}
 | 
			
		||||
                        ></input>{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    :
 | 
			
		||||
                    <label>
 | 
			
		||||
                        <span class="is-sr-only">Seconds input</span>
 | 
			
		||||
                        <input
 | 
			
		||||
                            style={{
 | 
			
		||||
                                borderStyle: "none",
 | 
			
		||||
                                fontFamily: "monospace",
 | 
			
		||||
                                width: "calc(2ch + 4px)",
 | 
			
		||||
                                fontSize: "1rem",
 | 
			
		||||
                            }}
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            pattern="\d*"
 | 
			
		||||
                            maxlength={2}
 | 
			
		||||
                            placeholder="00"
 | 
			
		||||
                            value={time?.second.toLocaleString("en-US", {
 | 
			
		||||
                                minimumIntegerDigits: 2,
 | 
			
		||||
                            })}
 | 
			
		||||
                        ></input>{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                </div>
 | 
			
		||||
                <button
 | 
			
		||||
                    style={{
 | 
			
		||||
                        background: "none",
 | 
			
		||||
@@ -39,7 +160,7 @@ export const TimeInput = ({ defaultValue, onInput }) => {
 | 
			
		||||
                        ref.current.showPicker();
 | 
			
		||||
                    }}
 | 
			
		||||
                >
 | 
			
		||||
                    <span class="is-sr-only">Clear interval</span>
 | 
			
		||||
                    <span class="is-sr-only">Show time picker</span>
 | 
			
		||||
                    <span class="icon">
 | 
			
		||||
                        <i class="fas fa-calendar"></i>
 | 
			
		||||
                    </span>
 | 
			
		||||
@@ -54,8 +175,11 @@ export const TimeInput = ({ defaultValue, onInput }) => {
 | 
			
		||||
                class={"input"}
 | 
			
		||||
                type="datetime-local"
 | 
			
		||||
                step="1"
 | 
			
		||||
                name="time"
 | 
			
		||||
                value={time && time.toFormat("yyyy-LL-dd'T'HH:mm:ss")}
 | 
			
		||||
                value={
 | 
			
		||||
                    time
 | 
			
		||||
                        ? time.toFormat("yyyy-LL-dd'T'HH:mm:ss")
 | 
			
		||||
                        : DateTime.now().toFormat("yyyy-LL-dd'T'HH:mm:ss")
 | 
			
		||||
                }
 | 
			
		||||
                ref={ref}
 | 
			
		||||
                onInput={(ev) => {
 | 
			
		||||
                    setTime(DateTime.fromISO(ev.currentTarget.value));
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user