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 { 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));