156 lines
3.8 KiB
Svelte
156 lines
3.8 KiB
Svelte
<script lang="ts">
|
|
import { Eye, EyeSlash } from 'svelte-heros-v2';
|
|
import type { Snippet } from 'svelte';
|
|
|
|
let {
|
|
label,
|
|
notice,
|
|
id,
|
|
name,
|
|
type = 'text',
|
|
value = $bindable(),
|
|
placeholder,
|
|
pattern,
|
|
required = false,
|
|
disabled = false,
|
|
readonly = false,
|
|
checked = $bindable(false),
|
|
size = 'md',
|
|
pickyWidth = true,
|
|
containerClass = '',
|
|
inputElement = $bindable(),
|
|
oninput,
|
|
onclick
|
|
}: {
|
|
label?: Snippet;
|
|
notice?: Snippet;
|
|
id?: string;
|
|
name?: string;
|
|
type?: string;
|
|
value?: string;
|
|
placeholder?: string;
|
|
pattern?: RegExp;
|
|
required?: boolean;
|
|
disabled?: boolean;
|
|
readonly?: boolean;
|
|
checked?: boolean;
|
|
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
pickyWidth?: boolean;
|
|
containerClass?: string;
|
|
inputElement?: HTMLInputElement;
|
|
oninput?: (e: Event & { currentTarget: EventTarget & HTMLInputElement }) => void;
|
|
onclick?: (e: Event) => void;
|
|
} = $props();
|
|
|
|
let initialType = type;
|
|
|
|
let passwordEyeSize = {
|
|
xs: '14',
|
|
sm: '18',
|
|
md: '24',
|
|
lg: '30'
|
|
};
|
|
</script>
|
|
|
|
<!-- the cursor-not-allowed class must be set here because a disabled button does not respect the 'cursor' css property -->
|
|
<div class={containerClass} class:cursor-not-allowed={type === 'submit' && disabled}>
|
|
{#if type === 'submit'}
|
|
<input
|
|
class="btn"
|
|
class:btn-xs={size === 'xs'}
|
|
class:btn-sm={size === 'sm'}
|
|
class:btn-md={size === 'md'}
|
|
class:btn-lg={size === 'lg'}
|
|
{id}
|
|
type="submit"
|
|
{disabled}
|
|
bind:value
|
|
bind:this={inputElement}
|
|
{oninput}
|
|
{onclick}
|
|
/>
|
|
{:else}
|
|
<div>
|
|
{#if label}
|
|
<label class="label" for={id}>
|
|
<span class="label-text">
|
|
{@render label()}
|
|
{#if required}
|
|
<span class="text-red-700">*</span>
|
|
{/if}
|
|
</span>
|
|
</label>
|
|
{/if}
|
|
<div
|
|
class="relative flex items-center"
|
|
class:sm:max-w-[16rem]={type !== 'checkbox' && pickyWidth}
|
|
>
|
|
<input
|
|
class:checkbox={type === 'checkbox'}
|
|
class:checkbox-xs={type === 'checkbox' && size === 'xs'}
|
|
class:checkbox-sm={type === 'checkbox' && size === 'sm'}
|
|
class:checkbox-md={type === 'checkbox' && size === 'md'}
|
|
class:checkbox-lg={type === 'checkbox' && size === 'lg'}
|
|
class:input,w-full={type !== 'checkbox'}
|
|
class:input-xs={type !== 'checkbox' && size === 'xs'}
|
|
class:input-sm={type !== 'checkbox' && size === 'sm'}
|
|
class:input-md={type !== 'checkbox' && size === 'md'}
|
|
class:input-lg={type !== 'checkbox' && size === 'lg'}
|
|
class:input-bordered={type !== 'checkbox'}
|
|
class:pr-11={initialType === 'password'}
|
|
class:!border-none,!text-inherit={disabled}
|
|
{id}
|
|
{name}
|
|
{type}
|
|
{value}
|
|
{checked}
|
|
{placeholder}
|
|
{required}
|
|
{disabled}
|
|
{readonly}
|
|
bind:this={inputElement}
|
|
autocomplete="off"
|
|
onchange={() => {
|
|
if (type === 'checkbox') {
|
|
checked = !checked;
|
|
}
|
|
}}
|
|
oninput={(e: Event & { currentTarget: EventTarget & HTMLInputElement }) => {
|
|
value = e.currentTarget.value;
|
|
if (pattern && !pattern.test(value)) return;
|
|
oninput?.(e);
|
|
}}
|
|
onpaste={(e) => {
|
|
if (pattern && e.clipboardData && !pattern.test(e.clipboardData.getData('text'))) {
|
|
e.preventDefault();
|
|
}
|
|
}}
|
|
{onclick}
|
|
/>
|
|
{#if initialType === 'password'}
|
|
<button
|
|
class="absolute right-3"
|
|
type="button"
|
|
onclick={() => {
|
|
type = type === 'password' ? 'text' : 'password';
|
|
}}
|
|
>
|
|
{#if type === 'password'}
|
|
<EyeSlash variation="solid" size={passwordEyeSize[size]} />
|
|
{:else}
|
|
<Eye variation="solid" size={passwordEyeSize[size]} />
|
|
{/if}
|
|
</button>
|
|
{/if}
|
|
</div>
|
|
{#if notice}
|
|
<label class="label" for={id}>
|
|
<span class="label-text-alt">
|
|
{@render notice()}
|
|
</span>
|
|
</label>
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
</div>
|