| 1 | <script lang="ts"> |
| 2 | import { ChevronDown } from "carbon-icons-svelte"; |
| 3 | import { afterUpdate, createEventDispatcher, onMount } from "svelte"; |
| 4 | const dispatch = createEventDispatcher(); |
| 5 | |
| 6 | export let label: string; |
| 7 | export let items = [ |
| 8 | {id: 0, name: "No items listed"}, |
| 9 | ]; |
| 10 | |
| 11 | let open = false; |
| 12 | let button; |
| 13 | let list; |
| 14 | export let selected = items[0].name; |
| 15 | const default_value = selected; |
| 16 | |
| 17 | function handleSelect(item) { |
| 18 | const name = item.name; |
| 19 | selected = name; |
| 20 | dispatch("select", {selection: item}); |
| 21 | } |
| 22 | |
| 23 | afterUpdate(() => { |
| 24 | if (open && list) { |
| 25 | const { width, height, top } = list.getBoundingClientRect(); |
| 26 | //list.style.width = `${width}px`; |
| 27 | //button.style.width = `${width}px`; |
| 28 | } |
| 29 | }) |
| 30 | |
| 31 | $: selected = items[0].name; |
| 32 | </script> |
| 33 | |
| 34 | <svelte:window on:click={(e) => { |
| 35 | if (open && !button.contains(e.target)) { |
| 36 | open = false; |
| 37 | } |
| 38 | }}></svelte:window> |
| 39 | |
| 40 | <div class="select"> |
| 41 | <label for="selectButton" class="label">{label}:</label> |
| 42 | <div class="select-list" class:open> |
| 43 | <button name="selectButton" bind:this={button} on:click={() => {open = !open}}> |
| 44 | <span>{selected}</span> |
| 45 | <span class="arrow"><ChevronDown></ChevronDown></span> |
| 46 | </button> |
| 47 | {#if open} |
| 48 | <div bind:this={list} class="item-list"> |
| 49 | {#each items as item} |
| 50 | <!-- svelte-ignore a11y-click-events-have-key-events --> |
| 51 | <div id={item.id.toString()} class="item" on:click={() => { |
| 52 | handleSelect(item); |
| 53 | open = false; |
| 54 | }}> |
| 55 | {item.name} |
| 56 | {#if default_value === item.name} |
| 57 | <span class="default">default</span> |
| 58 | {/if} |
| 59 | </div> |
| 60 | {/each} |
| 61 | </div> |
| 62 | {/if} |
| 63 | </div> |
| 64 | </div> |
| 65 | |
| 66 | <style lang="scss"> |
| 67 | .select { |
| 68 | display: flex; |
| 69 | flex-direction: column; |
| 70 | align-items: flex-start; |
| 71 | justify-content: center; |
| 72 | margin: 10px 0; |
| 73 | } |
| 74 | .label { |
| 75 | font-size: 0.9rem; |
| 76 | } |
| 77 | .open { |
| 78 | .arrow { |
| 79 | transform: rotateZ(180deg) !important; |
| 80 | } |
| 81 | } |
| 82 | .select-list { |
| 83 | min-width: 20rem; |
| 84 | button { |
| 85 | display: flex; |
| 86 | align-items: center; |
| 87 | justify-content: space-between; |
| 88 | min-height: 2rem; |
| 89 | width: 100%; |
| 90 | padding: 0 20px; |
| 91 | span { |
| 92 | display: flex; |
| 93 | align-items: center; |
| 94 | &:nth-child(1) { |
| 95 | margin-right: 5px; |
| 96 | } |
| 97 | &.arrow { |
| 98 | transform: rotateZ(0); |
| 99 | transition: 0.2s; |
| 100 | margin-top: 3px; |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | } |
| 105 | .item-list { |
| 106 | position: relative; |
| 107 | top: 1px; |
| 108 | max-height: 15rem; |
| 109 | overflow-y: overlay; |
| 110 | z-index: 1; |
| 111 | &::-webkit-scrollbar { |
| 112 | width: 12px; |
| 113 | } |
| 114 | &::-webkit-scrollbar-thumb { |
| 115 | background-color: #4c4c4c38; |
| 116 | } |
| 117 | .item { |
| 118 | display: flex; |
| 119 | align-items: center; |
| 120 | min-height: 2rem; |
| 121 | justify-content: space-between; |
| 122 | cursor: pointer; |
| 123 | padding: 0 20px; |
| 124 | } |
| 125 | } |
| 126 | .default { |
| 127 | color: #8c8c8c; |
| 128 | } |
| 129 | </style> |