/
tablist.svelte
83 lines (82 loc) · 1.95 KB
/
tablist.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<script context="module">export {};
</script>
<script>/** Styling */
export let cStyle = null;
export let cClass = null;
/** Attributes */
export let tabs;
export let active = tabs[0];
/** Id */
import genID from "./id";
const id = genID();
/** Functions */
const setActive = (tab) => {
active = tab;
};
const getIndexOfId = (tabID) => {
for (let i = 0; i < tabs.length; ++i) {
if (tabID.match(id + tabs[i].key))
return i;
}
return -1;
};
const setFocus = (offset) => {
const focused = document.activeElement;
if (!focused)
return;
const index = getIndexOfId(focused.id);
if (index < 0)
return;
moveFocus(index + offset);
};
const moveFocus = (index) => {
const nextIndex = index % tabs.length;
const nextTab = tabs[nextIndex < 0 ? tabs.length - 1 : nextIndex];
document.getElementById(id + nextTab.key).focus();
};
const onKeyEvent = (e) => {
const tablist = document.getElementById(id);
if (!tablist.contains(document.activeElement))
return;
switch (e.key) {
case "ArrowLeft":
setFocus(-1);
e.preventDefault();
break;
case "ArrowRight":
setFocus(+1);
e.preventDefault();
break;
case "Home":
moveFocus(0);
e.preventDefault();
break;
case "End":
moveFocus(tabs.length - 1);
e.preventDefault();
break;
}
};
</script>
<svelte:window on:keydown={onKeyEvent} />
<div
role="tablist"
{id}
class="tablist {cClass}"
style={cStyle} >
{#each tabs as tab}
<button
role="tab"
aria-selected="{active.key === tab.key}"
id="{id+tab.key}"
class={active.key === tab.key ? "selected" : ""}
on:click={() => setActive(tab)}>
{#if tab?.icon}
<svg viewBox="0 0 24 24">
<path d="{tab.icon}" />
</svg>
{/if}
{tab.name}
</button>
{/each}
</div>