pin input: make name optional, custom class support, fix hidden input
This commit is contained in:
@@ -1,6 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { isValueValid, validate, type ValidatorOptions } from '@svelte-toolkit/validate';
|
||||
import Label from './Label.svelte';
|
||||
import type { ClassValue } from 'svelte/elements';
|
||||
import { generateIdentifier } from './util.js';
|
||||
|
||||
interface Props {
|
||||
label?: string;
|
||||
length: number;
|
||||
required?: boolean;
|
||||
name?: string;
|
||||
value?: string;
|
||||
oncomplete?: (value: string) => void;
|
||||
onchange?: (value: string) => void;
|
||||
class?: ClassValue | null | undefined;
|
||||
}
|
||||
|
||||
let {
|
||||
label,
|
||||
@@ -9,16 +22,11 @@
|
||||
name,
|
||||
value = $bindable(''),
|
||||
oncomplete,
|
||||
onchange
|
||||
}: {
|
||||
label?: string;
|
||||
length: number;
|
||||
required?: boolean;
|
||||
name: string;
|
||||
value?: string;
|
||||
oncomplete?: (value: string) => void;
|
||||
onchange?: (value: string) => void;
|
||||
} = $props();
|
||||
onchange,
|
||||
class: classValue
|
||||
}: Props = $props();
|
||||
|
||||
const id = $derived(generateIdentifier('pin-input', name));
|
||||
|
||||
let hiddenInput: HTMLInputElement;
|
||||
let valid: boolean = $state(true);
|
||||
@@ -148,41 +156,45 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<input
|
||||
class="hidden"
|
||||
use:validate={validateOpts}
|
||||
onvalidate={(e) => {
|
||||
valid = e.detail.valid;
|
||||
}}
|
||||
bind:this={hiddenInput}
|
||||
/>
|
||||
<div class={classValue}>
|
||||
<input
|
||||
{id}
|
||||
{name}
|
||||
class="hidden"
|
||||
use:validate={validateOpts}
|
||||
onvalidate={(e) => {
|
||||
valid = e.detail.valid;
|
||||
}}
|
||||
bind:this={hiddenInput}
|
||||
/>
|
||||
|
||||
{#if label}
|
||||
<Label bigError={!valid} for={name}>{label}</Label>
|
||||
{/if}
|
||||
{#if label}
|
||||
<Label bigError={!valid} for={id}>{label}</Label>
|
||||
{/if}
|
||||
|
||||
<div>
|
||||
<div class="flex gap-4">
|
||||
{#each { length: length } as _, i}
|
||||
<input
|
||||
type="text"
|
||||
class={[
|
||||
'px[1.125rem] w-[5ch] rounded-sm pt-4 pb-3.5 transition-colors',
|
||||
'text-center align-middle font-mono font-normal placeholder:font-normal',
|
||||
'border-accent dark:border-accent/50 border',
|
||||
'text-text placeholder:text-text/30 dark:text-background dark:placeholder:text-background/30',
|
||||
'dark:bg-text-800 bg-white dark:sm:bg-slate-800',
|
||||
!valid && i >= value.length && 'border-red-500!'
|
||||
]}
|
||||
value={value[i] || ''}
|
||||
{required}
|
||||
maxlength="1"
|
||||
onfocus={onfocusinput(i)}
|
||||
onmousedown={onmousedown(i)}
|
||||
onkeydown={onkeydowninput(i)}
|
||||
bind:this={inputs[i]}
|
||||
placeholder="0"
|
||||
/>
|
||||
{/each}
|
||||
<div>
|
||||
<div class="flex gap-4">
|
||||
{#each { length: length } as _, i}
|
||||
<input
|
||||
type="text"
|
||||
class={[
|
||||
'px[1.125rem] w-[5ch] rounded-sm pt-4 pb-3.5 transition-colors',
|
||||
'text-center align-middle font-mono font-normal placeholder:font-normal',
|
||||
'border-accent dark:border-accent/50 border',
|
||||
'text-text placeholder:text-text/30 dark:text-background dark:placeholder:text-background/30',
|
||||
'dark:bg-text-800 bg-white dark:sm:bg-slate-800',
|
||||
!valid && i >= value.length && 'border-red-500!'
|
||||
]}
|
||||
value={value[i] || ''}
|
||||
{required}
|
||||
maxlength="1"
|
||||
onfocus={onfocusinput(i)}
|
||||
onmousedown={onmousedown(i)}
|
||||
onkeydown={onkeydowninput(i)}
|
||||
bind:this={inputs[i]}
|
||||
placeholder="0"
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
|
||||
<div class="component">
|
||||
<p class="title">Pin Input</p>
|
||||
<PinInput name="pin" length={6} />
|
||||
<PinInput label="Please enter your 6-digit PIN" length={6} />
|
||||
</div>
|
||||
|
||||
<div class="component">
|
||||
|
||||
Reference in New Issue
Block a user