From 42581b46ed6b2e842d3fed5c5283bd62a2986fa8 Mon Sep 17 00:00:00 2001
From: Robert Wozniak <30414211+robwozniak@users.noreply.github.com>
Date: Mon, 29 Apr 2019 15:19:59 +0200
Subject: [PATCH] #52307 - Tab and tabs code refactoring - move to atomic
desing
---
components/src/atoms/tab/Tab.html | 3 +
components/src/atoms/tab/Tab.js | 21 ++++
components/src/atoms/tab/Tab.vue | 3 +
components/src/molecules/tabs/Tabs.html | 24 ++++
components/src/molecules/tabs/Tabs.js | 43 +++++++
components/src/molecules/tabs/Tabs.scss | 110 ++++++++++++++++++
components/src/molecules/tabs/Tabs.stories.js | 46 ++++++++
components/src/molecules/tabs/Tabs.vue | 5 +
8 files changed, 255 insertions(+)
create mode 100644 components/src/atoms/tab/Tab.html
create mode 100644 components/src/atoms/tab/Tab.js
create mode 100644 components/src/atoms/tab/Tab.vue
create mode 100644 components/src/molecules/tabs/Tabs.html
create mode 100644 components/src/molecules/tabs/Tabs.js
create mode 100644 components/src/molecules/tabs/Tabs.scss
create mode 100644 components/src/molecules/tabs/Tabs.stories.js
create mode 100644 components/src/molecules/tabs/Tabs.vue
diff --git a/components/src/atoms/tab/Tab.html b/components/src/atoms/tab/Tab.html
new file mode 100644
index 000000000..fd8e9d802
--- /dev/null
+++ b/components/src/atoms/tab/Tab.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/components/src/atoms/tab/Tab.js b/components/src/atoms/tab/Tab.js
new file mode 100644
index 000000000..3f4aaa16d
--- /dev/null
+++ b/components/src/atoms/tab/Tab.js
@@ -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
+ }
+}
diff --git a/components/src/atoms/tab/Tab.vue b/components/src/atoms/tab/Tab.vue
new file mode 100644
index 000000000..d2c9d116e
--- /dev/null
+++ b/components/src/atoms/tab/Tab.vue
@@ -0,0 +1,3 @@
+
+
+
diff --git a/components/src/molecules/tabs/Tabs.html b/components/src/molecules/tabs/Tabs.html
new file mode 100644
index 000000000..4d0b2f9f6
--- /dev/null
+++ b/components/src/molecules/tabs/Tabs.html
@@ -0,0 +1,24 @@
+
+
+
+
+ {{ tab.name }}
+
+
+
+
+
+
+
diff --git a/components/src/molecules/tabs/Tabs.js b/components/src/molecules/tabs/Tabs.js
new file mode 100644
index 000000000..c1435c61c
--- /dev/null
+++ b/components/src/molecules/tabs/Tabs.js
@@ -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
+ })
+ }
+ }
+}
diff --git a/components/src/molecules/tabs/Tabs.scss b/components/src/molecules/tabs/Tabs.scss
new file mode 100644
index 000000000..180b3103f
--- /dev/null
+++ b/components/src/molecules/tabs/Tabs.scss
@@ -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);
+ }
+ }
+ }
+}
diff --git a/components/src/molecules/tabs/Tabs.stories.js b/components/src/molecules/tabs/Tabs.stories.js
new file mode 100644
index 000000000..667d9e09a
--- /dev/null
+++ b/components/src/molecules/tabs/Tabs.stories.js
@@ -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: `
+
+
+ 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.
+
+
+ ...
+
+
+ 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.
+
+
+ `
+ }))
+ .add('Custom tab button', () => ({
+ components: { ATabs, ATab, AIcon },
+ template: `
+
+
+ {{ data.tab.name }}
+
+
+
+ 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.
+
+
+ ...
+
+
+ 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.
+
+
+ `
+ }))
diff --git a/components/src/molecules/tabs/Tabs.vue b/components/src/molecules/tabs/Tabs.vue
new file mode 100644
index 000000000..9515792cf
--- /dev/null
+++ b/components/src/molecules/tabs/Tabs.vue
@@ -0,0 +1,5 @@
+
+
+
+
+