Files
ss-tools/frontend/src/lib/ui/Input.svelte
2026-02-19 18:24:36 +03:00

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] -->