|
|
<template lang="pug"> .tabset.elevation-2 ul.tabset-tabs(ref='tabs', role='tablist') slot(name='tabs') .tabset-content(ref='content') slot(name='content') </template>
<script> import { customAlphabet } from 'nanoid/non-secure'
const nanoid = customAlphabet('1234567890abcdef', 10)
export default { data() { return { currentTab: 0 } }, watch: { currentTab (newValue, oldValue) { this.setActiveTab() } }, methods: { setActiveTab () { this.$refs.tabs.childNodes.forEach((node, idx) => { if (idx === this.currentTab) { node.className = 'is-active' node.setAttribute('aria-selected', 'true') } else { node.className = '' node.setAttribute('aria-selected', 'false') } }) this.$refs.content.childNodes.forEach((node, idx) => { if (idx === this.currentTab) { node.className = 'tabset-panel is-active' node.removeAttribute('hidden') } else { node.className = 'tabset-panel' node.setAttribute('hidden', '') } }) } }, mounted () { // Handle scroll to header on load within hidden tab content
if (window.location.hash && window.location.hash.length > 1) { const headerId = decodeURIComponent(window.location.hash) let foundIdx = -1 this.$refs.content.childNodes.forEach((node, idx) => { if (node.querySelector(headerId)) { foundIdx = idx } }) if (foundIdx >= 0) { this.currentTab = foundIdx } }
this.setActiveTab()
const tabRefId = nanoid()
this.$refs.tabs.childNodes.forEach((node, idx) => { node.setAttribute('id', `${tabRefId}-${idx}`) node.setAttribute('role', 'tab') node.setAttribute('aria-controls', `${tabRefId}-${idx}-tab`) node.setAttribute('tabindex', '0') node.addEventListener('click', ev => { this.currentTab = [].indexOf.call(ev.target.parentNode.children, ev.target) }) node.addEventListener('keydown', ev => { if (ev.key === 'ArrowLeft' && idx > 0) { this.currentTab = idx - 1 this.$refs.tabs.childNodes[idx - 1].focus() } else if (ev.key === 'ArrowRight' && idx < this.$refs.tabs.childNodes.length - 1) { this.currentTab = idx + 1 this.$refs.tabs.childNodes[idx + 1].focus() } else if (ev.key === 'Enter' || ev.key === ' ') { this.currentTab = idx node.focus() } else if (ev.key === 'Home') { this.currentTab = 0 ev.preventDefault() ev.target.parentNode.children[0].focus() } else if (ev.key === 'End') { this.currentTab = this.$refs.tabs.childNodes.length - 1 ev.preventDefault() ev.target.parentNode.children[this.$refs.tabs.childNodes.length - 1].focus() } }) })
this.$refs.content.childNodes.forEach((node, idx) => { node.setAttribute('id', `${tabRefId}-${idx}-tab`) node.setAttribute('role', 'tabpanel') node.setAttribute('aria-labelledby', `${tabRefId}-${idx}`) node.setAttribute('tabindex', '0') }) } } </script>
<style lang="scss"> .tabset { border-radius: 5px; margin-top: 10px;
@at-root .theme--dark & { background-color: #292929; }
> .tabset-tabs { padding-left: 0; margin: 0; display: flex; align-items: stretch; background: linear-gradient(to bottom, #FFF, #FAFAFA); box-shadow: inset 0 -1px 0 0 #DDD; border-radius: 5px 5px 0 0; overflow: auto;
@at-root .theme--dark & { background: linear-gradient(to bottom, #424242, #333); box-shadow: inset 0 -1px 0 0 #555; }
> li { display: block; padding: 16px; margin-top: 0; cursor: pointer; transition: color 1s ease; border-right: 1px solid #FFF; font-size: 14px; font-weight: 500; margin-bottom: 1px; user-select: none;
@at-root .theme--dark & { border-right-color: #555; }
&.is-active { background-color: #FFF; margin-bottom: 0; padding-bottom: 17px; padding-top: 13px; color: mc('blue', '700'); border-top: 3px solid mc('blue', '700');
@at-root .theme--dark & { background-color: #292929; color: mc('blue', '300'); } }
&:last-child { border-right: none;
&.is-active { border-right: 1px solid #EEE;
@at-root .theme--dark & { border-right-color: #555; } } }
&:hover { background-color: rgba(#CCC, .1);
@at-root .theme--dark & { background-color: rgba(#222, .25); }
&.is-active { background-color: #FFF;
@at-root .theme--dark & { background-color: #292929; } } }
& + li { border-left: 1px solid #EEE;
@at-root .theme--dark & { border-left-color: #222; } } } }
> .tabset-content { .tabset-panel { padding: 2px 16px 16px; display: none;
&.is-active { display: block; } } } } </style>
|