Skip to content

Commit

Permalink
feat(tabs): Introduce Tabs component (#868)
Browse files Browse the repository at this point in the history
* feat(tabs): Introduce tabs component

* Fixed active color and border color

Border color wasn’t using a global variable, and the active tab color wasn’t meeting accessibility requirements.

* Added active tab to scroll example

* Fixed bottom border of active tabs with secondary

The bottom border of the active tab would stay visible whenever secondary tabs were present. This commit elevates the active tab’s z-index to make sure that its new bottom border overlaps the secondary’s appropriately, making them look connected.

* Updated variables

Scroll button padding variables weren’t being used. The buttons are the same height as the tab container and a width variable is implemented instead.

Border width is now controlled by a variable.

Border color of scroll buttons is now set to its own variable.

* Fix active tab overlapping scroll buttons

Adds a z-index to the scroll buttons to make sure the active tab does not overlap when scrolled below them.

* Changed button modifiers: pf-m-start and pf-m-end

To align with logical rather than physical values.

* Add pf-m-start-current modifier

If a current tab scrolls past a scroll button, the scroll button should be given a similar visual treatment to indicate that the current tab is “over there”. This is done with an additional modifier on .pf-c-tabs.

* Design review updates

Border color changed. Hover state border/box-shadow changed. Secondary tab hover color changed. Scroll buttons now include the same hover state.

* Reordered scroll buttons to match visual order

* Remove focus styling on scroll buttons

* Removed role attributes

Until we figure out a keyboard focus management strategy.

* Removed custom focus states

Sticking with browser defaults until we implement our own system-wide focus state in the future.

* Fixed scroll button bg color variable

This new background color should theoretically change based on the theme.

* Add hidden attribute to non-visible scroll buttons

To ensure that they aren’t read by screen readers.

* Clarified reference to the Nav component

* Moved pf-m-current to first secondary tab

* BoxShadow variable tweaks

* Changed current color variable

* First tab is now the current tab in all examples

The first tab being active/current is the more typical default case.

* Added tabs-section.hbs

* Updated handlebars indentation

To be consistent with other components.

* Re-enabled stylelint around variables

* Fixed scroll button background color in dark theme

* Fixed incorrect section modifier handlebars

* Added handlebars block for tabs--attribute

* Fixed border and box shadow color variables

* Removed unnecessary box shadow declaration

* Removed unnecessary width declaration

* Switched to new Handlebars contains utility

* Updated example titles

Clarified that the primary tabs example includes sections.

* Condensed scroll button display CSS

* Set borders to variables and adjusted syntax

* Fix contains Handlebars utility

* Z index tweaks

* Added base classes to tabs-primary documentation

* Update current variable name

Needs a -m because it’s a modifier class.

* Removed global variable from box shadow color

The new variable is close enough.

* Testing putting box-shadow within ::before

* Added tabs-button.hbs and aria-controls

Also moved the ID to the the button element itself rather than the li parent.

* Testing using borders within ::before

* Added tabs-list.hbs

And updated every example to make use of it.

* Replace box-shadows with fancy borders

Box-shadow doesn’t appear in Windows’ high contrast mode, so this switches Tabs to use borders on ::before and ::after pseudo elements to achieve the same result.

This change required significant restructuring of the SCSS file.

* Switched to hiding scroll buttons solely via CSS

Setting display: none; and visibility: hidden; has proven to be an effective way to hide scroll buttons from screen readers, so the hidden attribute is no longer necessary.

* Updated documentation

Removed outdated parts, updated accessibility and usage sections to reflect the latest structure.

* Removed unneeded flex

* Fixed filled style

Forgot to move the modifier, and adjusted the CSS

* Added newline to two docs

* Removed aria-controls from non-primary examples

Since we’re keeping sections to the primary example only, including aria-controls in other examples without corresponding sections was invalid.

* Changed secondary tabs doc heading

* Moving scroll buttons around

* More scroll button movements

* Updated secondary tabs styling and docs

* Updated primary tabs docs

* Fixed scrollbar style within secondary tabs

* Added more tabs to scrolling example

* Updated flex implementation

To keep primary and secondary tabs consistent, primary tabs now use flex rather than inline-flex as well. Also removed some redundant declarations.

* Removed extraneous quotation mark

* Clarified secondary tabs title

* Made secondary tab selector more robust

Just in case the secondary tabs themselves are not directly adjacent to the primary, they can be contained so long as the modifier is present.
  • Loading branch information
andybraren authored and mattnolting committed Nov 15, 2018
1 parent 04316a9 commit 6f1aeb1
Show file tree
Hide file tree
Showing 19 changed files with 601 additions and 4 deletions.
2 changes: 1 addition & 1 deletion build/helpers/contains.js
@@ -1,6 +1,6 @@
const util = require('handlebars-utils');

module.exports = (collection, value, options) => {
const hasIt = collection.indexOf(value) >= 0;
const hasIt = collection && collection.indexOf(value) >= 0;
return util.value(hasIt, this, options);
};
3 changes: 3 additions & 0 deletions src/patternfly/components/Tabs/docs/code.md
@@ -0,0 +1,3 @@
## Overview

`Tabs` should only be used to change content views within a page. The similar-looking but semantically different [Horizontal Nav component](https://pf-next.com/components/Nav/examples/) is available for general navigation use cases.
34 changes: 34 additions & 0 deletions src/patternfly/components/Tabs/docs/design.md
@@ -0,0 +1,34 @@
# Component Name
_Include a short (1-2 sentence) description of the component here and fill out the following sections as needed_

## Usage
_(Required)
Inform readers about when and how this component or pattern should be used, including any variations or related best practices._
* What problem does this solve?
* When to use
* When not to use
* Alternative solutions
* How to use it in context (in my design)
* Layout or sizing considerations
* Using with other components or patterns
* Examples

## Behavior
_(Optional)
You can include behavioral specifications to help readers understand any complex aspects of behavior that might not be obvious from the implementation examples.
This will aid readers in understanding aspects of behavior that may not be
obvious from looking at implementation examples._
* Include mockups (can be low or mid-fi) with enumerated callouts to describe intended interactions.
* Mockups can be low or mid-fi.

## Styling
_(Optional)
If there are styling considerations that may not be obvious from looking at the implementation examples, they should be explained here._

## Content
_(optional)
Provide content standards and writing suggestions for this component or pattern to help designers and developers deliver consistent and thoughtful content. You can include guidelines, messaging standards, or similar best practices specific to this component or pattern.This will extend
any general terminology and wording best practices to provide component specific guidance._
* Editorial guidelines for labeling and message text
* Length restrictions and/or what to do if text overflows
* Localization considerations
5 changes: 5 additions & 0 deletions src/patternfly/components/Tabs/docs/tabs-filled.md
@@ -0,0 +1,5 @@
## Modifiers

| Class | Applied To | Outcome |
| -- | -- | -- |
| `.pf-m-fill` | `.pf-c-tabs` | Enables the filled tab list layout. **Required** |
24 changes: 24 additions & 0 deletions src/patternfly/components/Tabs/docs/tabs-primary.md
@@ -0,0 +1,24 @@
### Accessibility

| Attribute | Applied To | Outcome |
| -- | -- | -- |
| `aria-controls="tabsection1"` | `.pf-c-tabs__button` | Identifies the section controlled by the tab. **Required** |
| `aria-labelledby="tab1"` | `section` | Identifies the tab associated with the section. **Required** |
| `hidden` | `section` | Indicates that a tab panel is not currently active. **Required** |

### Usage

| Attribute | Applied To | Outcome |
| -- | -- | -- |
| `.pf-c-tabs` | `<div>` | Creates a tab component. **Required** |
| `.pf-c-tabs__scroll-button` | `<button>` | Creates a scroll button. **Required** |
| `.pf-c-tabs__list` | `<ul>` | Creates a tab list. **Required** |
| `.pf-c-tabs__item` | `<li>` | Creates a tab item. **Required** |
| `.pf-c-tabs__button` | `<button>` | Creates a tab button. **Required** |
| `id="tab1"` | `.pf-c-tabs__button` | Uniquely identifies the tab. **Required** |

### Modifiers

| Class | Applied To | Outcome |
| -- | -- | -- |
| `.pf-m-current`| `.pf-c-tabs__item` | Highlights the current tab. |
12 changes: 12 additions & 0 deletions src/patternfly/components/Tabs/docs/tabs-scroll.md
@@ -0,0 +1,12 @@
### Note

Whenever a `.pf-m-current` tab is scrolled beyond the width of the container, the appropriate scroll button should be highlighted using `.pf-m-start-current` or `.pf-m-end-current` to indicate that the current tab exists in that direction.

## Modifiers

| Class | Applied To | Outcome |
| -- | -- | -- |
| `.pf-m-start` | `.pf-c-tabs` | Enables the first directional scroll button. |
| `.pf-m-start-current` | `.pf-c-tabs` | Highlights the first directional scroll button. |
| `.pf-m-end` | `.pf-c-tabs` | Enables the second directional scroll button. |
| `.pf-m-end-current` | `.pf-c-tabs` | Highlights the second directional scroll button. |
11 changes: 11 additions & 0 deletions src/patternfly/components/Tabs/docs/tabs-secondary.md
@@ -0,0 +1,11 @@
### Note

Secondary tabs can be placed as an independent component anywhere within an interface. If placed directly adjacent to a set of primary tabs, they adopt a small amount of styling to properly align the two tab sets.

If secondary tabs cannot be placed directly adjacent to primary tabs, `.pf-m-tabs-secondary` can be applied to a directly adjacent container `<div>` with `.pf-c-tabs` as a child to achieve the same effect.

### Modifiers

| Class | Applied To | Outcome |
| -- | -- | -- |
| `.pf-m-tabs-secondary` | `.pf-c-tabs` or `<div>` | Creates a secondary tabs component. **Required** |
55 changes: 55 additions & 0 deletions src/patternfly/components/Tabs/examples/index.js
@@ -0,0 +1,55 @@
import React from 'react';
import Documentation from '@siteComponents/Documentation';
import Example from '@siteComponents/Example';

// Raw
import tabsExamplePrimaryRaw from '!raw!./tabs-primary.hbs';
import tabsExampleSecondaryRaw from '!raw!./tabs-secondary.hbs';
import tabsExampleFilledRaw from '!raw!./tabs-filled.hbs';
import tabsExampleScrollRaw from '!raw!./tabs-scroll.hbs';

// Primary tabs
import TabsExamplePrimary from './tabs-primary.hbs';
import tabsPrimaryDocs from '../docs/tabs-primary.md';

// Secondary tabs
import TabsExampleSecondary from './tabs-secondary.hbs';
import tabsSecondaryDocs from '../docs/tabs-secondary.md';

// Filled tabs
import TabsExampleFilled from './tabs-filled.hbs';
import tabsFilledDocs from '../docs/tabs-filled.md';

// Scroll buttons
import TabsExampleScroll from './tabs-scroll.hbs';
import tabsScrollDocs from '../docs/tabs-scroll.md';

import docs from '../docs/code.md';
import '../tabs.scss';

export const headingText = 'Tabs';
export const Docs = docs;

export default () => {
const tabsExamplePrimary = TabsExamplePrimary();
const tabsExampleSecondary = TabsExampleSecondary();
const tabsExampleFilled = TabsExampleFilled();
const tabsExampleScroll = TabsExampleScroll();

return (
<Documentation docs={Docs} heading={headingText}>
<Example heading="Primary tabs with sections" handlebars={tabsExamplePrimaryRaw} docs={tabsPrimaryDocs}>
{tabsExamplePrimary}
</Example>
<Example heading="Scroll buttons" handlebars={tabsExampleScrollRaw} docs={tabsScrollDocs}>
{tabsExampleScroll}
</Example>
<Example heading="Primary tabs with secondary tabs" handlebars={tabsExampleSecondaryRaw} docs={tabsSecondaryDocs}>
{tabsExampleSecondary}
</Example>
<Example heading="Filled tabs" handlebars={tabsExampleFilledRaw} docs={tabsFilledDocs}>
{tabsExampleFilled}
</Example>
</Documentation>
);
};
19 changes: 19 additions & 0 deletions src/patternfly/components/Tabs/examples/tabs-filled.hbs
@@ -0,0 +1,19 @@
{{#> tabs tabs--modifier="pf-m-fill" tabs--attribute='aria-label="Filled tabs example"'}}
{{#> tabs-list}}
{{#> tabs-item tabs-item--current="true"}}
{{#> tabs-button tabs-button--attribute='id="ex4-tab1"'}}
Tab item 1
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex4-tab2"'}}
Tab item 2
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex4-tab3"'}}
Tab item 3
{{/tabs-button}}
{{/tabs-item}}
{{/tabs-list}}
{{/tabs}}
29 changes: 29 additions & 0 deletions src/patternfly/components/Tabs/examples/tabs-primary.hbs
@@ -0,0 +1,29 @@
{{#> tabs tabs--attribute='aria-label="Primary tabs with sections example"'}}
{{#> tabs-list}}
{{#> tabs-item tabs-item--attribute='' tabs-item--current="true"}}
{{#> tabs-button tabs-button--attribute='id="ex1-tab1" aria-controls="ex1-section1"'}}
Tab item 1
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex1-tab2" aria-controls="ex1-section2"'}}
Tab item 2
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex1-tab3" aria-controls="ex1-section3"'}}
Tab item 3
{{/tabs-button}}
{{/tabs-item}}
{{/tabs-list}}
{{/tabs}}

{{#> tabs-section tabs-section--attribute='id="ex1-section1" aria-labelledby="ex1-tab1"'}}
Tab 1 section
{{/tabs-section}}
{{#> tabs-section tabs-section--attribute='id="ex1-section2" aria-labelledby="ex1-tab2" hidden'}}
Tab 2 section
{{/tabs-section}}
{{#> tabs-section tabs-section--attribute='id="ex1-section3" aria-labelledby="ex1-tab3" hidden'}}
Tab 3 section
{{/tabs-section}}
54 changes: 54 additions & 0 deletions src/patternfly/components/Tabs/examples/tabs-scroll.hbs
@@ -0,0 +1,54 @@
{{#> tabs tabs--modifier="pf-m-start pf-m-start-current pf-m-end" tabs--attribute='aria-label="Scroll buttons example"'}}
{{#> tabs-list}}
{{#> tabs-item tabs-item--current="true"}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab1"'}}
Tab item 1
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab2"'}}
Tab item 2
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab3"'}}
Tab item 3
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab4"'}}
Tab item 4
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab5"'}}
Tab item 5
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab6"'}}
Tab item 6
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab7"'}}
Tab item 7
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab8"'}}
Tab item 8
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab9"'}}
Tab item 9
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex2-tab10"'}}
Tab item 10
{{/tabs-button}}
{{/tabs-item}}
{{/tabs-list}}
{{/tabs}}
39 changes: 39 additions & 0 deletions src/patternfly/components/Tabs/examples/tabs-secondary.hbs
@@ -0,0 +1,39 @@
{{#> tabs tabs--attribute='aria-label="Primary tabs example"'}}
{{#> tabs-list}}
{{#> tabs-item tabs-item--current="true"}}
{{#> tabs-button tabs-button--attribute='id="ex3-tab1"'}}
Tab item 1
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex3-tab2"'}}
Tab item 2
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex3-tab3"'}}
Tab item 3
{{/tabs-button}}
{{/tabs-item}}
{{/tabs-list}}
{{/tabs}}

{{#> tabs tabs--modifier="pf-m-tabs-secondary" tabs--attribute='aria-label="Secondary tabs example"'}}
{{#> tabs-list}}
{{#> tabs-item tabs-item--current="true"}}
{{#> tabs-button tabs-button--attribute='id="ex3-secondary-tab1"'}}
Secondary tab item 1
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex3-secondary-tab2"'}}
Secondary tab item 2
{{/tabs-button}}
{{/tabs-item}}
{{#> tabs-item}}
{{#> tabs-button tabs-button--attribute='id="ex3-secondary-tab3"'}}
Secondary tab item 3
{{/tabs-button}}
{{/tabs-item}}
{{/tabs-list}}
{{/tabs}}
6 changes: 6 additions & 0 deletions src/patternfly/components/Tabs/tabs-button.hbs
@@ -0,0 +1,6 @@
<button class="pf-c-tabs__button{{#if tab-button--modifier}} {{tab-button--modifier}}{{/if}}"
{{#if tabs-button--attribute}}
{{{tabs-button--attribute}}}
{{/if}}>
{{> @partial-block}}
</button>
6 changes: 6 additions & 0 deletions src/patternfly/components/Tabs/tabs-item.hbs
@@ -0,0 +1,6 @@
<li class="pf-c-tabs__item{{#if tabs-item--current}} pf-m-current{{/if}}{{#if tabs-item--modifier}} {{tabs-item--modifier}}{{/if}}"
{{#if tabs-item--attribute}}
{{{tabs-item--attribute}}}
{{/if}}>
{{> @partial-block}}
</li>
18 changes: 18 additions & 0 deletions src/patternfly/components/Tabs/tabs-list.hbs
@@ -0,0 +1,18 @@
<button class="pf-c-tabs__scroll-button" aria-label="Scroll left"
{{#if tabs-scroll-buttons--attribute}}
{{{tabs-scroll-buttons--attribute}}}
{{/if}}>
<i class="fas fa-angle-left" hidden></i>
</button>
<ul class="pf-c-tabs__list{{#if tabs-list--modifier}} {{tabs-list--modifier}}{{/if}}"
{{#if tabs-list--attribute}}
{{{tabs-list--attribute}}}
{{/if}}>
{{> @partial-block}}
</ul>
<button class="pf-c-tabs__scroll-button" aria-label="Scroll right"
{{#if tabs-scroll-buttons--attribute}}
{{{tabs-scroll-buttons--attribute}}}
{{/if}}>
<i class="fas fa-angle-right" hidden></i>
</button>
6 changes: 6 additions & 0 deletions src/patternfly/components/Tabs/tabs-section.hbs
@@ -0,0 +1,6 @@
<section class="pf-c-tabs__section"{{#if tabs-section--modifier}} {{tabs-section--modifier}}{{/if}}
{{#if tabs-section--attribute}}
{{{tabs-section--attribute}}}
{{/if}}>
{{> @partial-block}}
</section>
6 changes: 6 additions & 0 deletions src/patternfly/components/Tabs/tabs.hbs
@@ -0,0 +1,6 @@
<div class="pf-c-tabs{{#if tabs--modifier}} {{tabs--modifier}}{{/if}}"
{{#if tabs--attribute}}
{{{tabs--attribute}}}
{{/if}}>
{{> @partial-block}}
</div>

0 comments on commit 6f1aeb1

Please sign in to comment.