71 lines
1.6 KiB
Vue
71 lines
1.6 KiB
Vue
<script setup>
|
|
import { inject, computed } from 'vue';
|
|
|
|
defineOptions({ name: 'TabsContent' });
|
|
|
|
const props = defineProps({
|
|
value: {
|
|
type: [String, Number],
|
|
required: true
|
|
}
|
|
});
|
|
|
|
const { activeTab, orientation } = inject('tabs');
|
|
|
|
const isActive = computed(() => activeTab.value === props.value);
|
|
|
|
const transitionClasses = computed(() => {
|
|
const baseClasses = 'transition-all duration-300';
|
|
|
|
if (orientation === 'responsive') {
|
|
return {
|
|
[baseClasses]: true,
|
|
'translate-x-0 opacity-100': isActive.value,
|
|
'translate-x-2 opacity-0': !isActive.value,
|
|
'md:translate-x-0 md:translate-y-0': isActive.value,
|
|
'md:translate-x-0 md:translate-y-2 md:opacity-0': !isActive.value,
|
|
'hidden': !isActive.value
|
|
};
|
|
}
|
|
|
|
if (orientation === 'vertical') {
|
|
return {
|
|
[baseClasses]: true,
|
|
'translate-y-0 opacity-100': isActive.value,
|
|
'translate-y-2 opacity-0': !isActive.value,
|
|
'hidden': !isActive.value
|
|
};
|
|
}
|
|
|
|
return {
|
|
[baseClasses]: true,
|
|
'translate-x-0 opacity-100': isActive.value,
|
|
'translate-x-2 opacity-0': !isActive.value,
|
|
'hidden': !isActive.value
|
|
};
|
|
});
|
|
|
|
const contentClasses = computed(() => [
|
|
'ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
|
'mt-2',
|
|
transitionClasses.value
|
|
]);
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
role="tabpanel"
|
|
:class="contentClasses"
|
|
:tabindex="isActive ? 0 : -1"
|
|
:aria-hidden="!isActive"
|
|
>
|
|
<slot v-if="isActive" />
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
[role="tabpanel"] {
|
|
transform-origin: top left;
|
|
will-change: transform, opacity;
|
|
}
|
|
</style> |