Implemented Tabs for Volt

pull/7404/head
Cagatay Civici 2025-03-11 09:57:31 +03:00
parent 4edfa8a12c
commit 08176ee6fd
20 changed files with 835 additions and 11 deletions

View File

@ -1,6 +1,6 @@
<template> <template>
<DocSectionText v-bind="$attrs"> <DocSectionText v-bind="$attrs">
<p>Tabs is defined using <i>TabList</i>, <i>Tab</i>, <i>TabPanels</i> and <i>TabPanel</i> components. Tab and TabPanel components are associated with their <i>value</i> properties</p> <p>Tabs is defined using <i>TabList</i>, <i>Tab</i>, <i>TabPanels</i> and <i>TabPanel</i> components. Tab and TabPanel components are associated with their <i>value</i> properties.</p>
</DocSectionText> </DocSectionText>
<div class="card"> <div class="card">
<Tabs value="0"> <Tabs value="0">

View File

@ -102,6 +102,10 @@
"name": "Slider", "name": "Slider",
"to": "/slider" "to": "/slider"
}, },
{
"name": "Tabs",
"to": "/tabs"
},
{ {
"name": "Tag", "name": "Tag",
"to": "/tag" "to": "/tag"

View File

@ -55,4 +55,5 @@
@custom-variant p-custom (&[data-p~="custom"]); @custom-variant p-custom (&[data-p~="custom"]);
@custom-variant p-outlined (&[data-p~="outlined"]); @custom-variant p-outlined (&[data-p~="outlined"]);
@custom-variant p-text (&[data-p~="text"]); @custom-variant p-text (&[data-p~="text"]);
@custom-variant p-simple (&[data-p~="simple"]); @custom-variant p-simple (&[data-p~="simple"]);
@custom-variant p-scrollable (&[data-p~="scrollable"]);

View File

@ -0,0 +1,86 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Tabs is defined using <i>TabList</i>, <i>Tab</i>, <i>TabPanels</i> and <i>TabPanel</i> components. Tab and TabPanel components are associated with their <i>value</i> properties.</p>
</DocSectionText>
<div class="card">
<Tabs value="0">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p class="m-0!">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p class="m-0!">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p class="m-0!">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Tabs from '@/volt/tabs';
import Tab from '@/volt/tabs/tab';
import TabList from '@/volt/tabs/tablist';
import TabPanel from '@/volt/tabs/tabpanel';
import TabPanels from '@/volt/tabs/tabpanels';
import { ref } from 'vue';
const code = ref(`
<template>
<div class="card">
<Tabs value="0">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</template>
<script setup>
import Tabs from '@/volt/tabs';
import TabList from '@/volt/tabs/tablist';
import Tab from '@/volt/tabs/tab';
import TabPanels from '@/volt/tabs/tabpanels';
import TabPanel from '@/volt/tabs/tabpanel';
<\/script>
`);
</script>

View File

@ -0,0 +1,105 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Tabs can be controlled programmatically using <i>value</i> property as a model.</p>
</DocSectionText>
<div class="card">
<div class="flex mb-2 gap-2 justify-end">
<Button @click="value = '0'" rounded label="1" class="w-8 h-8 p-0" :outlined="value !== '0'" />
<Button @click="value = '1'" rounded label="2" class="w-8 h-8 p-0" :outlined="value !== '1'" />
<Button @click="value = '2'" rounded label="3" class="w-8 h-8 p-0" :outlined="value !== '2'" />
</div>
<Tabs v-model:value="value">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p class="m-0!">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p class="m-0!">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p class="m-0!">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Button from '@/volt/button';
import Tabs from '@/volt/tabs';
import Tab from '@/volt/tabs/tab';
import TabList from '@/volt/tabs/tablist';
import TabPanel from '@/volt/tabs/tabpanel';
import TabPanels from '@/volt/tabs/tabpanels';
import { ref } from 'vue';
const value = ref('0');
const code = ref(`
<template>
<div class="card">
<div class="flex mb-2 gap-2 justify-end">
<Button @click="value = '0'" rounded label="1" class="w-8 h-8 p-0" :outlined="value !== '0'" />
<Button @click="value = '1'" rounded label="2" class="w-8 h-8 p-0" :outlined="value !== '1'" />
<Button @click="value = '2'" rounded label="3" class="w-8 h-8 p-0" :outlined="value !== '2'" />
</div>
<Tabs v-model:value="value">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</template>
<script setup>
import Button from '@/volt/button';
import Tabs from '@/volt/tabs';
import TabList from '@/volt/tabs/tablist';
import Tab from '@/volt/tabs/tab';
import TabPanels from '@/volt/tabs/tabpanels';
import TabPanel from '@/volt/tabs/tabpanel';
import { ref } from 'vue';
const value = ref('0');
<\/script>
`);
</script>

View File

@ -0,0 +1,88 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Enabling <i>disabled</i> property of a Tab prevents user interaction.</p>
</DocSectionText>
<div class="card">
<Tabs value="0">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
<Tab disabled>Header IV</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p class="m-0!">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p class="m-0!">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p class="m-0!">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Tabs from '@/volt/tabs';
import Tab from '@/volt/tabs/tab';
import TabList from '@/volt/tabs/tablist';
import TabPanel from '@/volt/tabs/tabpanel';
import TabPanels from '@/volt/tabs/tabpanels';
import { ref } from 'vue';
const code = ref(`
<template>
<div class="card">
<Tabs value="0">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
<Tab disabled>Header IV</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</template>
<script setup>
import Tabs from '@/volt/tabs';
import TabList from '@/volt/tabs/tablist';
import Tab from '@/volt/tabs/tab';
import TabPanels from '@/volt/tabs/tabpanels';
import TabPanel from '@/volt/tabs/tabpanel';
<\/script>
`);
</script>

View File

@ -0,0 +1,65 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Tabs can be generated dynamically using the standard <i>v-for</i> directive on Tab and TabPanel.</p>
</DocSectionText>
<div class="card">
<Tabs value="0">
<TabList>
<Tab v-for="tab in tabs" :key="tab.title" :value="tab.value">{{ tab.title }}</Tab>
</TabList>
<TabPanels>
<TabPanel v-for="tab in tabs" :key="tab.content" :value="tab.value">
<p class="m-0!">{{ tab.content }}</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Tabs from '@/volt/tabs';
import Tab from '@/volt/tabs/tab';
import TabList from '@/volt/tabs/tablist';
import TabPanel from '@/volt/tabs/tabpanel';
import TabPanels from '@/volt/tabs/tabpanels';
import { ref } from 'vue';
const tabs = ref([
{ title: 'Tab 1', content: 'Tab 1 Content', value: '0' },
{ title: 'Tab 2', content: 'Tab 2 Content', value: '1' },
{ title: 'Tab 3', content: 'Tab 3 Content', value: '2' }
]);
const code = ref(`
<template>
<div class="card">
<Tabs value="0">
<TabList>
<Tab v-for="tab in tabs" :key="tab.title" :value="tab.value">{{ tab.title }}</Tab>
</TabList>
<TabPanels>
<TabPanel v-for="tab in tabs" :key="tab.content" :value="tab.value">
<p>{{ tab.content }}</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</template>
<script setup>
import Tabs from '@/volt/tabs';
import TabList from '@/volt/tabs/tablist';
import Tab from '@/volt/tabs/tab';
import TabPanels from '@/volt/tabs/tabpanels';
import TabPanel from '@/volt/tabs/tabpanel';
import { ref } from 'vue';
const tabs = ref([
{ title: 'Tab 1', content: 'Tab 1 Content', value: '0' },
{ title: 'Tab 2', content: 'Tab 2 Content', value: '1' },
{ title: 'Tab 3', content: 'Tab 3 Content', value: '2' }
]);
<\/script>
`);
</script>

View File

@ -0,0 +1,15 @@
<template>
<DocSectionText v-bind="$attrs" />
<DocSectionCode :code="code" lang="script" />
</template>
<script setup>
import { ref } from 'vue';
const code = ref(`import Tabs from '@/volt/tabs';
import TabList from '@/volt/tabs/tablist';
import Tab from '@/volt/tabs/tab';
import TabPanels from '@/volt/tabs/tabpanels';
import TabPanel from '@/volt/tabs/tabpanel';
`);
</script>

View File

@ -0,0 +1,86 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Tabs is defined using <i>TabList</i>, <i>Tab</i>, <i>TabPanels</i> and <i>TabPanel</i> components. Tab and TabPanel components are associated with their <i>value</i> properties</p>
</DocSectionText>
<div class="card">
<Tabs value="0">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Tabs from '@/volt/tabs';
import Tab from '@/volt/tabs/tab';
import TabList from '@/volt/tabs/tablist';
import TabPanel from '@/volt/tabs/tabpanel';
import TabPanels from '@/volt/tabs/tabpanels';
import { ref } from 'vue';
const code = ref(`
<template>
<div class="card">
<Tabs value="0">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</template>
<script setup>
import Tabs from '@/volt/tabs';
import TabList from '@/volt/tabs/tablist';
import Tab from '@/volt/tabs/tab';
import TabPanels from '@/volt/tabs/tabpanels';
import TabPanel from '@/volt/tabs/tabpanel';
<\/script>
`);
</script>

View File

@ -0,0 +1,62 @@
<template>
<DocSectionText v-bind="$attrs">
<p>
A navigation menu is implemented using tabs without the panels where the content of a tab is provided by a route component like
<a href="https://router.vuejs.org/guide/essentials/nested-routes#Nested-Named-Routes" target="_blank" rel="noopener noreferrer">router-view</a>. For the purpose of this demo, <i>router-view</i> is not included.
</p>
</DocSectionText>
<div class="card">
<Tabs value="/dashboard">
<TabList>
<Tab v-for="tab in items" :key="tab.label" :value="tab.route" as="div" class="flex items-center gap-2">
<i :class="tab.icon" />
<span>{{ tab.label }}</span>
</Tab>
</TabList>
</Tabs>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Tabs from '@/volt/tabs';
import Tab from '@/volt/tabs/tab';
import TabList from '@/volt/tabs/tablist';
import { ref } from 'vue';
const items = ref([
{ route: '/dashboard', label: 'Dashboard', icon: 'pi pi-home' },
{ route: '/transactions', label: 'Transactions', icon: 'pi pi-chart-line' },
{ route: '/products', label: 'Products', icon: 'pi pi-list' },
{ route: '/messages', label: 'Messages', icon: 'pi pi-inbox' }
]);
const code = ref(`
<template>
<div class="card">
<Tabs value="/dashboard">
<TabList>
<Tab v-for="tab in items" :key="tab.label" :value="tab.route" as="div" class="flex items-center gap-2">
<i :class="tab.icon" />
<span>{{ tab.label }}</span>
</Tab>
</TabList>
</Tabs>
</div>
</template>
<script setup>
import Tabs from '@/volt/tabs';
import Tab from '@/volt/tabs/tab';
import TabList from '@/volt/tabs/tablist';
import { ref } from "vue";
const items = ref([
{ route: '/dashboard', label: 'Dashboard', icon: 'pi pi-home' },
{ route: '/transactions', label: 'Transactions', icon: 'pi pi-chart-line' },
{ route: '/products', label: 'Products', icon: 'pi pi-list' },
{ route: '/messages', label: 'Messages', icon: 'pi pi-inbox' }
]);
<\/script>
`);
</script>

View File

@ -0,0 +1,110 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Custom content for a tab is defined with the default slot.</p>
</DocSectionText>
<div class="card">
<Tabs value="0">
<TabList>
<Tab value="0" class="flex items-center gap-2">
<Avatar image="https://primefaces.org/cdn/primevue/images/avatar/amyelsner.png" shape="circle" />
<span class="font-bold whitespace-nowrap">Amy Elsner</span>
</Tab>
<Tab value="1" class="flex items-center gap-2">
<Avatar image="https://primefaces.org/cdn/primevue/images/avatar/onyamalimba.png" shape="circle" />
<span class="font-bold whitespace-nowrap">Onyama Limba</span>
</Tab>
<Tab value="2" class="flex items-center gap-2">
<Avatar image="https://primefaces.org/cdn/primevue/images/avatar/ionibowcher.png" shape="circle" />
<span class="font-bold whitespace-nowrap">Ioni Bowcher</span>
<Badge value="2" />
</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p class="m-0!">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p class="m-0!">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p class="m-0!">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Avatar from '@/volt/avatar';
import Badge from '@/volt/badge';
import Tabs from '@/volt/tabs';
import Tab from '@/volt/tabs/tab';
import TabList from '@/volt/tabs/tablist';
import TabPanel from '@/volt/tabs/tabpanel';
import TabPanels from '@/volt/tabs/tabpanels';
import { ref } from 'vue';
const code = ref(`
<template>
<div class="card">
<Tabs value="0">
<TabList>
<Tab value="0" class="flex items-center gap-2">
<Avatar image="https://primefaces.org/cdn/primevue/images/avatar/amyelsner.png" shape="circle" />
<span class="font-bold whitespace-nowrap">Amy Elsner</span>
</Tab>
<Tab value="1" class="flex items-center gap-2">
<Avatar image="https://primefaces.org/cdn/primevue/images/avatar/onyamalimba.png" shape="circle" />
<span class="font-bold whitespace-nowrap">Onyama Limba</span>
</Tab>
<Tab value="2" class="flex items-center gap-2">
<Avatar image="https://primefaces.org/cdn/primevue/images/avatar/ionibowcher.png" shape="circle" />
<span class="font-bold whitespace-nowrap">Ioni Bowcher</span>
<Badge value="2" />
</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in
culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</template>
<script setup>
import Avatar from '@/volt/avatar';
import Badge from '@/volt/badge';
import Tabs from '@/volt/tabs';
import TabList from '@/volt/tabs/tablist';
import Tab from '@/volt/tabs/tab';
import TabPanels from '@/volt/tabs/tabpanels';
import TabPanel from '@/volt/tabs/tabpanel';
<\/script>
`);
</script>

View File

@ -0,0 +1,63 @@
<template>
<DocComponent title="Vue Tabs Component" header="Tabs" description="Tabs is a container component to group content between different tabs." :componentDocs="docs" />
</template>
<script>
import BasicDoc from '@/doc/tabs/BasicDoc.vue';
import ControlledDoc from '@/doc/tabs/ControlledDoc.vue';
import DisabledDoc from '@/doc/tabs/DisabledDoc.vue';
import DynamicDoc from '@/doc/tabs/DynamicDoc.vue';
import ImportDoc from '@/doc/tabs/ImportDoc.vue';
import ScrollableDoc from '@/doc/tabs/ScrollableDoc.vue';
import TabMenuDoc from '@/doc/tabs/TabMenuDoc.vue';
import TemplateDoc from '@/doc/tabs/TemplateDoc.vue';
export default {
data() {
return {
docs: [
{
id: 'import',
label: 'Import',
component: ImportDoc
},
{
id: 'basic',
label: 'Basic',
component: BasicDoc
},
{
id: 'dynamic',
label: 'Dynamic',
component: DynamicDoc
},
{
id: 'controlled',
label: 'Controlled',
component: ControlledDoc
},
{
id: 'scrollable',
label: 'Scrollable',
component: ScrollableDoc
},
{
id: 'disabled',
label: 'Disabled',
component: DisabledDoc
},
{
id: 'template',
label: 'Template',
component: TemplateDoc
},
{
id: 'tabmenu',
label: 'Tab Menu',
component: TabMenuDoc
}
]
};
}
};
</script>

View File

@ -2,6 +2,8 @@ import PrimeVue from 'primevue/config';
import StyleClass from 'primevue/styleclass'; import StyleClass from 'primevue/styleclass';
export default defineNuxtPlugin((nuxtApp) => { export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(PrimeVue); nuxtApp.vueApp.use(PrimeVue, {
unstyled: true
});
nuxtApp.vueApp.directive('styleclass', StyleClass); nuxtApp.vueApp.directive('styleclass', StyleClass);
}); });

