/**
* GnTabs - Accessible tab interface for Vue.
*
* @slots default - GnTab components
* @slots panels - GnTabPanel components (optional)
* @emits change
*/
import { defineComponent, h, provide, ref, computed, onMounted, watch } from "vue";
import { cx, normalizeVariant } from "../utils.js";
export const tabsKey = Symbol("vmk-ui-kit-tabs");
export default defineComponent({
name: "GnTabs",
props: {
modelValue: { type: [String, Number], default: null },
variant: { type: String, default: "default" },
vertical: { type: Boolean, default: false }
},
emits: ["update:modelValue", "change"],
setup(props, { emit, slots }) {
const activeKey = ref(props.modelValue);
const tablistRef = ref(null);
let tabItems = [];
let panelItems = [];
const registerTab = (key, label) => {
tabItems.push({ key, label });
};
const registerPanel = key => {
panelItems.push({ key });
};
const select = key => {
activeKey.value = key;
emit("update:modelValue", key);
emit("change", key);
};
const isActive = key => activeKey.value === key;
const classes = computed(() => cx("tabs", {
"tabs-compact": props.variant === "compact",
"tabs-vertical": props.vertical
}));
const focusTab = direction => {
const enabled = tabItems.filter((_, i) => {
const el = tablistRef.value?.children[i];
return el && !el.disabled && el.getAttribute("aria-disabled") !== "true";
});
const current = enabled.findIndex(item => item.key === activeKey.value);
const nextIndex = (current + direction + enabled.length) % enabled.length;
const next = enabled[nextIndex];
if (next) select(next.key);
};
watch(() => props.modelValue, value => {
activeKey.value = value;
});
provide(tabsKey, {
activeKey,
registerTab,
registerPanel,
select,
isActive
});
return () => h("div", { class: classes.value }, [
h("div", {
ref: tablistRef,
class: "tabs-list",
role: "tablist",
ariaOrientation: props.vertical ? "vertical" : "horizontal",
onKeydown: event => {
if (event.key === "ArrowRight" || event.key === "ArrowDown") {
event.preventDefault();
focusTab(1);
} else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
event.preventDefault();
focusTab(-1);
} else if (event.key === "Home") {
event.preventDefault();
focusTab(1 - tabItems.length);
} else if (event.key === "End") {
event.preventDefault();
focusTab(-1);
}
}
}, slots.default?.()),
slots.panels && h("div", { class: "tabs-panels" }, slots.panels())
]);
}
});