diff --git a/.gitignore b/.gitignore
index 37b6881acdb2..855c73dc0ecf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,4 @@
/libpeerconnection.log
npm-debug.log
testem.log
+/.chrome
diff --git a/.travis.yml b/.travis.yml
index a86024956813..aba30cd4acff 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@ language: node_js
sudo: false
node_js:
- - '5.6.0'
+ - '6.9.1'
addons:
apt:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7c8e48793964..7003cd93a2b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,117 @@
+
+# [2.0.0-alpha.10 mithril-hoverboard](https://github.com/angular/material2/compare/2.0.0-alpha.9...2.0.0-alpha.10) (2016-11-10)
+
+## Breaking Changes
+* `MdSnackbarConfig` no longer takes a `ViewContainerRef` as a contructor argument because the
+ `ViewContainerRef` is now optional.
+* Tabs no longer use an `md-tab-content` directive. Instead, the non-label content of the tab is
+ used as its content. Labels can also be specified via attribute, so the tabs can now be given as:
+ ```html
+
+
+ This is the overview tab
+
+
+ This is the details tab
+
+
+ ```
+
+ You can still use `md-tab-label` to provide a label template.
+
+
+### Features
+
+* **tab-nav-bar:** new component! Provides a tab-bar for use with a router-outlet ([#1589](https://github.com/angular/material2/issues/1589)) ([572b36e](https://github.com/angular/material2/commit/572b36e))
+* **a11y:** manager for list keyboard events ([#1599](https://github.com/angular/material2/issues/1599)) ([95b2a34](https://github.com/angular/material2/commit/95b2a34))
+* **checkbox:** add color attribute. ([#1463](https://github.com/angular/material2/issues/1463)) ([333b11e](https://github.com/angular/material2/commit/333b11e))
+* **checkbox:** add ripple ([#1611](https://github.com/angular/material2/issues/1611)) ([ef4c3c9](https://github.com/angular/material2/commit/ef4c3c9))
+* **dialog:** add disableClose option ([#1678](https://github.com/angular/material2/issues/1678)) ([93f8e04](https://github.com/angular/material2/commit/93f8e04)), closes [#1419](https://github.com/angular/material2/issues/1419)
+* **dialog:** allow for an object literal to be passed on init ([#1679](https://github.com/angular/material2/issues/1679)) ([f525db1](https://github.com/angular/material2/commit/f525db1))
+* **dialog:** don't require a ViewContainerRef ([#1704](https://github.com/angular/material2/issues/1704)) ([f59030e](https://github.com/angular/material2/commit/f59030e))
+* **menu:** add animations ([#1685](https://github.com/angular/material2/issues/1685)) ([7fcf511](https://github.com/angular/material2/commit/7fcf511))
+* **menu:** allow menu-trigger to take a menu interface. ([#1564](https://github.com/angular/material2/issues/1564)) ([96d196a](https://github.com/angular/material2/commit/96d196a)), closes [#1560](https://github.com/angular/material2/issues/1560)
+* **menu:** support icons ([#1702](https://github.com/angular/material2/issues/1702)) ([982cdaa](https://github.com/angular/material2/commit/982cdaa))
+* **overlay:** add custom classes for backdrop ([#1532](https://github.com/angular/material2/issues/1532)) ([0b54668](https://github.com/angular/material2/commit/0b54668))
+* **overlay:** set overlay size ([#1583](https://github.com/angular/material2/issues/1583)) ([ffbc295](https://github.com/angular/material2/commit/ffbc295))
+* **overlay:** support all overlay config properties ([#1591](https://github.com/angular/material2/issues/1591)) ([6f322cf](https://github.com/angular/material2/commit/6f322cf))
+* **overlay:** support custom offsets ([#1660](https://github.com/angular/material2/issues/1660)) ([1738d24](https://github.com/angular/material2/commit/1738d24))
+* **overlay:** support rtl in overlays ([#1593](https://github.com/angular/material2/issues/1593)) ([b56f520](https://github.com/angular/material2/commit/b56f520))
+* **radio:** add ripple ([#1553](https://github.com/angular/material2/issues/1553)) ([d83b3e0](https://github.com/angular/material2/commit/d83b3e0))
+* **slider:** fire change event ([#1618](https://github.com/angular/material2/issues/1618)) ([780a654](https://github.com/angular/material2/commit/780a654))
+* **slider:** implement ControlValueAccessor setDisabledState ([#1603](https://github.com/angular/material2/issues/1603)) ([437ec8e](https://github.com/angular/material2/commit/437ec8e))
+* **snack bar:** add enter and exit animations. ([#1320](https://github.com/angular/material2/issues/1320)) ([6df29dc](https://github.com/angular/material2/commit/6df29dc))
+* **snackbar:** don't require a ViewContainerRef ([#1783](https://github.com/angular/material2/issues/1783)) ([9115538](https://github.com/angular/material2/commit/9115538))
+* **tabs:** simplify api ([#1645](https://github.com/angular/material2/issues/1645)) ([ea6c817](https://github.com/angular/material2/commit/ea6c817))
+* **textarea:** initial md-textarea. Does not yet support auto-size. ([#1562](https://github.com/angular/material2/issues/1562)) ([aff22e5](https://github.com/angular/material2/commit/aff22e5))
+* **tooltip:** add tooltip animations ([#1644](https://github.com/angular/material2/issues/1644)) ([52582f4](https://github.com/angular/material2/commit/52582f4))
+
+
+### Bug Fixes
+
+* **aot:** export dialog/snackbar containers through index ([#1378](https://github.com/angular/material2/issues/1378)) ([bb61928](https://github.com/angular/material2/commit/bb61928))
+* **aot:** fix aot error w/ live announcer ([#1355](https://github.com/angular/material2/issues/1355)) ([276d07d](https://github.com/angular/material2/commit/276d07d))
+* **button:** Changed button corner radius from 3px to 2px ([#1441](https://github.com/angular/material2/issues/1441)) ([ec48b34](https://github.com/angular/material2/commit/ec48b34))
+* **button:** set vertical alignment for md-button and md-raised-button ([#1565](https://github.com/angular/material2/issues/1565)) ([f10ac7c](https://github.com/angular/material2/commit/f10ac7c))
+* **button-toggle:** add exportAs ([#1528](https://github.com/angular/material2/issues/1528)) ([d2c288d](https://github.com/angular/material2/commit/d2c288d))
+* **button-toggle:** disable user-select in button-toggle ([#1720](https://github.com/angular/material2/issues/1720)) ([83f6efc](https://github.com/angular/material2/commit/83f6efc))
+* **checkbox:** disable for all non-false values ([#1631](https://github.com/angular/material2/issues/1631)) ([80491a9](https://github.com/angular/material2/commit/80491a9))
+* **checkbox:** prevent checkbox being squished ([#1713](https://github.com/angular/material2/issues/1713)) ([6601949](https://github.com/angular/material2/commit/6601949))
+* **checkbox:** vertically align for when there's no text ([#1721](https://github.com/angular/material2/issues/1721)) ([7fd0fcd](https://github.com/angular/material2/commit/7fd0fcd))
+* **gestures:** don't clobber native drag events ([#1458](https://github.com/angular/material2/issues/1458)) ([b09465c](https://github.com/angular/material2/commit/b09465c)) ([#1744](https://github.com/angular/material2/issues/1744)) ([4af3cd3](https://github.com/angular/material2/commit/4af3cd3)), closes [#1025](https://github.com/angular/material2/issues/1025)
+* **input:** correctly position md-hint in IE11 when position start ([#1674](https://github.com/angular/material2/issues/1674)) ([ecefb89](https://github.com/angular/material2/commit/ecefb89))
+* **input:** remove invalid aria-target attribute ([#1513](https://github.com/angular/material2/issues/1513)) ([601c036](https://github.com/angular/material2/commit/601c036)), closes [#929](https://github.com/angular/material2/issues/929)
+* **input:** set line-height to normal ([#1734](https://github.com/angular/material2/issues/1734)) ([f1f660e](https://github.com/angular/material2/commit/f1f660e))
+* **list:** ensure multi-line lists expand to fill space ([#1466](https://github.com/angular/material2/issues/1466)) ([e7b872a](https://github.com/angular/material2/commit/e7b872a))
+* **list:** prevent default black border from applying ([#1548](https://github.com/angular/material2/issues/1548)) ([4086b32](https://github.com/angular/material2/commit/4086b32)), closes [#1336](https://github.com/angular/material2/issues/1336)
+* **list:** set flex-shrink for avatar ([#1464](https://github.com/angular/material2/issues/1464)) ([5a528aa](https://github.com/angular/material2/commit/5a528aa)), closes [#1403](https://github.com/angular/material2/issues/1403)
+* **menu:** improve a11y for screenreaders ([#1715](https://github.com/angular/material2/issues/1715)) ([267e323](https://github.com/angular/material2/commit/267e323))
+* **menu:** make menu open idempotent ([#1478](https://github.com/angular/material2/issues/1478)) ([a5b3296](https://github.com/angular/material2/commit/a5b3296))
+* **menu:** properly handle spacebar events ([#1533](https://github.com/angular/material2/issues/1533)) ([cfe3e98](https://github.com/angular/material2/commit/cfe3e98)), closes [#1175](https://github.com/angular/material2/issues/1175)
+* **menu:** update menu to use overlay rtl ([#1687](https://github.com/angular/material2/issues/1687)) ([2b913de](https://github.com/angular/material2/commit/2b913de))
+* **menu:** update to use overlay backdrop ([#1534](https://github.com/angular/material2/issues/1534)) ([add0d23](https://github.com/angular/material2/commit/add0d23))
+* **overlay:** ensure container covers entire screen ([#1634](https://github.com/angular/material2/issues/1634)) ([af39236](https://github.com/angular/material2/commit/af39236))
+* **overlay:** fix connected position calculation while scrolled ([#1732](https://github.com/angular/material2/issues/1732)) ([2de461e](https://github.com/angular/material2/commit/2de461e))
+* **overlay:** not taking up entire viewport if body is scrollable ([#1661](https://github.com/angular/material2/issues/1661)) ([16cbbab](https://github.com/angular/material2/commit/16cbbab)), closes [#1633](https://github.com/angular/material2/issues/1633)
+* **overlay:** raise z-index for overlay-container ([#1614](https://github.com/angular/material2/issues/1614)) ([8f50c35](https://github.com/angular/material2/commit/8f50c35))
+* **portal:** cleanup PortalHost on directive destroy ([#1703](https://github.com/angular/material2/issues/1703)) ([7e08468](https://github.com/angular/material2/commit/7e08468))
+* **progress-bar:** bar being thrown off by parent's text-align ([#1717](https://github.com/angular/material2/issues/1717)) ([309d54c](https://github.com/angular/material2/commit/309d54c)), closes [#1165](https://github.com/angular/material2/issues/1165)
+* **progress-circle:** allow value to be set to 0 ([#1536](https://github.com/angular/material2/issues/1536)) ([25c7fd5](https://github.com/angular/material2/commit/25c7fd5))
+* **progress-spinner:** animation expanding parent element ([#1742](https://github.com/angular/material2/issues/1742)) ([4203d09](https://github.com/angular/material2/commit/4203d09)), closes [#1259](https://github.com/angular/material2/issues/1259)
+* **radio:** only call change callback with user input ([#1521](https://github.com/angular/material2/issues/1521)) ([920c875](https://github.com/angular/material2/commit/920c875))
+* **radio:** only emit change event on user interaction ([#1680](https://github.com/angular/material2/issues/1680)) ([0d552f5](https://github.com/angular/material2/commit/0d552f5))
+* **radio:** only fire group change if there is a group ([#1622](https://github.com/angular/material2/issues/1622)) ([065469a](https://github.com/angular/material2/commit/065469a))
+* **radio:** Uncheck radio group if uncheck radio button programmatically ([#1561](https://github.com/angular/material2/issues/1561)) ([c108607](https://github.com/angular/material2/commit/c108607)), closes [#609](https://github.com/angular/material2/issues/609)
+* **ripple:** disable pointer events on ripple ([#1623](https://github.com/angular/material2/issues/1623)) ([f91ea21](https://github.com/angular/material2/commit/f91ea21)) ([#1684](https://github.com/angular/material2/issues/1684)) ([7336b90](https://github.com/angular/material2/commit/7336b90))
+* **ripple:** prevent color flicker on radio/checkbox ([#1705](https://github.com/angular/material2/issues/1705)) ([8ce65ca](https://github.com/angular/material2/commit/8ce65ca))
+* **sidenav:** resolve the promise when sidenav is initialized opened. ([#1666](https://github.com/angular/material2/issues/1666)) ([a0d85d8](https://github.com/angular/material2/commit/a0d85d8)), closes [#1382](https://github.com/angular/material2/issues/1382)
+* **slide-toggle:** disabled theme not working and dragging works if disabled ([#1268](https://github.com/angular/material2/issues/1268)) ([8908366](https://github.com/angular/material2/commit/8908366))
+* **slide-toggle:** emit change event after drag end ([#1405](https://github.com/angular/material2/issues/1405)) ([0b5b6f2](https://github.com/angular/material2/commit/0b5b6f2))
+* **slide-toggle:** remove view encapsulation ([#1446](https://github.com/angular/material2/issues/1446)) ([cbecbce](https://github.com/angular/material2/commit/cbecbce)), closes [#1343](https://github.com/angular/material2/issues/1343)
+* **slide-toggle:** thumb spacing at end for rtl ([#1659](https://github.com/angular/material2/issues/1659)) ([ad3100e](https://github.com/angular/material2/commit/ad3100e))
+* **slide-toggle:** update colors to match spec ([#1612](https://github.com/angular/material2/issues/1612)) ([596d994](https://github.com/angular/material2/commit/596d994))
+* **slider:** clamp thumb between min and max ([#1617](https://github.com/angular/material2/issues/1617)) ([783dbb3](https://github.com/angular/material2/commit/783dbb3)), closes [#1557](https://github.com/angular/material2/issues/1557)
+* **slider:** correctly detect when sidenav align changes. ([#1758](https://github.com/angular/material2/issues/1758)) ([5ffdea6](https://github.com/angular/material2/commit/5ffdea6))
+* **slider:** update thumb pos & ticks when min/max change ([#1598](https://github.com/angular/material2/issues/1598)) ([ff84842](https://github.com/angular/material2/commit/ff84842))
+* **slider:** update thumb position when value changes. Closes [#1386](https://github.com/angular/material2/issues/1386) ([#1610](https://github.com/angular/material2/issues/1610)) ([8e7f80d](https://github.com/angular/material2/commit/8e7f80d))
+* **slider:** use percent values for the track ([#1663](https://github.com/angular/material2/issues/1663)) ([8815846](https://github.com/angular/material2/commit/8815846)), closes [#1389](https://github.com/angular/material2/issues/1389) [#1304](https://github.com/angular/material2/issues/1304) [#1234](https://github.com/angular/material2/issues/1234)
+* **snackbar:** add explicit box-sizing ([#1413](https://github.com/angular/material2/issues/1413)) ([580da74](https://github.com/angular/material2/commit/580da74)), closes [#1412](https://github.com/angular/material2/issues/1412)
+* **snackbar:** always clear ref when dismissing ([#1773](https://github.com/angular/material2/issues/1773)) ([3c5b632](https://github.com/angular/material2/commit/3c5b632))
+* **snackbar:** remove even if still animating open ([#1797](https://github.com/angular/material2/issues/1797)) ([523a48e](https://github.com/angular/material2/commit/523a48e))
+* **snackbar:** snackbars sometimes don't get removed ([#1795](https://github.com/angular/material2/issues/1795)) ([fcd29c8](https://github.com/angular/material2/commit/fcd29c8))
+* **tabs:** make [@Output](https://github.com/Output) not private ([#1636](https://github.com/angular/material2/issues/1636)) ([04e2201](https://github.com/angular/material2/commit/04e2201))
+* **tabs:** set correct min-width on mobile devices ([#1351](https://github.com/angular/material2/issues/1351)) ([e270e50](https://github.com/angular/material2/commit/e270e50)), closes [#1350](https://github.com/angular/material2/issues/1350)
+* **tooltip:** remove tooltip component after its parent destroyed ([#1470](https://github.com/angular/material2/issues/1470)) ([92ac392](https://github.com/angular/material2/commit/92ac392)), closes [#1111](https://github.com/angular/material2/issues/1111)
+* correct EventEmitter generic type across lib ([#1620](https://github.com/angular/material2/issues/1620)) ([0174fa9](https://github.com/angular/material2/commit/0174fa9))
+* disable ripples when parent component is disabled ([#1778](https://github.com/angular/material2/issues/1778)) ([6b9e11c](https://github.com/angular/material2/commit/6b9e11c))
+
+
+### Performance Improvements
+
+* **progress-circle:** improved rendering performance ([#1635](https://github.com/angular/material2/issues/1635)) ([0883fb2](https://github.com/angular/material2/commit/0883fb2))
+
+
+
# [2.0.0-alpha.9 cobalt-kraken](https://github.com/angular/material2/compare/2.0.0-alpha.8...2.0.0-alpha.9) (2016-09-26)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9bc26372a89f..d3bf583f350d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -150,8 +150,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
* All public API methods **must be documented**. (Details TBD).
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
- **100 characters**. An automated formatter is available, see
- [DEVELOPER.md](DEVELOPER.md#clang-format).
+ **100 characters**.
## Commit Message Guidelines
@@ -234,7 +233,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/preview
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
-[dev-doc]: https://github.com/angular/material2/blob/master/DEVELOPER.md
+[dev-doc]: https://github.com/angular/material2/blob/master/DEV_ENVIRONMENT.md
[github]: https://github.com/angular/material2
[gitter]: https://gitter.im/angular/material2
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md
index f8af7ef9e3b7..2f547f906138 100644
--- a/GETTING_STARTED.md
+++ b/GETTING_STARTED.md
@@ -33,9 +33,11 @@ import { MaterialModule } from '@angular/material';
export class PizzaPartyAppModule { }
```
-### Including core and theme styles:
-See the [theming guide](docs/theming.md) for more information.
+## Include the core and theme styles:
+This is **required** to apply all of the core and theme styles to your application. You can either
+use a pre-built theme, or define your own custom theme.
+:trident: See the [theming guide](docs/theming.md) for instructions.
### Additional setup for `md-slide-toggle` and `md-slider`:
The slide-toggle and slider components have a dependency on [HammerJS](http://hammerjs.github.io/).
@@ -44,16 +46,31 @@ Add HammerJS to your application via [npm](https://www.npmjs.com/package/hammerj
(such as the [Google CDN](https://developers.google.com/speed/libraries/#hammerjs)), or served
directly from your app.
+## Configuring SystemJS
+If your project is using SystemJS for module loading, you will need to add `@angular/material`
+to the SystemJS configuration:
+
+```js
+System.config({
+ // existing configuration options
+ map: {
+ ...,
+ '@angular/material': 'npm:@angular/material/material.umd.js'
+ }
+});
+```
+
### [Optional] Using Material Design icons with `md-icon`:
-- If you want to use Material Design icons, load the Material Design font in your `index.html`.
-`md-icon` supports any font icons or svg icons, so this is only one potential option.
+- If you want to use Material Design icons in addition to Angular Material components,
+load the Material Design font in your `index.html`.
+`md-icon` supports any font icons or svg icons, so this is only one option for an icon source.
**src/index.html**
```html
```
-### Sample Angular Material 2 projects
+## Sample Angular Material 2 projects
- [Material 2 Sample App](https://github.com/jelbourn/material2-app)
- [Angular Connect 2016 Demo](https://github.com/kara/leashed-in)
diff --git a/README.md b/README.md
index 56bfc77810a0..bbdaea8d65e1 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Material Design for Angular 2
-[](https://www.npmjs.com/package/%2540angular2-material%2Fcore)
+[](https://www.npmjs.com/package/%40angular%2Fmaterial)
[](https://travis-ci.org/angular/material2)
[](https://gitter.im/angular/material2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
@@ -28,13 +28,15 @@ and which pieces are blocked) and make a comment.
Also see our [`Good for community contribution`](https://github.com/angular/material2/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+for+community+contribution%22)
label.
-High level items planned for September 2016:
-* Work on Angular core towards 2.0.0 final
-* Preparing for conferences (Angular Connect and ng-europe)
-* Final features for dialog
-* Initial version of snackbar.
-* Additional behaviors for menu, start design for select.
-* Finalize high-level design details for data-table.
+High level items planned for November 2016:
+* Initial version of md-select
+* Continued bug bashing
+* Initial versions of autocomplete and chips
+* AoT compile e2e app
+* Continue work on https://material.angular.io site
+* Major refactoring for md-input
+* Tabs animations
+* Expanding e2e test coverage
#### Feature status:
@@ -60,17 +62,17 @@ High level items planned for September 2016:
| menu | Initial version, needs enhancements | [README][17] | [#119][0119] |
| tooltip | Initial version, needs enhancements | [README][18] | - |
| ripples | Available, but needs to be applied | [README][19] | [#108][0108] |
-| dialog | Started, not yet ready for release | - | [#114][0114] |
-| snackbar / toast | Proof-of-concept | - | [#115][0115] |
+| dialog | Started, not yet ready for release | [README][22] | [#114][0114] |
+| snackbar / toast | Initial version, needs enhancements | [README][21] | [#115][0115] |
| select | Design started | - | [#118][0118] |
-| textarea | Not started | - | [#546][0546] |
-| autocomplete | Not started | - | [#117][0117] |
-| chips | Not started | - | [#120][0120] |
-| theming | In master, not released, some bugs | [Guide][20] | [#123][0123] |
+| textarea | Started | - | [#546][0546] |
+| autocomplete | Design started | - | [#117][0117] |
+| chips | Design started | - | [#120][0120] |
+| theming | Initial version, needs enhancements | [Guide][20] | - |
| prod build | Not started | - | - |
| docs site | UX design and tooling in progress | - | - |
| typography | Not started | - | [#205][0205] |
-| layout | Not started | - | - |
+| layout | Design in-progress, prototyped | - | - |
| fab speed-dial | Not started | - | [#860][0860] |
| fab toolbar | Not started | - | - |
| bottom-sheet | Not started | - | - |
@@ -100,6 +102,8 @@ High level items planned for September 2016:
[18]: https://github.com/angular/material2/blob/master/src/lib/tooltip/README.md
[19]: https://github.com/angular/material2/blob/master/src/lib/core/ripple/README.md
[20]: https://github.com/angular/material2/blob/master/docs/theming.md
+[21]: https://github.com/angular/material2/blob/master/src/lib/snack-bar/README.md
+[22]: https://github.com/angular/material2/blob/master/src/lib/dialog/README.md
[0107]: https://github.com/angular/material2/issues/107
[0119]: https://github.com/angular/material2/issues/119
diff --git a/build/autoprefixer-options.js b/build/autoprefixer-options.js
deleted file mode 100644
index 7747b94f43e3..000000000000
--- a/build/autoprefixer-options.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Options for autoprefixer. See https://github.com/postcss/autoprefixer#options
-module.exports = {
- // To see the full list of supported browers, you can direcly use `browserslist`
- browsers: [
- 'last 2 versions',
- 'not ie <= 10',
- 'not ie_mob <= 10',
- ]
-};
diff --git a/config/environment.dev.ts b/config/environment.dev.ts
deleted file mode 100644
index ffe8aed76642..000000000000
--- a/config/environment.dev.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const environment = {
- production: false
-};
diff --git a/config/environment.js b/config/environment.js
deleted file mode 100644
index 4fa28880da9f..000000000000
--- a/config/environment.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/* jshint node: true */
-
-module.exports = function(environment) {
- return {
- environment: environment,
- baseURL: '/',
- locationType: 'auto'
- };
-};
-
diff --git a/config/environment.prod.ts b/config/environment.prod.ts
deleted file mode 100644
index 3612073bc31c..000000000000
--- a/config/environment.prod.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const environment = {
- production: true
-};
diff --git a/docs/theming-your-components.md b/docs/theming-your-components.md
new file mode 100644
index 000000000000..6481e5e222fe
--- /dev/null
+++ b/docs/theming-your-components.md
@@ -0,0 +1,69 @@
+#Theming your custom components
+In order to style your own components with Angular Material's tooling, the component's styles must be defined with Sass.
+
+## Using `@mixin` to automatically apply a theme
+
+### Why using `@mixin`
+The advantage of using a `@mixin` function is that when you change your theme, every file that uses it will be updated automatically.
+Calling it with a different theme argument allow multiple themes within the app or component.
+
+### How to use `@mixin`
+We can better theming our custom components adding a `@mixin` function to its theme file and then calling this function to apply a theme.
+
+All you need is to create a `@mixin` function in the custom-component-theme.scss
+
+```sass
+// Import all the tools needed to customize the theme and extract parts of it
+@import '~@angular/material/core/theming/all-theme';
+
+// Define a mixin that accepts a theme and outputs the color styles for the component.
+@mixin candy-carousel-theme($theme) {
+ // Extract whichever individual palettes you need from the theme.
+ $primary: map-get($theme, primary);
+ $accent: map-get($theme, accent);
+
+ // Use md-color to extract individual colors from a palette as necessary.
+ .candy-carousel {
+ background-color: md-color($primary);
+ border-color: md-color($accent, A400);
+ }
+}
+```
+Now you just have have to call the `@mixin` function to apply the theme:
+
+```sass
+// Import a pre-built theme
+@import '~@angular/material/core/theming/prebuilt/deep-purple-amber';
+// Import your custom input theme file so you can call the custom-input-theme function
+@import 'app/candy-carousel/candy-carousel-theme.scss';
+
+// Using the $theme variable from the pre-built theme you can call the theming function
+@include candy-carousel-theme($theme);
+```
+
+For more details about the theming functions, see the comments in the
+[source](https://github.com/angular/material2/blob/master/src/lib/core/theming/_theming.scss).
+
+### Best practices using `@mixin`
+When using `@mixin`, the theme file should only contain the definitions that are affected by the passed-in theme.
+
+All styles that are not affected by the theme should be placed in a `candy-carousel.scss` file. This file should contain everything that is not affected by the theme like sizes, transitions...
+
+Styles that are affected by the theme should be placed in a separated theming file as `_candy-carousel-theme.scss` and the file should have a `_` before the name. This file should contain the `@mixin` function responsible for applying the theme to the component.
+
+
+## Using colors from a pallete
+You can consume the theming functions from the `@angular/material/core/theming/theming` and Material pallete vars from `@angular/material/core/theming/palette`. You can use the `md-color` function to extract a specific color from a palette. For example:
+
+```scss
+// Import theming functions
+@import '~@angular/material/core/theming/theming';
+// Import your custom theme
+@import 'src/unicorn-app-theme.scss';
+
+// Use md-color to extract individual colors from a palette as necessary.
+.candy-carousel {
+ background-color: md-color($candy-app-primary);
+ border-color: md-color($candy-app-accent, A400);
+}
+```
diff --git a/docs/theming.md b/docs/theming.md
index 16a242516f52..cef94c7b891e 100644
--- a/docs/theming.md
+++ b/docs/theming.md
@@ -3,9 +3,9 @@
### What is a theme?
A **theme** is the set of colors that will be applied to the Angular Material components. The
-library's approach to theming is based on the guidance from the [Material Design spec][1].
+library's approach to theming is based on the guidance from the [Material Design spec][1].
-In Angular Material, a theme is created by composing multiple palettes. In particular,
+In Angular Material, a theme is created by composing multiple palettes. In particular,
a theme consists of:
* A primary palette: colors most widely used across all screens and components.
* An accent palette: colors used for the floating action button and interactive elements.
@@ -21,9 +21,9 @@ app doesn't have to spend cycles generating theme styles on startup.
### Using a pre-built theme
Angular Material comes prepackaged with several pre-built theme css files. These theme files also
include all of the styles for core (styles common to all components), so you only have to include a
-single css file for Angular Material in your app.
+single css file for Angular Material in your app.
-You can include a theme file directly into your application from
+You can include a theme file directly into your application from
`@angular/material/core/theming/prebuilt`
If you're using Angular CLI, this is as simple as including one line
@@ -35,8 +35,8 @@ in your `style.css` file:
Alternatively, you can just reference the file directly. This would look something like
```html
-```
-The actual path will depend on your server setup.
+```
+The actual path will depend on your server setup.
You can also concatenate the file with the rest of your application's css.
@@ -56,25 +56,25 @@ the corresponding styles. A typical theme file will look something like this:
// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue.
-$primary: md-palette($md-indigo);
-$accent: md-palette($md-pink, A200, A100, A400);
+$candy-app-primary: md-palette($md-indigo);
+$candy-app-accent: md-palette($md-pink, A200, A100, A400);
// The warn palette is optional (defaults to red).
-$warn: md-palette($md-red);
+$candy-app-warn: md-palette($md-red);
// Create the theme object (a Sass map containing all of the palettes).
-$theme: md-light-theme($primary, $accent, $warn);
+$candy-app-theme: md-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);
// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
-@include angular-material-theme($theme);
+@include angular-material-theme($candy-app-theme);
```
You only need this single Sass file; you do not need to use Sass to style the rest of your app.
-If you are using the Angular CLI, support for compiling Sass to css is built-in; you only have to
-add a new entry to the `"styles"` list in `angular-cli.json` pointing to the theme
+If you are using the Angular CLI, support for compiling Sass to css is built-in; you only have to
+add a new entry to the `"styles"` list in `angular-cli.json` pointing to the theme
file (e.g., `unicorn-app-theme.scss`).
If you're not using the Angular CLI, you can use any existing Sass tooling to build the file (such
@@ -87,8 +87,8 @@ and then include the output file in your application.
The theme file can be concatenated and minified with the rest of the application's css.
#### Multiple themes
-You can extend the example above to define a second (or third or fourth) theme that is gated by
-some selector. For example, we could append the following to the example above to define a
+You can extend the example above to define a second (or third or fourth) theme that is gated by
+some selector. For example, we could append the following to the example above to define a
secondary dark theme:
```scss
.unicorn-dark-theme {
@@ -97,26 +97,16 @@ secondary dark theme:
$dark-warn: md-palette($md-deep-orange);
$dark-theme: md-dark-theme($dark-primary, $dark-accent, $dark-warn);
-
-@include angular-material-theme($dark-theme);
+
+ @include angular-material-theme($dark-theme);
}
```
With this, any element inside of a parent with the `unicorn-dark-theme` class will use this
dark theme.
-### Styling your own components
-In order to style your own components with our tooling, the component's styles must be defined
-with Sass.
-
-You can consume the theming functions and variables from the `@angular/material/core/theming`.
-You can use the `md-color` function to extract a specific color from a palette. For example:
-```scss
-.unicorn-carousel {
- background-color: md-color($primary);
- color: md-color($primary, default-contrast);
-}
-```
+### Theming your own components
+For more details about theming your own components, see [theming-your-components.md](https://github.com/angular/material2/blob/master/docs/theming-your-components.md)
### Future work
* Once CSS variables (custom properties) are available in all the browsers we support,
diff --git a/e2e/components/checkbox/checkbox.e2e.ts b/e2e/components/checkbox/checkbox.e2e.ts
new file mode 100644
index 000000000000..d4b0008c95bf
--- /dev/null
+++ b/e2e/components/checkbox/checkbox.e2e.ts
@@ -0,0 +1,18 @@
+describe('checkbox', function () {
+ describe('check behavior', function () {
+ beforeEach(function() {
+ browser.get('/checkbox');
+ });
+ it('should be checked when clicked, and be unchecked when clicked again', function () {
+ element(by.id('test-checkbox')).click();
+ element(by.css('input[id=input-test-checkbox]')).getAttribute('checked').then((value: string) => {
+ expect(value).toBeTruthy('Expect checkbox "checked" property to be true');
+ });
+
+ element(by.id('test-checkbox')).click();
+ element(by.css('input[id=input-test-checkbox]')).getAttribute('checked').then((value: string) => {
+ expect(value).toBeFalsy('Expect checkbox "checked" property to be false');
+ });
+ });
+ });
+});
diff --git a/e2e/components/dialog/dialog.e2e.ts b/e2e/components/dialog/dialog.e2e.ts
new file mode 100644
index 000000000000..105f8e91abe6
--- /dev/null
+++ b/e2e/components/dialog/dialog.e2e.ts
@@ -0,0 +1,105 @@
+describe('dialog', () => {
+ beforeEach(() => browser.get('/dialog'));
+
+ it('should open a dialog', () => {
+ element(by.id('default')).click();
+ waitForDialog().then(isPresent => expect(isPresent).toBe(true));
+ });
+
+ it('should close by clicking on the backdrop', () => {
+ element(by.id('default')).click();
+
+ waitForDialog().then(() => {
+ clickOnBackrop();
+ waitForDialog().then(isPresent => expect(isPresent).toBe(false));
+ });
+ });
+
+ it('should close by pressing escape', () => {
+ element(by.id('default')).click();
+
+ waitForDialog().then(() => {
+ pressEscape();
+ waitForDialog().then(isPresent => expect(isPresent).toBe(false));
+ });
+ });
+
+ it('should close by clicking on the "close" button', () => {
+ element(by.id('default')).click();
+
+ waitForDialog().then(() => {
+ element(by.id('close')).click();
+ waitForDialog().then(isPresent => expect(isPresent).toBe(false));
+ });
+ });
+
+ it('should focus the first focusable element', () => {
+ element(by.id('default')).click();
+
+ waitForDialog().then(() => {
+ expectFocusOn(element(by.css('md-dialog-container input')));
+ });
+ });
+
+ it('should restore focus to the element that opened the dialog', () => {
+ let openButton = element(by.id('default'));
+
+ openButton.click();
+
+ waitForDialog().then(() => {
+ clickOnBackrop();
+ expectFocusOn(openButton);
+ });
+ });
+
+ it('should prevent tabbing out of the dialog', () => {
+ element(by.id('default')).click();
+
+ waitForDialog().then(() => {
+ let tab = protractor.Key.TAB;
+
+ browser.actions().sendKeys(tab, tab, tab).perform();
+ expectFocusOn(element(by.id('close')));
+ });
+ });
+
+ it('should be able to prevent closing by clicking on the backdrop', () => {
+ element(by.id('disabled')).click();
+
+ waitForDialog().then(() => {
+ clickOnBackrop();
+ waitForDialog().then(isPresent => expect(isPresent).toBe(true));
+ });
+ });
+
+ it('should be able to prevent closing by pressing escape', () => {
+ element(by.id('disabled')).click();
+
+ waitForDialog().then(() => {
+ pressEscape();
+ waitForDialog().then(isPresent => expect(isPresent).toBe(true));
+ });
+ });
+
+ function waitForDialog() {
+ return browser.isElementPresent(by.css('md-dialog-container'));
+ }
+
+ function clickOnBackrop() {
+ browser.actions()
+ // We need to move the cursor to the top left so
+ // the dialog doesn't receive the click accidentally.
+ .mouseMove(element(by.css('.md-overlay-backdrop')).getWebElement(), { x: 0, y: 0 })
+ .click()
+ .perform();
+ }
+
+ function pressEscape() {
+ browser.actions().sendKeys(protractor.Key.ESCAPE).perform();
+ }
+
+ // TODO(crisbeto): should be moved to a common util. copied from the menu e2e setup.
+ function expectFocusOn(el: any): void {
+ expect(browser.driver.switchTo().activeElement().getInnerHtml()).toBe(el.getInnerHtml());
+ }
+});
diff --git a/e2e/components/grid-list/grid-list.e2e.ts b/e2e/components/grid-list/grid-list.e2e.ts
new file mode 100644
index 000000000000..b3c19563df20
--- /dev/null
+++ b/e2e/components/grid-list/grid-list.e2e.ts
@@ -0,0 +1,12 @@
+describe('grid-list', () => {
+ beforeEach(() => browser.get('/grid-list'));
+
+ it('should render a grid list container', () => {
+ expect(element(by.css('md-grid-list')).isPresent()).toBe(true);
+ });
+
+ it('should render list items inside the grid list container', () => {
+ let container = element(by.css('md-grid-list'));
+ expect(container.isElementPresent(by.css('md-grid-tile'))).toBe(true);
+ });
+});
diff --git a/e2e/components/icon/icon.e2e.ts b/e2e/components/icon/icon.e2e.ts
index 4d5648ac5d8d..9894a2fd9a3b 100644
--- a/e2e/components/icon/icon.e2e.ts
+++ b/e2e/components/icon/icon.e2e.ts
@@ -15,7 +15,8 @@ describe('icon', () => {
it('should have the correct class when used', () => {
testIcon.getAttribute('class').then((attr: string) => {
- expect(attr).toEqual('md-24 material-icons');
+ expect(attr).toContain('md-24');
+ expect(attr).toContain('material-icons');
});
});
diff --git a/e2e/components/list/list.e2e.ts b/e2e/components/list/list.e2e.ts
new file mode 100644
index 000000000000..708ff9943ef0
--- /dev/null
+++ b/e2e/components/list/list.e2e.ts
@@ -0,0 +1,12 @@
+describe('list', () => {
+ beforeEach(() => browser.get('/list'));
+
+ it('should render a list container', () => {
+ expect(element(by.css('md-list')).isPresent()).toBe(true);
+ });
+
+ it('should render list items inside the list container', () => {
+ let container = element(by.css('md-list'));
+ expect(container.isElementPresent(by.css('md-list-item'))).toBe(true);
+ });
+});
diff --git a/e2e/components/menu/menu-page.ts b/e2e/components/menu/menu-page.ts
index 7e25d774004c..3938ad7e8a0a 100644
--- a/e2e/components/menu/menu-page.ts
+++ b/e2e/components/menu/menu-page.ts
@@ -6,7 +6,7 @@ export class MenuPage {
browser.get('/menu');
}
- menu() { return element(by.css('.md-menu')); }
+ menu() { return element(by.css('.md-menu-panel')); }
start() { return element(by.id('start')); }
@@ -14,7 +14,7 @@ export class MenuPage {
triggerTwo() { return element(by.id('trigger-two')); }
- body() { return element(by.tagName('body')); }
+ backdrop() { return element(by.css('.md-overlay-backdrop')); }
items(index: number) {
return element.all(by.css('[md-menu-item]')).get(index);
@@ -28,11 +28,11 @@ export class MenuPage {
combinedTrigger() { return element(by.id('combined-t')); }
- beforeMenu() { return element(by.css('.md-menu.before')); }
+ beforeMenu() { return element(by.css('.md-menu-panel.before')); }
- aboveMenu() { return element(by.css('.md-menu.above')); }
+ aboveMenu() { return element(by.css('.md-menu-panel.above')); }
- combinedMenu() { return element(by.css('.md-menu.combined')); }
+ combinedMenu() { return element(by.css('.md-menu-panel.combined')); }
// TODO(kara): move to common testing utility
pressKey(key: any): void {
@@ -46,7 +46,7 @@ export class MenuPage {
}
expectMenuPresent(expected: boolean) {
- return browser.isElementPresent(by.css('.md-menu')).then((isPresent) => {
+ return browser.isElementPresent(by.css('.md-menu-panel')).then(isPresent => {
expect(isPresent).toBe(expected);
});
}
diff --git a/e2e/components/menu/menu.e2e.ts b/e2e/components/menu/menu.e2e.ts
index b247bc113ef8..564db6175bad 100644
--- a/e2e/components/menu/menu.e2e.ts
+++ b/e2e/components/menu/menu.e2e.ts
@@ -15,12 +15,6 @@ describe('menu', () => {
expect(page.menu().getText()).toEqual("One\nTwo\nThree\nFour");
});
- it('should close menu when area outside menu is clicked', () => {
- page.trigger().click();
- page.body().click();
- page.expectMenuPresent(false);
- });
-
it('should close menu when menu item is clicked', () => {
page.trigger().click();
page.items(0).click();
@@ -48,21 +42,23 @@ describe('menu', () => {
expect(page.menu().getText()).toEqual("One\nTwo\nThree\nFour");
page.expectMenuAlignedWith(page.menu(), 'trigger-two');
- page.body().click();
+ page.backdrop().click();
page.expectMenuPresent(false);
+ // TODO(kara): temporary, remove when #1607 is fixed
+ browser.sleep(250);
page.trigger().click();
expect(page.menu().getText()).toEqual("One\nTwo\nThree\nFour");
page.expectMenuAlignedWith(page.menu(), 'trigger');
- page.body().click();
+ page.backdrop().click();
page.expectMenuPresent(false);
});
it('should mirror classes on host to menu template in overlay', () => {
page.trigger().click();
page.menu().getAttribute('class').then((classes) => {
- expect(classes).toEqual('md-menu custom');
+ expect(classes).toContain('md-menu-panel custom');
});
});
@@ -73,11 +69,16 @@ describe('menu', () => {
page.pressKey(protractor.Key.TAB);
});
- it('should auto-focus the first item when opened with keyboard', () => {
+ it('should auto-focus the first item when opened with ENTER', () => {
page.pressKey(protractor.Key.ENTER);
page.expectFocusOn(page.items(0));
});
+ it('should auto-focus the first item when opened with SPACE', () => {
+ page.pressKey(protractor.Key.SPACE);
+ page.expectFocusOn(page.items(0));
+ });
+
it('should not focus the first item when opened with mouse', () => {
page.trigger().click();
page.expectFocusOn(page.trigger());
@@ -111,9 +112,10 @@ describe('menu', () => {
page.pressKey(protractor.Key.TAB);
page.expectMenuPresent(false);
- page.start().click();
page.pressKey(protractor.Key.TAB);
page.pressKey(protractor.Key.ENTER);
+ page.expectMenuPresent(true);
+
page.pressKey(protractor.Key.chord(protractor.Key.SHIFT, protractor.Key.TAB));
page.expectMenuPresent(false);
});
diff --git a/e2e/components/radio/radio.e2e.ts b/e2e/components/radio/radio.e2e.ts
new file mode 100644
index 000000000000..7fccd196a68a
--- /dev/null
+++ b/e2e/components/radio/radio.e2e.ts
@@ -0,0 +1,51 @@
+describe('radio', function () {
+
+ describe('disabling behavior', function () {
+ beforeEach(function() {
+ browser.get('/radio');
+ });
+
+ it('should be checked when clicked', function () {
+ element(by.id('water')).click();
+ element(by.id('water')).getAttribute('class').then((value: string) => {
+ expect(value).toContain('md-radio-checked');
+ });
+ element(by.css('input[id=water-input]')).getAttribute('checked').then((value: string) => {
+ expect(value).toBeTruthy();
+ });
+ element(by.css('input[id=leaf-input]')).getAttribute('checked').then((value: string) => {
+ expect(value).toBeFalsy();
+ });
+
+ element(by.id('leaf')).click();
+ element(by.id('leaf')).getAttribute('class').then((value: string) => {
+ expect(value).toContain('md-radio-checked');
+ });
+ element(by.css('input[id=leaf-input]')).getAttribute('checked').then((value: string) => {
+ expect(value).toBeTruthy();
+ });
+ element(by.css('input[id=water-input]')).getAttribute('checked').then((value: string) => {
+ expect(value).toBeFalsy();
+ });
+ });
+
+ it('should be disabled when disable the radio group', function () {
+ element(by.id('toggle-disable')).click();
+ element(by.id('water')).click();
+ element(by.id('water')).getAttribute('class').then((value: string) => {
+ expect(value).toContain('md-radio-disabled');
+ });
+ element(by.css('input[id=water-input]')).getAttribute('disabled').then((value: string) => {
+ expect(value).toBeTruthy();
+ });
+
+ element(by.id('leaf')).click();
+ element(by.id('leaf')).getAttribute('class').then((value: string) => {
+ expect(value).toContain('md-radio-disabled');
+ });
+ element(by.css('input[id=leaf-input]')).getAttribute('disabled').then((value: string) => {
+ expect(value).toBeTruthy();
+ });
+ });
+ });
+});
diff --git a/e2e/components/tabs/tabs.e2e.ts b/e2e/components/tabs/tabs.e2e.ts
index daf4171824a7..61f8a9b9f95e 100644
--- a/e2e/components/tabs/tabs.e2e.ts
+++ b/e2e/components/tabs/tabs.e2e.ts
@@ -11,17 +11,17 @@ describe('tabs', () => {
browser.get('/tabs');
tabGroup = element(by.css('md-tab-group'));
tabLabels = element.all(by.css('.md-tab-label'));
- tabBodies = element.all(by.css('.md-tab-body'));
+ tabBodies = element.all(by.css('md-tab-body'));
});
it('should change tabs when the label is clicked', () => {
tabLabels.get(1).click();
- expect(getActiveStates(tabLabels)).toEqual([false, true, false]);
- expect(getActiveStates(tabBodies)).toEqual([false, true, false]);
+ expect(getLabelActiveStates(tabLabels)).toEqual([false, true, false]);
+ expect(getBodyActiveStates(tabBodies)).toEqual([false, true, false]);
tabLabels.get(0).click();
- expect(getActiveStates(tabLabels)).toEqual([true, false, false]);
- expect(getActiveStates(tabBodies)).toEqual([true, false, false]);
+ expect(getLabelActiveStates(tabLabels)).toEqual([true, false, false]);
+ expect(getBodyActiveStates(tabBodies)).toEqual([true, false, false]);
});
it('should change focus with keyboard interaction', () => {
@@ -49,18 +49,13 @@ describe('tabs', () => {
});
});
-/**
- * A helper function to perform the sendKey action
- * @param key
- */
+/** A helper function to perform the sendKey action. */
function pressKey(key: string) {
browser.actions().sendKeys(key).perform();
}
/**
- * Returns an array of true/false that represents the focus states of the provided elements
- * @param elements
- * @returns {webdriver.promise.Promise[]>|webdriver.promise.Promise}
+ * Returns an array of true/false that represents the focus states of the provided elements.
*/
function getFocusStates(elements: ElementArrayFinder) {
return elements.map(element => {
@@ -72,21 +67,19 @@ function getFocusStates(elements: ElementArrayFinder) {
});
}
-/**
- * Returns an array of true/false that represents the active states for the provided elements
- * @param elements
- * @returns {webdriver.promise.Promise[]>|webdriver.promise.Promise}
- */
-function getActiveStates(elements: ElementArrayFinder) {
- return getClassStates(elements, 'md-tab-active');
+/** Returns an array of true/false that represents the active states for the provided elements. */
+function getLabelActiveStates(elements: ElementArrayFinder) {
+ return getClassStates(elements, 'md-tab-label-active');
+}
+
+/** Returns an array of true/false that represents the active states for the provided elements */
+function getBodyActiveStates(elements: ElementArrayFinder) {
+ return getClassStates(elements, 'md-tab-body-active');
}
/**
* Returns an array of true/false values that represents whether the provided className is on
- * each element
- * @param elements
- * @param className
- * @returns {webdriver.promise.Promise[]>|webdriver.promise.Promise}
+ * each element.
*/
function getClassStates(elements: ElementArrayFinder, className: string) {
return elements.map(element => {
diff --git a/firebase.json b/firebase.json
index 48d40be158b7..c9467c51676e 100644
--- a/firebase.json
+++ b/firebase.json
@@ -1,23 +1,30 @@
{
- "firebase": "material2-test",
- "public": "dist",
- "ignore": [
- "firebase.json",
- "**/.*",
- "**/node_modules/**",
- "tmp",
- "deploy",
- "typings"
- ],
- "headers": [{
- "source": "*",
- "headers": [{
- "key": "Cache-Control",
- "value": "no-cache"
- }]
- }],
- "rewrites": [{
- "source": "/**/!(*.@(js|ts|html|css|json|svg|png|jpg|jpeg))",
- "destination": "/index.html"
- }]
+ "hosting": {
+ "public": "dist",
+ "rewrites": [
+ {
+ "source": "/**/!(*.@(js|ts|html|css|json|svg|png|jpg|jpeg))",
+ "destination": "/index.html"
+ }
+ ],
+ "headers": [
+ {
+ "source": "*",
+ "headers": [
+ {
+ "key": "Cache-Control",
+ "value": "no-cache"
+ }
+ ]
+ }
+ ],
+ "ignore": [
+ "firebase.json",
+ "**/.*",
+ "**/node_modules/**",
+ "tmp",
+ "deploy",
+ "typings"
+ ]
+ }
}
diff --git a/package.json b/package.json
index a5770adefb17..97fd10eff170 100644
--- a/package.json
+++ b/package.json
@@ -17,10 +17,10 @@
"deploy": "firebase deploy",
"webdriver-manager": "webdriver-manager"
},
- "version": "2.0.0-alpha.9",
+ "version": "2.0.0-alpha.10",
"license": "MIT",
"engines": {
- "node": ">= 4.2.1 < 5"
+ "node": ">= 5.4.1 < 7"
},
"dependencies": {
"@angular/common": "^2.0.0",
@@ -38,7 +38,7 @@
"zone.js": "^0.6.23"
},
"devDependencies": {
- "@angular/compiler-cli": "0.6.0",
+ "@angular/compiler-cli": "^2.0.0",
"@angular/platform-server": "^2.0.0",
"@types/glob": "^5.0.29",
"@types/gulp": "^3.8.29",
@@ -48,14 +48,17 @@
"@types/minimist": "^1.1.28",
"@types/node": "^6.0.34",
"@types/run-sequence": "0.0.27",
- "browserstacktunnel-wrapper": "^1.4.2",
+ "@types/rx": "^2.5.33",
+ "browserstacktunnel-wrapper": "^2.0.0",
"conventional-changelog": "^1.1.0",
"express": "^4.14.0",
"firebase-tools": "^2.2.1",
"fs-extra": "^0.26.5",
"glob": "^6.0.4",
"gulp": "^3.9.1",
+ "gulp-autoprefixer": "^3.1.1",
"gulp-clean": "^0.3.2",
+ "gulp-cli": "^1.2.2",
"gulp-sass": "^2.3.2",
"gulp-server-livereload": "^1.8.2",
"gulp-shell": "^0.5.2",
@@ -79,7 +82,7 @@
"run-sequence": "^1.2.2",
"sass": "^0.5.0",
"strip-ansi": "^3.0.0",
- "stylelint": "^6.9.0",
+ "stylelint": "^7.5.0",
"symlink-or-copy": "^1.0.1",
"ts-node": "^0.7.3",
"tslint": "^3.13.0",
diff --git a/scripts/browserstack/start_tunnel.js b/scripts/browserstack/start_tunnel.js
index cae1738541d5..54c5087e8c79 100644
--- a/scripts/browserstack/start_tunnel.js
+++ b/scripts/browserstack/start_tunnel.js
@@ -34,7 +34,12 @@ var tunnel = new BrowserStackTunnel({
});
console.log('Starting tunnel on ports', PORTS.join(', '));
-tunnel.start(function(error) {
+
+// Emit a `newer_available` event to force an update of the Browserstack binaries (necessary due to Travis caching)
+// This also starts a new tunnel after the latest binaries are available.
+tunnel.emit('newer_available');
+
+tunnel.once('started', function(error) {
if (error) {
console.error('Can not establish the tunnel', error);
} else {
@@ -44,7 +49,7 @@ tunnel.start(function(error) {
});
if (READY_FILE) {
- fs.writeFile(READY_FILE, '');
+ fs.writeFile(READY_FILE, process.pid);
}
}
});
diff --git a/scripts/browserstack/teardown_tunnel.sh b/scripts/browserstack/teardown_tunnel.sh
index 86fd334284e3..ba09b621e803 100755
--- a/scripts/browserstack/teardown_tunnel.sh
+++ b/scripts/browserstack/teardown_tunnel.sh
@@ -4,5 +4,17 @@ set -e -o pipefail
echo "Shutting down Browserstack tunnel"
-echo "TODO: implement me"
-exit 1
\ No newline at end of file
+
+PID=$(cat $BROWSER_PROVIDER_READY_FILE);
+
+# Resolving the PID from the readyfile.
+kill $PID
+
+
+while [[ -n `ps -ef | grep $PID | grep -v "grep"` ]]; do
+ printf "."
+ sleep .5
+done
+
+echo ""
+echo "Browserstack tunnel has been shut down"
\ No newline at end of file
diff --git a/scripts/browserstack/waitfor_tunnel.sh b/scripts/browserstack/waitfor_tunnel.sh
index a603a317b066..cb2e7d15324c 100755
--- a/scripts/browserstack/waitfor_tunnel.sh
+++ b/scripts/browserstack/waitfor_tunnel.sh
@@ -2,18 +2,18 @@
# Wait for Connect to be ready before exiting
-# Time out if we wait for more than 2 minutes, so that we can print logs.
+# Time out if we wait for more than 2 minutes, so the process won't run forever.
let "counter=0"
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
let "counter++"
+
if [ $counter -gt 240 ]; then
- echo "Timed out after 2 minutes waiting for browser provider ready file"
- # We must manually print logs here because travis will not run
- # after_script commands if the failure occurs before the script
- # phase.
- ./scripts/ci/print-logs.sh
+ echo
+ echo "Timed out after 2 minutes waiting for tunnel ready file"
exit 5
fi
+
+ printf "."
sleep .5
done
diff --git a/scripts/ci/sources/tunnel.sh b/scripts/ci/sources/tunnel.sh
index 1074fe1163f8..62d29160ba86 100644
--- a/scripts/ci/sources/tunnel.sh
+++ b/scripts/ci/sources/tunnel.sh
@@ -34,7 +34,7 @@ teardown_tunnel() {
./scripts/sauce/sauce_connect_teardown.sh
;;
browserstack*)
- # ./scripts/browserstack/teardown_tunnel.sh
+ ./scripts/browserstack/teardown_tunnel.sh
;;
*)
;;
diff --git a/scripts/e2e.sh b/scripts/e2e.sh
deleted file mode 100755
index f9acbb3e4129..000000000000
--- a/scripts/e2e.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-
-export MODE=e2e
-export LOGS_DIR=/tmp/angular-material2-build/logs
-export SAUCE_USERNAME=angular-ci
-export SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
-export TRAVIS_JOB_NUMBER=12345
-export BROWSER_PROVIDER_READY_FILE=/tmp/angular-material2-build/readyfile
-
-
-mkdir -p $LOGS_DIR
-rm -f $BROWSER_PROVIDER_READY_FILE
-
-# Force cleanup (shouldn't be necessary)
-killall angular-cli
-./scripts/sauce/sauce_connect_teardown.sh
-# Run the script
-./scripts/ci/build-and-test.sh
-# Actual cleanup
-./scripts/sauce/sauce_connect_teardown.sh
-killall angular-cli
diff --git a/scripts/release/changelog.js b/scripts/release/changelog.js
index d33b6e660826..037076e7d24d 100755
--- a/scripts/release/changelog.js
+++ b/scripts/release/changelog.js
@@ -7,7 +7,7 @@
*/
const fs = require('fs');
-const addStream = require('add-stream');
+const merge2 = require('merge2');
const changelog = require('conventional-changelog');
const spawnSync = require('child_process').spawnSync;
const npmVersion = require('../../package.json').version;
@@ -17,7 +17,7 @@ const npmVersion = require('../../package.json').version;
* By default, it will only create the changelog from the latest tag to head and prepends it to the changelog.
*/
const isForce = process.argv.indexOf('--force') !== -1;
-const inStream = fs.createReadStream('CHANGELOG.md');
+const previousChangelog = fs.createReadStream('CHANGELOG.md');
const gitTags = getAvailableTags();
// Whether the npm version is later than the most recent tag.
@@ -27,33 +27,40 @@ const currentTag = isNpmLatest ? npmVersion : gitTags[0];
// When the npm version is the latest use the most recent tag. Otherwise use the previous tag.
const previousTag = isNpmLatest ? gitTags[0] : gitTags[1];
-inStream.on('error', function(err) {
- console.error('An error occurred, while reading the previous changelog file.\n' +
- 'If there is no previous changelog, then you should create an empty file or use the `--force` flag.\n' + err);
+if (!isForce) {
+ previousChangelog.on('error', function(err) {
+ console.error('An error occurred, while reading the previous changelog file.\n' +
+ 'If there is changelog file, you should create an empty file or use the `--force` flag.\n' + err);
- process.exit(1);
-});
+ process.exit(1);
+ });
+}
-var config = {
+const config = {
preset: 'angular',
releaseCount: isForce ? 0 : 1
};
-var context = {
+const context = {
currentTag: currentTag,
previousTag: previousTag
};
-var stream = changelog(config, context)
- .on('error', function(err) {
- console.error('An error occurred while generating the changelog: ' + err);
- })
- .pipe(!isForce && addStream(inStream) || getOutputStream());
+let stream = changelog(config, context).on('error', function(err) {
+ console.error('An error occurred while generating the changelog: ' + err);
+});
+
+if (!isForce) {
+ // Append the previous changelog to the new generated one.
+ stream = merge2(stream, previousChangelog);
+} else {
+ stream.pipe(getOutputStream())
+}
// When we are pre-pending the new changelog, then we need to wait for the input stream to be ending,
// otherwise we can't write into the same destination.
if (!isForce) {
- inStream.on('end', function() {
+ previousChangelog.on('end', function() {
stream.pipe(getOutputStream());
});
}
diff --git a/scripts/sauce/sauce_connect_block.sh b/scripts/sauce/sauce_connect_block.sh
index 7aa105032eda..4a519d288111 100755
--- a/scripts/sauce/sauce_connect_block.sh
+++ b/scripts/sauce/sauce_connect_block.sh
@@ -2,9 +2,24 @@
# Wait for Connect to be ready before exiting
echo "Connecting to Sauce Labs"
+
+
+# Wait for Saucelabs Connect to be ready before exiting
+# Time out if we wait for more than 2 minutes, so the process won't run forever.
+let "counter=0"
+
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
+ let "counter++"
+
+ if [ $counter -gt 240 ]; then
+ echo
+ echo "Timed out after 2 minutes waiting for tunnel ready file"
+ exit 5
+ fi
+
printf "."
sleep .5
done
+
echo
echo "Connected"
diff --git a/scripts/sauce/sauce_connect_setup.sh b/scripts/sauce/sauce_connect_setup.sh
index be110f567c53..3eb7e2202191 100755
--- a/scripts/sauce/sauce_connect_setup.sh
+++ b/scripts/sauce/sauce_connect_setup.sh
@@ -23,10 +23,10 @@ CONNECT_STDERR="$LOGS_DIR/sauce-connect.stderr"
if [ `uname -s` = "Darwin" ]; then
# If the user is running Mac, download the OSX version
# https://en.wikipedia.org/wiki/Darwin_(operating_system)
- CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.11-osx.zip"
+ CONNECT_URL="https://saucelabs.com/downloads/sc-4.4.1-osx.zip"
else
# Otherwise, default to Linux for Travis-CI
- CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.11-linux.tar.gz"
+ CONNECT_URL="https://saucelabs.com/downloads/sc-4.4.1-linux.tar.gz"
fi
mkdir -p $CONNECT_DIR
cd $CONNECT_DIR
diff --git a/src/demo-app/button/button-demo.html b/src/demo-app/button/button-demo.html
index e8d9b17ae78e..5fb68da3df3c 100644
--- a/src/demo-app/button/button-demo.html
+++ b/src/demo-app/button/button-demo.html
@@ -89,4 +89,16 @@
SEARCH
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/demo-app/checkbox/checkbox-demo.html b/src/demo-app/checkbox/checkbox-demo.html
index 9fd9c922cd8e..713f8b008d4c 100644
--- a/src/demo-app/checkbox/checkbox-demo.html
+++ b/src/demo-app/checkbox/checkbox-demo.html
@@ -2,6 +2,7 @@