This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / lib / components / ui / Input.svelte
2.5 kB 84 lines
1<script module lang="ts"> 2 import { tv, type VariantProps } from "tailwind-variants"; 3 4 export const inputField = tv({ 5 base: "flex min-h-9 items-center gap-2 rounded-sm border bg-background-default px-2 py-1 transition-colors", 6 variants: { 7 error: { 8 false: 9 "border-border-default focus-within:border-border-strong focus-within:ring-1 focus-within:ring-border-strong", 10 true: "border-border-danger bg-background-danger-subtle text-foreground-danger focus-within:border-border-focus-danger focus-within:ring-1 focus-within:ring-border-focus-danger" 11 }, 12 disabled: { 13 false: "", 14 true: "cursor-not-allowed bg-background-inset text-foreground-disabled" 15 } 16 }, 17 defaultVariants: { 18 error: false, 19 disabled: false 20 } 21 }); 22 23 export type InputFieldVariants = VariantProps<typeof inputField>; 24</script> 25 26<script lang="ts"> 27 import type { Component } from "svelte"; 28 import type { HTMLInputAttributes, SvelteHTMLElements } from "svelte/elements"; 29 import Spinner from "./Spinner.svelte"; 30 31 interface Props extends Omit<HTMLInputAttributes, "class" | "value"> { 32 value?: string; 33 error?: boolean; 34 disabled?: boolean; 35 loading?: boolean; 36 iconLeft?: Component<SvelteHTMLElements["svg"]>; 37 iconRight?: Component<SvelteHTMLElements["svg"]>; 38 /** static, non-editable trailing text shown inside the field, e.g. a domain suffix */ 39 suffix?: string; 40 /** the input itself, for callers that have to focus or measure it */ 41 element?: HTMLInputElement; 42 class?: string; 43 } 44 45 let { 46 value = $bindable(""), 47 error = false, 48 disabled = false, 49 loading = false, 50 iconLeft, 51 iconRight, 52 suffix, 53 element = $bindable(), 54 class: className, 55 ...rest 56 }: Props = $props(); 57 58 const classes = $derived(inputField({ error, disabled, class: className })); 59</script> 60 61<div class={classes}> 62 {#if iconLeft} 63 {@const IconLeft = iconLeft} 64 <IconLeft class="size-4 shrink-0 text-foreground-subtle" aria-hidden="true" /> 65 {/if} 66 <input 67 bind:this={element} 68 bind:value 69 {disabled} 70 aria-invalid={error} 71 aria-busy={loading} 72 class="flex-1 bg-transparent outline-none placeholder:text-foreground-placeholder disabled:cursor-not-allowed mt-px" 73 {...rest} 74 /> 75 {#if suffix} 76 <span class="shrink-0 text-foreground-muted select-none">{suffix}</span> 77 {/if} 78 {#if loading} 79 <Spinner class="size-4 shrink-0" /> 80 {:else if iconRight} 81 {@const IconRight = iconRight} 82 <IconRight class="size-4 shrink-0 text-foreground-subtle" aria-hidden="true" /> 83 {/if} 84</div>