Shopping List v2.0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ListInput.svelte 2.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. <script>
  2. import { createEventDispatcher } from 'svelte';
  3. import { fade } from 'svelte/transition';
  4. export let words;
  5. let dispatch = createEventDispatcher();
  6. let inputEl;
  7. let hidden = true;
  8. let wordList = [];
  9. function updateWords() {
  10. wordList = [];
  11. let q = inputEl.value.toLowerCase();
  12. for (let content in words) {
  13. if (content.includes(q))
  14. wordList.push({ content, score: words[content] });
  15. }
  16. wordList.sort((a, b) => b.score - a.score);
  17. }
  18. function onBlur() {
  19. setTimeout(() => hidden = true, 50);
  20. }
  21. function onFocus() {
  22. updateWords();
  23. hidden = false;
  24. }
  25. function onSubmit(evt) {
  26. let val = inputEl.value.toLowerCase();
  27. if (!val)
  28. return;
  29. inputEl.value = "";
  30. dispatch("add", val);
  31. }
  32. function add(content) {
  33. inputEl.value = "";
  34. dispatch("add", content.toLowerCase());
  35. }
  36. function capitalize(str) {
  37. var first = str[0].toUpperCase();
  38. return first + str.substring(1);
  39. }
  40. </script>
  41. <style>
  42. .add {
  43. padding-top: 12px;
  44. }
  45. .add .content,
  46. .add .submit {
  47. box-sizing: content-box;
  48. -webkit-appearance: none;
  49. font-size: 16px;
  50. border: 1px solid #aaa;
  51. border-radius: 5px;
  52. background-color: #fff;
  53. height: 20px;
  54. padding: 6px;
  55. line-height: 0px;
  56. }
  57. .add .content {
  58. width: 78%;
  59. border-top-right-radius: 0px;
  60. border-bottom-right-radius: 0px;
  61. }
  62. .add .submit {
  63. width: 8%;
  64. background-color: #eee;
  65. border-top-left-radius: 0px;
  66. border-bottom-left-radius: 0px;
  67. }
  68. .add .submit:hover {
  69. background-color: #ddd;
  70. }
  71. .add .suggestions {
  72. z-index: 2;
  73. background: white;
  74. box-shadow: 0px 0px 10px 1px #ccc;
  75. position: absolute;
  76. width: 90%;
  77. margin: auto;
  78. left: 0px;
  79. right: 0px;
  80. margin-top: 15px;
  81. padding-top: 6px;
  82. padding-bottom: 6px;
  83. max-height: 70%;
  84. overflow-y: auto;
  85. overflow-x: hidden;
  86. }
  87. .add .suggestions .suggestion:last-child {
  88. border-bottom: none;
  89. }
  90. .add .suggestions .suggestion {
  91. padding: 12px;
  92. cursor: pointer;
  93. border-bottom: 1px solid #ccc;
  94. text-overflow: ellipsis;
  95. max-width: 100%;
  96. overflow: hidden;
  97. }
  98. </style>
  99. <form on:submit|preventDefault={onSubmit} class="add">
  100. <input
  101. class="content" name="content" autocomplete="off"
  102. on:focus={onFocus} on:blur={onBlur} on:keydown={() => window.setTimeout(updateWords, 50)} bind:this={inputEl}>
  103. <button class="submit" type="submit">+</button>
  104. {#if !hidden}
  105. <div transition:fade={{duration: 50}} class="suggestions">
  106. {#each wordList as word}
  107. <div class="suggestion" on:click={() => add(word.content)}>
  108. {capitalize(word.content)}
  109. </div>
  110. {/each}
  111. </div>
  112. {/if}
  113. </form>