95 lines
1.7 KiB
Svelte
95 lines
1.7 KiB
Svelte
<script lang="ts">
|
|
import { fade } from 'svelte/transition';
|
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
|
|
interface Props extends HTMLInputAttributes {
|
|
value?: string;
|
|
label?: string;
|
|
placeholder?: string;
|
|
type?: 'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url';
|
|
error?: string;
|
|
uppercase?: boolean;
|
|
[key: string]: any;
|
|
}
|
|
|
|
let {
|
|
value = $bindable(''),
|
|
label,
|
|
placeholder = '',
|
|
type = 'text',
|
|
error = '',
|
|
uppercase = false,
|
|
...rest
|
|
}: Props = $props();
|
|
|
|
let isFocussed = $state(false);
|
|
</script>
|
|
|
|
<div class="input-wrapper" class:focussed={isFocussed} class:has-error={!!error}>
|
|
{#if label}
|
|
<label for="adaptive-input">{label}</label>
|
|
{/if}
|
|
|
|
<input
|
|
id="adaptive-input"
|
|
class:all-caps={uppercase}
|
|
{type}
|
|
{placeholder}
|
|
bind:value
|
|
onfocus={() => (isFocussed = true)}
|
|
onblur={() => (isFocussed = false)}
|
|
{...rest}
|
|
/>
|
|
|
|
{#if error}
|
|
<span class="error-message" transition:fade>{error}</span>
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
.input-wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
width: 100%;
|
|
font-family: 'URW Gothic', sans-serif;
|
|
}
|
|
|
|
label {
|
|
font-size: 0.9rem;
|
|
font-weight: 400;
|
|
color: var(--color-title);
|
|
}
|
|
|
|
input {
|
|
min-height: 40px;
|
|
padding: 0 16px;
|
|
background-color: var(--color-title);
|
|
border: 2px solid transparent;
|
|
border-radius: 20px;
|
|
color: var(--color-bg-dark);
|
|
font-size: 1.2rem;
|
|
transition: all 0.2s ease-in-out;
|
|
outline: none;
|
|
text-align: center;
|
|
}
|
|
|
|
.all-caps {
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.focussed input {
|
|
border-color: var(--color-bg-light);
|
|
}
|
|
|
|
.has-error input {
|
|
border-color: #ff4d4d;
|
|
}
|
|
|
|
.error-message {
|
|
color: #ff4d4d;
|
|
font-size: 1rem;
|
|
text-align: center;
|
|
}
|
|
</style>
|