Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
feat(tabs): Add tab indicator inside tab (#2565)
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickrodee authored Apr 16, 2018
1 parent b5f3406 commit cf9489b
Show file tree
Hide file tree
Showing 17 changed files with 535 additions and 134 deletions.
293 changes: 249 additions & 44 deletions demos/tab.html

Large diffs are not rendered by default.

24 changes: 13 additions & 11 deletions demos/tab.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
@import "./common";
@import "../packages/mdc-tab/mixins";
@import "../packages/mdc-tab/mdc-tab";
@import "../packages/mdc-tab-indicator/mdc-tab-indicator";
@import "../packages/mdc-tab-indicator/mixins";
@import "../packages/mdc-elevation/mixins";
@import "../packages/mdc-ripple/mixins";
@import "../packages/mdc-theme/color-palette";
Expand All @@ -39,22 +41,22 @@
padding: 24px;
}

.custom-tab1 {
@include mdc-states($material-color-yellow-a700);
@include mdc-tab-text-label-color($material-color-pink-600);
.custom-tab {
@include mdc-tab-text-label-color($material-color-blue-300);
@include mdc-tab-icon-color($material-color-orange-300);

&.mdc-tab--active {
@include mdc-tab-text-label-color($material-color-cyan-600);
.custom-tab-indicator {
@include mdc-tab-indicator-underline-color($material-color-pink-a700);
@include mdc-tab-indicator-underline-height(5px);
@include mdc-tab-indicator-underline-top-corner-radius(5px);
}
}

.custom-tab2 {
@include mdc-states($material-color-amber-a700);
@include mdc-tab-text-label-color($material-color-red-300);
@include mdc-tab-icon-color($material-color-orange-300);
.mdc-tab__ripple {
@include mdc-states($material-color-pink-100);
}

&.mdc-tab--active {
@include mdc-tab-text-label-color($material-color-red-900);
@include mdc-tab-text-label-color($material-color-blue-900);
@include mdc-tab-icon-color($material-color-orange-900);
}
}
6 changes: 5 additions & 1 deletion packages/mdc-tab-indicator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ npm install --save @material/tab-indicator
</span>
```

#### Active Indicator

Add the `mdc-tab-indicator--active` class to the `mdc-tab-indicator` element to make the Tab Indicator active.

#### Sliding Underline Indicator
```html
<span class="mdc-tab-indicator">
Expand Down Expand Up @@ -92,7 +96,7 @@ Mixin | Description
`mdc-tab-indicator-icon-color($color)` | Customizes the color of the icon subelement
`mdc-tab-indicator-underline-height($height)` | Customizes the height of the underline
`mdc-tab-indicator-icon-height($height)` | Customizes the height of the icon subelement
`mdc-tab-indicator-underline-top-radius($radius)` | Customizes the top left and top right border radius of the underline subelement
`mdc-tab-indicator-underline-top-corner-radius($radius)` | Customizes the top left and top right border radius of the underline subelement

### `MDCTabIndicator`

Expand Down
6 changes: 0 additions & 6 deletions packages/mdc-tab-indicator/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@
position: relative;
}

@mixin mdc-tab-indicator-active_ {
> .mdc-tab-indicator__content {
opacity: 1;
}
}

@mixin mdc-tab-indicator-underline-color($color) {
> .mdc-tab-indicator__content--underline {
@include mdc-theme-prop(background-color, $color);
Expand Down
12 changes: 6 additions & 6 deletions packages/mdc-tab-indicator/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
*/

import MDCFoundation from '@material/base/foundation';
import MDCTabIndcatorAdapter from './adapter';
import MDCTabIndicatorAdapter from './adapter';
import {
cssClasses,
strings,
} from './constants';

/**
* @extends {MDCFoundation<!MDCTabIndcatorAdapter>}
* @extends {MDCFoundation<!MDCTabIndicatorAdapter>}
* @abstract
*/
class MDCTabIndicatorFoundation extends MDCFoundation {
Expand All @@ -38,11 +38,11 @@ class MDCTabIndicatorFoundation extends MDCFoundation {
}

/**
* @see MDCTabIndcatorAdapter for typing information
* @return {!MDCTabIndcatorAdapter}
* @see MDCTabIndicatorAdapter for typing information
* @return {!MDCTabIndicatorAdapter}
*/
static get defaultAdapter() {
return /** @type {!MDCTabIndcatorAdapter} */ ({
return /** @type {!MDCTabIndicatorAdapter} */ ({
registerEventHandler: () => {},
deregisterEventHandler: () => {},
addClass: () => {},
Expand All @@ -52,7 +52,7 @@ class MDCTabIndicatorFoundation extends MDCFoundation {
});
}

/** @param {!MDCTabIndcatorAdapter} adapter */
/** @param {!MDCTabIndicatorAdapter} adapter */
constructor(adapter) {
super(Object.assign(MDCTabIndicatorFoundation.defaultAdapter, adapter));
}
Expand Down
4 changes: 3 additions & 1 deletion packages/mdc-tab-indicator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ class MDCTabIndicator extends MDCComponent {
return new MDCTabIndicator(root);
}

/**
* @param {...?} args
*/
constructor(...args) {
super(...args);

/** @type {?Element} */
this.content_;
}
Expand Down
10 changes: 5 additions & 5 deletions packages/mdc-tab-indicator/mdc-tab-indicator.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

@import "@material/animation/functions";
@import "@material/animation/variables";
@import "./mixins";

.mdc-tab-indicator {
Expand All @@ -34,10 +34,6 @@
z-index: 1;
}

.mdc-tab-indicator--active {
@include mdc-tab-indicator-active_;
}

.mdc-tab-indicator__content {
transform-origin: left;
opacity: 0;
Expand All @@ -53,6 +49,10 @@
margin: 0 auto;
}

.mdc-tab-indicator--active > .mdc-tab-indicator__content {
opacity: 1;
}

.mdc-tab-indicator--sliding-activate > .mdc-tab-indicator__content {
transition: 250ms transform $mdc-animation-standard-curve-timing-function;
}
Expand Down
42 changes: 37 additions & 5 deletions packages/mdc-tab/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,32 @@ npm install --save @material/tab
### HTML Structure

```html
<button class="mdc-tab" role="tab" aria-selected="false">
<button class="mdc-tab" role="tab" aria-selected="false" tabindex="-1">
<div class="mdc-tab__content">
<span class="mdc-tab__icon">heart</div>
<span class="mdc-tab__text-label">Favorites</div>
</div>
<span class="mdc-tab-indicator">
<span class="mdc-tab-indicator__content mdc-tab-indicator__content--underline"></span>
</span>
<div class="mdc-tab__ripple"></div>
</button>
```

#### Active Tab

>*NOTE*: Don't forget to add the `mdc-tab-indicator--active` class to the `mdc-tab-indicator` subcomponent.
```html
<button class="mdc-tab mdc-tab--active" role="tab" aria-selected="true">
<div class="mdc-tab__content">
<span class="mdc-tab__icon">heart</div>
<span class="mdc-tab__text-label">Favorites</div>
</div>
<span class="mdc-tab-indicator mdc-tab-indicator--active">
<span class="mdc-tab-indicator__content mdc-tab-indicator__content--underline"></span>
</span>
<div class="mdc-tab__ripple"></div>
</button>
```

Expand All @@ -45,8 +66,10 @@ npm install --save @material/tab
CSS Class | Description
--- | ---
`mdc-tab` | Mandatory.
`mdc-tab--active` | Optional. Indicates that the tab is active.
`mdc-tab__content` | Mandatory. Indicates the text label of the tab
`mdc-tab__ripple` | Mandatory. Denotes the ripple surface for the tab
`mdc-tab--active` | Optional. Indicates that the tab is active
`mdc-tab--stacked` | Optional. Indicates that the tab content should be displayed vertically instead of horizontally
`mdc-tab__text-label` | Optional. Indicates an icon in the tab
`mdc-tab__icon` | Optional. Indicates a leading icon in the tab

Expand All @@ -63,8 +86,13 @@ Mixin | Description

Property | Value Type | Description
--- | --- | ---
`active` | `boolean` | Allows getting/setting the active state of the tab
`ripple` | `MDCRipple` | The `MDCRipple` instance for the root element that `MDCChip` initializes
`active` | `boolean` | Allows getting the active state of the tab

Method Signature | Description
--- | ---
`activate(previousIndicatorClientRect: ClientRect=) => void` | Activates the indicator. `previousIndicatorClientRect` is an optional argument
`deactivate() => void` | Deactivates the indicator


### `MDCTabAdapter`

Expand All @@ -76,12 +104,16 @@ Method Signature | Description
`registerEventHandler(evtType: string, handler: EventListener) => void` | Registers an event listener on the root element
`deregisterEventHandler(evtType: string, handler: EventListener) => void` | Deregisters an event listener on the root element
`setAttr(attr: string, value: string) => void` | Sets the given attribute on the root element to the given value
`activateIndicator(previousIndicatorClientRect: ClientRect=) => void` | Activates the tab indicator subcomponent. `previousIndicatorClientRect` is an optional argument
`deactivateIndicator() => void` | Deactivates the tab indicator subcomponent
`computeIndicatorClientRect() => ClientRect` | Returns the tab indicator subcomponent's content bounding client rect

### `MDCTabFoundation`

Method Signature | Description
--- | ---
`handleTransitionEnd(evt: Event) => void` | Handles the logic for the `"transitionend"` event
`isActive() => boolean` | Returns whether the tab is active
`activate() => void` | Activates the tab
`activate(previousIndicatorClientRect: ClientRect=) => void` | Activates the tab. `previousIndicatorClientRect` is an optional argument
`deactivate() => void` | Deactivates the tab
`computeIndicatorClientRect() => ClientRect` | Returns the tab indicator subcomponent's content bounding client rect
15 changes: 15 additions & 0 deletions packages/mdc-tab/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ class MDCTabAdapter {
* @param {string} value The value so give the attribute
*/
setAttr(attr, value) {}

/**
* Activates the indicator element.
* @param {!ClientRect=} previousIndicatorClientRect The client rect of the previously activated indicator
*/
activateIndicator(previousIndicatorClientRect) {}

/** Deactivates the indicator */
deactivateIndicator() {}

/**
* Returns the client rect of the indicator
* @return {!ClientRect}
*/
computeIndicatorClientRect() {}
}

export default MDCTabAdapter;
3 changes: 3 additions & 0 deletions packages/mdc-tab/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const cssClasses = {
/** @enum {string} */
const strings = {
ARIA_SELECTED: 'aria-selected',
RIPPLE_SELECTOR: '.mdc-tab__ripple',
TAB_INDICATOR_SELECTOR: '.mdc-tab-indicator',
TABINDEX: 'tabIndex',
};

export {
Expand Down
20 changes: 19 additions & 1 deletion packages/mdc-tab/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class MDCTabFoundation extends MDCFoundation {
removeClass: () => {},
hasClass: () => {},
setAttr: () => {},
activateIndicator: () => {},
deactivateIndicator: () => {},
computeIndicatorClientRect: () => {},
});
}

Expand Down Expand Up @@ -84,16 +87,20 @@ class MDCTabFoundation extends MDCFoundation {

/**
* Activates the Tab
* @param {!ClientRect=} previousIndicatorClientRect
*/
activate() {
activate(previousIndicatorClientRect) {
// Early exit
if (this.isActive()) {
return;
}

this.adapter_.registerEventHandler('transitionend', this.handleTransitionEnd_);
this.adapter_.addClass(cssClasses.ANIMATING_ACTIVATE);
this.adapter_.addClass(cssClasses.ACTIVE);
this.adapter_.setAttr(strings.ARIA_SELECTED, 'true');
this.adapter_.setAttr(strings.TABINDEX, '0');
this.adapter_.activateIndicator(previousIndicatorClientRect);
}

/**
Expand All @@ -104,10 +111,21 @@ class MDCTabFoundation extends MDCFoundation {
if (!this.isActive()) {
return;
}

this.adapter_.registerEventHandler('transitionend', this.handleTransitionEnd_);
this.adapter_.addClass(cssClasses.ANIMATING_DEACTIVATE);
this.adapter_.removeClass(cssClasses.ACTIVE);
this.adapter_.setAttr(strings.ARIA_SELECTED, 'false');
this.adapter_.setAttr(strings.TABINDEX, '-1');
this.adapter_.deactivateIndicator();
}

/**
* Returns the indicator's client rect
* @return {!ClientRect}
*/
computeIndicatorClientRect() {
return this.adapter_.computeIndicatorClientRect();
}
}

Expand Down
Loading

0 comments on commit cf9489b

Please sign in to comment.