Match native datetime-local format in DatePicker input variant
Pad 12-hour display to 2 digits to match Chrome native input format: 03/03/2026 03:12 AM (was 3:12 AM). Relax day/month parser to accept 1-2 digit input while still outputting zero-padded ISO strings. Update placeholder to DD/MM/YYYY hh:mm AM. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
59a4f67b42
commit
247c701e12
@ -34,7 +34,7 @@ function to24Hour(h12: number, ampm: string): number {
|
||||
return isPM ? h12 + 12 : h12;
|
||||
}
|
||||
|
||||
/** ISO string → user-friendly display: DD/MM/YYYY or DD/MM/YYYY h:mm AM/PM */
|
||||
/** ISO string → user-friendly display: DD/MM/YYYY or DD/MM/YYYY hh:mm AM */
|
||||
function isoToDisplay(iso: string, mode: 'date' | 'datetime'): string {
|
||||
if (!iso) return '';
|
||||
const parts = iso.split('T');
|
||||
@ -47,20 +47,20 @@ function isoToDisplay(iso: string, mode: 'date' | 'datetime'): string {
|
||||
const h = parseInt(tp[0], 10);
|
||||
if (isNaN(h)) return dateStr;
|
||||
const { hour: h12, ampm } = to12Hour(h);
|
||||
return `${dateStr} ${h12}:${tp[1].slice(0, 2)} ${ampm}`;
|
||||
return `${dateStr} ${pad(h12)}:${tp[1].slice(0, 2)} ${ampm}`;
|
||||
}
|
||||
|
||||
/** User-friendly display → ISO string, or null if incomplete/invalid */
|
||||
function displayToIso(display: string, mode: 'date' | 'datetime'): string | null {
|
||||
if (!display) return null;
|
||||
if (mode === 'date') {
|
||||
const m = display.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
|
||||
const m = display.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
|
||||
if (!m) return null;
|
||||
const d = parseInt(m[1], 10), mo = parseInt(m[2], 10), y = parseInt(m[3], 10);
|
||||
if (mo < 1 || mo > 12 || d < 1 || d > getDaysInMonth(y, mo - 1)) return null;
|
||||
return `${m[3]}-${m[2]}-${m[1]}`;
|
||||
return `${m[3]}-${pad(mo)}-${pad(d)}`;
|
||||
}
|
||||
const m = display.match(/^(\d{2})\/(\d{2})\/(\d{4})\s+(\d{1,2}):(\d{2})\s*(AM|PM)$/i);
|
||||
const m = display.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})\s+(\d{1,2}):(\d{2})\s*(AM|PM)$/i);
|
||||
if (!m) return null;
|
||||
const d = parseInt(m[1], 10), mo = parseInt(m[2], 10), y = parseInt(m[3], 10);
|
||||
if (mo < 1 || mo > 12 || d < 1 || d > getDaysInMonth(y, mo - 1)) return null;
|
||||
@ -68,7 +68,7 @@ function displayToIso(display: string, mode: 'date' | 'datetime'): string | null
|
||||
const min = parseInt(m[5], 10);
|
||||
if (h < 1 || h > 12 || min < 0 || min > 59) return null;
|
||||
h = to24Hour(h, m[6]);
|
||||
return `${m[3]}-${m[2]}-${m[1]}T${pad(h)}:${pad(min)}`;
|
||||
return `${m[3]}-${pad(mo)}-${pad(d)}T${pad(h)}:${pad(min)}`;
|
||||
}
|
||||
|
||||
const MONTH_NAMES = [
|
||||
@ -152,7 +152,7 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
|
||||
const [hour, setHour] = React.useState(parsed?.hour ?? 0);
|
||||
const [minute, setMinute] = React.useState(parsed?.minute ?? 0);
|
||||
|
||||
// Input variant: user-friendly display string (DD/MM/YYYY or DD/MM/YYYY h:mm AM/PM)
|
||||
// Input variant: user-friendly display string (DD/MM/YYYY or DD/MM/YYYY hh:mm AM)
|
||||
const [displayValue, setDisplayValue] = React.useState(() =>
|
||||
variant === 'input' ? isoToDisplay(value, mode) : ''
|
||||
);
|
||||
@ -520,7 +520,7 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
|
||||
}}
|
||||
required={required}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder || (mode === 'datetime' ? 'DD/MM/YYYY h:mm AM/PM' : 'DD/MM/YYYY')}
|
||||
placeholder={placeholder || (mode === 'datetime' ? 'DD/MM/YYYY hh:mm AM' : 'DD/MM/YYYY')}
|
||||
className={cn(
|
||||
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 pr-9 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user