@setoelkahfi / svara / commits / e57e1e8

feat!: added selection component

mellbacon committed Jul 12, 2023 at 18:53 UTC e57e1e8bc403ef1b9c74e4fa529ccb3cb050b99b
1 file changed +134
src/lib/utility/Select.svelte new
+134
@@ -0,0 +1,134 @@
1 +<script lang="ts">
2 + import { ChevronDown } from "carbon-icons-svelte";
3 + import { afterUpdate, createEventDispatcher } 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(name) {
18 + selected = name;
19 + dispatch("select", {selection: name});
20 + }
21 +
22 + afterUpdate(() => {
23 + if (open && list) {
24 + const { _ , width } = button.getBoundingClientRect();
25 + list.style.width = `${width}px`;
26 + }
27 + })
28 +
29 + $: selected = items[0].name;
30 +</script>
31 +
32 +<svelte:window on:click={(e) => {
33 + if (open && !button.contains(e.target)) {
34 + open = false;
35 + }
36 +}}></svelte:window>
37 +
38 +<div class="select">
39 + <label for="selectButton" class="label">{label}:</label>
40 + <div class="select-list" class:open>
41 + <button name="selectButton" bind:this={button} on:click={() => {open = !open}}>
42 + <span>{selected}</span>
43 + <span class="arrow"><ChevronDown></ChevronDown></span>
44 + </button>
45 + {#if open}
46 + <div bind:this={list} class="item-list">
47 + {#each items as item}
48 + <!-- svelte-ignore a11y-click-events-have-key-events -->
49 + <div id={item.id.toString()} class="item" on:click={() => {
50 + handleSelect(item.name);
51 + open = false;
52 + }}>
53 + {item.name}
54 + {#if default_value === item.name}
55 + <span class="default">default</span>
56 + {/if}
57 + </div>
58 + {/each}
59 + </div>
60 + {/if}
61 + </div>
62 +</div>
63 +
64 +<style lang="scss">
65 + .select {
66 + display: flex;
67 + flex-direction: column;
68 + align-items: flex-start;
69 + justify-content: center;
70 + margin: 10px 0;
71 + }
72 + .label {
73 + font-size: 0.9rem;
74 + }
75 + .open {
76 + .arrow {
77 + transform: rotateZ(180deg) !important;
78 + }
79 + }
80 + .select-list {
81 + min-width: 7rem;
82 + button {
83 + color: white;
84 + display: flex;
85 + align-items: center;
86 + justify-content: center;
87 + min-height: 2rem;
88 + width: 100%;
89 + background-color: #333;
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: absolute;
107 + border: 1px solid #333;
108 + background-color: #1f1f1f;
109 + max-height: 15rem;
110 + overflow-y: overlay;
111 + min-width: 20rem;
112 + z-index: 1;
113 + &::-webkit-scrollbar {
114 + width: 12px;
115 + }
116 + &::-webkit-scrollbar-thumb {
117 + background-color: #4c4c4c38;
118 + }
119 + .item {
120 + display: flex;
121 + align-items: center;
122 + min-height: 2rem;
123 + justify-content: space-between;
124 + cursor: pointer;
125 + padding: 0 20px;
126 + &:hover {
127 + background-color: #373737;
128 + }
129 + }
130 + }
131 + .default {
132 + color: #8c8c8c;
133 + }
134 +</style>
\ No newline at end of file