View File

@ -0,0 +1,21 @@
<template>
<Tabs
unstyled
:pt="theme"
:ptOptions="{
mergeProps: ptViewMerge
}"
>
<slot></slot>
</Tabs>
</template>
<script setup>
import Tabs from 'primevue/tabs';
import { ref } from 'vue';
import { ptViewMerge } from '../utils';
const theme = ref({
root: `flex flex-col`
});
</script>

View File

@ -0,0 +1,28 @@
<template>
<Tab
unstyled
:pt="theme"
:ptOptions="{
mergeProps: ptViewMerge
}"
>
<slot></slot>
</Tab>
</template>
<script setup>
import Tab from 'primevue/tab';
import { ref } from 'vue';
import { ptViewMerge } from '../utils';
const theme = ref({
root: `flex-shrink-0 cursor-pointer select-none relative whitespace-nowrap py-4 px-[1.125rem]
border-b border-surface-200 dark:border-surface-700 font-semibold
text-surface-500 dark:text-surface-400
transition-colors duration-200 -mb-px
not-p-active:enabled:hover:text-surface-700 dark:not-p-active:enabled:hover:text-surface-0
p-active:border-primary p-active:text-primary
disabled:pointer-events-none disabled:opacity-60
focus-visible:z-10 focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-[-1px] focus-visible:outline-primary`
});
</script>

