60 lines
1.6 KiB
Svelte
60 lines
1.6 KiB
Svelte
<!-- #region Select [C:2] [TYPE Component] [SEMANTICS select, dropdown, form, atom, option] -->
|
|
<!-- @BRIEF Standardized select dropdown component with label and Tailwind styling. -->
|
|
<!-- @LAYER UI -->
|
|
<!--
|
|
@COMPLEXITY: 2
|
|
@SEMANTICS: select, dropdown, form-field, ui-atom
|
|
@PURPOSE: Standardized dropdown selection component.
|
|
@LAYER: Atom
|
|
@RELATION: DEPENDS_ON -> Utils
|
|
|
|
@UX_STATE: Idle -> Current value is selectable from the provided options.
|
|
@UX_STATE: Disabled -> Native disabled state prevents selection changes.
|
|
-->
|
|
|
|
<script>
|
|
// [SECTION: IMPORTS]
|
|
import { cn } from "$lib/utils.js";
|
|
// [/SECTION: IMPORTS]
|
|
|
|
// [SECTION: PROPS]
|
|
let {
|
|
label = "",
|
|
value = $bindable(""),
|
|
options = [],
|
|
disabled = false,
|
|
class: className = "",
|
|
...rest
|
|
} = $props();
|
|
// [/SECTION: PROPS]
|
|
|
|
let id = "select-" + 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}
|
|
|
|
<select
|
|
{id}
|
|
{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 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",
|
|
className,
|
|
)}
|
|
{...rest}
|
|
>
|
|
{#each options as option}
|
|
<option value={option.value}>{option.label}</option>
|
|
{/each}
|
|
</select>
|
|
</div>
|
|
<!-- [/SECTION: TEMPLATE] -->
|
|
|
|
<!-- #endregion Select -->
|