69 lines
1.5 KiB
Svelte
69 lines
1.5 KiB
Svelte
<script lang="ts">
|
|
import Label from './Label.svelte';
|
|
import StyledRawInput from './StyledRawInput.svelte';
|
|
import { generateIdentifier } from './util';
|
|
import type { ClassValue } from 'svelte/elements';
|
|
import type { ComponentProps } from 'svelte';
|
|
|
|
interface Props extends ComponentProps<typeof StyledRawInput> {
|
|
id?: string;
|
|
label?: string;
|
|
value?: string;
|
|
invalidMessage?: string | null;
|
|
ref?: HTMLInputElement | null;
|
|
asterisk?: boolean | null;
|
|
class?: ClassValue | null | undefined;
|
|
}
|
|
|
|
let {
|
|
id = generateIdentifier('text-input'),
|
|
label,
|
|
value = $bindable(''),
|
|
invalidMessage = 'Field is required',
|
|
ref = $bindable<HTMLInputElement | null>(null),
|
|
asterisk = null,
|
|
class: classValue,
|
|
forceInvalid = false,
|
|
...others
|
|
}: Props = $props();
|
|
|
|
let valid: boolean = $state(true);
|
|
let displayAsterisk = $derived(
|
|
asterisk === true || (asterisk !== false && others.validate && others.validate.required)
|
|
);
|
|
|
|
export const focus = () => {
|
|
if (ref) ref.focus();
|
|
};
|
|
</script>
|
|
|
|
<div class={['w-full', classValue]}>
|
|
{#if label}
|
|
<Label for={id}>
|
|
{label}
|
|
{#if displayAsterisk}
|
|
<span class="text-red-500">*</span>
|
|
{/if}
|
|
</Label>
|
|
{/if}
|
|
|
|
<StyledRawInput
|
|
{id}
|
|
bind:value
|
|
bind:ref
|
|
onvalidate={(e) => {
|
|
valid = e.detail.valid;
|
|
}}
|
|
{forceInvalid}
|
|
{...others}
|
|
/>
|
|
|
|
{#if others.validate && invalidMessage !== null}
|
|
<div class={['opacity-0 transition-opacity', (!valid || forceInvalid) && 'opacity-100']}>
|
|
<Label for={id} error>
|
|
{invalidMessage}
|
|
</Label>
|
|
</div>
|
|
{/if}
|
|
</div>
|