Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#52307 - Tab and tabs code refactoring #168

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions components/src/atoms/tab/Tab.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="tab" v-show="isActive">
<slot />
</div>
21 changes: 21 additions & 0 deletions components/src/atoms/tab/Tab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @vue/component
export default {
props: {
name: {
type: String,
required: true
},
selected: {
type: Boolean,
default: false
}
},
data () {
return {
isActive: false
}
},
mounted () {
this.isActive = this.selected
}
}
3 changes: 3 additions & 0 deletions components/src/atoms/tab/Tab.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template src="./Tab.html" />

<script src="./Tab.js" />
24 changes: 24 additions & 0 deletions components/src/molecules/tabs/Tabs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class="tabs">
<a-button
v-for="(tab, idx) in tabs"
:key="`tab_${idx}`"
@click.native="selectTab(tab)"
:style="{ order: idx }"
:class="[
'tabs__nav-button',
{ 'tabs__nav-button--active': tab.isActive }
]"
>
<!-- @slot Custom tab button content (Scoped slot) -->
<slot name="tab-button" :tab="tab">
{{ tab.name }}
</slot>
</a-button>

<div
class="tabs__content"
:style="{ order: getContentOrder }"
>
<slot />
</div>
</div>
43 changes: 43 additions & 0 deletions components/src/molecules/tabs/Tabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import AButton from '../../atoms/button/Button.vue'

const DESKTOP_BREAKPOINT = 992

// @vue/component
export default {
components: {
AButton
},
data () {
return {
tabs: [],
isDesktop: window.innerWidth >= DESKTOP_BREAKPOINT
}
},
computed: {
indexOfAlreadySelected () {
return this.tabs.findIndex(tab => tab.isActive)
},
getContentOrder () {
return this.isDesktop ? this.tabs.length : this.indexOfAlreadySelected
}
},
mounted () {
this.tabs = this.$children.filter(({ name }) => name && name.length)

const mediaCheck = window.matchMedia(`(min-width: ${DESKTOP_BREAKPOINT}px)`)
mediaCheck.addListener(media => {
this.isDesktop = media.matches
})

if (this.tabs && this.indexOfAlreadySelected < 0) {
this.selectTab(this.tabs[0])
}
},
methods: {
selectTab (selectedTab) {
this.tabs.forEach(tab => {
tab.isActive = tab.name === selectedTab.name
})
}
}
}
110 changes: 110 additions & 0 deletions components/src/molecules/tabs/Tabs.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
@import '../../../assets/styles/_globals.scss';

$tabs__border-width : 1px !default;
$tabs__border-width--large : 8px !default;

// title
$tabs__title-padding : $spacer--medium !default;
$tabs__title-border : $tabs__border-width solid $gray-light !default;
$tabs__title-border\@large : $tabs__border-width--large solid $gray-lightest !default;
$tabs__title-border\@large--active : $tabs__border-width--large solid $color-primary !default;
$tabs__title-color : $gray !default;
$tabs__title-color--active : $gray-darker !default;
$tabs__title-font-weight\@large : $font-weight-normal !default;
$tabs__title-font-weight\@large--active: $font-weight-bold !default;
$tabs__title-font-weight : $font-weight-bold !default;
$tabs__title-background : $bg-color-base !default;
$tabs__title-background--active : $gray-lightest !default;
$tabs__title-background\@large-active : $gray-lightest !default;
$tabs__content-padding : $spacer--medium !default;
$tabs__content-padding\@large : $spacer--large $spacer--extra-large !default;

// icon
$tabs__icon-color : $gray !default;
$tabs__icon-color--active : $gray-darker !default;
$tabs__icon-padding : 16px !default;
$tabs__icon-size : 48px !default;

