PronounsPage/components/TabsNav.vue

82 lines
2.5 KiB
Vue

<script setup lang="ts">
import useHash from '~/composables/useHash.ts';
const props = defineProps<{
tabs: (string | undefined)[];
pills?: boolean;
showheaders?: boolean;
navclass?: string;
anchors?: boolean;
}>();
const { handleHash, setHash } = useHash();
const visibleTabs = computed(() => props.tabs.filter((x) => x !== undefined));
const activeTab = ref(visibleTabs.value[0]);
watch(activeTab, () => {
if (!props.anchors) {
return;
}
setHash('', activeTab.value);
});
onMounted(() => {
if (!props.anchors) {
return;
}
handleHash('', (hash) => {
if (!visibleTabs.value.includes(hash)) {
return;
}
activeTab.value = hash;
}, false);
});
const tablist = useTemplateRef('tablist');
const tabKeydown = (event: KeyboardEvent) => {
const activeIndex = visibleTabs.value.indexOf(activeTab.value);
if (activeIndex === -1) {
return;
}
if ((event.key === 'ArrowUp' || event.key === 'ArrowLeft') &&
activeIndex > 0) {
activeTab.value = visibleTabs.value[activeIndex - 1];
(tablist.value?.children[activeIndex - 1].firstElementChild as HTMLButtonElement | undefined)?.focus();
} else if ((event.key === 'ArrowDown' || event.key === 'ArrowRight') &&
activeIndex < visibleTabs.value.length - 1) {
activeTab.value = visibleTabs.value[activeIndex + 1];
(tablist.value?.children[activeIndex + 1].firstElementChild as HTMLButtonElement | undefined)?.focus();
}
};
</script>
<template>
<div>
<ul ref="tablist" :class="['nav', pills ? 'nav-pills' : 'nav-tabs', navclass]" role="tablist">
<li v-for="tab in visibleTabs" :key="tab" class="nav-item" role="tab">
<button
type="button"
:tabindex="activeTab === tab ? 0 : -1"
:class="['nav-link', activeTab === tab ? 'active' : '']"
:aria-selected="activeTab === tab"
@click="activeTab = tab"
@keydown="tabKeydown"
>
<slot :name="`${tab}-header`"></slot>
</button>
</li>
</ul>
<div class="card" role="tabpanel">
<div class="card-body">
<h3 v-if="showheaders" class="h4 mb-3">
<slot :name="`${activeTab}-header`"></slot>
</h3>
<slot :name="activeTab"></slot>
</div>
</div>
</div>
</template>