Experiments >

Code animation: Property UI components 4

Experiment #13917th April, 2021by Joshua Nussbaum

Continuing to build out controls for the property grid.

This experiment will look at implementing the PositionField control:

PositionField component

The position field is actually 2 inputs, the “line number” and “character number”, seperated by a colon. I considered using a masked input, but I think 2 inputs would work better, since line and char are 2 distinct values.

Though, instead of using <input type=number> for the values, I used <span> with contenteditable=true, this is done to hide the up/down arrows and shrink the input size, ie. if there is only one character, it should only take up one character space. It was hard to do with just an input.

It also meant handling keydown events, to block non-numeric characters and handle ArrowUp/ArrowDown keyboard events.

Here’s the code:

<script>
  import Field from './Field.svelte'

  export let orientation = 'vertical'
  export let label = null
  export let line = 0, char = 0

  // handle keydown to prevent non-numeric keys
  // while still supporting ArrowUp/ArrowDown
  function keydown(event) {
    if (event.key == 'ArrowUp') {
      event.preventDefault()

      // increment value
      event.target.innerHTML = Number(event.target.innerHTML) + 1
      return
    }

    if (event.key == 'ArrowDown') {
      event.preventDefault()

      // decrement value
      // cannot be less than 0
      event.target.innerHTML = Math.max(0, Number(event.target.innerHTML) - 1)
      return
    }

    // prevent non-numeric letters
    if (event.key.length == 1 && !('1234567890'.split('').includes(event.key))) {
      // eat event and stop bubbling
      event.preventDefault()
      event.stopPropagation()
    }
  }
</script>

<Field {orientation} {label} for="line">
  <div class="input-container">
    <span role="textbox" contenteditable bind:innerHTML={line} type=number min=0 placeholder="line" on:keydown={keydown}/>
    <span class="spacer">:</span>
    <span role="textbox" contenteditable bind:innerHTML={char} type=number min=0 placeholder="char" on:keydown={keydown}/>
  </div>
</Field>

Snapshot

https://gitpod.io#snapshot/af46e314-e9b8-48c6-b499-978cac1bfeaf

Demo

Notes

  • Is it worth not using <input>? is there an alternative way that would be easier
view all experiments

Stay tuned in

Learn how to add more experimentation to your workflow