61 lines
1.5 KiB
Svelte
61 lines
1.5 KiB
Svelte
<!-- [DEF:Input:Component] -->
|
|
<!--
|
|
@TIER: TRIVIAL
|
|
@SEMANTICS: input, form-field, ui-atom
|
|
@PURPOSE: Standardized text input component with label and error handling.
|
|
@LAYER: Atom
|
|
|
|
@INVARIANT: Consistent spacing and focus states.
|
|
-->
|
|
|
|
<script>
|
|
// [SECTION: IMPORTS]
|
|
import { cn } from "$lib/utils.js";
|
|
// [/SECTION: IMPORTS]
|
|
|
|
// [SECTION: PROPS]
|
|
let {
|
|
label = "",
|
|
value = $bindable(""),
|
|
placeholder = "",
|
|
error = "",
|
|
disabled = false,
|
|
type = "text",
|
|
class: className = "",
|
|
...rest
|
|
} = $props();
|
|
// [/SECTION: PROPS]
|
|
|
|
let id = "input-" + Math.random().toString(36).substr(2, 9);
|
|
</script>
|
|
|
|
<!-- [SECTION: TEMPLATE] -->
|
|
<div class="flex flex-col gap-1.5 w-full">
|
|
{#if label}
|
|
<label for={id} class="text-sm font-medium text-gray-700">
|
|
{label}
|
|
</label>
|
|
{/if}
|
|
|
|
<input
|
|
{id}
|
|
{type}
|
|
{placeholder}
|
|
{disabled}
|
|
bind:value
|
|
class={cn(
|
|
"flex h-10 w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
error ? "border-destructive" : "",
|
|
className,
|
|
)}
|
|
{...rest}
|
|
/>
|
|
|
|
{#if error}
|
|
<span class="text-xs text-destructive">{error}</span>
|
|
{/if}
|
|
</div>
|
|
<!-- [/SECTION: TEMPLATE] -->
|
|
|
|
<!-- [/DEF:Input:Component] -->
|