Open
Description
I migrated the code to Svelte 5... feel free to update:
<script lang="ts">
import { tick } from 'svelte'
let { cols = 20, inputClasses = '', labelClasses = '', onblur = () => {}, options = [], placeholder = '', rows = 2, selectCaret, type = 'text', value = $bindable() } = $props()
let editing = $state(false)
let inputEl: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | undefined = $state()
let selectedIndex = $state(options.findIndex(o => o.value === value))
let isNumber = $derived(type === 'number')
let isSelect = $derived(type === 'select')
let isText = $derived(type === 'text')
let isTextArea = $derived(type === 'textarea')
let label = $derived.by(() => {
if (isNumber) return value === '' ? placeholder : value
if (isText || isTextArea) return value ? value : placeholder
return selectedIndex === -1 ? placeholder : options[selectedIndex].label
})
const toggle = async () => {
editing = !editing
if (editing) {
await tick()
inputEl.focus()
}
}
const handleInput = (e: InputEvent) => {
const target = e.target as HTMLInputElement // Narrowing the type of the target
value = isNumber ? +target.value : target.value // Using the unary plus operator to cast a string to number if isNumber is true
}
const handleEnter = (e: KeyboardEvent) => {
if (e.key === 'Enter') inputEl.blur()
}
const handleBlur = () => {
toggle()
onblur?.(value)
}
const handleChange = (e: Event) => {
const target = e.target as HTMLSelectElement // Narrowing the type of the target
selectedIndex = placeholder ? target.selectedIndex - 1 : target.selectedIndex
value = options[selectedIndex].value
}
</script>
{#if editing && (isText || isNumber)}
<input bind:this={inputEl} class={inputClasses} {type} {value} {placeholder} oninput={handleInput} onkeyup={handleEnter} onblur={handleBlur} />
{:else if editing && isTextArea}
<textarea bind:this={inputEl} class={inputClasses} {value} {rows} {cols} {placeholder} oninput={handleInput} onblur={handleBlur}></textarea>
{:else if editing && isSelect}
<select bind:this={inputEl} class={inputClasses} {value} onchange={handleChange} onblur={handleBlur}>
{#if placeholder}
<option selected value disabled>{placeholder}</option>
{/if}
{#each options as { label, value }}
<option {value}>{label}</option>
{/each}
</select>
{:else}
<button type="button" class={labelClasses} onclick={toggle}>
{label}
{#if isSelect && selectCaret}
{@render selectCaret()}
{:else if isSelect}
<span>▼</span>
{/if}
</button>
{/if}
<style>
button {
all: unset;
}
</style>
Metadata
Metadata
Assignees
Labels
No labels