diff --git a/demos/images/ic_progress_activity.svg b/demos/images/ic_progress_activity.svg new file mode 100644 index 00000000000..209cd1068bf --- /dev/null +++ b/demos/images/ic_progress_activity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demos/index.html b/demos/index.html index e7ba7a25f4a..f68b055dbb6 100644 --- a/demos/index.html +++ b/demos/index.html @@ -166,6 +166,14 @@ +
  • + + + Linear progress + Fills from 0% to 100%, represented by bars + +
  • +
  • diff --git a/demos/linear-progress.html b/demos/linear-progress.html new file mode 100644 index 00000000000..4c45492cb20 --- /dev/null +++ b/demos/linear-progress.html @@ -0,0 +1,190 @@ + + + + + + Linear Progress - Material Compoonents Catalog + + + + + + + + + +
    +
    +
    + + + + Linear Progress Indicators +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    + Linear Progress Indicators + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    Determinate
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    Indeterminate
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    Buffer
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    Reversed
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    Indeterminate Reversed
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    Buffer Reversed
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    Accent
    +
    + +
    +
    + +
    + + + + diff --git a/package.json b/package.json index e7e7033c77b..824d16136da 100644 --- a/package.json +++ b/package.json @@ -129,6 +129,7 @@ "grid-list", "icon-toggle", "layout-grid", + "linear-progress", "list", "menu", "radio", diff --git a/packages/material-components-web/index.js b/packages/material-components-web/index.js index 003c4d565b1..f6e2c911844 100644 --- a/packages/material-components-web/index.js +++ b/packages/material-components-web/index.js @@ -25,6 +25,7 @@ import * as dialog from '@material/dialog'; import * as drawer from '@material/drawer'; import * as textfield from '@material/textfield'; import * as snackbar from '@material/snackbar'; +import * as linearProgress from '@material/linear-progress'; import * as menu from '@material/menu'; import * as select from '@material/select'; import * as tabs from '@material/tabs'; @@ -39,6 +40,7 @@ autoInit.register('MDCTemporaryDrawer', drawer.MDCTemporaryDrawer); autoInit.register('MDCRipple', ripple.MDCRipple); autoInit.register('MDCGridList', gridList.MDCGridList); autoInit.register('MDCIconToggle', iconToggle.MDCIconToggle); +autoInit.register('MDCLinearProgress', linearProgress.MDCLinearProgress); autoInit.register('MDCRadio', radio.MDCRadio); autoInit.register('MDCSnackbar', snackbar.MDCSnackbar); autoInit.register('MDCTab', tabs.MDCTab); @@ -52,14 +54,15 @@ autoInit.register('MDCToolbar', toolbar.MDCToolbar); export { base, checkbox, + dialog, + drawer, formField, gridList, iconToggle, + linearProgress, radio, ripple, snackbar, - dialog, - drawer, tabs, textfield, menu, diff --git a/packages/material-components-web/material-components-web.scss b/packages/material-components-web/material-components-web.scss index e8f91b111e3..81f17d693ad 100644 --- a/packages/material-components-web/material-components-web.scss +++ b/packages/material-components-web/material-components-web.scss @@ -26,6 +26,7 @@ @import "@material/grid-list/mdc-grid-list"; @import "@material/icon-toggle/mdc-icon-toggle"; @import "@material/layout-grid/mdc-layout-grid"; +@import "@material/linear-progress/mdc-linear-progress"; @import "@material/list/mdc-list"; @import "@material/menu/mdc-menu"; @import "@material/radio/mdc-radio"; diff --git a/packages/material-components-web/package.json b/packages/material-components-web/package.json index 52570fe6e35..64d5976e1ab 100644 --- a/packages/material-components-web/package.json +++ b/packages/material-components-web/package.json @@ -27,6 +27,7 @@ "@material/grid-list": "^0.2.2", "@material/icon-toggle": "^0.1.11", "@material/layout-grid": "^0.1.2", + "@material/linear-progress": "^0.1.0", "@material/list": "^0.2.8", "@material/menu": "^0.2.6", "@material/radio": "^0.2.4", diff --git a/packages/mdc-animation/index.js b/packages/mdc-animation/index.js index 38d5f5bad1d..7c1cefe32f8 100644 --- a/packages/mdc-animation/index.js +++ b/packages/mdc-animation/index.js @@ -118,6 +118,8 @@ function getAnimationName(windowObj, eventType) { // Public functions to access getAnimationName() for JavaScript events or CSS // property names. +export const transformStyleProperties = ['transform', 'WebkitTransform', 'MozTransform', 'OTransform', 'MSTransform']; + /** * @param {!Object} windowObj * @param {string} eventType diff --git a/packages/mdc-linear-progress/README.md b/packages/mdc-linear-progress/README.md new file mode 100644 index 00000000000..b1ef90cdd15 --- /dev/null +++ b/packages/mdc-linear-progress/README.md @@ -0,0 +1,78 @@ + + +# Linear Progress + + + +The MDC Linear Progress component is a spec-aligned linear progress indicator component adhering to the +[Material Design progress & activity requirements](https://material.io/guidelines/components/progress-activity.html). + +## Design & API Documentation + +
    +
    +
    +
    + +
    +
    + +
    +
    + +## Installation + +``` +npm install --save @material/linear-progress +``` + +## Usage + +### CSS Modifiers + +The provided modifiers are: + +| Class | Description | +| --------------------- | ------------------------------------------------------- | +| `mdc-linear-progress--indeterminate` | Puts the linear progress indicator in an indeterminate state. | +| `mdc-linear-progress--reversed` | Reverses the direction of the linear progress indicator. | +| `mdc-linear-progress--accent` | Colors the button with the accent color. | + +### Using the Foundation Class + +MDC Linear Progress ships with an `MDCLinearProgressFoundation` class that external frameworks and libraries can +use to integrate the component. As with all foundation classes, an adapter object must be provided. +The adapter for temporary drawers must provide the following functions, with correct signatures: + +| Method Signature | Description | +| --- | --- | +| `addClass(className: string) => void` | Adds a class to the root element. | +| `removeClass(className: string) => void` | Removes a class from the root element. | +| `hasClass(className: string) => boolean` | Returns boolean indicating whether the root element has a given class. | +| `getPrimaryBar() => Element` | Returns the primary bar element. | +| `getBuffer() => Element` | Returns the buffer element. | +| `setTransform(el: Element, value: string) => void` | Sets the css transform property on the given element. | + +### MDCLinearProgress API + +MDC Linear Progress exposes the following methods: + +| Method Signature | Description | +| --- | --- | +| `set determinate(value: boolean) => void` | Toggles the components between the determinate and indeterminate state. | +| `set progress(value: number) => void` | Sets the progress bar to this value. Value should be between [0, 1]. | +| `set buffer(value: number) => void` | Sets the buffer bar to this value. Value should be between [0, 1]. | +| `set reverse(value: boolean) => void` | Reverses the direction of the linear progress indicator. | +| `open() => void` | Puts the component in the open state. | +| `close() => void` | Puts the component in the closed state. | diff --git a/packages/mdc-linear-progress/_keyframes.scss b/packages/mdc-linear-progress/_keyframes.scss new file mode 100644 index 00000000000..dbdf35baaad --- /dev/null +++ b/packages/mdc-linear-progress/_keyframes.scss @@ -0,0 +1,150 @@ +// +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +@keyframes primary-indeterminate-translate { + 0% { + transform: translateX(0); + } + + 20% { + animation-timing-function: cubic-bezier(.5, 0, .701732, .495819); + transform: translateX(0); + } + + 59.15% { + animation-timing-function: cubic-bezier(.302435, .381352, .55, .956352); + transform: translateX(83.67142%); + } + + 100% { + transform: translateX(200.611057%); + } +} + +@keyframes primary-indeterminate-scale { + 0% { + transform: scaleX(.08); + } + + 36.65% { + animation-timing-function: cubic-bezier(.334731, .12482, .785844, 1); + transform: scaleX(.08); + } + + 69.15% { + animation-timing-function: cubic-bezier(.06, .11, .6, 1); + transform: scaleX(.661479); + } + + 100% { + transform: scaleX(.08); + } +} + +@keyframes secondary-indeterminate-translate { + 0% { + animation-timing-function: cubic-bezier(.15, 0, .515058, .409685); + transform: translateX(0); + } + + 25% { + animation-timing-function: cubic-bezier(.31033, .284058, .8, .733712); + transform: translateX(37.651913%); + } + + 48.35% { + animation-timing-function: cubic-bezier(.4, .627035, .6, .902026); + transform: translateX(84.386165%); + } + + 100% { + transform: translateX(160.277782%); + } +} + +@keyframes secondary-indeterminate-scale { + 0% { + animation-timing-function: cubic-bezier(.205028, .057051, .57661, .453971); + transform: scaleX(.08); + } + + 19.15% { + animation-timing-function: cubic-bezier(.152313, .196432, .648374, 1.004315); + transform: scaleX(.457104); + } + + 44.15% { + animation-timing-function: cubic-bezier(.257759, -.003163, .211762, 1.38179); + transform: scaleX(.72796); + } + + 100% { + transform: scaleX(.08); + } +} + +@keyframes buffering { + to { + transform: translateX(-10px); + } +} + +@keyframes primary-indeterminate-translate-reverse { + 0% { + transform: translateX(0); + } + + 20% { + animation-timing-function: cubic-bezier(.5, 0, .701732, .495819); + transform: translateX(0); + } + + 59.15% { + animation-timing-function: cubic-bezier(.302435, .381352, .55, .956352); + transform: translateX(-83.67142%); + } + + 100% { + transform: translateX(-200.611057%); + } +} + +@keyframes secondary-indeterminate-translate-reverse { + 0% { + animation-timing-function: cubic-bezier(.15, 0, .515058, .409685); + transform: translateX(0); + } + + 25% { + animation-timing-function: cubic-bezier(.31033, .284058, .8, .733712); + transform: translateX(-37.651913%); + } + + 48.35% { + animation-timing-function: cubic-bezier(.4, .627035, .6, .902026); + transform: translateX(-84.386165%); + } + + 100% { + transform: translateX(-160.277782%); + } +} + +@keyframes buffering-reverse { + to { + transform: translateX(10px); + } +} diff --git a/packages/mdc-linear-progress/constants.js b/packages/mdc-linear-progress/constants.js new file mode 100644 index 00000000000..232d686a92a --- /dev/null +++ b/packages/mdc-linear-progress/constants.js @@ -0,0 +1,26 @@ +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const cssClasses = { + CLOSED_CLASS: 'mdc-linear-progress--closed', + INDETERMINATE_CLASS: 'mdc-linear-progress--indeterminate', + REVERSED_CLASS: 'mdc-linear-progress--reversed', +}; + +export const strings = { + PRIMARY_BAR_SELECTOR: '.mdc-linear-progress__primary-bar', + BUFFER_SELECTOR: '.mdc-linear-progress__buffer', +}; diff --git a/packages/mdc-linear-progress/foundation.js b/packages/mdc-linear-progress/foundation.js new file mode 100644 index 00000000000..c6aa64d6859 --- /dev/null +++ b/packages/mdc-linear-progress/foundation.js @@ -0,0 +1,97 @@ +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {MDCFoundation} from '@material/base'; +import {transformStyleProperties} from '@material/animation'; + +import {cssClasses, strings} from './constants'; + +export default class MDCLinearProgressFoundation extends MDCFoundation { + static get cssClasses() { + return cssClasses; + } + + static get strings() { + return strings; + } + + static get defaultAdapter() { + return { + addClass: (/* className: string */) => {}, + getPrimaryBar: () => /* el: Element */ {}, + getBuffer: () => /* el: Element */ {}, + hasClass: (/* className: string */) => false, + removeClass: (/* className: string */) => {}, + setStyle: (/* el: Element, styleProperty: string, value: number */) => {}, + }; + } + + constructor(adapter) { + super(Object.assign(MDCLinearProgressFoundation.defaultAdapter, adapter)); + } + + init() { + this.determinate_ = !this.adapter_.hasClass(cssClasses.INDETERMINATE_CLASS); + this.reverse_ = this.adapter_.hasClass(cssClasses.REVERSED_CLASS); + } + + set determinate(isDeterminate) { + this.determinate_ = isDeterminate; + if (this.determinate_) { + this.adapter_.removeClass(cssClasses.INDETERMINATE_CLASS); + } else { + this.adapter_.addClass(cssClasses.INDETERMINATE_CLASS); + this.setScale(this.adapter_.getPrimaryBar(), 1); + this.setScale(this.adapter_.getBuffer(), 1); + } + } + + set progress(value) { + if (this.determinate_) { + this.setScale(this.adapter_.getPrimaryBar(), value); + } + } + + set buffer(value) { + if (this.determinate_) { + this.setScale(this.adapter_.getBuffer(), value); + } + } + + set reverse(isReversed) { + this.reverse_ = isReversed; + if (this.reverse_) { + this.adapter_.addClass(cssClasses.REVERSED_CLASS); + } else { + this.adapter_.removeClass(cssClasses.REVERSED_CLASS); + } + } + + open() { + this.adapter_.removeClass(cssClasses.CLOSED_CLASS); + } + + close() { + this.adapter_.addClass(cssClasses.CLOSED_CLASS); + } + + setScale(el, scaleValue) { + const value = 'scaleX(' + scaleValue + ')'; + transformStyleProperties.forEach((transformStyleProperty) => { + this.adapter_.setStyle(el, transformStyleProperty, value); + }); + } +} diff --git a/packages/mdc-linear-progress/index.js b/packages/mdc-linear-progress/index.js new file mode 100644 index 00000000000..6dc9a7fc36a --- /dev/null +++ b/packages/mdc-linear-progress/index.js @@ -0,0 +1,61 @@ +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {MDCComponent} from '@material/base'; +import MDCLinearProgressFoundation from './foundation'; + +export {MDCLinearProgressFoundation}; + +export class MDCLinearProgress extends MDCComponent { + static attachTo(root) { + return new MDCLinearProgress(root); + } + + set determinate(value) { + this.foundation_.determinate = value; + } + + set progress(value) { + this.foundation_.progress = value; + } + + set buffer(value) { + this.foundation_.buffer = value; + } + + set reverse(value) { + this.foundation_.reverse = value; + } + + open() { + this.foundation_.open(); + } + + close() { + this.foundation_.close(); + } + + getDefaultFoundation() { + return new MDCLinearProgressFoundation({ + addClass: (className) => this.root_.classList.add(className), + getPrimaryBar: () => this.root_.querySelector(MDCLinearProgressFoundation.strings.PRIMARY_BAR_SELECTOR), + getBuffer: () => this.root_.querySelector(MDCLinearProgressFoundation.strings.BUFFER_SELECTOR), + hasClass: (className) => this.root_.classList.contains(className), + removeClass: (className) => this.root_.classList.remove(className), + setStyle: (el, styleProperty, value) => el.style[styleProperty] = value, + }); + } +} diff --git a/packages/mdc-linear-progress/mdc-linear-progress.scss b/packages/mdc-linear-progress/mdc-linear-progress.scss new file mode 100644 index 00000000000..4ed1f6f64ed --- /dev/null +++ b/packages/mdc-linear-progress/mdc-linear-progress.scss @@ -0,0 +1,135 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import "@material/animation/functions"; +@import "@material/theme/mixins"; +@import "./keyframes"; + +.mdc-linear-progress { + position: relative; + width: 100%; + height: 4px; + transform: translateZ(0); + transition: mdc-animation-exit(opacity, 250ms); + overflow: hidden; + + &__bar { + animation: none; + position: absolute; + width: 100%; + height: 100%; + transform-origin: top left; + transition: mdc-animation-exit(transform, 250ms); + } + + &__bar-inner { + @include mdc-theme-prop(background-color, primary); + + animation: none; + display: inline-block; + position: absolute; + width: 100%; + height: 100%; + } + + &--accent .mdc-linear-progress__bar-inner { + @include mdc-theme-prop(background-color, accent); + } + + &__buffering-dots { + position: absolute; + width: 100%; + height: 100%; + // SVG is optimized for data URI (https://codepen.io/tigt/post/optimizing-svgs-in-data-uris) + // stylelint-disable-next-line function-url-quotes + background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' enable-background='new 0 0 5 2' xml:space='preserve' viewBox='0 0 5 2' preserveAspectRatio='none slice'%3E%3Ccircle cx='1' cy='1' r='1' fill='%23e6e6e6'/%3E%3C/svg%3E"); + background-repeat: repeat-x; + background-size: 10px 4px; + animation: buffering 250ms infinite linear; + } + + &__buffer { + position: absolute; + width: 100%; + height: 100%; + transform-origin: top left; + transition: mdc-animation-exit(transform, 250ms); + background-color: #e6e6e6; + } + + &__secondary-bar { + visibility: hidden; + } + + &--indeterminate { + .mdc-linear-progress__bar { + transition: none; + } + + .mdc-linear-progress__primary-bar { + animation: primary-indeterminate-translate 2s infinite linear; + left: -145.166611%; + + > .mdc-linear-progress__bar-inner { + animation: primary-indeterminate-scale 2s infinite linear; + } + } + + .mdc-linear-progress__secondary-bar { + animation: secondary-indeterminate-translate 2s infinite linear; + left: -54.888891%; + visibility: visible; + + > .mdc-linear-progress__bar-inner { + animation: secondary-indeterminate-scale 2s infinite linear; + } + } + } + + &--reversed { + .mdc-linear-progress__bar, + .mdc-linear-progress__buffer { + right: 0; + transform-origin: center right; + } + + .mdc-linear-progress__primary-bar { + animation-name: primary-indeterminate-translate-reverse; + } + + .mdc-linear-progress__secondary-bar { + animation-name: secondary-indeterminate-translate-reverse; + } + + .mdc-linear-progress__buffering-dots { + animation: buffering-reverse 250ms infinite linear; + } + } + + &--closed { + opacity: 0; + } +} + +.mdc-linear-progress--indeterminate.mdc-linear-progress--reversed { + .mdc-linear-progress__primary-bar { + right: -145.166611%; + left: auto; + } + + .mdc-linear-progress__secondary-bar { + right: -54.888891%; + left: auto; + } +} diff --git a/packages/mdc-linear-progress/package.json b/packages/mdc-linear-progress/package.json new file mode 100644 index 00000000000..fffd7ca684f --- /dev/null +++ b/packages/mdc-linear-progress/package.json @@ -0,0 +1,20 @@ +{ + "name": "@material/linear-progress", + "description": "The Material Components for the web linear progress indicator component", + "version": "0.1.0", + "license": "Apache-2.0", + "keywords": [ + "material components", + "material design", + "linear progress" + ], + "repository": { + "type": "git", + "url": "https://github.com/material-components/material-components-web.git" + }, + "dependencies": { + "@material/animation": "^0.2.2", + "@material/base": "^0.1.3", + "@material/theme": "^0.1.5" + } +} diff --git a/test/unit/mdc-linear-progress/foundation.test.js b/test/unit/mdc-linear-progress/foundation.test.js new file mode 100644 index 00000000000..57771800044 --- /dev/null +++ b/test/unit/mdc-linear-progress/foundation.test.js @@ -0,0 +1,136 @@ +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {assert} from 'chai'; +import td from 'testdouble'; + +import {setupFoundationTest} from '../helpers/setup'; +import {verifyDefaultAdapter} from '../helpers/foundation'; +import MDCLinearProgressFoundation from '../../../packages/mdc-linear-progress/foundation'; + +const {cssClasses} = MDCLinearProgressFoundation; + +suite('MDCLinearProgressFoundation'); + +test('exports strings', () => { + assert.isOk('strings' in MDCLinearProgressFoundation); +}); + +test('exports cssClasses', () => { + assert.isOk('cssClasses' in MDCLinearProgressFoundation); +}); + +test('defaultAdapter returns a complete adapter implementation', () => { + verifyDefaultAdapter(MDCLinearProgressFoundation, [ + 'addClass', 'getPrimaryBar', 'getBuffer', 'hasClass', 'removeClass', 'setStyle', + ]); +}); + +const setupTest = () => setupFoundationTest(MDCLinearProgressFoundation); + +test('#set indeterminate adds class and resets transforms', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.INDETERMINATE_CLASS)).thenReturn(false); + const primaryBar = {}; + td.when(mockAdapter.getPrimaryBar()).thenReturn(primaryBar); + const buffer = {}; + td.when(mockAdapter.getBuffer()).thenReturn(buffer); + foundation.init(); + foundation.determinate = false; + td.verify(mockAdapter.addClass(cssClasses.INDETERMINATE_CLASS)); + td.verify(mockAdapter.setStyle(primaryBar, 'transform', 'scaleX(1)')); + td.verify(mockAdapter.setStyle(buffer, 'transform', 'scaleX(1)')); +}); + +test('#set determinate removes class', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.INDETERMINATE_CLASS)).thenReturn(false); + foundation.init(); + foundation.determinate = true; + td.verify(mockAdapter.removeClass(cssClasses.INDETERMINATE_CLASS)); +}); + +test('#set progress sets transform', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.INDETERMINATE_CLASS)).thenReturn(false); + const primaryBar = {}; + td.when(mockAdapter.getPrimaryBar()).thenReturn(primaryBar); + foundation.init(); + foundation.progress = 0.5; + td.verify(mockAdapter.setStyle(primaryBar, 'transform', 'scaleX(0.5)')); +}); + +test('#set progress on indeterminate does nothing', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.INDETERMINATE_CLASS)).thenReturn(true); + const primaryBar = {}; + td.when(mockAdapter.getPrimaryBar()).thenReturn(primaryBar); + foundation.init(); + foundation.progress = 0.5; + td.verify(mockAdapter.setStyle(), {times: 0, ignoreExtraArgs: true}); +}); + +test('#set buffer sets transform', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.INDETERMINATE_CLASS)).thenReturn(false); + const buffer = {}; + td.when(mockAdapter.getBuffer()).thenReturn(buffer); + foundation.init(); + foundation.buffer = 0.5; + td.verify(mockAdapter.setStyle(buffer, 'transform', 'scaleX(0.5)')); +}); + +test('#set buffer on indeterminate does nothing', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.INDETERMINATE_CLASS)).thenReturn(true); + const buffer = {}; + td.when(mockAdapter.getBuffer()).thenReturn(buffer); + foundation.init(); + foundation.buffer = 0.5; + td.verify(mockAdapter.setStyle(), {times: 0, ignoreExtraArgs: true}); +}); + +test('#set reverse adds class', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.REVERSED_CLASS)).thenReturn(false); + foundation.init(); + foundation.reverse = true; + td.verify(mockAdapter.addClass(cssClasses.REVERSED_CLASS)); +}); + +test('#set not reverse removes class', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.REVERSED_CLASS)).thenReturn(true); + foundation.init(); + foundation.reverse = false; + td.verify(mockAdapter.removeClass(cssClasses.REVERSED_CLASS)); +}); + +test('#open removes class', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.REVERSED_CLASS)).thenReturn(true); + foundation.init(); + foundation.open(); + td.verify(mockAdapter.removeClass(cssClasses.CLOSED_CLASS)); +}); + +test('#close adds class', () => { + const {foundation, mockAdapter} = setupTest(); + td.when(mockAdapter.hasClass(cssClasses.REVERSED_CLASS)).thenReturn(true); + foundation.init(); + foundation.close(); + td.verify(mockAdapter.addClass(cssClasses.CLOSED_CLASS)); +}); diff --git a/test/unit/mdc-linear-progress/mdc-linear-progress.test.js b/test/unit/mdc-linear-progress/mdc-linear-progress.test.js new file mode 100644 index 00000000000..d83df518637 --- /dev/null +++ b/test/unit/mdc-linear-progress/mdc-linear-progress.test.js @@ -0,0 +1,87 @@ +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {assert} from 'chai'; +import bel from 'bel'; + +import {MDCLinearProgress, MDCLinearProgressFoundation} from '../../../packages/mdc-linear-progress'; + +function getFixture() { + return bel` +
    +
    +
    +
    + +
    +
    + +
    +
    + `; +} + +function setupTest() { + const root = getFixture(); + const component = new MDCLinearProgress(root); + return {root, component}; +} + +suite('MDCLinearProgress'); + +test('attachTo initializes and returns a MDCLinearProgress instance', () => { + assert.isOk(MDCLinearProgress.attachTo(getFixture()) instanceof MDCLinearProgress); +}); + +test('set indeterminate', () => { + const {root, component} = setupTest(); + + component.determinate = false; + assert.isOk(root.classList.contains('mdc-linear-progress--indeterminate')); +}); + +test('set progress', () => { + const {root, component} = setupTest(); + + component.progress = 0.5; + const primaryBar = root.querySelector(MDCLinearProgressFoundation.strings.PRIMARY_BAR_SELECTOR); + assert.equal('scaleX(0.5)', primaryBar.style.transform); +}); + +test('set buffer', () => { + const {root, component} = setupTest(); + + component.buffer = 0.5; + const buffer = root.querySelector(MDCLinearProgressFoundation.strings.BUFFER_SELECTOR); + assert.equal('scaleX(0.5)', buffer.style.transform); +}); + +test('set reverse', () => { + const {root, component} = setupTest(); + + component.reverse = true; + assert.isOk(root.classList.contains('mdc-linear-progress--reversed')); +}); + +test('open and close', () => { + const {root, component} = setupTest(); + + component.close(); + assert.isOk(root.classList.contains('mdc-linear-progress--closed')); + + component.open(); + assert.isNotOk(root.classList.contains('mdc-linear-progress--closed')); +}); diff --git a/webpack.config.js b/webpack.config.js index fb87bf3f43c..7e93065facf 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -161,6 +161,7 @@ module.exports = [{ 'mdc.grid-list': path.resolve('./packages/mdc-grid-list/mdc-grid-list.scss'), 'mdc.icon-toggle': path.resolve('./packages/mdc-icon-toggle/mdc-icon-toggle.scss'), 'mdc.layout-grid': path.resolve('./packages/mdc-layout-grid/mdc-layout-grid.scss'), + 'mdc.linear-progress': path.resolve('./packages/mdc-linear-progress/mdc-linear-progress.scss'), 'mdc.list': path.resolve('./packages/mdc-list/mdc-list.scss'), 'mdc.menu': path.resolve('./packages/mdc-menu/mdc-menu.scss'), 'mdc.radio': path.resolve('./packages/mdc-radio/mdc-radio.scss'),