Skip to content

Commit 39b1646

Browse files
authored
Fix type on Tabs component Vue (#912)
* add `tabs` example to Vue * use useResolveButtonType for Tabs * update changelog
1 parent 2599655 commit 39b1646

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222
- Allow to click on elements inside a `DialogOverlay` ([#816](https://github.com/tailwindlabs/headlessui/pull/816))
2323
- Fix SSR crash because of `useWindowEvent` ([#817](https://github.com/tailwindlabs/headlessui/pull/817))
2424
- Improve tree shaking ([#859](https://github.com/tailwindlabs/headlessui/pull/859))
25+
- Add `type="button"` to `Tabs` component ([#912](https://github.com/tailwindlabs/headlessui/pull/912))
2526

2627
## [@headlessui/react@v1.4.1] - 2021-08-30
2728

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<template>
2+
<div class="flex flex-col items-start w-screen h-full p-12 bg-gray-50 space-y-12">
3+
<SwitchGroup as="div" class="flex items-center space-x-4">
4+
<SwitchLabel>Manual keyboard activation</SwitchLabel>
5+
6+
<Switch as="button" v-model="manual" :className="resolveSwitchClass" v-slot="{ checked }">
7+
<span
8+
class="inline-block w-5 h-5 transition duration-200 ease-in-out transform bg-white rounded-full"
9+
:class="{ 'translate-x-5': checked, 'translate-x-0': !checked }"
10+
/>
11+
</Switch>
12+
</SwitchGroup>
13+
14+
<TabGroup class="flex flex-col max-w-3xl w-full" as="div" :manual="manual">
15+
<TabList class="relative z-0 rounded-lg shadow flex divide-x divide-gray-200">
16+
<Tab
17+
v-for="(tab, tabIdx) in tabs"
18+
key="tab.name"
19+
:disabled="tab.disabled"
20+
class="group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-sm font-medium text-center hover:bg-gray-50 focus:z-10"
21+
:class="{
22+
'text-gray-900': selected,
23+
'text-gray-500 hover:text-gray-700': !selected,
24+
'rounded-l-lg': tabIdx === 0,
25+
'rounded-r-lg': tabIdx === tabs.length - 1,
26+
'opacity-50': tab.disabled,
27+
}"
28+
v-slot="{ selected }"
29+
>
30+
<span>{{tab.name}}</span>
31+
<small v-if="tab.disabled" class="inline-block px-4 text-xs">(disabled)</small>
32+
<span
33+
aria-hidden="true"
34+
class="absolute inset-x-0 bottom-0 h-0.5"
35+
:class="{'bg-indigo-500': selected, 'bg-transparent':!selected}"
36+
/>
37+
</Tab>
38+
</TabList>
39+
40+
<TabPanels class="mt-4">
41+
<TabPanel v-for="tab in tabs" class="bg-white rounded-lg p-4 shadow" key="tab.name">
42+
{{tab.content}}
43+
</TabPanel>
44+
</TabPanels>
45+
</TabGroup>
46+
</div>
47+
</template>
48+
49+
<script>
50+
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
51+
import { SwitchGroup, Switch, SwitchLabel, TabGroup, TabList, Tab, TabPanels, TabPanel } from '@headlessui/vue'
52+
53+
function classNames(...classes) {
54+
return classes.filter(Boolean).join(' ')
55+
}
56+
57+
let tabs = [
58+
{ name: 'My Account', content: 'Tab content for my account' },
59+
{ name: 'Company', content: 'Tab content for company', disabled: true },
60+
{ name: 'Team Members', content: 'Tab content for team members' },
61+
{ name: 'Billing', content: 'Tab content for billing' },
62+
]
63+
64+
export default {
65+
components: { SwitchGroup, Switch, SwitchLabel, TabGroup, TabList, Tab, TabPanels, TabPanel },
66+
setup(props, context) {
67+
let manual = ref(false)
68+
69+
return {
70+
tabs: ref(tabs),
71+
manual,
72+
resolveSwitchClass({ checked }) {
73+
return classNames(
74+
'relative inline-flex flex-shrink-0 h-6 transition-colors duration-200 ease-in-out border-2 border-transparent rounded-full cursor-pointer w-11 focus:outline-none focus:shadow-outline',
75+
checked ? 'bg-indigo-600' : 'bg-gray-200'
76+
)
77+
},
78+
}
79+
},
80+
}
81+
</script>

packages/@headlessui-vue/examples/src/routes.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@
6161
}
6262
]
6363
},
64+
{
65+
"name": "Tabs",
66+
"path": "/tabs",
67+
"children": [
68+
{
69+
"name": "Tabs (basic)",
70+
"path": "/tabs/tabs",
71+
"component": "./components/tabs/tabs.vue"
72+
}
73+
]
74+
},
6475
{
6576
"name": "Focus Trap",
6677
"path": "/focus-trap",

packages/@headlessui-vue/src/components/tabs/tabs.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { Keys } from '../../keyboard'
1616
import { dom } from '../../utils/dom'
1717
import { match } from '../../utils/match'
1818
import { focusIn, Focus } from '../../utils/focus-management'
19+
import { useResolveButtonType } from '../../hooks/use-resolve-button-type'
1920

2021
type StateDefinition = {
2122
// State
@@ -217,7 +218,6 @@ export let Tab = defineComponent({
217218

218219
let myIndex = computed(() => api.tabs.value.indexOf(tabRef))
219220
let selected = computed(() => myIndex.value === api.selectedIndex.value)
220-
let type = computed(() => attrs.type ?? (props.as === 'button' ? 'button' : undefined))
221221

222222
function handleKeyDown(event: KeyboardEvent) {
223223
let list = api.tabs.value.map(tab => dom(tab)).filter(Boolean) as HTMLElement[]
@@ -276,7 +276,10 @@ export let Tab = defineComponent({
276276
id,
277277
selected,
278278
myIndex,
279-
type,
279+
type: useResolveButtonType(
280+
computed(() => ({ as: props.as, type: attrs.type })),
281+
tabRef
282+
),
280283
handleKeyDown,
281284
handleFocus,
282285
handleSelection,

0 commit comments

Comments
 (0)