-
Notifications
You must be signed in to change notification settings - Fork 135
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #251 from shariquerik/tabs-component-fix-3
- Loading branch information
Showing
12 changed files
with
303 additions
and
148 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
23 changes: 11 additions & 12 deletions
23
src/components/ListView.story.vue → src/components/ListView/ListView.story.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<template> | ||
<TabList | ||
class="relative flex" | ||
:class=" | ||
vertical | ||
? 'flex-col border-r overflow-y-auto' | ||
: 'gap-7.5 border-b overflow-x-auto items-center px-5' | ||
" | ||
> | ||
<Tab | ||
ref="tabRef" | ||
as="template" | ||
v-for="(tab, i) in tabs" | ||
:key="i" | ||
v-slot="{ selected }" | ||
class="focus:outline-none focus:transition-none" | ||
> | ||
<slot v-bind="{ tab, selected }"> | ||
<button | ||
class="flex items-center gap-1.5 text-base text-ink-gray-5 duration-300 ease-in-out hover:text-ink-gray-9" | ||
:class="[ | ||
selected ? 'text-ink-gray-9' : '', | ||
vertical | ||
? 'py-2.5 px-4 border-r border-transparent hover:border-outline-gray-3' | ||
: 'py-3 border-b border-transparent hover:border-outline-gray-3', | ||
]" | ||
> | ||
<component v-if="tab.icon" :is="tab.icon" class="size-4" /> | ||
{{ tab.label }} | ||
</button> | ||
</slot> | ||
</Tab> | ||
<div | ||
ref="indicator" | ||
class="tab-indicator absolute bg-surface-gray-7" | ||
:class="[vertical ? 'right-0 w-px' : 'bottom-0 h-px', transitionClass]" | ||
/> | ||
</TabList> | ||
</template> | ||
<script setup> | ||
import { TabList, Tab } from '@headlessui/vue' | ||
import { ref, watch, computed, onMounted, nextTick, inject } from 'vue' | ||
const tabIndex = inject('tabIndex') | ||
const tabs = inject('tabs') | ||
const vertical = inject('vertical') | ||
const tabRef = ref([]) | ||
const indicator = ref(null) | ||
const tabsLength = computed(() => tabs.value?.length) | ||
const transitionClass = ref('') | ||
function moveIndicator(index) { | ||
if (index >= tabsLength.value) { | ||
index = tabsLength.value - 1 | ||
} | ||
const selectedTab = tabRef.value[index].el | ||
if (vertical) { | ||
indicator.value.style.height = `${selectedTab.offsetHeight}px` | ||
indicator.value.style.top = `${selectedTab.offsetTop}px` | ||
} else { | ||
indicator.value.style.width = `${selectedTab.offsetWidth}px` | ||
indicator.value.style.left = `${selectedTab.offsetLeft}px` | ||
} | ||
} | ||
watch(tabIndex, (index) => { | ||
if (index >= tabsLength.value) { | ||
tabIndex.value = tabsLength.value - 1 | ||
} | ||
transitionClass.value = 'transition-all duration-300 ease-in-out' | ||
nextTick(() => moveIndicator(index)) | ||
}) | ||
onMounted(() => { | ||
nextTick(() => moveIndicator(tabIndex.value)) | ||
// Fix for indicator not moving on initial load | ||
setTimeout(() => moveIndicator(tabIndex.value), 100) | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<template> | ||
<TabPanels class="flex flex-1 overflow-hidden"> | ||
<TabPanel | ||
class="flex flex-1 flex-col overflow-y-auto focus:outline-none" | ||
v-for="(tab, i) in tabs" | ||
:key="i" | ||
> | ||
<slot v-bind="{ tab }" /> | ||
</TabPanel> | ||
</TabPanels> | ||
</template> | ||
<script setup> | ||
import { TabPanels, TabPanel } from '@headlessui/vue' | ||
import { inject } from 'vue' | ||
const tabs = inject('tabs') | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
## Props | ||
|
||
### tabs | ||
|
||
It is an array of objects which contains the following attributes: | ||
|
||
1. `label` is the name of the tab, it is required. | ||
2. `icon` is the icon to be shown in the tab, it accept component and it is | ||
optional. | ||
3. You can add more attributes which can be used for custom rendering in the tab | ||
header or content. | ||
|
||
### v-model | ||
|
||
It is used to set the active tab or change the active tab. It is required. | ||
|
||
### vertical | ||
|
||
It is used to show the tabs vertically. It is optional. | ||
|
||
### as | ||
|
||
You can set it to `div` to wrap tabs in a `div`. It can be any valid HTML tag. | ||
This is useful to control the layout of the tabs. It is optional. | ||
|
||
1. `as="div"` or any valid HTML tag | ||
|
||
```html | ||
<div> | ||
<!-- container div --> | ||
<div> | ||
<div active>Tab 1</div> | ||
<div>Tab 2</div> | ||
<div>Tab 3</div> | ||
</div> | ||
<div> | ||
<div active>Content 1</div> | ||
<div>Content 2</div> | ||
<div>Content 3</div> | ||
</div> | ||
</div> | ||
``` | ||
|
||
2. `as` is not set | ||
|
||
```html | ||
<div> | ||
<div active>Tab 1</div> | ||
<div>Tab 2</div> | ||
<div>Tab 3</div> | ||
</div> | ||
<div> | ||
<div active>Content 1</div> | ||
<div>Content 2</div> | ||
<div>Content 3</div> | ||
</div> | ||
``` | ||
|
||
## Slots | ||
|
||
1. **tab-item:** You can use this slot to render custom tab items. It is | ||
optional. | ||
2. **tab-panel:** You can use this slot to render custom tab panels. It is | ||
required. Example: | ||
|
||
```vue | ||
<Tabs v-model="tabIndex" :tabs="tabs"> | ||
<template #tab-item="{ tab, selected }"> | ||
<div :class="{ 'text-gray-900 font-semibold': selected }"> | ||
<span>{{ tab.label }}</span> | ||
<span>{{ tab.icon }}</span> | ||
</div> | ||
</template> | ||
<template #tab-panel="{ tab }"> | ||
<div>{{ tab.content }}</div> | ||
</template> | ||
</Tabs> | ||
``` | ||
|
||
## Layout Customization | ||
|
||
You can customize the layout of the tabs by using `<TabList />` and `<TabPanels />` | ||
components. | ||
|
||
```vue | ||
<Tabs v-model="tabIndex" :tabs="tabs"> | ||
<TabList v-slot="{ tab, selected }"> | ||
<div :class="{ 'text-gray-900 font-semibold': selected }"> | ||
<span>{{ tab.label }}</span> | ||
<span>{{ tab.icon }}</span> | ||
</div> | ||
</TabList> | ||
<TabPanel v-slot="{ tab }"> | ||
<div>{{ tab.content }}</div> | ||
</TabPanel> | ||
</Tabs> | ||
``` |
Oops, something went wrong.