Update input components
This commit is contained in:
@@ -1,26 +1,47 @@
|
|||||||
import type { DateInputProps } from "$/types/InputTypes";
|
import type { DateInputProps } from "$/types/InputTypes";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import moment from "moment";
|
import { type ChangeEvent } from "react";
|
||||||
|
|
||||||
|
|
||||||
export default function DateInput({
|
export default function DateInput({
|
||||||
id,
|
|
||||||
className,
|
className,
|
||||||
defaultValue,
|
|
||||||
value,
|
value,
|
||||||
onChange
|
onChange,
|
||||||
}: DateInputProps){
|
...inputProps
|
||||||
|
}: Readonly<DateInputProps>){
|
||||||
|
//Used to translate the string from the input to a date for onChange
|
||||||
|
const changeDate = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const [ year, month, day ] = e.target.value.split("-").map(Number);
|
||||||
|
const newDate = new Date(year, month - 1, day);
|
||||||
|
|
||||||
|
onChange(Number.isNaN(newDate.getTime()) ? undefined : newDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
id={id}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"border rounded-lg px-2 py-1",
|
"border rounded-lg px-2 py-1",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
defaultValue={defaultValue ? moment(defaultValue).format("YYYY-MM-DD") : undefined}
|
value={formatDate(value)}
|
||||||
value={value ? moment(value).format("YYYY-MM-DD") : undefined}
|
onChange={changeDate}
|
||||||
onChange={(e) => onChange?.(new Date(moment(e.target.value, "YYYY-MM-DD").toDate()))}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Used to translate the date to a string for the input
|
||||||
|
function formatDate(date: Date | undefined): string{
|
||||||
|
if(!date || Number.isNaN(date.getTime())){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
|
const day = String(date.getDate()).padStart(2, "0");
|
||||||
|
|
||||||
|
return `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,38 @@
|
|||||||
import type { DateInputProps } from "$/types/InputTypes";
|
import type { DateInputProps } from "$/types/InputTypes";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import moment from "moment";
|
import type { ChangeEvent } from "react";
|
||||||
|
|
||||||
|
|
||||||
export default function DateTimeInput({
|
export default function DateTimeInput({
|
||||||
id,
|
id,
|
||||||
className,
|
className,
|
||||||
defaultValue,
|
step = 60,
|
||||||
value,
|
value,
|
||||||
onChange
|
onChange,
|
||||||
}: DateInputProps){
|
...inputProps
|
||||||
|
}: Readonly<DateInputProps>){
|
||||||
|
const changeDateTime = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const match = new RegExp(/^(\d+)-(\d+)-(\d+)T(\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?$/).exec(e.target.value);
|
||||||
|
|
||||||
|
if(!match){
|
||||||
|
onChange(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ ,
|
||||||
|
y, mo, d,
|
||||||
|
h, mi, s = "0", ms = "0"
|
||||||
|
] = match;
|
||||||
|
|
||||||
|
const date = new Date(
|
||||||
|
Number(y), Number(mo) - 1, Number(d),
|
||||||
|
Number(h), Number(mi), Number(s), Number(ms)
|
||||||
|
);
|
||||||
|
|
||||||
|
onChange(Number.isNaN(date.getTime()) ? undefined : date);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
@@ -18,9 +41,28 @@ export default function DateTimeInput({
|
|||||||
"border rounded-lg px-2 py-1 outline-none",
|
"border rounded-lg px-2 py-1 outline-none",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
defaultValue={defaultValue ? moment(defaultValue).format("YYYY-MM-DDTHH:mm") : undefined}
|
value={formatDateTime(value)}
|
||||||
value={value ? moment(value).format("YYYY-MM-DDTHH:mm") : undefined}
|
onChange={changeDateTime}
|
||||||
onChange={(e) => onChange?.(new Date(moment(e.target.value, "YYYY-MM-DDTHH:mm").toDate()))}
|
step={step}
|
||||||
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatDateTime(date: Date | undefined){
|
||||||
|
if(!date || Number.isNaN(date.getTime())){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const y = date.getFullYear();
|
||||||
|
const mo = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
|
const d = String(date.getDate()).padStart(2, "0");
|
||||||
|
|
||||||
|
const h = String(date.getHours()).padStart(2, "0");
|
||||||
|
const mi = String(date.getMinutes()).padStart(2, "0");
|
||||||
|
const s = String(date.getSeconds()).padStart(2, "0");
|
||||||
|
const ms = String(date.getMilliseconds()).padStart(2, "0");
|
||||||
|
|
||||||
|
return `${y}-${mo}-${d}T${h}:${mi}:${s}.${ms}`;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,33 @@
|
|||||||
import type { DateInputProps } from "$/types/InputTypes";
|
import type { DateInputProps } from "$/types/InputTypes";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import moment from "moment";
|
import type { ChangeEvent } from "react";
|
||||||
|
|
||||||
|
|
||||||
export default function TimeInput({
|
export default function TimeInput({
|
||||||
id,
|
id,
|
||||||
className,
|
className,
|
||||||
defaultValue,
|
step = 60,
|
||||||
value,
|
value,
|
||||||
onChange
|
onChange,
|
||||||
}: DateInputProps){
|
...inputProps
|
||||||
|
}: Readonly<DateInputProps>){
|
||||||
|
const changeTime = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const match = new RegExp(/^(\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?$/).exec(e.target.value);
|
||||||
|
|
||||||
|
if(!match){
|
||||||
|
onChange(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ , h, m, s = "0", ms = "0"] = match;
|
||||||
|
|
||||||
|
const newDate = new Date();
|
||||||
|
newDate.setHours(Number(h), Number(m), Number(s), Number(ms));
|
||||||
|
|
||||||
|
onChange(Number.isNaN(newDate) ? undefined : newDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
type="time"
|
type="time"
|
||||||
@@ -18,9 +36,32 @@ export default function TimeInput({
|
|||||||
"border rounded-lg px-2 py-1 outline-none",
|
"border rounded-lg px-2 py-1 outline-none",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
defaultValue={defaultValue ? moment(defaultValue).format("YYYY-MM-DDTHH:mm") : undefined}
|
value={formatTime(value, step)}
|
||||||
value={value ? moment(value).format("YYYY-MM-DDTHH:mm") : undefined}
|
onChange={changeTime}
|
||||||
onChange={(e) => onChange?.(new Date(moment(e.target.value, "YYYY-MM-DDTHH:mm").toDate()))}
|
step={step}
|
||||||
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatTime(date: Date | undefined, step: number){
|
||||||
|
if(!date || Number.isNaN(date.getTime())){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const h = String(date.getHours()).padStart(2, "0");
|
||||||
|
const m = String(date.getMinutes()).padStart(2, "0");
|
||||||
|
const s = String(date.getSeconds()).padStart(2, "0");
|
||||||
|
const ms = String(date.getMilliseconds()).padStart(3, "0");
|
||||||
|
|
||||||
|
let time = `${h}:${m}`;
|
||||||
|
if(step < 60){
|
||||||
|
time += `:${s}`;
|
||||||
|
}
|
||||||
|
if(step < 1){
|
||||||
|
time += `.${ms}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type React from "react";
|
import type React from "react";
|
||||||
import type { ChangeEventHandler } from "react";
|
import type { ChangeEventHandler, InputHTMLAttributes } from "react";
|
||||||
|
|
||||||
|
|
||||||
export interface TextInputProps {
|
export interface TextInputProps {
|
||||||
@@ -164,10 +164,8 @@ export interface RadioListProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface DateInputProps {
|
export interface DateInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "step">{
|
||||||
id?: string;
|
step?: number;
|
||||||
className?: string;
|
value: Date | undefined;
|
||||||
defaultValue?: Date;
|
onChange: (newValue: Date | undefined) => void;
|
||||||
value?: Date;
|
|
||||||
onChange?: (newValue: Date) => void;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { MattrixwvTabGroup } from "$/component/tab";
|
|||||||
import type { TabGroupContent } from "$/types/TabTypes";
|
import type { TabGroupContent } from "$/types/TabTypes";
|
||||||
import { CheckboxContent, DateContent, FileContent, RadioContent, SwitchContent, TextContent } from "@/util/InputUtils";
|
import { CheckboxContent, DateContent, FileContent, RadioContent, SwitchContent, TextContent } from "@/util/InputUtils";
|
||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/input/')({
|
export const Route = createFileRoute('/input/')({
|
||||||
@@ -10,15 +11,21 @@ export const Route = createFileRoute('/input/')({
|
|||||||
|
|
||||||
|
|
||||||
function InputPage(){
|
function InputPage(){
|
||||||
|
const [ date, setDate ] = useState<Date>();
|
||||||
|
const [ dateTime, setDateTime ] = useState<Date>();
|
||||||
|
const [ time, setTime ] = useState<Date>();
|
||||||
|
|
||||||
|
|
||||||
const tabs: TabGroupContent[] = [
|
const tabs: TabGroupContent[] = [
|
||||||
{ tab: "Checkbox", content: <CheckboxContent/>},
|
{ tab: "Checkbox", content: <CheckboxContent/>},
|
||||||
{ tab: "Radio", content: <RadioContent/> },
|
{ tab: "Radio", content: <RadioContent/> },
|
||||||
{ tab: "Date", content: <DateContent/> },
|
{ tab: "Date", content: <DateContent date={date} setDate={setDate} dateTime={dateTime} setDateTime={setDateTime} time={time} setTime={setTime}/> },
|
||||||
{ tab: "File", content: <FileContent/> },
|
{ tab: "File", content: <FileContent/> },
|
||||||
{ tab: "Switch", content: <SwitchContent/> },
|
{ tab: "Switch", content: <SwitchContent/> },
|
||||||
{ tab: "Text", content: <TextContent/> }
|
{ tab: "Text", content: <TextContent/> }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex flex-col items-center justify-center"
|
className="flex flex-col items-center justify-center"
|
||||||
|
|||||||
@@ -822,16 +822,36 @@ function RadioDisplay({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DateContent(){
|
export function DateContent({
|
||||||
|
date,
|
||||||
|
setDate,
|
||||||
|
dateTime,
|
||||||
|
setDateTime,
|
||||||
|
time,
|
||||||
|
setTime
|
||||||
|
}:Readonly<{
|
||||||
|
date: Date | undefined;
|
||||||
|
setDate: (newDate: Date | undefined) => void;
|
||||||
|
dateTime: Date | undefined;
|
||||||
|
setDateTime: (newDateTime: Date | undefined) => void;
|
||||||
|
time: Date | undefined;
|
||||||
|
setTime: (newTime: Date | undefined) => void;
|
||||||
|
}>){
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex flex-col items-center justify-center my-8 gap-y-8"
|
className="flex flex-col items-center justify-center my-8 gap-y-8"
|
||||||
>
|
>
|
||||||
<DateInput
|
<DateInput
|
||||||
|
onChange={setDate}
|
||||||
|
value={date}
|
||||||
/>
|
/>
|
||||||
<DateTimeInput
|
<DateTimeInput
|
||||||
|
onChange={setDateTime}
|
||||||
|
value={dateTime}
|
||||||
/>
|
/>
|
||||||
<TimeInput
|
<TimeInput
|
||||||
|
onChange={setTime}
|
||||||
|
value={time}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user