Improve time inputs

Split into multiple inputs. Intercept pastes to fill out all fields.
This commit is contained in:
jude 2023-11-19 10:38:25 +00:00
parent 3d70be22e3
commit 67ce9077b6

View File

@ -1,8 +1,8 @@
import { useEffect, useRef, useState } from "preact/hooks"; import { useEffect, useRef, useState } from "preact/hooks";
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import { useFlash } from "../App/FlashContext";
export const TimeInput = ({ defaultValue, onInput }) => { export const TimeInput = ({ defaultValue, onInput }) => {
const format = "yyyy-LL-dd, HH:mm:ss";
const ref = useRef(null); const ref = useRef(null);
const [time, setTime] = useState(defaultValue); const [time, setTime] = useState(defaultValue);
@ -11,23 +11,144 @@ export const TimeInput = ({ defaultValue, onInput }) => {
onInput(time); onInput(time);
}, [time]); }, [time]);
const flash = useFlash();
return ( return (
<> <>
<div class={"input"}> <div
<input class={"input"}
placeholder={"YYYY-MM-DD, hh:mm:ss"} onPaste={(ev) => {
style={{ ev.preventDefault();
border: "none", const pasteValue = ev.clipboardData.getData("text/plain");
fontSize: "16px", let dt = DateTime.fromISO(pasteValue);
}}
value={time && time.toFormat(format)}
onBlur={(ev) => {
const dt = DateTime.fromFormat(ev.currentTarget.value, format);
if (dt.isValid) { if (dt.isValid) {
setTime(dt); 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",
});
}} }}
></input> >
<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 <button
style={{ style={{
background: "none", background: "none",
@ -39,7 +160,7 @@ export const TimeInput = ({ defaultValue, onInput }) => {
ref.current.showPicker(); ref.current.showPicker();
}} }}
> >
<span class="is-sr-only">Clear interval</span> <span class="is-sr-only">Show time picker</span>
<span class="icon"> <span class="icon">
<i class="fas fa-calendar"></i> <i class="fas fa-calendar"></i>
</span> </span>
@ -54,8 +175,11 @@ export const TimeInput = ({ defaultValue, onInput }) => {
class={"input"} class={"input"}
type="datetime-local" type="datetime-local"
step="1" step="1"
name="time" value={
value={time && time.toFormat("yyyy-LL-dd'T'HH:mm:ss")} time
? time.toFormat("yyyy-LL-dd'T'HH:mm:ss")
: DateTime.now().toFormat("yyyy-LL-dd'T'HH:mm:ss")
}
ref={ref} ref={ref}
onInput={(ev) => { onInput={(ev) => {
setTime(DateTime.fromISO(ev.currentTarget.value)); setTime(DateTime.fromISO(ev.currentTarget.value));