date input: add labels, validation, fix NaN checking
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
import { InputValidatorEvent, liveValidator, validate } from '@svelte-toolkit/validate';
|
||||
import { CalendarBlank } from 'phosphor-svelte';
|
||||
import { type Snippet } from 'svelte';
|
||||
import type { ClassValue, FormEventHandler, KeyboardEventHandler } from 'svelte/elements';
|
||||
import type { ClassValue, KeyboardEventHandler } from 'svelte/elements';
|
||||
import { generateIdentifier } from './util.js';
|
||||
import Label from './Label.svelte';
|
||||
|
||||
type FormatString = 'year' | 'month' | 'day';
|
||||
const blankState = {
|
||||
@@ -16,7 +18,9 @@
|
||||
value?: Date;
|
||||
min?: Date;
|
||||
max?: Date;
|
||||
label?: string;
|
||||
required?: boolean;
|
||||
invalidMessage?: string;
|
||||
class?: ClassValue | undefined | null;
|
||||
format?: FormatString[];
|
||||
}
|
||||
@@ -24,13 +28,19 @@
|
||||
let {
|
||||
name,
|
||||
value = $bindable<Date | undefined>(),
|
||||
/** min specifies lower bounds for the date input (WARNING: NOT IMPLEMENTED) */
|
||||
min = new Date(1900, 0, 1),
|
||||
/** max specifies upper bounds for the date input (WARNING: NOT IMPLEMENTED) */
|
||||
max = new Date(2100, 11, 31),
|
||||
label,
|
||||
required = false,
|
||||
invalidMessage = 'Valid date is required',
|
||||
class: classList,
|
||||
format = ['year', 'month', 'day']
|
||||
}: Props = $props();
|
||||
|
||||
const id = $derived(generateIdentifier('dateinput', name));
|
||||
|
||||
const inputSnippets = $derived.by(() => {
|
||||
const found: Partial<Record<FormatString, boolean>> = {};
|
||||
const arr: Snippet[] = [];
|
||||
@@ -56,11 +66,8 @@
|
||||
|
||||
let valid = $state(true);
|
||||
let containerElement: HTMLDivElement;
|
||||
let yearValid = $state(true);
|
||||
let yearElement = $state<HTMLDivElement | null>(null);
|
||||
let monthValid = $state(true);
|
||||
let monthElement = $state<HTMLDivElement | null>(null);
|
||||
let dayValid = $state(true);
|
||||
let dayElement = $state<HTMLDivElement | null>(null);
|
||||
let previousYearValue = $state<string | undefined>(undefined);
|
||||
let yearValue = $derived.by(() => {
|
||||
@@ -108,8 +115,8 @@
|
||||
setPrevious();
|
||||
previousYearValue = undefined;
|
||||
value = undefined;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,8 +128,8 @@
|
||||
setPrevious();
|
||||
previousMonthValue = undefined;
|
||||
value = undefined;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,8 +141,8 @@
|
||||
setPrevious();
|
||||
previousDayValue = undefined;
|
||||
value = undefined;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +200,13 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<div
|
||||
<div>
|
||||
<!-- Date input Label -->
|
||||
{#if label}
|
||||
<Label for={id}>{label}</Label>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
bind:this={containerElement}
|
||||
class={[
|
||||
'inline-flex w-54 items-center justify-start gap-1',
|
||||
@@ -203,8 +216,14 @@
|
||||
!valid && 'border-red-500!',
|
||||
classList
|
||||
]}
|
||||
>
|
||||
<input type="hidden" {name} value={value?.toISOString() ?? ''} />
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
{name}
|
||||
{id}
|
||||
value={value?.toISOString() ?? ''}
|
||||
use:validate={{ required }}
|
||||
/>
|
||||
|
||||
{#each inputSnippets as snippet, i}
|
||||
{@render snippet()}
|
||||
@@ -215,6 +234,12 @@
|
||||
{/each}
|
||||
|
||||
<CalendarBlank size="1.5em" class="ml-auto" />
|
||||
</div>
|
||||
|
||||
<!-- Error message if invalid -->
|
||||
<div class={['opacity-0 transition-opacity', !valid && 'opacity-100']}>
|
||||
<Label for={id} error>{invalidMessage}</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#snippet year()}
|
||||
@@ -235,7 +260,6 @@
|
||||
}}
|
||||
use:liveValidator={{ constrain: true }}
|
||||
onvalidate={(e) => {
|
||||
yearValid = e.detail.valid;
|
||||
handleComponentValidate(e);
|
||||
}}
|
||||
></div>
|
||||
@@ -259,7 +283,6 @@
|
||||
}}
|
||||
use:liveValidator={{ constrain: true }}
|
||||
onvalidate={(e) => {
|
||||
monthValid = e.detail.valid;
|
||||
handleComponentValidate(e);
|
||||
}}
|
||||
></div>
|
||||
@@ -283,7 +306,6 @@
|
||||
}}
|
||||
use:liveValidator={{ constrain: true }}
|
||||
onvalidate={(e) => {
|
||||
dayValid = e.detail.valid;
|
||||
handleComponentValidate(e);
|
||||
}}
|
||||
></div>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
'transition-fontColor block',
|
||||
error && !bigError
|
||||
? 'mt-1 text-sm font-normal text-red-500'
|
||||
: 'text-text dark:text-background mb-3 text-base font-medium',
|
||||
: 'text-text dark:text-background mb-2 text-base font-medium',
|
||||
bigError && 'text-red-500!'
|
||||
]}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user