Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svelte 5 Version now available #9

Open
evdama opened this issue Dec 15, 2024 · 0 comments
Open

Svelte 5 Version now available #9

evdama opened this issue Dec 15, 2024 · 0 comments

Comments

@evdama
Copy link

evdama commented Dec 15, 2024

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>&#9660;</span>
    {/if}
  </button>
{/if}

<style>
  button {
    all: unset;
  }
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant