2024-08-12 11:00:25 +02:00
|
|
|
<script lang="ts">
|
2025-03-11 14:16:42 -05:00
|
|
|
import DatePicker from '$lib/components/form/date-picker.svelte';
|
|
|
|
|
import { Input, type FormInputEvent } from '$lib/components/ui/input';
|
2024-08-12 11:00:25 +02:00
|
|
|
import { Label } from '$lib/components/ui/label';
|
2025-06-09 12:15:37 -07:00
|
|
|
import { m } from '$lib/paraglide/messages';
|
2024-08-12 11:00:25 +02:00
|
|
|
import type { FormInput } from '$lib/utils/form-util';
|
2025-06-09 12:15:37 -07:00
|
|
|
import { LucideExternalLink } from '@lucide/svelte';
|
2024-08-12 11:00:25 +02:00
|
|
|
import type { Snippet } from 'svelte';
|
2024-08-24 00:49:08 +02:00
|
|
|
import type { HTMLAttributes } from 'svelte/elements';
|
2024-08-12 11:00:25 +02:00
|
|
|
|
|
|
|
|
let {
|
|
|
|
|
input = $bindable(),
|
|
|
|
|
label,
|
2024-08-13 20:51:10 +02:00
|
|
|
description,
|
2025-06-09 12:15:37 -07:00
|
|
|
docsLink,
|
2025-01-19 06:02:07 -06:00
|
|
|
placeholder,
|
2024-09-09 10:29:41 +02:00
|
|
|
disabled = false,
|
|
|
|
|
type = 'text',
|
2024-08-24 00:49:08 +02:00
|
|
|
children,
|
2024-10-02 08:43:44 +02:00
|
|
|
onInput,
|
2024-08-24 00:49:08 +02:00
|
|
|
...restProps
|
|
|
|
|
}: HTMLAttributes<HTMLDivElement> & {
|
2025-05-03 23:42:17 +02:00
|
|
|
input?: FormInput<string | boolean | number | Date | undefined>;
|
2024-10-28 18:11:54 +01:00
|
|
|
label?: string;
|
2024-08-13 20:51:10 +02:00
|
|
|
description?: string;
|
2025-06-09 12:15:37 -07:00
|
|
|
docsLink?: string;
|
2025-01-19 06:02:07 -06:00
|
|
|
placeholder?: string;
|
2024-09-09 10:29:41 +02:00
|
|
|
disabled?: boolean;
|
2025-03-11 14:16:42 -05:00
|
|
|
type?: 'text' | 'password' | 'email' | 'number' | 'checkbox' | 'date';
|
2024-10-02 08:43:44 +02:00
|
|
|
onInput?: (e: FormInputEvent) => void;
|
2024-08-12 11:00:25 +02:00
|
|
|
children?: Snippet;
|
|
|
|
|
} = $props();
|
|
|
|
|
|
2024-10-28 18:11:54 +01:00
|
|
|
const id = label?.toLowerCase().replace(/ /g, '-');
|
2024-08-12 11:00:25 +02:00
|
|
|
</script>
|
|
|
|
|
|
2024-08-24 00:49:08 +02:00
|
|
|
<div {...restProps}>
|
2024-10-28 18:11:54 +01:00
|
|
|
{#if label}
|
|
|
|
|
<Label class="mb-0" for={id}>{label}</Label>
|
|
|
|
|
{/if}
|
2024-08-13 20:51:10 +02:00
|
|
|
{#if description}
|
2025-06-09 12:15:37 -07:00
|
|
|
<p class="text-muted-foreground mt-1 text-xs">
|
|
|
|
|
{description}
|
|
|
|
|
{#if docsLink}
|
|
|
|
|
<a
|
|
|
|
|
class="relative text-white after:absolute after:bottom-0 after:left-0 after:h-px after:w-full after:translate-y-[-1px] after:bg-white"
|
|
|
|
|
href={docsLink}
|
|
|
|
|
target="_blank"
|
|
|
|
|
>
|
|
|
|
|
{m.docs()}
|
|
|
|
|
<LucideExternalLink class="inline size-3 align-text-top" />
|
|
|
|
|
</a>
|
|
|
|
|
{/if}
|
|
|
|
|
</p>
|
2024-08-12 11:00:25 +02:00
|
|
|
{/if}
|
2024-10-28 18:11:54 +01:00
|
|
|
<div class={label || description ? 'mt-2' : ''}>
|
2024-08-13 20:51:10 +02:00
|
|
|
{#if children}
|
|
|
|
|
{@render children()}
|
2024-08-24 00:49:08 +02:00
|
|
|
{:else if input}
|
2025-03-11 14:16:42 -05:00
|
|
|
{#if type === 'date'}
|
|
|
|
|
<DatePicker {id} bind:value={input.value as Date} />
|
|
|
|
|
{:else}
|
|
|
|
|
<Input
|
2025-05-21 12:15:27 -05:00
|
|
|
aria-invalid={!!input.error}
|
2025-03-11 14:16:42 -05:00
|
|
|
{id}
|
|
|
|
|
{placeholder}
|
|
|
|
|
{type}
|
|
|
|
|
bind:value={input.value}
|
|
|
|
|
{disabled}
|
2025-05-21 12:15:27 -05:00
|
|
|
oninput={(e) => onInput?.(e)}
|
2025-03-11 14:16:42 -05:00
|
|
|
/>
|
|
|
|
|
{/if}
|
2024-08-13 20:51:10 +02:00
|
|
|
{/if}
|
2024-08-24 00:49:08 +02:00
|
|
|
{#if input?.error}
|
2025-06-27 15:01:10 -05:00
|
|
|
<p class="text-destructive mt-1 text-xs text-start">{input.error}</p>
|
2024-08-13 20:51:10 +02:00
|
|
|
{/if}
|
|
|
|
|
</div>
|
2024-08-12 11:00:25 +02:00
|
|
|
</div>
|