View File

@ -0,0 +1,35 @@
<template>
<TabList
unstyled
:pt="theme"
:ptOptions="{
mergeProps: ptViewMerge
}"
>
<slot></slot>
</TabList>
</template>
<script setup>
import TabList from 'primevue/tablist';
import { ref } from 'vue';
import { ptViewMerge } from '../utils';
const navButton = `!absolute flex-shrink-0 top-0 z-20 h-full flex items-center justify-center cursor-pointer
bg-surface-0 dark:bg-surface-900 text-surface-500 dark:text-surface-400 hover:text-surface-700 dark:hover:text-surface-0 w-10
shadow-[0px_0px_10px_50px_rgba(255,255,255,0.6)] dark:shadow-[0px_0px_10px_50px] dark:shadow-surface-900/50
focus-visible:z-10 focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-[-1px] focus-visible:outline-primary
transition-colors duration-200`;
const theme = ref({
root: `flex relative`,
prevButton: navButton + ` start-0`,
nextButton: navButton + ` end-0`,
content: `flex-grow
p-scrollable:overflow-x-auto p-scrollable:overflow-y-hidden p-scrollable:overscroll-y-contain p-scrollable:overscroll-x-auto
p-scrollable:[scrollbar-behavior:smooth] p-scrollable:[scrollbar-width:none]`,
tabList: `relative flex bg-surface-0 dark:bg-surface-900 border-b border-surface-200 dark:border-surface-700
p-scrollable:overflow-hidden`,
activeBar: `z-10 block absolute -bottom-px h-px bg-primary transition-[left] duration-200 ease-[cubic-bezier(0.35,0,0.25,1)]`
});
</script>

