<input type="text"
  bind:this={input}
  use:action={maskRef}
  {...attrs}
  on:accept={accept}
  on:accept
  on:complete
>

<script type="text/javascript">
  import { onMount, onDestroy, tick } from 'svelte';
  import IMaskSvelte from '@imask/svelte';
  import IMask from 'imask';
	const action = IMaskSvelte.imask; // REPL does not understand named import

  let input;
  export let value = null;
  export let isComplete = false;
  export let focusOnMount = false;

  let maskRef, imask, unmask, attrs;

  $: {
    ({ imask, unmask, ...attrs } = $$props);

    if (maskRef) {
      writeValue(value);
      attrs.value = maskRef.value;
      tick().then(() => value = getValue());
    }
  }

  function getValue () {
    if (unmask === 'typed') return maskRef.typedValue;
    if (unmask) return maskRef.unmaskedValue;
    return maskRef.value;
  }

  function setValue (v) {
    v = v == null ? '' : v;
    if (unmask === 'typed') maskRef.typedValue = v;
    else if (unmask) maskRef.unmaskedValue = v;
    else maskRef.value = v;
    isComplete = maskRef.masked.isComplete;
  }

  function writeValue (v) {
    if (getValue() !== v ||
      // handle cases like Number('') === 0,
      // for details see https://github.com/uNmAnNeR/imaskjs/issues/134
      (typeof v !== 'string' && value === '') && !maskRef.el.isActive
    ) {
      setValue(v);
    }
  }

  onMount(() => {
    maskRef = IMask(input, imask);
    if (focusOnMount)
      input.focus();
    setValue(value);
  });

  onDestroy(() => {
    if (maskRef) maskRef.destroy();
    maskRef = undefined;
    isComplete = false;
  });

  function accept ({ detail: mask }) {
    value = getValue();
    isComplete = mask.masked.isComplete;
  }
</script>