.tabs {
position: relative;
display: flex;
flex-direction: column;

@include mq($screen-l) {
flex-direction: row;
flex-wrap: wrap;
}

&__content {
flex: 100%;
padding: $tabs__content-padding;

@include mq($screen-l) {
padding: $tabs__content-padding\@large;
}
}

&__icon {
position: absolute;
top: 50%;
right: 0;
width: $tabs__icon-size;
height: $tabs__icon-size;
padding: $tabs__icon-padding;
transform: translateY(-50%);
transform-origin: center;
transition: $transition-base;
fill: $tabs__icon-color;
}

&__nav-button {
position: relative;
flex: 1;
padding: $tabs__title-padding;
color: $tabs__title-color;
font-weight: $tabs__title-font-weight;
text-align: center;
background: $tabs__title-background;
border: $tabs__title-border;
border-width: $tabs__border-width 0 0 0;
border-radius: $reset;
cursor: pointer;

&:hover,
&:active,
&:focus {
color: $tabs__title-color;
background: $tabs__title-background;
}

@include mq($screen-l) {
font-weight: $tabs__title-font-weight\@large;
border-top: none;
border-bottom: $tabs__title-border\@large;
}

&--active {
color: $tabs__title-color--active;
background: $tabs__title-background--active;
border-top: none;
border-bottom: none;

&:hover,
&:active,
&:focus {
color: $tabs__title-color--active;
background: $tabs__title-background--active;
}

@include mq($screen-l) {
font-weight: $tabs__title-font-weight\@large--active;
background-color: $tabs__title-background\@large-active;
border-bottom: $tabs__title-border\@large--active;
}

.tabs__icon {
transform: translateY(-50%) rotate(180deg);
}
}
}
}
46 changes: 46 additions & 0 deletions components/src/molecules/tabs/Tabs.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { storiesOf } from '@storybook/vue'

import ATab from './../../atoms/tab/Tab.vue'
import AIcon from './../../atoms/icon/Icon.vue'

import ATabs from './Tabs.vue'

storiesOf('Molecules/Tabs', module)
.addParameters({ info: true })
// @vue/component
.add('Default', () => ({
components: { ATabs, ATab, AIcon },
template: `
<a-tabs>
<a-tab name="Tab title" selected>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque pharetra ut magna ornare lacinia. Cras sodales elit ac pellentesque aliquet. Nulla nec viverra turpis. Mauris eget quam interdum, viverra enim eget, ultricies purus. Suspendisse eleifend, turpis id pretium consectetur, massa nunc suscipit elit, a porta neque neque sed ex. Curabitur nec ante non urna rhoncus semper. Maecenas id pulvinar erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque mollis sit amet quam id vestibulum. Nunc faucibus quam non venenatis laoreet. Pellentesque eu feugiat tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
</a-tab>
<a-tab name="Tab title II">
...
</a-tab>
<a-tab name="Tab title III">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque pharetra ut magna ornare lacinia. Cras sodales elit ac pellentesque aliquet. Nulla nec viverra turpis. Mauris eget quam interdum, viverra enim eget, ultricies purus. Suspendisse eleifend, turpis id pretium consectetur, massa nunc suscipit elit, a porta neque neque sed ex. Curabitur nec ante non urna rhoncus semper. Maecenas id pulvinar erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</a-tab>
</a-tabs>
`
}))
.add('Custom tab button', () => ({
components: { ATabs, ATab, AIcon },
template: `
<a-tabs>
<template #tab-button="data">
{{ data.tab.name }} <a-icon icon="angle-down" class="tabs__icon" />
</template>

<a-tab name="Tab title">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque pharetra ut magna ornare lacinia. Cras sodales elit ac pellentesque aliquet. Nulla nec viverra turpis. Mauris eget quam interdum, viverra enim eget, ultricies purus. Suspendisse eleifend, turpis id pretium consectetur, massa nunc suscipit elit, a porta neque neque sed ex. Curabitur nec ante non urna rhoncus semper. Maecenas id pulvinar erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque mollis sit amet quam id vestibulum. Nunc faucibus quam non venenatis laoreet. Pellentesque eu feugiat tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
</a-tab>
<a-tab name="Tab title II">
...
</a-tab>
<a-tab name="Tab title III" selected>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque pharetra ut magna ornare lacinia. Cras sodales elit ac pellentesque aliquet. Nulla nec viverra turpis. Mauris eget quam interdum, viverra enim eget, ultricies purus. Suspendisse eleifend, turpis id pretium consectetur, massa nunc suscipit elit, a porta neque neque sed ex. Curabitur nec ante non urna rhoncus semper. Maecenas id pulvinar erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</a-tab>
</a-tabs>
`
}))
5 changes: 5 additions & 0 deletions components/src/molecules/tabs/Tabs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template src="./Tabs.html" />

<script src="./Tabs.js" />

<style lang="scss" src="./Tabs.scss" />