View File

@ -0,0 +1,21 @@
<template>
<TabPanel
unstyled
:pt="theme"
:ptOptions="{
mergeProps: ptViewMerge
}"
>
<slot></slot>
</TabPanel>
</template>
<script setup>
import TabPanel from 'primevue/tabpanel';
import { ref } from 'vue';
import { ptViewMerge } from '../utils';
const theme = ref({
root: ``
});
</script>

View File

@ -0,0 +1,22 @@
<template>
<TabPanels
unstyled
:pt="theme"
:ptOptions="{
mergeProps: ptViewMerge
}"
>
<slot></slot>
</TabPanels>
</template>
<script setup>
import TabPanels from 'primevue/tabpanels';
import { ref } from 'vue';
import { ptViewMerge } from '../utils';
const theme = ref({
root: `bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0
pt-[0.875rem] pb-[1.125rem] px-[1.125rem] outline-none`
});
</script>

View File

@ -1,11 +1,12 @@
<template> <template>
<component v-if="!asChild" :is="as" v-ripple :class="cx('root')" @click="onClick" v-bind="attrs"> <component v-if="!asChild" :is="as" v-ripple :class="cx('root')" :data-p="dataP" @click="onClick" v-bind="attrs">
<slot></slot> <slot></slot>
</component> </component>
<slot v-else :class="cx('root')" :active="active" :a11yAttrs="a11yAttrs" :onClick="onClick"></slot> <slot v-else :dataP="dataP" :class="cx('root')" :active="active" :a11yAttrs="a11yAttrs" :onClick="onClick"></slot>
</template> </template>
<script> <script>
import { cn } from '@primeuix/utils';
import { findSingle, focus, getAttribute } from '@primeuix/utils/dom'; import { findSingle, focus, getAttribute } from '@primeuix/utils/dom';
import { equals } from '@primeuix/utils/object'; import { equals } from '@primeuix/utils/object';
import Ripple from 'primevue/ripple'; import Ripple from 'primevue/ripple';
@ -159,6 +160,11 @@ export default {
active: this.active active: this.active
} }
}; };
},
dataP() {
return cn({
active: this.active
});
} }
}, },
directives: { directives: {

View File

@ -1,5 +1,5 @@
<template> <template>
<div ref="list" :class="cx('root')" v-bind="ptmi('root')"> <div ref="list" :class="cx('root')" :data-p="dataP" v-bind="ptmi('root')">
<button <button
v-if="showNavigators && isPrevButtonEnabled" v-if="showNavigators && isPrevButtonEnabled"
ref="prevButton" ref="prevButton"
@ -14,12 +14,10 @@
> >
<component :is="templates.previcon || 'ChevronLeftIcon'" aria-hidden="true" v-bind="ptm('prevIcon')" /> <component :is="templates.previcon || 'ChevronLeftIcon'" aria-hidden="true" v-bind="ptm('prevIcon')" />
</button> </button>
<div ref="content" :class="cx('content')" @scroll="onScroll" v-bind="ptm('content')"> <div ref="content" :class="cx('content')" @scroll="onScroll" :data-p="dataP" v-bind="ptm('content')">
<div ref="tabs" :class="cx('tabList')" role="tablist" <div ref="tabs" :class="cx('tabList')" role="tablist" :aria-orientation="$pcTabs.orientation || 'horizontal'" v-bind="ptm('tabList')">
:aria-orientation="$pcTabs.orientation || 'horizontal'" v-bind="ptm('tabList')">
<slot></slot> <slot></slot>
<span ref="inkbar" :class="cx('activeBar')" role="presentation" aria-hidden="true" <span ref="inkbar" :class="cx('activeBar')" role="presentation" aria-hidden="true" v-bind="ptm('activeBar')"></span>
v-bind="ptm('activeBar')"></span>
</div> </div>
</div> </div>
<button <button
@ -40,6 +38,7 @@
</template> </template>
<script> <script>
import { cn } from '@primeuix/utils';
import { findSingle, getHeight, getOffset, getOuterHeight, getOuterWidth, getWidth, isRTL } from '@primeuix/utils/dom'; import { findSingle, getHeight, getOffset, getOuterHeight, getOuterWidth, getWidth, isRTL } from '@primeuix/utils/dom';
import ChevronLeftIcon from '@primevue/icons/chevronleft'; import ChevronLeftIcon from '@primevue/icons/chevronleft';
import ChevronRightIcon from '@primevue/icons/chevronright'; import ChevronRightIcon from '@primevue/icons/chevronright';
@ -174,6 +173,11 @@ export default {
}, },
nextButtonAriaLabel() { nextButtonAriaLabel() {
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.next : undefined; return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.next : undefined;
},
dataP() {
return cn({
scrollable: this.$pcTabs.scrollable
});
} }
}, },
components: { components: {