diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index dfe9c2d88b55..c57d5bc2d6b2 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -10,7 +10,7 @@
#### What are the steps to reproduce?
Providing a Plunker (or similar) is the *best* way to get the team to see your issue.
-Plunker template: http://plnkr.co/edit/o077B6uEiiIgkC0S06dd
+Plunker template: https://goo.gl/DlHd6U
#### What is the use-case or motivation for changing an existing behavior?
diff --git a/.gitignore b/.gitignore
index 1f3d7145c431..9fded7174921 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
/dist
/tmp
/deploy
+/screenshots
# dependencies
/node_modules
diff --git a/.travis.yml b/.travis.yml
index 2f9210e483e7..5d3e851f7b2a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,14 +2,7 @@ language: node_js
sudo: false
node_js:
- - '6.9.1'
-
-addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - libstdc++6
+ - '6.9.4'
branches:
only:
@@ -22,20 +15,16 @@ env:
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- BROWSER_STACK_USERNAME=angularteam1
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
- - ARCH=linux-x64
- BROWSER_PROVIDER_READY_FILE=/tmp/angular-material2-build/readyfile
- BROWSER_PROVIDER_ERROR_FILE=/tmp/angular-material2-build/errorfile
- # GITHUB_TOKEN_ANGULAR
- - secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
matrix:
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
- MODE=lint
- - MODE=extract_metadata
+ - MODE=aot
+ - MODE=payload
- MODE=e2e
- MODE=saucelabs_required
- MODE=browserstack_required
- - MODE=saucelabs_optional
- - MODE=browserstack_optional
matrix:
fast_finish: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18e30c67f4c2..20213136d1fa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,249 @@
+
+# [2.0.0-beta.2 flannel-papaya](https://github.com/angular/material2/compare/2.0.0-beta.1...2.0.0-beta.2) (2017-02-15)
+
+### Breaking changes from beta.1
+* Styling is no longer prefixed by `md-`. All styling is now prefixed by `mat-` so that apps can upgrade from AngularJS Material to Angular Material without styling conflicts between the two library components.
+See ([#2790](https://github.com/angular/material2/issues/2790)) for the details on the code change and some useful regular expressions that can help migrate styles.
+* Checkbox tab index @Input has been changed from `tabindex` to `tabIndex`. ([#2953](https://github.com/angular/material2/issues/2953))
+* Ripple no longer has the `mdRippleBackgroundColor` input to change the background color. ([#2859](https://github.com/angular/material2/issues/2859))
+* The deprecated use of `` and `` has been removed. Use `mdInput` on an input or textarea within a `md-input-container`. `md-prefix` and `md-suffix` are now `mdPrefix` and `mdSuffix`. ([#2788](https://github.com/angular/material2/issues/2788))
+
+ ```html
+
+
+
+ ```
+
+* The deprecated use of `` has been removed. Use `` instead. ([#2283](https://github.com/angular/material2/issues/2283))
+* Input floating placeholder @Input has changed from a boolean (`true` and `false`) to a state (`always`, `never`, and `auto`) and was renamed from `floatingPlaceholder` to `floatPlaceholder`. For details on when to use which state, see ([#2585](https://github.com/angular/material2/issues/2585))
+* The use of Module `forRoot` has been deprecated and will be removed in the next release. Instead, just simply import MaterialModule directly:
+
+ ```ts
+ @NgModule({
+ imports: [
+ ...
+ MaterialModule,
+ ...
+ ]
+ ...
+ });
+ ```
+
+### Bug Fixes
+
+* **autocomplete:** add mat version of autocomplete [@Input](https://github.com/Input) ([#2928](https://github.com/angular/material2/issues/2928)) ([e5521a8](https://github.com/angular/material2/commit/e5521a8))
+* **autocomplete:** allow basic use without forms directives ([#2958](https://github.com/angular/material2/issues/2958)) ([4ee2980](https://github.com/angular/material2/commit/4ee2980))
+* **autocomplete:** close panel when options list is empty ([#2834](https://github.com/angular/material2/issues/2834)) ([8a3b6fd](https://github.com/angular/material2/commit/8a3b6fd))
+* **autocomplete:** double-clicking input shouldnt close the panel ([#2835](https://github.com/angular/material2/issues/2835)) ([18969f4](https://github.com/angular/material2/commit/18969f4))
+* **autocomplete:** hide instead of close when options empty ([#2997](https://github.com/angular/material2/issues/2997)) ([a022035](https://github.com/angular/material2/commit/a022035))
+* **autocomplete:** placeholder should float while panel is open ([#2730](https://github.com/angular/material2/issues/2730)) ([eec4dc6](https://github.com/angular/material2/commit/eec4dc6))
+* **autocomplete:** scroll options below fold into view ([#2728](https://github.com/angular/material2/issues/2728)) ([6c84603](https://github.com/angular/material2/commit/6c84603))
+* **autocomplete:** support rtl ([#2648](https://github.com/angular/material2/issues/2648)) ([4f59ad0](https://github.com/angular/material2/commit/4f59ad0))
+* **autocomplete:** up arrow should set last item active ([#2776](https://github.com/angular/material2/issues/2776)) ([fd5e4d9](https://github.com/angular/material2/commit/fd5e4d9))
+* **autosize:** export md-autosize directive ([#2432](https://github.com/angular/material2/issues/2432)) ([f2d73da](https://github.com/angular/material2/commit/f2d73da)), closes [#2419](https://github.com/angular/material2/issues/2419)
+* **button:** add default color for mat-raised-button ([#3052](https://github.com/angular/material2/issues/3052)) ([6fe1d9a](https://github.com/angular/material2/commit/6fe1d9a))
+* **button:** only flat button and icon buttons should inherit the color ([#2561](https://github.com/angular/material2/issues/2561)) ([ac363df](https://github.com/angular/material2/commit/ac363df)), closes [#2539](https://github.com/angular/material2/issues/2539)
+* **button:** raised buttons in dark theme ([#3070](https://github.com/angular/material2/issues/3070)) ([87ab712](https://github.com/angular/material2/commit/87ab712))
+* **button:** reuse _getHostElement() to avoid redundant elementRef.nativeElement calls ([#2625](https://github.com/angular/material2/issues/2625)) ([c7d1c17](https://github.com/angular/material2/commit/c7d1c17))
+* **button-toggle:** add the setDisabledState from ControlValueAccessor ([#2430](https://github.com/angular/material2/issues/2430)) ([fb750b4](https://github.com/angular/material2/commit/fb750b4))
+* **button-toggle:** conflict with radio component ([#2343](https://github.com/angular/material2/issues/2343)) ([9e99374](https://github.com/angular/material2/commit/9e99374)), closes [#2274](https://github.com/angular/material2/issues/2274)
+* **button-toggle:** make conform with design specs ([#2570](https://github.com/angular/material2/issues/2570)) ([fed5d7b](https://github.com/angular/material2/commit/fed5d7b))
+* **card:** fix padding for md-card-actions in xs screens ([#2567](https://github.com/angular/material2/issues/2567)) ([ad0df31](https://github.com/angular/material2/commit/ad0df31))
+* **checkbox:** Emit event when checkbox's indeterminate value changes ([#2130](https://github.com/angular/material2/issues/2130)) ([f11c5eb](https://github.com/angular/material2/commit/f11c5eb))
+* **checkbox:** rename tabindex to tabIndex ([#2953](https://github.com/angular/material2/issues/2953)) ([b91964a](https://github.com/angular/material2/commit/b91964a))
+* **checkbox:** ripple color does not change ([#2857](https://github.com/angular/material2/issues/2857)) ([7ac29f8](https://github.com/angular/material2/commit/7ac29f8))
+* **checkbox, radio:** not using theme border color ([#2744](https://github.com/angular/material2/issues/2744)) ([07ec765](https://github.com/angular/material2/commit/07ec765))
+* **compatibility:** add missing mat- selectors ([#2923](https://github.com/angular/material2/issues/2923)) ([f29f7ab](https://github.com/angular/material2/commit/f29f7ab))
+* **connected-position-strategy:** wrong logic when determining whether element is on screen ([#2677](https://github.com/angular/material2/issues/2677)) ([e055d05](https://github.com/angular/material2/commit/e055d05)), closes [#2102](https://github.com/angular/material2/issues/2102) [#2658](https://github.com/angular/material2/issues/2658)
+* **dialog:** escape key not working once element loses focus ([#3082](https://github.com/angular/material2/issues/3082)) ([a08dc55](https://github.com/angular/material2/commit/a08dc55)), closes [#3009](https://github.com/angular/material2/issues/3009)
+* **dialog:** prevent error when restoring focus on IE ([#2771](https://github.com/angular/material2/issues/2771)) ([153fcd3](https://github.com/angular/material2/commit/153fcd3)), closes [#2760](https://github.com/angular/material2/issues/2760)
+* **dialog:** prevent the close button from submitting forms ([#2659](https://github.com/angular/material2/issues/2659)) ([29f939a](https://github.com/angular/material2/commit/29f939a)), closes [#2599](https://github.com/angular/material2/issues/2599)
+* **dialog:** use injector from viewContainerRef if provided ([#2655](https://github.com/angular/material2/issues/2655)) ([be0da09](https://github.com/angular/material2/commit/be0da09))
+* **docs:** properly create links in guide files ([#2770](https://github.com/angular/material2/issues/2770)) ([60f03ed](https://github.com/angular/material2/commit/60f03ed))
+* **icon:** add caching of md-icon aria-label ([#2649](https://github.com/angular/material2/issues/2649)) ([08e9d70](https://github.com/angular/material2/commit/08e9d70)), closes [#2642](https://github.com/angular/material2/issues/2642)
+* **input:** add more padding so that the hint doesn't overflow the container ([#2246](https://github.com/angular/material2/issues/2246)) ([d7831d9](https://github.com/angular/material2/commit/d7831d9))
+* **input:** camel-case md-prefix and md-suffix ([#2639](https://github.com/angular/material2/issues/2639)) ([7562322](https://github.com/angular/material2/commit/7562322)), closes [#2636](https://github.com/angular/material2/issues/2636)
+* **input:** disable underline with reactive forms ([#2565](https://github.com/angular/material2/issues/2565)) ([f9dd34f](https://github.com/angular/material2/commit/f9dd34f)), closes [#2558](https://github.com/angular/material2/issues/2558)
+* **input:** disabled inputs should be grayed out ([#2513](https://github.com/angular/material2/issues/2513)) ([ed3ffe0](https://github.com/angular/material2/commit/ed3ffe0))
+* **input:** ensure that property bindings work ([#2431](https://github.com/angular/material2/issues/2431)) ([b4b4224](https://github.com/angular/material2/commit/b4b4224)), closes [#2428](https://github.com/angular/material2/issues/2428)
+* **input:** fix chrome 56 warning ([#2906](https://github.com/angular/material2/issues/2906)) ([62189a3](https://github.com/angular/material2/commit/62189a3))
+* **input:** fix placeholder for number input with bad input. ([#2362](https://github.com/angular/material2/issues/2362)) ([52aa715](https://github.com/angular/material2/commit/52aa715))
+* **input:** hints not being read out by screen readers ([#2856](https://github.com/angular/material2/issues/2856)) ([f899b5f](https://github.com/angular/material2/commit/f899b5f)), closes [#2798](https://github.com/angular/material2/issues/2798)
+* **input:** horizontal overflow in IE and Edge ([#2784](https://github.com/angular/material2/issues/2784)) ([e0fe635](https://github.com/angular/material2/commit/e0fe635))
+* **input:** properly determine input value ([#2455](https://github.com/angular/material2/issues/2455)) ([3a11927](https://github.com/angular/material2/commit/3a11927)), closes [#2441](https://github.com/angular/material2/issues/2441) [#2363](https://github.com/angular/material2/issues/2363)
+* **input:** remove md-input and md-textarea in favor of md-input-container ([#2788](https://github.com/angular/material2/issues/2788)) ([7b30fdc](https://github.com/angular/material2/commit/7b30fdc))
+* **input:** vendor-prefix ::placeholder ([#2547](https://github.com/angular/material2/issues/2547)) ([3b16648](https://github.com/angular/material2/commit/3b16648))
+* **input-container:** prefix and suffix stretching together with parent ([#2496](https://github.com/angular/material2/issues/2496)) ([64f6d1b](https://github.com/angular/material2/commit/64f6d1b)), closes [#2493](https://github.com/angular/material2/issues/2493) [#1881](https://github.com/angular/material2/issues/1881) [#1421](https://github.com/angular/material2/issues/1421)
+* **input-container:** reduce redundancy when forwarding the NgControl classes ([#2442](https://github.com/angular/material2/issues/2442)) ([8c0eef2](https://github.com/angular/material2/commit/8c0eef2))
+* **option:** revert duplicate prop ([#3051](https://github.com/angular/material2/issues/3051)) ([516720f](https://github.com/angular/material2/commit/516720f))
+* **overlay:** disable pointer events if overlay is detached ([#2747](https://github.com/angular/material2/issues/2747)) ([453fa7f](https://github.com/angular/material2/commit/453fa7f)), closes [#2739](https://github.com/angular/material2/issues/2739)
+* **overlay:** fix pointer events for ie11 ([#3023](https://github.com/angular/material2/issues/3023)) ([597e3de](https://github.com/angular/material2/commit/597e3de)), closes [#3022](https://github.com/angular/material2/issues/3022)
+* **progress-bar:** buffer animation not working in IE ([#2941](https://github.com/angular/material2/issues/2941)) ([ab8f98f](https://github.com/angular/material2/commit/ab8f98f)), closes [#2881](https://github.com/angular/material2/issues/2881)
+* **progress-bar:** unable to apply visibility in indeterminate mode and reduce CSS ([#2417](https://github.com/angular/material2/issues/2417)) ([eb96b0c](https://github.com/angular/material2/commit/eb96b0c)), closes [#2413](https://github.com/angular/material2/issues/2413)
+* **progress-spinner:** fix color input on md-spinner ([#2396](https://github.com/angular/material2/issues/2396)) ([6cb6576](https://github.com/angular/material2/commit/6cb6576)), closes [#2393](https://github.com/angular/material2/issues/2393)
+* **radio:** change radio button trigger element to input element ([#2838](https://github.com/angular/material2/issues/2838)) ([2f10a95](https://github.com/angular/material2/commit/2f10a95))
+* **ripple:** camel-cased CSS classes ([#2340](https://github.com/angular/material2/issues/2340)) ([c67f4e5](https://github.com/angular/material2/commit/c67f4e5))
+* **ripple:** make ripples conform with specs ([#2859](https://github.com/angular/material2/issues/2859)) ([6381948](https://github.com/angular/material2/commit/6381948))
+* **select:** avoid going into infinite loop under certain conditions ([#2955](https://github.com/angular/material2/issues/2955)) ([998a583](https://github.com/angular/material2/commit/998a583)), closes [#2950](https://github.com/angular/material2/issues/2950)
+* **select:** don't open menu if there are no options ([#2924](https://github.com/angular/material2/issues/2924)) ([cc77ef4](https://github.com/angular/material2/commit/cc77ef4))
+* **select:** fix select panel animation ([#2699](https://github.com/angular/material2/issues/2699)) ([15eb33a](https://github.com/angular/material2/commit/15eb33a)), closes [#2695](https://github.com/angular/material2/issues/2695)
+* **select:** fix selection color ([#2697](https://github.com/angular/material2/issues/2697)) ([4e94da4](https://github.com/angular/material2/commit/4e94da4)), closes [#2696](https://github.com/angular/material2/issues/2696)
+* **select:** selected option not being highlighted when options are added asynchronously ([#2499](https://github.com/angular/material2/issues/2499)) ([7fc38b9](https://github.com/angular/material2/commit/7fc38b9)), closes [#2497](https://github.com/angular/material2/issues/2497)
+* **select:** set default font size ([#2976](https://github.com/angular/material2/issues/2976)) ([40bc486](https://github.com/angular/material2/commit/40bc486))
+* **select:** set select value to trigger height and center text ([#3021](https://github.com/angular/material2/issues/3021)) ([ac9c090](https://github.com/angular/material2/commit/ac9c090))
+* **select:** support use inside a custom value accessor ([#2704](https://github.com/angular/material2/issues/2704)) ([651440f](https://github.com/angular/material2/commit/651440f)), closes [#2609](https://github.com/angular/material2/issues/2609)
+* **select:** transparent background when overscrolling ([#2117](https://github.com/angular/material2/issues/2117)) ([d9b2d85](https://github.com/angular/material2/commit/d9b2d85))
+* **select:** trim long labels inside md-option ([#2444](https://github.com/angular/material2/issues/2444)) ([416f56f](https://github.com/angular/material2/commit/416f56f)), closes [#2440](https://github.com/angular/material2/issues/2440)
+* **select:** view not updating when using OnPush detection strategy ([#2894](https://github.com/angular/material2/issues/2894)) ([3bcb7c3](https://github.com/angular/material2/commit/3bcb7c3)), closes [#2663](https://github.com/angular/material2/issues/2663) [#2269](https://github.com/angular/material2/issues/2269)
+* **select:** parent align affects placeholder ([#2572](https://github.com/angular/material2/issues/2572)) ([a1c90b3](https://github.com/angular/material2/commit/a1c90b3))
+* **sidenav:** animate content resizing for side mode. ([#2486](https://github.com/angular/material2/issues/2486)) ([4d33449](https://github.com/angular/material2/commit/4d33449))
+* **sidenav:** fix animation issue for initially open sidenav ([#3045](https://github.com/angular/material2/issues/3045)) ([37e4bad](https://github.com/angular/material2/commit/37e4bad))
+* **slide-toggle:** consistent naming of aria attributes ([#2688](https://github.com/angular/material2/issues/2688)) ([10bd6da](https://github.com/angular/material2/commit/10bd6da))
+* **slider:** fire change event on value change via keyboard. ([#2807](https://github.com/angular/material2/issues/2807)) ([7f50d11](https://github.com/angular/material2/commit/7f50d11))
+* **slider:** hide ticks when slider is disabled ([#2687](https://github.com/angular/material2/issues/2687)) ([e9ec8ab](https://github.com/angular/material2/commit/e9ec8ab))
+* apply font-family to text components ([#2821](https://github.com/angular/material2/issues/2821)) ([d11673a](https://github.com/angular/material2/commit/d11673a))
+* **slider:** make disabled state look like mocks ([#2604](https://github.com/angular/material2/issues/2604)) ([8263ffb](https://github.com/angular/material2/commit/8263ffb))
+* **slider:** make min value style match mocks ([#2641](https://github.com/angular/material2/issues/2641)) ([737b608](https://github.com/angular/material2/commit/737b608))
+* **slider:** round decimals in the thumb label ([#2527](https://github.com/angular/material2/issues/2527)) ([987897c](https://github.com/angular/material2/commit/987897c)), closes [#2511](https://github.com/angular/material2/issues/2511)
+* **snack-bar:** improper button styling and improved handling of long text ([#2991](https://github.com/angular/material2/issues/2991)) ([93937e6](https://github.com/angular/material2/commit/93937e6)), closes [#2979](https://github.com/angular/material2/issues/2979)
+* **snack-bar:** prevent error when opening multiple snack bars in fast succession ([#2392](https://github.com/angular/material2/issues/2392)) ([161f319](https://github.com/angular/material2/commit/161f319)), closes [#2390](https://github.com/angular/material2/issues/2390)
+* **snack-bar:** SimpleSnackBar not being exported ([#3016](https://github.com/angular/material2/issues/3016)) ([a7a3967](https://github.com/angular/material2/commit/a7a3967)), closes [#3010](https://github.com/angular/material2/issues/3010)
+* **tabs:** crashing on chrome under certain conditions ([#2411](https://github.com/angular/material2/issues/2411)) ([727ce53](https://github.com/angular/material2/commit/727ce53)), closes [#2151](https://github.com/angular/material2/issues/2151)
+* **tabs:** fix ink not showing on chrome 57 ([#3041](https://github.com/angular/material2/issues/3041)) ([f24832c](https://github.com/angular/material2/commit/f24832c))
+* **tabs:** infinite loop when selectedIndex is set to NaN ([#2389](https://github.com/angular/material2/issues/2389)) ([f4cfc2d](https://github.com/angular/material2/commit/f4cfc2d))
+* **toolbar:** add toolbar role to host element ([#2914](https://github.com/angular/material2/issues/2914)) ([67032ca](https://github.com/angular/material2/commit/67032ca)), closes [#2909](https://github.com/angular/material2/issues/2909)
+* **toolbar:** correct font-weight ([#2485](https://github.com/angular/material2/issues/2485)) ([1b44880](https://github.com/angular/material2/commit/1b44880))
+* **toolbar:** prevent content overflow and line-wrapping ([#2454](https://github.com/angular/material2/issues/2454)) ([e728771](https://github.com/angular/material2/commit/e728771)), closes [#2451](https://github.com/angular/material2/issues/2451)
+* **tooltip:** better handling of multi-line text ([#2472](https://github.com/angular/material2/issues/2472)) ([7863e38](https://github.com/angular/material2/commit/7863e38)), closes [#2205](https://github.com/angular/material2/issues/2205)
+* **tooltip:** not working properly with ChangeDetectionStrategy.OnPush ([#2721](https://github.com/angular/material2/issues/2721)) ([632b964](https://github.com/angular/material2/commit/632b964)), closes [#2713](https://github.com/angular/material2/issues/2713)
+* **tooltip:** provide a maximum width ([#2678](https://github.com/angular/material2/issues/2678)) ([fb5e1d4](https://github.com/angular/material2/commit/fb5e1d4)), closes [#2671](https://github.com/angular/material2/issues/2671)
+
+
+### Features
+
+* **autocomplete:** add autocomplete panel toggling ([#2452](https://github.com/angular/material2/issues/2452)) ([d4ab3d3](https://github.com/angular/material2/commit/d4ab3d3))
+* **autocomplete:** add fallback positions ([#2726](https://github.com/angular/material2/issues/2726)) ([8fc7706](https://github.com/angular/material2/commit/8fc7706))
+* **autocomplete:** add keyboard events to autocomplete ([#2723](https://github.com/angular/material2/issues/2723)) ([fcea9d4](https://github.com/angular/material2/commit/fcea9d4))
+* **autocomplete:** add screenreader support ([#2729](https://github.com/angular/material2/issues/2729)) ([bd7f240](https://github.com/angular/material2/commit/bd7f240))
+* **autocomplete:** add value support ([#2516](https://github.com/angular/material2/issues/2516)) ([5def001](https://github.com/angular/material2/commit/5def001))
+* **autocomplete:** allow use of obj values ([#2792](https://github.com/angular/material2/issues/2792)) ([55e1847](https://github.com/angular/material2/commit/55e1847))
+* **button-toggle:** Show selected option when md-button-toggle is disabled ([#3012](https://github.com/angular/material2/issues/3012)) ([1547440](https://github.com/angular/material2/commit/1547440)), closes [#3007](https://github.com/angular/material2/issues/3007)
+* **compatibility:** remove conflicts with material1 css styling ([#2790](https://github.com/angular/material2/issues/2790)) ([210ff02](https://github.com/angular/material2/commit/210ff02))
+* **dialog:** add a config option for passing in data ([#2266](https://github.com/angular/material2/issues/2266)) ([29cbe61](https://github.com/angular/material2/commit/29cbe61)), closes [#2181](https://github.com/angular/material2/issues/2181)
+* **dialog:** add events (observables) for open & closeAll ([#2522](https://github.com/angular/material2/issues/2522)) ([23ab152](https://github.com/angular/material2/commit/23ab152))
+* **dialog:** add the ability to align the content of md-dialog-actions ([#2557](https://github.com/angular/material2/issues/2557)) ([e18ab5d](https://github.com/angular/material2/commit/e18ab5d)), closes [#2483](https://github.com/angular/material2/issues/2483)
+* **dialog:** support open with TemplateRef ([#2910](https://github.com/angular/material2/issues/2910)) ([bf0f625](https://github.com/angular/material2/commit/bf0f625))
+* **focus-classes:** expose focus origin changes through observable ([#2974](https://github.com/angular/material2/issues/2974)) ([d4ba648](https://github.com/angular/material2/commit/d4ba648))
+* **FocusOriginMonitor:** add support for touch events ([#3020](https://github.com/angular/material2/issues/3020)) ([ec7e2e4](https://github.com/angular/material2/commit/ec7e2e4))
+* **input:** option to imperatively float placeholder ([#2585](https://github.com/angular/material2/issues/2585)) ([fb0cf8a](https://github.com/angular/material2/commit/fb0cf8a)), closes [#2466](https://github.com/angular/material2/issues/2466)
+* **list-key-manager:** active descendant support ([#2606](https://github.com/angular/material2/issues/2606)) ([e2ad3a0](https://github.com/angular/material2/commit/e2ad3a0))
+* **menu:** Added ability to show the menu overlay around the menu trigger ([#1771](https://github.com/angular/material2/issues/1771)) ([592f33f](https://github.com/angular/material2/commit/592f33f))
+* **overlay:** add fullscreen-enabled overlay class ([#1949](https://github.com/angular/material2/issues/1949)) ([0640302](https://github.com/angular/material2/commit/0640302))
+* **screenshot:** Add screenshot function to e2e test (button and checkbox) ([#2532](https://github.com/angular/material2/issues/2532)) ([8ba8deb](https://github.com/angular/material2/commit/8ba8deb))
+* **scripts:** push generated docs to material assets repo ([#2720](https://github.com/angular/material2/issues/2720)) ([ba12f44](https://github.com/angular/material2/commit/ba12f44))
+* **select:** emit change event ([#2458](https://github.com/angular/material2/issues/2458)) ([e5bd15c](https://github.com/angular/material2/commit/e5bd15c)), closes [#2248](https://github.com/angular/material2/issues/2248)
+* **sidenav:** add disableClose option ([#2501](https://github.com/angular/material2/issues/2501)) ([52ade97](https://github.com/angular/material2/commit/52ade97)), closes [#2462](https://github.com/angular/material2/issues/2462)
+* **slide-toggle:** add support for labelPosition ([#2836](https://github.com/angular/material2/issues/2836)) ([68a0c90](https://github.com/angular/material2/commit/68a0c90)), closes [#2820](https://github.com/angular/material2/issues/2820)
+* **slider:** emit input event when slider thumb moves ([#2325](https://github.com/angular/material2/issues/2325)) ([99963c4](https://github.com/angular/material2/commit/99963c4)), closes [#2296](https://github.com/angular/material2/issues/2296)
+* **snack-bar:** allow addition of extra css classes ([#2804](https://github.com/angular/material2/issues/2804)) ([e783494](https://github.com/angular/material2/commit/e783494)), closes [#2664](https://github.com/angular/material2/issues/2664)
+* **style:** add directive to determine how elements were focused. ([#2646](https://github.com/angular/material2/issues/2646)) ([8a6d902](https://github.com/angular/material2/commit/8a6d902))
+* **tabs:** add the ability to invert the header ([#2391](https://github.com/angular/material2/issues/2391)) ([a494c92](https://github.com/angular/material2/commit/a494c92)), closes [#2387](https://github.com/angular/material2/issues/2387)
+* **theming:** provide a content wrapper attribute ([#2170](https://github.com/angular/material2/issues/2170)) ([4bf4b87](https://github.com/angular/material2/commit/4bf4b87)), closes [#1938](https://github.com/angular/material2/issues/1938) [#2106](https://github.com/angular/material2/issues/2106)
+* **tooltip:** reposition on scroll ([#2703](https://github.com/angular/material2/issues/2703)) ([bc52298](https://github.com/angular/material2/commit/bc52298))
+* **viewport-ruler:** cache document client rect ([#2538](https://github.com/angular/material2/issues/2538)) ([d0c8f18](https://github.com/angular/material2/commit/d0c8f18))
+* add a common class to be used when dealing with selection logic ([#2562](https://github.com/angular/material2/issues/2562)) ([c295fa9](https://github.com/angular/material2/commit/c295fa9))
+* add simplified checkbox component for usage in other components ([#2619](https://github.com/angular/material2/issues/2619)) ([3b6cab0](https://github.com/angular/material2/commit/3b6cab0))
+* remove the need for forRoot on material NgModules ([#2556](https://github.com/angular/material2/issues/2556)) ([b49bfce](https://github.com/angular/material2/commit/b49bfce))
+
+
+### Performance Improvements
+
+* **tabs:** reduce amount of reflows when aligning the ink bar ([#2372](https://github.com/angular/material2/issues/2372)) ([dab742f](https://github.com/angular/material2/commit/dab742f))
+
+
+
+# [2.0.0-beta.1 rebar-teacup](https://github.com/angular/material2/compare/2.0.0-beta.0...2.0.0-beta.1) (2016-12-23)
+
+### Bug Fixes
+* Remove `MdAutocompleteModule` that was accidentally included in beta.0
+* Correct path to umd bundle in package.json ([#2368](https://github.com/angular/material2/issues/2368)) ([d286e6d](https://github.com/angular/material2/commit/d286e6d6472910ab41b8437d405cd3e902c9c848)), closes [#2366](https://github.com/angular/material2/issues/2366)
+
+
+
+# [2.0.0-beta.0 velvet-pizza](https://github.com/angular/material2/compare/2.0.0-alpha.9...2.0.0-beta.0) (2016-12-22)
+
+### Breaking changes from alpha.11
+* The `svgSrc` propert of `` has been removed. All SVG URLs must now be explicitly marked
+as trusted using Angular's `DomSanitizer` service.
+* The `` element is deprecated in favor of ``. This new component
+allows for direct access to the native input element.
+* All `@Input` properties have been changed to use their camelCase names for binding. The old names
+are still available as deprecated but will be removed in the next release.
+* All `@Directive` selectors are now camelCase to be consistent with Angular core. For example,
+`[md-tooltip]` is now `[mdTooltip]` The old selectors are still available as deprecated but will
+be removed in the next release.
+* `` has been renamed to ``. The old selector and symbols
+are still available as deprecated but will be removed in the next release.
+* `` has been renamed to ``. The old selector is still
+available as deprecated but will be removed in the next release.
+* Several components in `core/`, such as Overlay, have had their prefix changed to `cdk-` (short
+for "component dev kit"). This signifies that these are general-purpose tools for building
+components that are not coupled to Material Design.The old selectors are still
+available as deprecated but will be removed in the next release. The CSS classes have been changed.
+* The `align` property for `md-checkbox` and `md-radio-button` has been changed to `labelPosition`
+with values `before` and `after`.
+* `MdTooltip` properties are now prefixed, e.g., `mdTooltipPosition`, `mdTooltipHideDelay`, etc.
+
+### Note on HammerJS
+HammerJS is now optional. It is still necessary for gestures to work within certain components, but
+should no longer throw an error if it is missing.
+
+### Bug Fixes
+
+* **a11y:** add all providers to forRoot ([#2222](https://github.com/angular/material2/issues/2222)) ([9272b4b](https://github.com/angular/material2/commit/9272b4b)), closes [#2189](https://github.com/angular/material2/issues/2189)
+* add re-exports for symbols needed by Aot ([#2149](https://github.com/angular/material2/issues/2149)) ([c324142](https://github.com/angular/material2/commit/c324142))
+* **icon:** remove svgSrc, only allow trusted urls ([#1933](https://github.com/angular/material2/issues/1933)) ([4571561](https://github.com/angular/material2/commit/4571561))
+* **input:** copy input state classes to md-input-container ([#2191](https://github.com/angular/material2/issues/2191)) ([f0c4148](https://github.com/angular/material2/commit/f0c4148))
+* **input:** fix underline color to match spec ([#2167](https://github.com/angular/material2/issues/2167)) ([b850fed](https://github.com/angular/material2/commit/b850fed)), closes [#2126](https://github.com/angular/material2/issues/2126)
+* **input:** label alignment in rtl ([#2047](https://github.com/angular/material2/issues/2047)) ([7b3a059](https://github.com/angular/material2/commit/7b3a059)), closes [#2034](https://github.com/angular/material2/issues/2034)
+* **input:** treat number 0 as non-empty ([#2245](https://github.com/angular/material2/issues/2245)) ([a818579](https://github.com/angular/material2/commit/a818579))
+* **input:** unable to focus input in IE 11 ([#2233](https://github.com/angular/material2/issues/2233)) ([8ec3a19](https://github.com/angular/material2/commit/8ec3a19))
+* **overlay:** proper backdrop stacking with multiple overlays ([#2276](https://github.com/angular/material2/issues/2276)) ([b16031a](https://github.com/angular/material2/commit/b16031a)), closes [#2272](https://github.com/angular/material2/issues/2272)
+* **platform:** Remove assumption of `window' in MdPlatform ([#2221](https://github.com/angular/material2/issues/2221)) ([e436775](https://github.com/angular/material2/commit/e436775))
+* **positioning:** fallback positions should work while scrolled ([#2193](https://github.com/angular/material2/issues/2193)) ([8df30db](https://github.com/angular/material2/commit/8df30db))
+* **progress-circle, progress-bar:** bind color via [color] rather than [attr.color] ([#2299](https://github.com/angular/material2/issues/2299)) ([e4d2bef](https://github.com/angular/material2/commit/e4d2bef))
+* **progress-spinner:** Rename ProgressCircle to ProgressSpinner ([#2300](https://github.com/angular/material2/issues/2300)) ([221c234](https://github.com/angular/material2/commit/221c234))
+* **select:** clear select if no option matches value ([#2110](https://github.com/angular/material2/issues/2110)) ([2855cc3](https://github.com/angular/material2/commit/2855cc3)), closes [#2109](https://github.com/angular/material2/issues/2109)
+* **select:** make invalid selector more specific ([#2166](https://github.com/angular/material2/issues/2166)) ([a7c88c5](https://github.com/angular/material2/commit/a7c88c5))
+* **sidenav:** make `focus-trap` occupy full height of sidenav ([#2145](https://github.com/angular/material2/issues/2145)) ([13223df](https://github.com/angular/material2/commit/13223df))
+* **sidenav:** Rename md-sidenav-layout to md-sidenav-container. ([#2183](https://github.com/angular/material2/issues/2183)) ([8f1c5a9](https://github.com/angular/material2/commit/8f1c5a9))
+* **slider:** prevent thumb from getting stuck on Mobile Safari ([#2142](https://github.com/angular/material2/issues/2142)) ([4adee46](https://github.com/angular/material2/commit/4adee46))
+* **snack-bar:** clean up element when associated viewContainer is destroyed ([#2219](https://github.com/angular/material2/issues/2219)) ([db9608f](https://github.com/angular/material2/commit/db9608f)), closes [#2190](https://github.com/angular/material2/issues/2190)
+* **tabs:** observing tab header label changes to recalculate width ([#2186](https://github.com/angular/material2/issues/2186)) ([7ab4430](https://github.com/angular/material2/commit/7ab4430)), closes [#2155](https://github.com/angular/material2/issues/2155)
+* TSError: ? Unable to compile TypeScript when running 'gulp:build' ([#2132](https://github.com/angular/material2/issues/2132)) ([714c2a4](https://github.com/angular/material2/commit/714c2a4))
+* **tests:** snackbar ref has unnecessary observable.of ([#2298](https://github.com/angular/material2/issues/2298)) ([d076bd3](https://github.com/angular/material2/commit/d076bd3))
+* **tooltip:** add missing rxjs import ([#2288](https://github.com/angular/material2/issues/2288)) ([ba7053f](https://github.com/angular/material2/commit/ba7053f))
+
+
+### Features
+* make hammerjs optional ([#2280](https://github.com/angular/material2/issues/2280)) ([28691ca](https://github.com/angular/material2/commit/28691ca))
+* **chips:** initial version of md-chip-list. ([#2242](https://github.com/angular/material2/issues/2242)) ([f45c315](https://github.com/angular/material2/commit/f45c315)) ([#2046](https://github.com/angular/material2/issues/2046)) ([ba85883](https://github.com/angular/material2/commit/ba85883)) ([#2332](https://github.com/angular/material2/issues/2332)) ([3f2db27](https://github.com/angular/material2/commit/3f2db27))
+* **dialog:** add dialog content elements ([#2090](https://github.com/angular/material2/issues/2090)) ([cac72aa](https://github.com/angular/material2/commit/cac72aa)), closes [#1624](https://github.com/angular/material2/issues/1624) [#2042](https://github.com/angular/material2/issues/2042)
+* **checkbox, radio:** change `align` to `labelPosition` (inverted) ([#2289](https://github.com/angular/material2/issues/2289)) ([a1f9028](https://github.com/angular/material2/commit/a1f9028))
+* **connected-position:** apply the fallback position that shows the largest area of the element ([#2102](https://github.com/angular/material2/issues/2102)) ([4f5b9c5](https://github.com/angular/material2/commit/4f5b9c5)), closes [#2049](https://github.com/angular/material2/issues/2049)
+* **core:** add scrollable view properties to connected pos strategy ([#2259](https://github.com/angular/material2/issues/2259)) ([b60d33f](https://github.com/angular/material2/commit/b60d33f))
+* **input:** create md-input-container to eventually replace md-input ([#2052](https://github.com/angular/material2/issues/2052)) ([ca2046b](https://github.com/angular/material2/commit/ca2046b))
+* **scroll:** provide directive and service to listen to scrolling ([#2188](https://github.com/angular/material2/issues/2188)) ([9b68e68](https://github.com/angular/material2/commit/9b68e68))
+* **sidenav:** close via escape key and restore focus to trigger element ([#1990](https://github.com/angular/material2/issues/1990)) ([a1331ec](https://github.com/angular/material2/commit/a1331ec))
+* **tooltip:** add input for delaying show and hide ([#2101](https://github.com/angular/material2/issues/2101)) ([e85d108](https://github.com/angular/material2/commit/e85d108))
+* **toolbar** add responsive heights as per spec ([#2157](https://github.com/angular/material2/issues/2157)) ([78d54fc](https://github.com/angular/material2/commit/78d54fc08491ce35f9ad06dc50488cc4d4c3a5e8))
+
+### Performance Improvements
+
+* **sidenav:** avoid extra repaints while scrolling ([#2156](https://github.com/angular/material2/issues/2156)) ([b967712](https://github.com/angular/material2/commit/b967712))
+
+
+
# [2.0.0-alpha.11 polyester-golem](https://github.com/angular/material2/compare/2.0.0-alpha.9...2.0.0-alpha.11) (2016-12-08)
@@ -191,7 +437,7 @@ contains all of the components. Build tools such as [`rollup.js`](http://rollupj
tree-shaking to eliminate the code for components that you aren't using.
The addition of theming as also changed the directory structure for bringing the core css into your
-application. See the new [theming guide](docs/theming.md) for more information.
+application. See the new [theming guide](guides/theming.md) for more information.
### Features
diff --git a/CODING_STANDARDS.md b/CODING_STANDARDS.md
index 16badedbe0ff..25b69346a9e7 100644
--- a/CODING_STANDARDS.md
+++ b/CODING_STANDARDS.md
@@ -12,7 +12,8 @@ ES6 or TypeScript.
### General
#### Write useful comments
-Comments that explain what some block of code does are nice; they can tell you something in less time than it would take to follow through the code itself.
+Comments that explain what some block of code does are nice; they can tell you something in less
+time than it would take to follow through the code itself.
Comments that explain why some block of code exists at all, or does something the way it does,
are _invaluable_. The "why" is difficult, or sometimes impossible, to track down without seeking out
@@ -42,8 +43,8 @@ if (!$attrs['tabindex']) {
For example, rather than doing this:
```html
Basic button
-FAB
-pony
+FAB
+pony
```
do this:
@@ -58,19 +59,122 @@ Keeping modules to a single responsibility makes the code easier to test, consum
ES6 modules offer a straightforward way to organize code into logical, granular units.
Ideally, individual files are 200 - 300 lines of code.
+As a rule of thumb, once a file draws near 400 lines (barring abnormally long constants / comments),
+start considering how to refactor into smaller pieces.
+
#### Less is more
Once a feature is released, it never goes away. We should avoid adding features that don't offer
high user value for price we pay both in maintenance, complexity, and payload size. When in doubt,
leave it out.
This applies especially so to providing two different APIs to accomplish the same thing. Always
-prefer sticking to a _single_ API for accomplishing something.
+prefer sticking to a _single_ API for accomplishing something.
+
+### 100 column limit
+All code and docs in the repo should be 100 columns or fewer. This applies to TypeScript, SCSS,
+ HTML, bash scripts, and markdown files.
### TypeScript
-#### Provide function descriptions
-For functions that are more complicated than a simple getter/setter, provide at least a brief
-sentence explaining what the function does and/or _why_ it does something.
+#### Typing
+Avoid `any` where possible. If you find yourself using `any`, consider whether a generic may be
+appropriate in your case.
+
+For methods and properties that are part of a component's public API, all types must be explicitly
+specified because our documentation tooling cannot currently infer types in places where TypeScript
+can.
+
+#### Fluent APIs
+When creating a fluent or builder-pattern style API, use the `this` return type for methods:
+```
+class ConfigBuilder {
+ withName(name: string): this {
+ this.config.name = name;
+ return this;
+ }
+}
+```
+
+#### Access modifiers
+* Omit the `public` keyword as it is the default behavior.
+* Use `private` when appropriate and possible, prefixing the name with an underscore.
+* Use `protected` when appropriate and possible with no prefix.
+* Prefix *library-internal* properties and methods with an underscore without using the `private`
+keyword. This is necessary for anything that must be public (to be used by Angular), but should not
+be part of the user-facing API. This typically applies to symbols used in template expressions,
+`@ViewChildren` / `@ContentChildren` properties, host bindings, and `@Input` / `@Output` properties
+(when using an alias).
+
+Additionally, the `@docs-private` JsDoc annotation can be used to hide any symbol from the public
+API docs.
+
+#### JsDoc comments
+
+All public APIs must have user-facing comments. These are extracted and shown in the documation
+on [material.angular.io](https://material.angular.io).
+
+Private and internal APIs should have JsDoc when they are not obvious. Ultimately it is the purview
+of the code reviwer as to what is "obvious", but the rule of thumb is that *most* classes,
+properties, and methods should have a JsDoc description.
+
+Properties should have a concise description of what the property means:
+```ts
+ /** The label position relative to the checkbox. Defaults to 'after' */
+ @Input() labelPosition: 'before' | 'after' = 'after';
+```
+
+Methods blocks should describe what the function does and provide a description for each parameter
+and the return value:
+```ts
+ /**
+ * Opens a modal dialog containing the given component.
+ * @param component Type of the component to load into the dialog.
+ * @param config Dialog configuration options.
+ * @returns Reference to the newly-opened dialog.
+ */
+ open(component: ComponentType, config?: MdDialogConfig): MdDialogRef { ... }
+```
+
+Boolean properties and return values should use "Whether..." as opposed to "True if...":
+```ts
+ /** Whether the button is disabled. */
+ disabled: boolean = false;
+```
+
+#### Naming
+
+##### General
+* Prefer writing out words instead of using abbreviations.
+* Prefer *exact* names over short names (within reason). E.g., `labelPosition` is better than
+`align` because the former much more exactly communicates what the property means.
+* Except for `@Input` properties, use `is` and `has` prefixes for boolean properties / methods.
+
+##### Classes
+Classes should be named based on what they're responsible for. Names should capture what the code
+*does*, not how it is used:
+```
+/** NO: */
+class RadioService { }
+
+/** YES: */
+class UniqueSelectionDispatcher { }
+```
+
+Avoid suffixing a class with "Service", as it communicates nothing about what the class does. Try to
+think of the class name as a person's job title.
+
+##### Methods
+The name of a method should capture the action that is performed *by* that method.
+
+### Angular
+
+#### Host bindings
+Prefer using the `host` object in the directive configuration instead of `@HostBinding` and
+`@HostListener`. We do this because TypeScript preserves the type information of methods with
+decorators, and when one of the arguments for the method is a native `Event` type, this preserved
+type information can lead to runtime errors in non-browser environments (e.g., server-side
+pre-rendering).
+
### CSS
@@ -83,18 +187,18 @@ elements like input and button.
#### Use lowest specificity possible
Always prioritize lower specificity over other factors. Most style definitions should consist of a
-single element or css selector plus necessary state modifiers. Avoid SCSS nesting for the sake of
-code organization. This will allow users to much more easily override styles.
+single element or css selector plus necessary state modifiers. **Avoid SCSS nesting for the sake of
+code organization.** This will allow users to much more easily override styles.
For example, rather than doing this:
```scss
-md-calendar {
+.mat-calendar {
display: block;
- .md-month {
+ .mat-month {
display: inline-block;
- .md-date.md-selected {
+ .mat-date.mat-selected {
font-weight: bold;
}
}
@@ -103,15 +207,15 @@ md-calendar {
do this:
```scss
-md-calendar {
+.mat-calendar {
display: block;
}
-.md-calendar-month {
+.mat-calendar-month {
display: inline-block;
}
-.md-calendar-date.md-selected {
+.mat-calendar-date.mat-selected {
font-weight: bold;
}
```
@@ -123,7 +227,7 @@ The end-user of a component should be the one to decide how much margin a compon
This makes it easier to override styles when necessary. For example, rather than
```scss
-:host {
+the-host-element {
// ...
.some-child-element {
@@ -134,7 +238,7 @@ This makes it easier to override styles when necessary. For example, rather than
you can write
```scss
-:host {
+the-host-element {
// ...
color: red;
}
@@ -156,11 +260,11 @@ This is a low-effort task that makes a big difference for low-vision users. Exam
When it is not super obvious, include a brief description of what a class represents. For example:
```scss
// The calendar icon button used to open the calendar pane.
-.md-datepicker-button { ... }
+.mat-datepicker-button { ... }
// Floating pane that contains the calendar at the bottom of the input.
-.md-datepicker-calendar-pane { ... }
+.mat-datepicker-calendar-pane { ... }
// Portion of the floating panel that sits, invisibly, on top of the input.
-.md-datepicker-input-mask { }
+.mat-datepicker-input-mask { }
```
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 333a29371e5d..f868890d6724 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,6 +1,6 @@
-# Contributing to Angular 2 Material
+# Contributing to Angular Material
-We would love for you to contribute to Angular 2 Material and help make it ever better!
+We would love for you to contribute to Angular Material and help make it ever better!
As a contributor, here are the guidelines we would like you to follow:
- [Code of Conduct](#coc)
@@ -19,7 +19,7 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
If you have questions about how to *use* Angular Material, please direct them to the
[Google Group][material-group] discussion list or [StackOverflow][stackoverflow].
-Please note that Angular 2 Material is still in very early development, and the team's capacity
+Please note that Angular Material is still in very early development, and the team's capacity
to answer usage questions is limited. Community chat is also available on [Gitter][gitter].
## Found an Issue?
@@ -33,7 +33,7 @@ You can help the team even more and [submit a Pull Request](#submit-pr) with a f
## Want a Feature?
You can *request* a new feature by [submitting an issue](#submit-issue) to our [GitHub
Repository][github]. If you would like to *implement* a new feature, please submit an issue with
-a proposal for your work first, to be sure that we can use it. Angular 2 Material is in very early
+a proposal for your work first, to be sure that we can use it. Angular Material is in very early
stages and we are not ready to accept major contributions ahead of the full release.
Please consider what kind of change it is:
diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md
deleted file mode 100644
index 724dbf0cdd77..000000000000
--- a/GETTING_STARTED.md
+++ /dev/null
@@ -1,102 +0,0 @@
-Get started with Angular Material 2 using the Angular CLI.
-
-## Install the CLI
-
- ```bash
- npm install -g angular-cli
- ```
-
-## Create a new project
-
- ```bash
- ng new my-project
- ```
-
-The new command creates a project with a build system for your Angular app.
-
-## Install Angular Material components
-
-```bash
-npm install --save @angular/material
-```
-
-## Import the Angular Material NgModule
-
-**src/app/app.module.ts**
-```ts
-import { MaterialModule } from '@angular/material';
-// other imports
-@NgModule({
- imports: [MaterialModule.forRoot()],
- ...
-})
-export class PizzaPartyAppModule { }
-```
-
-## 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/).
-
-Add HammerJS to your application via [npm](https://www.npmjs.com/package/hammerjs), a CDN
-(such as the [Google CDN](https://developers.google.com/speed/libraries/#hammerjs)), or served
-directly from your app.
-
-#### If you want to include HammerJS from npm, you can install it:
-
-```bash
-npm install --save hammerjs
-npm install --save-dev @types/hammerjs
-```
-
-Import HammerJS on your app's module.
-
-**src/app/app.module.ts**
-```ts
-import 'hammerjs';
-```
-
-Finally, you need to add `hammerjs` to the `types` section of your `tsconfig.json` file:
-
-```json
-{
- "compilerOptions": {
- "types": [
- "hammerjs"
- ]
- }
-}
-```
-
-## 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 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
-- [Material 2 Sample App](https://github.com/jelbourn/material2-app)
-- [Angular Connect 2016 Demo](https://github.com/kara/leashed-in)
diff --git a/LICENSE b/LICENSE
index 13a6fd789f83..47bfda24adf2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License
-Copyright (c) 2016 Google, Inc.
+Copyright (c) 2017 Google, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index ccb6e3b3c351..7a5b8ec63172 100644
--- a/README.md
+++ b/README.md
@@ -1,45 +1,53 @@
-# Material Design for Angular 2
+# Material Design for Angular
[![npm version](https://badge.fury.io/js/%40angular%2Fmaterial.svg)](https://www.npmjs.com/package/%40angular%2Fmaterial)
[![Build Status](https://travis-ci.org/angular/material2.svg?branch=master)](https://travis-ci.org/angular/material2)
[![Gitter](https://badges.gitter.im/angular/material2.svg)](https://gitter.im/angular/material2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
-This is the home for the Angular team's Material Design components built on top of Angular 2.
+This is the home for the Angular team's Material Design components built on top of Angular.
#### Quick links
[Google group](https://groups.google.com/forum/#!forum/angular-material2),
[Contributing](https://github.com/angular/material2/blob/master/CONTRIBUTING.md),
[Plunker Template](http://plnkr.co/edit/o077B6uEiiIgkC0S06dd?p=preview)
-### Getting started
+### Installation
-See our [Getting Started Guide](https://github.com/angular/material2/blob/master/GETTING_STARTED.md)
-if you're building your first project with Angular Material 2.
+The latest release of Angular Material can be installed from npm
+
+`npm install --save @angular/material`
+
+Playing with the latest changes from [master](https://github.com/angular/material2/tree/master) is also possible
+
+`npm install --save https://github.com/angular/material2-builds.git`
+
+### Getting started
+
+See our [Getting Started Guide][getting-started]
+if you're building your first project with Angular Material.
### Project status
-Angular Material 2 is currently in alpha and under active development.
-During alpha, breaking API and behavior changes will be occurring regularly.
+Angular Material is currently in beta and under active development.
+During beta, new features will be added regularly and APIs will evolve based on user feedback.
-Check out our [directory of design documents](https://github.com/angular/material2/wiki/Design-doc-directory)
+Check out our [directory of design documents](https://github.com/angular/material2/wiki/Design-doc-directory)
for more insight into our process.
-If you'd like to contribute, you must follow our [contributing guidelines](https://github.com/angular/material2/blob/master/CONTRIBUTING.md).
-You can look through the issues (which should be up-to-date on who is working on which features
-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)
+If you'd like to contribute, you must follow our [contributing guidelines](https://github.com/angular/material2/blob/master/CONTRIBUTING.md).
+You can look through the issues (which should be up-to-date on who is working on which features
+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 December 2016:
-* Continued work on initial versions of md-autocomplete and md-chips
-* Continued bug bashing
-* Continued work on https://material.angular.io site
-* Finish major refactoring for md-input (hit a few issues last month)
-* Continued expanding e2e test coverage
-* Paginated tabs.
-* Scroll / resize handling for overlays
-* Production build
-* AoT compile e2e app
-* Release beta.0
+High level items planned for next few months:
+- Initial version of datepicker
+- Initial version of data table
+- Initial version of tree
+- Select improvements (multi-select, etc)
+- Screenshot test improvements
+- Docs site improvements
+- A11y audit
+- Various bug fixes
#### Feature status:
@@ -62,16 +70,15 @@ High level items planned for December 2016:
| button-toggle | Available | [README][15] | - |
| slider | Available | [README][16] | - |
| menu | Available | [README][17] | [#119][0119] |
-| tooltip | Initial version, needs enhancements | [README][18] | - |
+| tooltip | Available | [README][18] | - |
| ripples | Available | [README][19] | [#108][0108] |
| dialog | Available | [README][22] | [#114][0114] |
| snackbar / toast | Available | [README][21] | [#115][0115] |
-| select | Will be released in alpha.11 | - | [#118][0118] |
-| textarea | Initial version, needs enhancements | - | - |
-| autocomplete | Design started | - | [#117][0117] |
-| chips | Started | - | [#120][0120] |
+| select | Available | [README][23] | [#118][0118] |
+| textarea | Available | [README][5] | - |
+| autocomplete | Initial version, features evolving | [README][24] | [#117][0117] |
+| chips | Initial version, features evolving | - | [#120][0120] |
| theming | Available, need guidance overlays | [Guide][20] | - |
-| prod build | Not started | - | - |
| docs site | UX design and tooling in progress | - | - |
| typography | Not started | - | [#205][0205] |
| fab speed-dial | Not started | - | [#860][0860] |
@@ -79,34 +86,37 @@ High level items planned for December 2016:
| bottom-sheet | Not started | - | - |
| bottom-nav | Not started | - | [#408][0408] |
| virtual-repeat | Not started | - | [#823][0823] |
-| datepicker | Not started | - | [#675][0675] |
-| data-table | Not started | - | [#581][0581] |
+| datepicker | In progress | - | [#675][0675] |
+| data-table | Design in-progress | - | [#581][0581] |
| stepper | Not started | - | [#508][0508] |
-| layout | see [angular/flex-layout][lay_rp] | - | - |
+| layout | See [angular/flex-layout][lay_rp] | [Wiki][0] | - |
[lay_rp]: https://github.com/angular/flex-layout
- [1]: https://github.com/angular/material2/blob/master/src/lib/button/README.md
- [2]: https://github.com/angular/material2/blob/master/src/lib/card/README.md
- [3]: https://github.com/angular/material2/blob/master/src/lib/checkbox/README.md
- [4]: https://github.com/angular/material2/blob/master/src/lib/radio/README.md
- [5]: https://github.com/angular/material2/blob/master/src/lib/input/README.md
- [6]: https://github.com/angular/material2/blob/master/src/lib/sidenav/README.md
- [7]: https://github.com/angular/material2/blob/master/src/lib/toolbar/README.md
- [8]: https://github.com/angular/material2/blob/master/src/lib/list/README.md
- [9]: https://github.com/angular/material2/blob/master/src/lib/grid-list/README.md
-[10]: https://github.com/angular/material2/blob/master/src/lib/icon/README.md
-[11]: https://github.com/angular/material2/blob/master/src/lib/progress-spinner/README.md
-[12]: https://github.com/angular/material2/blob/master/src/lib/progress-bar/README.md
-[13]: https://github.com/angular/material2/blob/master/src/lib/tabs/README.md
-[14]: https://github.com/angular/material2/blob/master/src/lib/slide-toggle/README.md
-[15]: https://github.com/angular/material2/blob/master/src/lib/button-toggle/README.md
-[16]: https://github.com/angular/material2/blob/master/src/lib/slider/README.md
-[17]: https://github.com/angular/material2/blob/master/src/lib/menu/README.md
-[18]: https://github.com/angular/material2/blob/master/src/lib/tooltip/README.md
+ [0]: https://github.com/angular/flex-layout/wiki
+ [1]: https://material.angular.io/components/component/button
+ [2]: https://material.angular.io/components/component/card
+ [3]: https://material.angular.io/components/component/checkbox
+ [4]: https://material.angular.io/components/component/radio
+ [5]: https://material.angular.io/components/component/input
+ [6]: https://material.angular.io/components/component/sidenav
+ [7]: https://material.angular.io/components/component/toolbar
+ [8]: https://material.angular.io/components/component/list
+ [9]: https://material.angular.io/components/component/grid-list
+[10]: https://material.angular.io/components/component/icon
+[11]: https://material.angular.io/components/component/progress-spinner
+[12]: https://material.angular.io/components/component/progress-bar
+[13]: https://material.angular.io/components/component/tabs
+[14]: https://material.angular.io/components/component/slide-toggle
+[15]: https://material.angular.io/components/component/button-toggle
+[16]: https://material.angular.io/components/component/slider
+[17]: https://material.angular.io/components/component/menu
+[18]: https://material.angular.io/components/component/tooltip
[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
+[20]: https://github.com/angular/material2/blob/master/guides/theming.md
+[21]: https://material.angular.io/components/component/snack-bar
+[22]: https://material.angular.io/components/component/dialog
+[23]: https://material.angular.io/components/component/select
+[24]: https://material.angular.io/components/component/autocomplete
[0107]: https://github.com/angular/material2/issues/107
[0119]: https://github.com/angular/material2/issues/119
@@ -126,13 +136,16 @@ High level items planned for December 2016:
[0675]: https://github.com/angular/material2/issues/675
[0581]: https://github.com/angular/material2/issues/581
+[getting-started]: https://github.com/angular/material2/blob/master/guides/getting-started.md
+[theming]: https://github.com/angular/material2/blob/master/guides/theming.md
+
"Available" means that the components or feature is published and available for use, but may still
be missing some behaviors or polish.
## The goal of Angular Material
-Our goal is to build a set of high-quality UI components built with Angular 2 and TypeScript,
-following the Material Design spec. These
+Our goal is to build a set of high-quality UI components built with Angular and TypeScript,
+following the Material Design spec. These
components will serve as an example of how to write Angular code following best practices.
### What do we mean by "high-quality"?
@@ -145,7 +158,7 @@ components will serve as an example of how to write Angular code following best
* Code is clean and well-documented to serve as an example for Angular devs.
## Browser and screen reader support
-Angular Material supports the most recent two versions of all major browsers:
+Angular Material supports the most recent two versions of all major browsers:
Chrome (including Android), Firefox, Safari (including iOS), and IE11 / Edge
We also aim for great user experience with the following screen readers:
diff --git a/e2e/components/button/button.e2e.ts b/e2e/components/button/button.e2e.ts
index 8bbab6c135b9..91719f606425 100644
--- a/e2e/components/button/button.e2e.ts
+++ b/e2e/components/button/button.e2e.ts
@@ -1,17 +1,24 @@
-import {browser, by, element} from 'protractor';
+import {browser, by, element, ExpectedConditions} from 'protractor';
+import {screenshot} from '../../screenshot';
-describe('button', function () {
- describe('disabling behavior', function () {
- beforeEach(function() {
- browser.get('/button');
- });
- it('should prevent click handlers from executing when disabled', function () {
+
+describe('button', () => {
+ describe('disabling behavior', () => {
+ beforeEach(() => browser.get('/button'));
+
+ it('should prevent click handlers from executing when disabled', () => {
element(by.id('test-button')).click();
expect(element(by.id('click-counter')).getText()).toEqual('1');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('clicked once'));
element(by.id('disable-toggle')).click();
element(by.id('test-button')).click();
expect(element(by.id('click-counter')).getText()).toEqual('1');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('click disabled'));
});
});
});
diff --git a/e2e/components/checkbox/checkbox.e2e.ts b/e2e/components/checkbox/checkbox.e2e.ts
index 18e2d434c348..8c81f63100b0 100644
--- a/e2e/components/checkbox/checkbox.e2e.ts
+++ b/e2e/components/checkbox/checkbox.e2e.ts
@@ -1,19 +1,47 @@
-import {browser, by, element} from 'protractor';
+import {browser, by, element, Key, ExpectedConditions} from 'protractor';
+import {screenshot} from '../../screenshot';
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) => {
+
+ it('should be checked when clicked, and be unchecked when clicked again', () => {
+ let checkboxEl = element(by.id('test-checkbox'));
+ let inputEl = element(by.css('input[id=input-test-checkbox]'));
+
+ screenshot('start');
+ checkboxEl.click();
+ inputEl.getAttribute('checked').then((value: string) => {
expect(value).toBeTruthy('Expect checkbox "checked" property to be true');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('checked'));
});
- element(by.id('test-checkbox')).click();
- element(by.css('input[id=input-test-checkbox]')).getAttribute('checked').then((value: string) => {
+ checkboxEl.click();
+ inputEl.getAttribute('checked').then((value: string) => {
expect(value).toBeFalsy('Expect checkbox "checked" property to be false');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('unchecked'));
+ });
+ });
+
+ it('should toggle the checkbox when pressing space', () => {
+ let inputEl = element(by.css('input[id=input-test-checkbox]'));
+
+ inputEl.getAttribute('checked').then((value: string) => {
+ expect(value).toBeFalsy('Expect checkbox "checked" property to be false');
+ });
+
+ inputEl.sendKeys(Key.SPACE);
+
+ inputEl.getAttribute('checked').then((value: string) => {
+ expect(value).toBeTruthy('Expect checkbox "checked" property to be true');
});
});
});
diff --git a/e2e/components/dialog/dialog.e2e.ts b/e2e/components/dialog/dialog.e2e.ts
index 74f1b397c1aa..7a9d862384c0 100644
--- a/e2e/components/dialog/dialog.e2e.ts
+++ b/e2e/components/dialog/dialog.e2e.ts
@@ -1,11 +1,20 @@
-import {browser, by, element, Key, ProtractorBy} from 'protractor';
+import {browser, by, element, Key} from 'protractor';
+import {expectToExist, expectFocusOn} from '../../util/asserts';
+import {pressKeys, clickElementAtPoint} from '../../util/actions';
+import {waitForElement} from '../../util/query';
describe('dialog', () => {
beforeEach(() => browser.get('/dialog'));
it('should open a dialog', () => {
element(by.id('default')).click();
- waitForDialog().then((isPresent: boolean) => expect(isPresent).toBe(true));
+ expectToExist('md-dialog-container');
+ });
+
+ it('should open a template dialog', () => {
+ expectToExist('.my-template-dialog', false);
+ element(by.id('template')).click();
+ expectToExist('.my-template-dialog');
});
it('should close by clicking on the backdrop', () => {
@@ -13,7 +22,7 @@ describe('dialog', () => {
waitForDialog().then(() => {
clickOnBackrop();
- waitForDialog().then((isPresent: boolean) => expect(isPresent).toBe(false));
+ expectToExist('md-dialog-container', false);
});
});
@@ -21,8 +30,18 @@ describe('dialog', () => {
element(by.id('default')).click();
waitForDialog().then(() => {
- pressEscape();
- waitForDialog().then((isPresent: boolean) => expect(isPresent).toBe(false));
+ pressKeys(Key.ESCAPE);
+ expectToExist('md-dialog-container', false);
+ });
+ });
+
+ it('should close by pressing escape when the first tabbable element has lost focus', () => {
+ element(by.id('default')).click();
+
+ waitForDialog().then(() => {
+ clickElementAtPoint('md-dialog-container', { x: 0, y: 0 });
+ pressKeys(Key.ESCAPE);
+ expectToExist('md-dialog-container', false);
});
});
@@ -31,7 +50,7 @@ describe('dialog', () => {
waitForDialog().then(() => {
element(by.id('close')).click();
- waitForDialog().then((isPresent: boolean) => expect(isPresent).toBe(false));
+ expectToExist('md-dialog-container', false);
});
});
@@ -39,7 +58,7 @@ describe('dialog', () => {
element(by.id('default')).click();
waitForDialog().then(() => {
- expectFocusOn(element(by.css('md-dialog-container input')));
+ expectFocusOn('md-dialog-container input');
});
});
@@ -60,8 +79,8 @@ describe('dialog', () => {
waitForDialog().then(() => {
let tab = Key.TAB;
- browser.actions().sendKeys(tab, tab, tab).perform();
- expectFocusOn(element(by.id('close')));
+ pressKeys(tab, tab, tab);
+ expectFocusOn('#close');
});
});
@@ -70,7 +89,7 @@ describe('dialog', () => {
waitForDialog().then(() => {
clickOnBackrop();
- waitForDialog().then((isPresent: boolean) => expect(isPresent).toBe(true));
+ expectToExist('md-dialog-container');
});
});
@@ -78,30 +97,16 @@ describe('dialog', () => {
element(by.id('disabled')).click();
waitForDialog().then(() => {
- pressEscape();
- waitForDialog().then((isPresent: boolean) => expect(isPresent).toBe(true));
+ pressKeys(Key.ESCAPE);
+ expectToExist('md-dialog-container');
});
});
function waitForDialog() {
- return browser.isElementPresent(by.css('md-dialog-container') as ProtractorBy);
+ return waitForElement('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('.cdk-overlay-backdrop')).getWebElement(), { x: 0, y: 0 })
- .click()
- .perform();
- }
-
- function pressEscape() {
- browser.actions().sendKeys(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());
+ clickElementAtPoint('.cdk-overlay-backdrop', { x: 0, y: 0 });
}
});
diff --git a/e2e/components/fullscreen/fullscreen.e2e.ts b/e2e/components/fullscreen/fullscreen.e2e.ts
new file mode 100644
index 000000000000..a9f4a8535c65
--- /dev/null
+++ b/e2e/components/fullscreen/fullscreen.e2e.ts
@@ -0,0 +1,40 @@
+import {browser, by, element} from 'protractor';
+
+describe('fullscreen', () => {
+
+ beforeEach(() => browser.get('/fullscreen'));
+
+ it('should open a dialog inside a fullscreen element and move it to the document body', () => {
+ element(by.id('fullscreen-open')).click();
+ element(by.id('dialog-open')).click();
+
+ expectOverlayInFullscreen();
+
+ element(by.id('dialog-fullscreen-exit')).click();
+ expectOverlayInBody();
+ });
+
+ it('should open a dialog inside the document body and move it to a fullscreen element', () => {
+ element(by.id('dialog-open')).click();
+ expectOverlayInBody();
+
+ element(by.id('dialog-fullscreen-open')).click();
+ expectOverlayInFullscreen();
+
+ element(by.id('dialog-fullscreen-exit')).click();
+ expectOverlayInBody();
+ });
+
+ /** Expects the overlay container to be inside of the body element. */
+ function expectOverlayInBody() {
+ expect(browser.isElementPresent(by.css('body > .cdk-overlay-container')))
+ .toBe(true, 'Expected the overlay container to be inside of the body.');
+ }
+
+ /** Expects the overlay container to be in fullscreen mode. */
+ function expectOverlayInFullscreen() {
+ expect(browser.isElementPresent(by.css('#fullscreen-pane > .cdk-overlay-container')))
+ .toBe(true, 'Expected the overlay container to be in fullscreen mode.');
+ }
+
+});
diff --git a/e2e/components/grid-list/grid-list.e2e.ts b/e2e/components/grid-list/grid-list.e2e.ts
index 64c4647fde5a..848f2b04a3cb 100644
--- a/e2e/components/grid-list/grid-list.e2e.ts
+++ b/e2e/components/grid-list/grid-list.e2e.ts
@@ -1,14 +1,16 @@
-import {browser, by, element} from 'protractor';
+import {browser} from 'protractor';
+import {expectToExist} from '../../util/asserts';
+import {screenshot} from '../../screenshot';
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);
+ expectToExist('md-grid-list');
+ screenshot();
});
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);
+ expectToExist('md-grid-list md-grid-tile');
});
});
diff --git a/e2e/components/icon/icon.e2e.ts b/e2e/components/icon/icon.e2e.ts
index e0cb1caa6910..1407f517d1ef 100644
--- a/e2e/components/icon/icon.e2e.ts
+++ b/e2e/components/icon/icon.e2e.ts
@@ -1,4 +1,5 @@
import {browser, by, element} from 'protractor';
+import {screenshot} from '../../screenshot';
describe('icon', () => {
describe('font icons by ligature', () => {
@@ -13,6 +14,7 @@ describe('icon', () => {
testIcon.getAttribute('aria-label').then((attr: string) => {
expect(attr).toEqual('favorite');
});
+ screenshot();
});
it('should have the correct class when used', () => {
diff --git a/e2e/components/list/list.e2e.ts b/e2e/components/list/list.e2e.ts
index 329f8a8dd19c..86da9dba1246 100644
--- a/e2e/components/list/list.e2e.ts
+++ b/e2e/components/list/list.e2e.ts
@@ -1,14 +1,16 @@
-import {browser, by, element} from 'protractor';
+import {browser} from 'protractor';
+import {expectToExist} from '../../util/asserts';
+import {screenshot} from '../../screenshot';
describe('list', () => {
beforeEach(() => browser.get('/list'));
it('should render a list container', () => {
- expect(element(by.css('md-list')).isPresent()).toBe(true);
+ expectToExist('md-list');
+ screenshot();
});
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);
+ expectToExist('md-list md-list-item');
});
});
diff --git a/e2e/components/menu/menu-page.ts b/e2e/components/menu/menu-page.ts
index 7100f0d494f1..0d5dc6f82142 100644
--- a/e2e/components/menu/menu-page.ts
+++ b/e2e/components/menu/menu-page.ts
@@ -1,69 +1,33 @@
-import {browser, by, element, ElementFinder, ProtractorBy} from 'protractor';
+import {browser, by, element, ElementFinder} from 'protractor';
export class MenuPage {
+ constructor() { browser.get('/menu'); }
- constructor() {
- browser.get('/menu');
- }
+ menu(): ElementFinder { return element(by.css('.mat-menu-panel')); }
- menu() { return element(by.css('.md-menu-panel')); }
+ start(): ElementFinder { return element(by.id('start')); }
- start() { return element(by.id('start')); }
+ trigger(): ElementFinder { return element(by.id('trigger')); }
- trigger() { return element(by.id('trigger')); }
+ triggerTwo(): ElementFinder { return element(by.id('trigger-two')); }
- triggerTwo() { return element(by.id('trigger-two')); }
+ backdrop(): ElementFinder { return element(by.css('.cdk-overlay-backdrop')); }
- backdrop() { return element(by.css('.cdk-overlay-backdrop')); }
+ items(index: number): ElementFinder { return element.all(by.css('[md-menu-item]')).get(index); }
- items(index: number) { return element.all(by.css('[md-menu-item]')).get(index); }
+ textArea(): ElementFinder { return element(by.id('text')); }
- textArea() { return element(by.id('text')); }
+ beforeTrigger(): ElementFinder { return element(by.id('before-t')); }
- beforeTrigger() { return element(by.id('before-t')); }
+ aboveTrigger(): ElementFinder { return element(by.id('above-t')); }
- aboveTrigger() { return element(by.id('above-t')); }
+ combinedTrigger(): ElementFinder { return element(by.id('combined-t')); }
- combinedTrigger() { return element(by.id('combined-t')); }
+ beforeMenu(): ElementFinder { return element(by.css('.mat-menu-panel.before')); }
- beforeMenu() { return element(by.css('.md-menu-panel.before')); }
+ aboveMenu(): ElementFinder { return element(by.css('.mat-menu-panel.above')); }
- aboveMenu() { return element(by.css('.md-menu-panel.above')); }
+ combinedMenu(): ElementFinder { return element(by.css('.mat-menu-panel.combined')); }
- combinedMenu() { return element(by.css('.md-menu-panel.combined')); }
-
- // TODO(kara): move to common testing utility
- pressKey(key: string): void {
- browser.actions().sendKeys(key).perform();
- }
-
- // TODO(kara): move to common testing utility
- expectFocusOn(el: any): void {
- expect(browser.driver.switchTo().activeElement().getInnerHtml())
- .toBe(el.getInnerHtml());
- }
-
- expectMenuPresent(expected: boolean) {
- return browser.isElementPresent(by.css('.md-menu-panel') as ProtractorBy)
- .then((isPresent: boolean) => {
- expect(isPresent).toBe(expected);
- });
- }
-
- expectMenuLocation(el: ElementFinder, {x, y}: {x: number, y: number}) {
- el.getLocation().then(loc => {
- expect(loc.x).toEqual(x, 'Expect the x-position to be equal');
- expect(loc.y).toEqual(y, 'Expect the y-position to be equal');
- });
- }
-
- expectMenuAlignedWith(el: ElementFinder, id: string) {
- element(by.id(id)).getLocation().then(loc => {
- this.expectMenuLocation(el, {x: loc.x, y: loc.y});
- });
- }
-
- getResultText() {
- return this.textArea().getText();
- }
+ getResultText() { return this.textArea().getText(); }
}
diff --git a/e2e/components/menu/menu.e2e.ts b/e2e/components/menu/menu.e2e.ts
index 79c3c394c77c..26b3e4dbb431 100644
--- a/e2e/components/menu/menu.e2e.ts
+++ b/e2e/components/menu/menu.e2e.ts
@@ -1,65 +1,72 @@
-import {browser, Key, protractor} from 'protractor';
+import {Key, protractor} from 'protractor';
import {MenuPage} from './menu-page';
+import {expectToExist, expectAlignedWith, expectFocusOn, expectLocation} from '../../util/asserts';
+import {pressKeys} from '../../util/actions';
+import {screenshot} from '../../screenshot';
describe('menu', () => {
+ const menuSelector = '.mat-menu-panel';
let page: MenuPage;
- beforeEach(function() {
- page = new MenuPage();
- });
+ beforeEach(() => page = new MenuPage());
it('should open menu when the trigger is clicked', () => {
- page.expectMenuPresent(false);
+ expectToExist(menuSelector, false);
page.trigger().click();
- page.expectMenuPresent(true);
+ expectToExist(menuSelector);
expect(page.menu().getText()).toEqual('One\nTwo\nThree\nFour');
+ screenshot();
});
it('should close menu when menu item is clicked', () => {
page.trigger().click();
page.items(0).click();
- page.expectMenuPresent(false);
+ expectToExist(menuSelector, false);
+ screenshot();
});
it('should run click handlers on regular menu items', () => {
page.trigger().click();
page.items(0).click();
expect(page.getResultText()).toEqual('one');
+ screenshot('one');
page.trigger().click();
page.items(1).click();
expect(page.getResultText()).toEqual('two');
+ screenshot('two');
});
it('should run not run click handlers on disabled menu items', () => {
page.trigger().click();
page.items(2).click();
expect(page.getResultText()).toEqual('');
+ screenshot();
});
it('should support multiple triggers opening the same menu', () => {
page.triggerTwo().click();
+
expect(page.menu().getText()).toEqual('One\nTwo\nThree\nFour');
- page.expectMenuAlignedWith(page.menu(), 'trigger-two');
+ expectAlignedWith(page.menu(), '#trigger-two');
page.backdrop().click();
- page.expectMenuPresent(false);
+ expectToExist(menuSelector, 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');
+ expectAlignedWith(page.menu(), '#trigger');
page.backdrop().click();
- page.expectMenuPresent(false);
+ expectToExist(menuSelector, false);
});
it('should mirror classes on host to menu template in overlay', () => {
page.trigger().click();
page.menu().getAttribute('class').then((classes: string) => {
- expect(classes).toContain('md-menu-panel custom');
+ expect(classes).toContain('mat-menu-panel custom');
});
});
@@ -67,82 +74,71 @@ describe('menu', () => {
beforeEach(() => {
// click start button to avoid tabbing past navigation
page.start().click();
- page.pressKey(Key.TAB);
+ pressKeys(Key.TAB);
});
it('should auto-focus the first item when opened with ENTER', () => {
- page.pressKey(Key.ENTER);
- page.expectFocusOn(page.items(0));
+ pressKeys(Key.ENTER);
+ expectFocusOn(page.items(0));
});
it('should auto-focus the first item when opened with SPACE', () => {
- page.pressKey(Key.SPACE);
- page.expectFocusOn(page.items(0));
+ pressKeys(Key.SPACE);
+ expectFocusOn(page.items(0));
});
it('should not focus the first item when opened with mouse', () => {
page.trigger().click();
- page.expectFocusOn(page.trigger());
+ expectFocusOn(page.trigger());
});
it('should focus subsequent items when down arrow is pressed', () => {
- page.pressKey(Key.ENTER);
- page.pressKey(Key.DOWN);
- page.expectFocusOn(page.items(1));
+ pressKeys(Key.ENTER, Key.DOWN);
+ expectFocusOn(page.items(1));
});
it('should focus previous items when up arrow is pressed', () => {
- page.pressKey(Key.ENTER);
- page.pressKey(Key.DOWN);
- page.pressKey(Key.UP);
- page.expectFocusOn(page.items(0));
+ pressKeys(Key.ENTER, Key.DOWN, Key.UP);
+ expectFocusOn(page.items(0));
});
it('should skip disabled items using arrow keys', () => {
- page.pressKey(Key.ENTER);
- page.pressKey(Key.DOWN);
- page.pressKey(Key.DOWN);
- page.expectFocusOn(page.items(3));
+ pressKeys(Key.ENTER, Key.DOWN, Key.DOWN);
+ expectFocusOn(page.items(3));
- page.pressKey(Key.UP);
- page.expectFocusOn(page.items(1));
+ pressKeys(Key.UP);
+ expectFocusOn(page.items(1));
});
it('should close the menu when tabbing past items', () => {
- page.pressKey(Key.ENTER);
- page.pressKey(Key.TAB);
- page.expectMenuPresent(false);
+ pressKeys(Key.ENTER, Key.TAB);
+ expectToExist(menuSelector, false);
- page.pressKey(Key.TAB);
- page.pressKey(Key.ENTER);
- page.expectMenuPresent(true);
+ pressKeys(Key.TAB, Key.ENTER);
+ expectToExist(menuSelector);
- page.pressKey(protractor.Key.chord(Key.SHIFT, Key.TAB));
- page.expectMenuPresent(false);
+ pressKeys(protractor.Key.chord(Key.SHIFT, Key.TAB));
+ expectToExist(menuSelector, false);
});
it('should wrap back to menu when arrow keying past items', () => {
- page.pressKey(Key.ENTER);
- page.pressKey(Key.DOWN);
- page.pressKey(Key.DOWN);
- page.pressKey(Key.DOWN);
- page.expectFocusOn(page.items(0));
-
- page.pressKey(Key.UP);
- page.expectFocusOn(page.items(3));
+ let down = Key.DOWN;
+ pressKeys(Key.ENTER, down, down, down);
+ expectFocusOn(page.items(0));
+
+ pressKeys(Key.UP);
+ expectFocusOn(page.items(3));
});
it('should focus before and after trigger when tabbing past items', () => {
- page.pressKey(Key.ENTER);
- page.pressKey(Key.TAB);
- page.expectFocusOn(page.triggerTwo());
+ let shiftTab = protractor.Key.chord(Key.SHIFT, Key.TAB);
- // navigate back to trigger
- page.pressKey(protractor.Key.chord(protractor.Key.SHIFT, protractor.Key.TAB));
- page.pressKey(Key.ENTER);
+ pressKeys(Key.ENTER, Key.TAB);
+ expectFocusOn(page.triggerTwo());
- page.pressKey(protractor.Key.chord(protractor.Key.SHIFT, protractor.Key.TAB));
- page.expectFocusOn(page.start());
+ // navigate back to trigger
+ pressKeys(shiftTab, Key.ENTER, shiftTab);
+ expectFocusOn(page.start());
});
});
@@ -153,7 +149,7 @@ describe('menu', () => {
page.trigger().click();
// menu.x should equal trigger.x, menu.y should equal trigger.y
- page.expectMenuAlignedWith(page.menu(), 'trigger');
+ expectAlignedWith(page.menu(), '#trigger');
});
it('should align overlay end to origin end when x-position is "before"', () => {
@@ -164,7 +160,7 @@ describe('menu', () => {
// menu = 112px wide. trigger = 60px wide. 112 - 60 = 52px of menu to the left of trigger.
// trigger.x (left corner) - 52px (menu left of trigger) = expected menu.x (left corner)
// menu.y should equal trigger.y because only x position has changed.
- page.expectMenuLocation(page.beforeMenu(), {x: trigger.x - 52, y: trigger.y});
+ expectLocation(page.beforeMenu(), {x: trigger.x - 52, y: trigger.y});
});
});
@@ -176,7 +172,7 @@ describe('menu', () => {
// menu.x should equal trigger.x because only y position has changed.
// menu = 64px high. trigger = 20px high. 64 - 20 = 44px of menu extending up past trigger.
// trigger.y (top corner) - 44px (menu above trigger) = expected menu.y (top corner)
- page.expectMenuLocation(page.aboveMenu(), {x: trigger.x, y: trigger.y - 44});
+ expectLocation(page.aboveMenu(), {x: trigger.x, y: trigger.y - 44});
});
});
@@ -186,7 +182,7 @@ describe('menu', () => {
// trigger.x (left corner) - 52px (menu left of trigger) = expected menu.x
// trigger.y (top corner) - 44px (menu above trigger) = expected menu.y
- page.expectMenuLocation(page.combinedMenu(), {x: trigger.x - 52, y: trigger.y - 44});
+ expectLocation(page.combinedMenu(), {x: trigger.x - 52, y: trigger.y - 44});
});
});
diff --git a/e2e/components/progress-bar/progress-bar.e2e.ts b/e2e/components/progress-bar/progress-bar.e2e.ts
index 33c5898400b8..7bc4eec54c3e 100644
--- a/e2e/components/progress-bar/progress-bar.e2e.ts
+++ b/e2e/components/progress-bar/progress-bar.e2e.ts
@@ -1,25 +1,22 @@
-import {browser, by, element} from 'protractor';
+import {browser} from 'protractor';
+import {expectToExist} from '../../util/asserts';
describe('progress-bar', () => {
beforeEach(() => browser.get('/progress-bar'));
it('should render a determinate progress bar', () => {
- shouldExist('md-progress-bar[mode="determinate"]');
+ expectToExist('md-progress-bar[mode="determinate"]');
});
it('should render a buffer progress bar', () => {
- shouldExist('md-progress-bar[mode="buffer"]');
+ expectToExist('md-progress-bar[mode="buffer"]');
});
it('should render a query progress bar', () => {
- shouldExist('md-progress-bar[mode="query"]');
+ expectToExist('md-progress-bar[mode="query"]');
});
it('should render a indeterminate progress bar', () => {
- shouldExist('md-progress-bar[mode="indeterminate"]');
+ expectToExist('md-progress-bar[mode="indeterminate"]');
});
-
- function shouldExist(selector: string): void {
- expect(element(by.css(selector)).isPresent()).toBe(true);
- }
});
diff --git a/e2e/components/radio/radio.e2e.ts b/e2e/components/radio/radio.e2e.ts
index 37c81509dc08..a2a5188838d2 100644
--- a/e2e/components/radio/radio.e2e.ts
+++ b/e2e/components/radio/radio.e2e.ts
@@ -1,16 +1,17 @@
-import {browser, by, element} from 'protractor';
+import {browser, by, element, ExpectedConditions} from 'protractor';
+import {screenshot} from '../../screenshot';
-describe('radio', function () {
+describe('radio', () => {
+ describe('disabling behavior', () => {
+ beforeEach(() => browser.get('/radio'));
- describe('disabling behavior', function () {
- beforeEach(function() {
- browser.get('/radio');
- });
-
- it('should be checked when clicked', function () {
+ it('should be checked when clicked', () => {
element(by.id('water')).click();
element(by.id('water')).getAttribute('class').then((value: string) => {
- expect(value).toContain('md-radio-checked');
+ expect(value).toContain('mat-radio-checked');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('water'));
});
element(by.css('input[id=water-input]')).getAttribute('checked').then((value: string) => {
expect(value).toBeTruthy();
@@ -21,7 +22,10 @@ describe('radio', function () {
element(by.id('leaf')).click();
element(by.id('leaf')).getAttribute('class').then((value: string) => {
- expect(value).toContain('md-radio-checked');
+ expect(value).toContain('mat-radio-checked');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('leaf'));
});
element(by.css('input[id=leaf-input]')).getAttribute('checked').then((value: string) => {
expect(value).toBeTruthy();
@@ -31,19 +35,24 @@ describe('radio', function () {
});
});
- it('should be disabled when disable the radio group', function () {
+ it('should be disabled when disable the radio group', () => {
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');
+ expect(value).toContain('mat-radio-disabled');
+ browser.wait(ExpectedConditions.presenceOf(element(by.css('.mat-radio-disabled'))))
+ .then(() => screenshot('water'));
});
- element(by.css('input[id=water-input]')).getAttribute('disabled').then((value: string) => {
+ 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');
+ expect(value).toContain('mat-radio-disabled');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('leaf'));
});
element(by.css('input[id=leaf-input]')).getAttribute('disabled').then((value: string) => {
expect(value).toBeTruthy();
diff --git a/e2e/components/slide-toggle/slide-toggle.e2e.ts b/e2e/components/slide-toggle/slide-toggle.e2e.ts
index c68610615a6a..38808fed43c4 100644
--- a/e2e/components/slide-toggle/slide-toggle.e2e.ts
+++ b/e2e/components/slide-toggle/slide-toggle.e2e.ts
@@ -1,49 +1,60 @@
-import {browser, element, by, protractor} from 'protractor';
+import {browser, element, by, Key, ExpectedConditions} from 'protractor';
+import {expectToExist} from '../../util/asserts';
+import {screenshot} from '../../screenshot';
describe('slide-toggle', () => {
+ const getInput = () => element(by.css('#normal-slide-toggle input'));
+ const getNormalToggle = () => element(by.css('#normal-slide-toggle'));
beforeEach(() => browser.get('slide-toggle'));
it('should render a slide-toggle', () => {
- expect(element(by.css('md-slide-toggle')).isPresent()).toBe(true);
+ expectToExist('md-slide-toggle');
+ screenshot();
});
it('should change the checked state on click', () => {
- let slideToggleEl = element(by.css('#normal-slide-toggle'));
- let inputEl = element(by.css('#normal-slide-toggle input'));
+ let inputEl = getInput();
expect(inputEl.getAttribute('checked')).toBeFalsy('Expect slide-toggle to be unchecked');
- slideToggleEl.click();
+ getNormalToggle().click();
expect(inputEl.getAttribute('checked')).toBeTruthy('Expect slide-toggle to be checked');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot());
});
it('should change the checked state on click', () => {
- let slideToggleEl = element(by.css('#normal-slide-toggle'));
- let inputEl = element(by.css('#normal-slide-toggle input'));
+ let inputEl = getInput();
expect(inputEl.getAttribute('checked')).toBeFalsy('Expect slide-toggle to be unchecked');
- slideToggleEl.click();
+ getNormalToggle().click();
expect(inputEl.getAttribute('checked')).toBeTruthy('Expect slide-toggle to be checked');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot());
});
it('should not change the checked state on click when disabled', () => {
- let slideToggleEl = element(by.css('#disabled-slide-toggle'));
- let inputEl = element(by.css('#disabled-slide-toggle input'));
+ let inputEl = getInput();
expect(inputEl.getAttribute('checked')).toBeFalsy('Expect slide-toggle to be unchecked');
- slideToggleEl.click();
+ element(by.css('#disabled-slide-toggle')).click();
expect(inputEl.getAttribute('checked')).toBeFalsy('Expect slide-toggle to be unchecked');
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot());
});
it('should move the thumb on state change', () => {
- let slideToggleEl = element(by.css('#normal-slide-toggle'));
- let thumbEl = element(by.css('#normal-slide-toggle .md-slide-toggle-thumb-container'));
+ let slideToggleEl = getNormalToggle();
+ let thumbEl = element(by.css('#normal-slide-toggle .mat-slide-toggle-thumb-container'));
let previousX = thumbEl.getLocation().then(pos => pos.x);
@@ -52,14 +63,17 @@ describe('slide-toggle', () => {
let newX = thumbEl.getLocation().then(pos => pos.x);
expect(previousX).not.toBe(newX);
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot());
});
it('should toggle the slide-toggle on space key', () => {
- let inputEl = element(by.css('#normal-slide-toggle input'));
+ let inputEl = getInput();
expect(inputEl.getAttribute('checked')).toBeFalsy('Expect slide-toggle to be unchecked');
- inputEl.sendKeys(protractor.Key.SPACE);
+ inputEl.sendKeys(Key.SPACE);
expect(inputEl.getAttribute('checked')).toBeTruthy('Expect slide-toggle to be checked');
});
diff --git a/e2e/components/tabs/tabs.e2e.ts b/e2e/components/tabs/tabs.e2e.ts
index 9a9fd53a3032..4092aa2b5c4f 100644
--- a/e2e/components/tabs/tabs.e2e.ts
+++ b/e2e/components/tabs/tabs.e2e.ts
@@ -1,4 +1,14 @@
-import {browser, by, element, ElementArrayFinder, ElementFinder, Key} from 'protractor';
+import {
+ browser,
+ by,
+ element,
+ ElementArrayFinder,
+ ElementFinder,
+ Key,
+ ExpectedConditions
+} from 'protractor';
+import {pressKeys} from '../../util/actions';
+import {screenshot} from '../../screenshot';
describe('tabs', () => {
describe('basic behavior', () => {
@@ -9,7 +19,7 @@ describe('tabs', () => {
beforeEach(() => {
browser.get('/tabs');
tabGroup = element(by.css('md-tab-group'));
- tabLabels = element.all(by.css('.md-tab-label'));
+ tabLabels = element.all(by.css('.mat-tab-label'));
tabBodies = element.all(by.css('md-tab-body'));
});
@@ -17,42 +27,46 @@ describe('tabs', () => {
tabLabels.get(1).click();
expect(getLabelActiveStates(tabLabels)).toEqual([false, true, false]);
expect(getBodyActiveStates(tabBodies)).toEqual([false, true, false]);
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('click1'));
tabLabels.get(0).click();
expect(getLabelActiveStates(tabLabels)).toEqual([true, false, false]);
expect(getBodyActiveStates(tabBodies)).toEqual([true, false, false]);
+ browser.wait(ExpectedConditions.not(
+ ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))))
+ .then(() => screenshot('click0'));
});
it('should change focus with keyboard interaction', () => {
+ let right = Key.RIGHT;
+ let left = Key.LEFT;
+
tabLabels.get(0).click();
expect(getFocusStates(tabLabels)).toEqual([true, false, false]);
- pressKey(Key.RIGHT);
+ pressKeys(right);
expect(getFocusStates(tabLabels)).toEqual([false, true, false]);
- pressKey(Key.RIGHT);
+ pressKeys(right);
expect(getFocusStates(tabLabels)).toEqual([false, false, true]);
- pressKey(Key.RIGHT);
+ pressKeys(right);
expect(getFocusStates(tabLabels)).toEqual([false, false, true]);
- pressKey(Key.LEFT);
+ pressKeys(left);
expect(getFocusStates(tabLabels)).toEqual([false, true, false]);
- pressKey(Key.LEFT);
+ pressKeys(left);
expect(getFocusStates(tabLabels)).toEqual([true, false, false]);
- pressKey(Key.LEFT);
+ pressKeys(left);
expect(getFocusStates(tabLabels)).toEqual([true, false, false]);
});
});
});
-/** 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.
*/
@@ -68,12 +82,12 @@ function getFocusStates(elements: ElementArrayFinder) {
/** 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');
+ return getClassStates(elements, 'mat-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');
+ return getClassStates(elements, 'mat-tab-body-active');
}
/**
diff --git a/e2e/index.e2e.ts b/e2e/index.e2e.ts
index dded58a17bae..36b27f6bd962 100644
--- a/e2e/index.e2e.ts
+++ b/e2e/index.e2e.ts
@@ -4,7 +4,7 @@ describe('hello, protractor', function () {
describe('index', function () {
browser.get('/');
it('should have a title', function () {
- expect(browser.getTitle()).toBe('Material2');
+ expect(browser.getTitle()).toBe('Angular Material');
});
});
});
diff --git a/e2e/screenshot.ts b/e2e/screenshot.ts
new file mode 100644
index 000000000000..f6a2d5af0901
--- /dev/null
+++ b/e2e/screenshot.ts
@@ -0,0 +1,61 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import {browser} from 'protractor';
+
+const OUTPUT_DIR = './screenshots/';
+const HEIGHT = 768;
+const WIDTH = 1024;
+
+let currentJasmineSpecName = '';
+
+/** Adds a custom jasmine reporter that simply keeps track of the current test name. */
+function initializeEnvironment(jasmine: any) {
+ browser.manage().window().setSize(WIDTH, HEIGHT);
+ let reporter = new jasmine.JsApiReporter({});
+ reporter.specStarted = function(result: any) {
+ currentJasmineSpecName = result.fullName;
+ };
+ jasmine.getEnv().addReporter(reporter);
+}
+
+initializeEnvironment(jasmine);
+
+export class Screenshot {
+ id: string;
+
+ /** The filename used to store the screenshot. */
+ get filename(): string {
+ return this.id
+ .toLowerCase()
+ .replace(/\s/g, '_')
+ .replace(/[^/a-z0-9_]+/g, '')
+ + '.screenshot.png';
+ }
+
+ /** The full path to the screenshot */
+ get fullPath(): string {
+ return path.resolve(OUTPUT_DIR, this.filename);
+ }
+
+ constructor(id?: string) {
+ this.id = id ? `${currentJasmineSpecName} ${id}` : currentJasmineSpecName;
+ browser.takeScreenshot().then(png => this.storeScreenshot(png));
+ }
+
+ /** Replaces the existing screenshot with the newly generated one. */
+ storeScreenshot(png: any) {
+ if (!fs.existsSync(OUTPUT_DIR)) {
+ fs.mkdirSync(OUTPUT_DIR, '744');
+ }
+
+ if (fs.existsSync(OUTPUT_DIR)) {
+ fs.writeFileSync(this.fullPath, png, {encoding: 'base64' });
+ }
+ }
+}
+
+export function screenshot(id?: string) {
+ if (process.env['TRAVIS']) {
+ return new Screenshot(id);
+ }
+}
diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json
index 06f19589b388..a4130cff60a6 100644
--- a/e2e/tsconfig.json
+++ b/e2e/tsconfig.json
@@ -13,7 +13,7 @@
"sourceMap": true,
"target": "es5",
"typeRoots": [
- "../node_modules/@types/"
+ "../node_modules/@types"
],
"types": [
"jasmine"
diff --git a/e2e/util/actions.ts b/e2e/util/actions.ts
new file mode 100644
index 000000000000..8199481a8951
--- /dev/null
+++ b/e2e/util/actions.ts
@@ -0,0 +1,21 @@
+import {browser} from 'protractor';
+import {getElement, FinderResult} from './query';
+
+/**
+ * Presses a single key or a sequence of keys.
+ */
+export function pressKeys(...keys: string[]): void {
+ let actions = browser.actions();
+ actions.sendKeys.call(actions, keys).perform();
+}
+
+/**
+ * Clicks an element at a specific point. Useful if there's another element
+ * that covers part of the target and can catch the click.
+ */
+export function clickElementAtPoint(element: FinderResult, coords: Point): void {
+ let webElement = getElement(element).getWebElement();
+ browser.actions().mouseMove(webElement, coords).click().perform();
+}
+
+export interface Point { x: number; y: number; }
diff --git a/e2e/util/asserts.ts b/e2e/util/asserts.ts
new file mode 100644
index 000000000000..dc624c00d579
--- /dev/null
+++ b/e2e/util/asserts.ts
@@ -0,0 +1,39 @@
+import {browser} from 'protractor';
+import {getElement, FinderResult, waitForElement} from './query';
+import {Point} from './actions';
+
+/**
+ * Asserts that an element exists.
+ */
+export function expectToExist(selector: string, expected = true) {
+ return waitForElement(selector).then((isPresent: boolean) => {
+ expect(isPresent).toBe(expected, `Expected "${selector}"${expected ? '' : ' not'} to exist`);
+ });
+}
+
+/**
+ * Asserts that an element is focused.
+ */
+export function expectFocusOn(element: FinderResult, expected = true): void {
+ expect(browser.driver.switchTo().activeElement().getId()).toBe(
+ getElement(element).getId(), `Expected element${expected ? '' : ' not'} to be focused.`);
+}
+
+/**
+ * Asserts that an element has a certan location.
+ */
+export function expectLocation(element: FinderResult, {x, y}: Point): void {
+ getElement(element).getLocation().then((location: Point) => {
+ expect(location.x).toEqual(x);
+ expect(location.y).toEqual(y);
+ });
+}
+
+/**
+ * Asserts that one element is aligned with another.
+ */
+export function expectAlignedWith(element: FinderResult, otherElement: FinderResult): void {
+ getElement(otherElement).getLocation().then((location: Point) => {
+ this.expectLocation(getElement(element), location);
+ });
+}
diff --git a/e2e/util/query.ts b/e2e/util/query.ts
new file mode 100644
index 000000000000..03f6b061920b
--- /dev/null
+++ b/e2e/util/query.ts
@@ -0,0 +1,18 @@
+import {ElementFinder, by, element, ProtractorBy, browser} from 'protractor';
+
+/**
+ * Normalizes either turning a selector into an
+ * ElementFinder or returning the finder itself.
+ */
+export function getElement(el: FinderResult): ElementFinder {
+ return typeof el === 'string' ? element(by.css(el)) : el;
+}
+
+/**
+ * Waits for an element to be rendered.
+ */
+export function waitForElement(selector: string) {
+ return browser.isElementPresent(by.css(selector) as ProtractorBy);
+}
+
+export type FinderResult = ElementFinder | string;
diff --git a/guides/getting-started.md b/guides/getting-started.md
new file mode 100644
index 000000000000..679676f8cc07
--- /dev/null
+++ b/guides/getting-started.md
@@ -0,0 +1,92 @@
+For help getting started with a new Angular app, check out the [Angular CLI](https://cli.angular.io/).
+
+For existing apps, follow these steps to begin using Angular Material.
+
+## Step 1: Install Angular Material
+
+```bash
+npm install --save @angular/material
+```
+
+## Step 2: Import the Module
+
+Add MaterialModule as an import in your app's root NgModule.
+
+```ts
+import { MaterialModule } from '@angular/material';
+
+@NgModule({
+ ...
+ imports: [MaterialModule],
+ ...
+})
+export class PizzaPartyAppModule { }
+```
+
+## Step 3: Include Theming
+
+Including a theme is **required** to apply all of the core and theme styles to your application.
+
+To get started with a prebuilt theme, include the following in your app's index.html:
+
+```html
+
+```
+
+Note that your app's project structure may have a different relative location for your node_modules.
+
+For more information on theming and instructions on how to create a custom theme, see the [theming guide](./theming.md).
+
+## Step 4: Gesture Support
+
+Some components (`md-slide-toggle`, `md-slider`, `mdTooltip`) rely on
+[HammerJS](http://hammerjs.github.io/) for gestures. In order to get the full feature-set of these
+components, HammerJS must be loaded into the application.
+
+You can add HammerJS to your application via [npm](https://www.npmjs.com/package/hammerjs), a CDN
+(such as the [Google CDN](https://developers.google.com/speed/libraries/#hammerjs)), or served
+directly from your app.
+
+To install via npm, use the following command:
+```bash
+npm install --save hammerjs
+```
+
+After installing, import it on your app's root module.
+```ts
+import 'hammerjs';
+```
+
+## Step 5 (Optional): Add Material Icons
+
+If you want your `md-icon` components to use [Material Icons](https://material.io/icons/), load the font in your `index.html`.
+
+```html
+
+```
+
+For more information on using Material Icons, check out the [Material Icons Guide](https://google.github.io/material-design-icons/).
+
+Note that `md-icon` has support for any font or svg icons, so using Material Icons is just one option.
+
+
+## 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/bundles/material.umd.js',
+ ...
+ }
+});
+```
+
+
+## Sample Angular Material projects
+- [Material Sample App](https://github.com/jelbourn/material2-app)
+- [Angular Connect 2016 Demo](https://github.com/kara/leashed-in)
diff --git a/docs/theming-your-components.md b/guides/theming-your-components.md
similarity index 85%
rename from docs/theming-your-components.md
rename to guides/theming-your-components.md
index d413c639f037..6922749b1b29 100644
--- a/docs/theming-your-components.md
+++ b/guides/theming-your-components.md
@@ -22,10 +22,10 @@ All you need is to create a `@mixin` function in the custom-component-theme.scss
$primary: map-get($theme, primary);
$accent: map-get($theme, accent);
- // Use md-color to extract individual colors from a palette as necessary.
+ // Use mat-color to extract individual colors from a palette as necessary.
.candy-carousel {
- background-color: md-color($primary);
- border-color: md-color($accent, A400);
+ background-color: mat-color($primary);
+ border-color: mat-color($accent, A400);
}
}
```
@@ -53,7 +53,7 @@ Styles that are affected by the theme should be placed in a separated theming fi
## Using colors from a palette
-You can consume the theming functions from the `@angular/material/core/theming/theming` and Material palette vars from `@angular/material/core/theming/palette`. You can use the `md-color` function to extract a specific color from a palette. For example:
+You can consume the theming functions from the `@angular/material/core/theming/theming` and Material palette vars from `@angular/material/core/theming/palette`. You can use the `mat-color` function to extract a specific color from a palette. For example:
```scss
// Import theming functions
@@ -61,9 +61,9 @@ You can consume the theming functions from the `@angular/material/core/theming/t
// Import your custom theme
@import 'src/unicorn-app-theme.scss';
-// Use md-color to extract individual colors from a palette as necessary.
+// Use mat-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);
+ background-color: mat-color($candy-app-primary);
+ border-color: mat-color($candy-app-accent, A400);
}
```
diff --git a/docs/theming.md b/guides/theming.md
similarity index 73%
rename from docs/theming.md
rename to guides/theming.md
index cef94c7b891e..591954ae9ce2 100644
--- a/docs/theming.md
+++ b/guides/theming.md
@@ -13,7 +13,7 @@ a theme consists of:
* A foreground palette: colors for text and icons.
* A background palette: colors used for element backgrounds.
-In Angular Material 2, all theme styles are generated _statically_ at build-time so that your
+In Angular Material, all theme styles are generated _statically_ at build-time so that your
app doesn't have to spend cycles generating theme styles on startup.
[1]: https://material.google.com/style/color.html#color-color-palette
@@ -27,12 +27,12 @@ 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
-in your `style.css` file:
+in your `styles.css` file:
```css
@import '~@angular/material/core/theming/prebuilt/deeppurple-amber.css';
```
-Alternatively, you can just reference the file directly. This would look something like
+Alternatively, you can just reference the file directly. This would look something like:
```html
```
@@ -40,6 +40,28 @@ The actual path will depend on your server setup.
You can also concatenate the file with the rest of your application's css.
+Finally, if your app's content **is not** placed inside of a `md-sidenav-container` element, you
+need to add the `mat-app-background` class to your wrapper element (for example the `body`). This
+ensures that the proper theme background is applied to your page.
+
+#### Theming overlay-based components
+Since certain components (e.g. `dialog`) are inside of a global overlay container, your theme may
+not be applied to them. In order to define the theme that will be used for overlay components, you
+have to specify it on the global `OverlayContainer` instance:
+
+```ts
+import {OverlayContainer} from '@angular/material';
+
+@NgModule({
+ // misc config goes here
+})
+export class YourAppModule {
+ constructor(overlayContainer: OverlayContainer) {
+ overlayContainer.themeClass = 'your-theme';
+ }
+}
+```
+
### Defining a custom theme
When you want more customization than a pre-built theme offers, you can create your own theme file.
@@ -51,19 +73,19 @@ the corresponding styles. A typical theme file will look something like this:
// Include the base styles for Angular Material core. We include this here so that you only
// have to load a single css file for Angular Material in your app.
-@include md-core();
+@include mat-core();
// 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.
-$candy-app-primary: md-palette($md-indigo);
-$candy-app-accent: md-palette($md-pink, A200, A100, A400);
+$candy-app-primary: mat-palette($mat-indigo);
+$candy-app-accent: mat-palette($mat-pink, A200, A100, A400);
// The warn palette is optional (defaults to red).
-$candy-app-warn: md-palette($md-red);
+$candy-app-warn: mat-palette($mat-red);
// Create the theme object (a Sass map containing all of the palettes).
-$candy-app-theme: md-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);
+$candy-app-theme: mat-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
@@ -92,13 +114,13 @@ some selector. For example, we could append the following to the example above t
secondary dark theme:
```scss
.unicorn-dark-theme {
- $dark-primary: md-palette($md-blue-grey);
- $dark-accent: md-palette($md-amber, A200, A100, A400);
- $dark-warn: md-palette($md-deep-orange);
+ $dark-primary: mat-palette($mat-blue-grey);
+ $dark-accent: mat-palette($mat-amber, A200, A100, A400);
+ $dark-warn: mat-palette($mat-deep-orange);
- $dark-theme: md-dark-theme($dark-primary, $dark-accent, $dark-warn);
+ $dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
- @include angular-material-theme($dark-theme);
+ @include angular-material-theme($dark-theme);
}
```
@@ -106,7 +128,7 @@ With this, any element inside of a parent with the `unicorn-dark-theme` class wi
dark theme.
### 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)
+For more details about theming your own components, see [theming-your-components.md](https://github.com/angular/material2/blob/master/guides/theming-your-components.md)
### Future work
* Once CSS variables (custom properties) are available in all the browsers we support,
diff --git a/package.json b/package.json
index 7aecd87d1294..0e7ead41f318 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
- "name": "material2",
- "description": "Material Design components for Angular 2",
+ "name": "material2-srcs",
+ "description": "Material Design components for Angular",
"homepage": "https://github.com/angular/material2",
"bugs": "https://github.com/angular/material2/issues",
"repository": {
@@ -17,92 +17,95 @@
"deploy": "firebase deploy",
"webdriver-manager": "webdriver-manager",
"docs": "gulp docs",
- "api": "gulp api"
+ "api": "gulp api-docs"
},
- "version": "2.0.0-alpha.11-2",
+ "version": "2.0.0-beta.2",
"license": "MIT",
"engines": {
"node": ">= 5.4.1 < 7"
},
"dependencies": {
- "@angular/common": "^2.2.0",
- "@angular/compiler": "^2.2.0",
- "@angular/core": "^2.2.0",
- "@angular/forms": "^2.2.0",
- "@angular/http": "^2.2.0",
- "@angular/platform-browser": "^2.2.0",
+ "@angular/common": "^2.3.0",
+ "@angular/compiler": "^2.3.0",
+ "@angular/core": "^2.3.0",
+ "@angular/forms": "^2.3.0",
+ "@angular/http": "^2.3.0",
+ "@angular/platform-browser": "^2.3.0",
"core-js": "^2.4.1",
- "rxjs": "5.0.0-beta.12",
- "systemjs": "0.19.38",
- "zone.js": "^0.6.23"
- },
- "optionalDependencies": {
- "hammerjs": "^2.0.8"
+ "rxjs": "^5.0.1",
+ "systemjs": "0.19.43",
+ "zone.js": "^0.7.2"
},
"devDependencies": {
- "@angular/compiler-cli": "^2.2.0",
- "@angular/platform-browser-dynamic": "^2.2.0",
- "@angular/platform-server": "^2.2.0",
- "@angular/router": "^3.2.0",
- "@types/glob": "^5.0.29",
- "@types/gulp": "^3.8.29",
- "@types/hammerjs": "^2.0.30",
- "@types/jasmine": "^2.2.31",
- "@types/merge2": "0.0.28",
- "@types/minimist": "^1.1.28",
- "@types/node": "^6.0.34",
- "@types/protractor": "^4.0.0",
- "@types/run-sequence": "0.0.27",
- "@types/rx": "^2.5.33",
- "@types/selenium-webdriver": "2.53.36",
- "axe-core": "^2.0.7",
- "axe-webdriverjs": "^0.4.0",
+ "@angular/compiler-cli": "^2.3.0",
+ "@angular/platform-browser-dynamic": "^2.3.0",
+ "@angular/platform-server": "^2.3.0",
+ "@angular/router": "^3.3.0",
+ "@types/fs-extra": "0.0.37",
+ "@types/glob": "^5.0.30",
+ "@types/gulp": "^3.8.32",
+ "@types/hammerjs": "^2.0.34",
+ "@types/jasmine": "2.5.41",
+ "@types/merge2": "^0.3.29",
+ "@types/minimist": "^1.2.0",
+ "@types/node": "^7.0.5",
+ "@types/run-sequence": "^0.0.28",
+ "@types/rx": "2.5.33",
+ "axe-core": "^2.1.7",
+ "axe-webdriverjs": "^0.5.0",
"conventional-changelog": "^1.1.0",
- "dgeni": "^0.4.2",
- "dgeni-packages": "^0.16.2",
- "express": "^4.14.0",
+ "dgeni": "^0.4.7",
+ "dgeni-packages": "^0.16.5",
+ "firebase-admin": "^4.1.2",
"firebase-tools": "^2.2.1",
- "fs-extra": "^0.26.5",
- "glob": "^6.0.4",
+ "fs-extra": "^2.0.0",
+ "glob": "^7.1.1",
+ "google-cloud": "^0.48.0",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.1",
"gulp-better-rollup": "^1.0.2",
"gulp-clean": "^0.3.2",
- "gulp-clean-css": "^2.3.0",
+ "gulp-clean-css": "^3.0.3",
"gulp-cli": "^1.2.2",
+ "gulp-connect": "^5.0.0",
+ "gulp-dom": "^0.9.17",
+ "gulp-flatten": "^0.3.1",
+ "gulp-highlight-files": "0.0.4",
"gulp-htmlmin": "^3.0.0",
"gulp-if": "^2.0.2",
"gulp-markdown": "^1.2.0",
- "gulp-sass": "^2.3.2",
- "gulp-server-livereload": "^1.8.2",
- "gulp-shell": "^0.5.2",
- "gulp-sourcemaps": "^1.6.0",
+ "gulp-rename": "^1.2.2",
+ "gulp-sass": "^3.1.0",
+ "gulp-sourcemaps": "^2.4.1",
"gulp-transform": "^1.1.0",
- "gulp-typescript": "^2.13.6",
- "jasmine-core": "^2.4.1",
- "karma": "^1.1.1",
- "karma-browserstack-launcher": "^1.0.1",
- "karma-chrome-launcher": "^1.0.1",
- "karma-firefox-launcher": "^1.0.0",
- "karma-jasmine": "^1.0.2",
- "karma-sauce-launcher": "^1.0.0",
- "madge": "^0.6.0",
+ "hammerjs": "^2.0.8",
+ "highlight.js": "^9.9.0",
+ "image-diff": "^1.6.3",
+ "jasmine-core": "^2.5.2",
+ "karma": "^1.5.0",
+ "karma-browserstack-launcher": "^1.2.0",
+ "karma-chrome-launcher": "^2.0.0",
+ "karma-coverage": "^1.1.1",
+ "karma-firefox-launcher": "^1.0.1",
+ "karma-jasmine": "^1.1.0",
+ "karma-sauce-launcher": "^1.1.0",
+ "karma-sourcemap-loader": "^0.3.7",
+ "madge": "^1.6.0",
"merge2": "^1.0.2",
"minimist": "^1.2.0",
- "node-sass": "^3.4.2",
- "protractor": "^4.0.8",
+ "node-sass": "^4.5.0",
+ "protractor": "^5.1.1",
"resolve-bin": "^0.4.0",
"run-sequence": "^1.2.2",
"sass": "^0.5.0",
- "selenium-webdriver": "2.53.3",
- "strip-ansi": "^3.0.0",
- "stylelint": "^7.7.0",
- "symlink-or-copy": "^1.0.1",
- "travis-after-modes": "0.0.6-2",
- "ts-node": "^0.7.3",
- "tslint": "^3.13.0",
- "typedoc": "^0.5.1",
- "typescript": "^2.0.2",
- "which": "^1.2.4"
+ "selenium-webdriver": "^3.1.0",
+ "stylelint": "^7.8.0",
+ "travis-after-modes": "0.0.7",
+ "ts-node": "^2.1.0",
+ "tslint": "^4.4.2",
+ "tslint-no-unused-var": "0.0.6",
+ "typescript": "~2.0.10",
+ "uglify-js": "^2.8.7",
+ "web-animations-js": "^2.2.2"
}
}
diff --git a/scripts/browserstack/start-tunnel.sh b/scripts/browserstack/start-tunnel.sh
index de270502a489..62df1d3f602b 100755
--- a/scripts/browserstack/start-tunnel.sh
+++ b/scripts/browserstack/start-tunnel.sh
@@ -33,8 +33,8 @@ rm $TUNNEL_FILE
ARGS=""
# Set tunnel-id only on Travis, to make local testing easier.
-if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then
- ARGS="$ARGS --local-identifier $TRAVIS_JOB_NUMBER"
+if [ ! -z "$TRAVIS_JOB_ID" ]; then
+ ARGS="$ARGS --local-identifier $TRAVIS_JOB_ID"
fi
echo "Starting Browserstack Local in the background, logging into:"
diff --git a/scripts/ci/after-success.sh b/scripts/ci/after-success.sh
index 37524389d1e3..599f097f2cec 100755
--- a/scripts/ci/after-success.sh
+++ b/scripts/ci/after-success.sh
@@ -10,4 +10,5 @@ cd $(dirname $0)/../..
if [ "$TRAVIS_PULL_REQUEST" = "false" ] && $(npm bin)/travis-after-modes; then
echo "All travis modes passed. Publishing the build artifacts..."
./scripts/release/publish-build-artifacts.sh
-fi
\ No newline at end of file
+ ./scripts/release/publish-docs-content.sh
+fi
diff --git a/scripts/ci/build-and-test.sh b/scripts/ci/build-and-test.sh
index 54b3f5684552..53eca7120f6e 100755
--- a/scripts/ci/build-and-test.sh
+++ b/scripts/ci/build-and-test.sh
@@ -11,15 +11,23 @@ source scripts/ci/sources/mode.sh
source scripts/ci/sources/tunnel.sh
start_tunnel
-
wait_for_tunnel
+
if is_lint; then
$(npm bin)/gulp ci:lint
elif is_e2e; then
$(npm bin)/gulp ci:e2e
-elif is_extract_metadata; then
- $(npm bin)/gulp ci:extract-metadata
+elif is_aot; then
+ $(npm bin)/gulp ci:aot
+elif is_payload; then
+ $(npm bin)/gulp ci:payload
else
$(npm bin)/gulp ci:test
fi
+
+# Upload coverage results if those are present.
+if [ -f dist/coverage/coverage-summary.json ]; then
+ $(npm bin)/gulp ci:coverage
+fi
+
teardown_tunnel
diff --git a/scripts/ci/forbidden-identifiers.js b/scripts/ci/forbidden-identifiers.js
deleted file mode 100755
index 301f22246023..000000000000
--- a/scripts/ci/forbidden-identifiers.js
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/env node
-
-'use strict';
-
-/*
- * The forbidden identifiers script will check for blocked statements and also detect invalid
- * imports of other scope packages.
- *
- * When running against a PR, the script will only analyze the specific amount of commits inside
- * of the Pull Request.
- *
- * By default it checks all source files and fail if any errors were found.
- */
-
-const child_process = require('child_process');
-const fs = require('fs');
-const path = require('path');
-const glob = require('glob').sync;
-
-const blocked_statements = [
- '\\bddescribe\\(',
- '\\bfdescribe\\(',
- '\\biit\\(',
- '\\bfit\\(',
- '\\bxdescribe\\(',
- '\\bxit\\(',
- '\\bdebugger;',
- 'from \\\'rxjs/Rx\\\'',
- '\\r'
-];
-
-const sourceFolders = ['./src', './e2e'];
-const blockedRegex = new RegExp(blocked_statements.join('|'), 'g');
-
-/*
- * Verify that the current PR is not adding any forbidden identifiers.
- * Run the forbidden identifiers check against all sources when not verifying a PR.
- */
-
-findTestFiles()
-
- /* Only match .js or .ts, and remove .d.ts files. */
- .then(files => files.filter(name => /\.(js|ts)$/.test(name) && !/\.d\.ts$/.test(name)))
-
- /* Read content of the filtered files */
- .then(files => files.map(name => ({ name, content: fs.readFileSync(name, 'utf-8') })))
-
- /* Run checks against content of the filtered files. */
- .then(diffList => findErrors(diffList))
-
- /* Groups similar errors to simplify console output */
- .then(errors => groupErrors(errors))
-
- /* Print the resolved errors to the console */
- .then(errors => printErrors(errors))
-
- .catch(err => {
- // An error occurred in this script. Output the error and the stack.
- console.error(err.stack || err);
- process.exit(2);
- });
-
-/**
- * Finds errors inside of changed files by running them against the blocked statements.
- * @param {{name: string, content: string}[]} diffList
- */
-function findErrors(diffList) {
- return diffList.reduce((errors, diffFile) => {
- let fileName = diffFile.name;
- let content = diffFile.content.split('\n');
- let lineNumber = 0;
-
- content.forEach(line => {
- lineNumber++;
-
- let matches = line.match(blockedRegex);
-
- if (matches) {
-
- errors.push({
- fileName,
- lineNumber,
- statement: matches[0]
- });
-
- }
- });
-
- return errors;
-
- }, []);
-}
-
-/**
- * Groups similar errors in the same file which are present over a range of lines.
- * @param {{fileName: string, lineNumber: number, statement: string}[]} errors
- */
-function groupErrors(errors) {
-
- let initialError, initialLine, previousLine;
-
- return errors.filter(error => {
-
- if (initialError && isSimilarError(error)) {
- previousLine = error.lineNumber;
-
- // Overwrite the lineNumber with a string, which indicates the range of lines.
- initialError.lineNumber = `${initialLine}-${previousLine}`;
-
- return false;
- }
-
- initialLine = previousLine = error.lineNumber;
- initialError = error;
-
- return true;
- });
-
- /** Checks whether the given error is similar to the previous one. */
- function isSimilarError(error) {
- return initialError.fileName === error.fileName &&
- initialError.statement === error.statement &&
- previousLine === (error.lineNumber - 1);
- }
-}
-
-/**
- * Prints all errors to the console and terminates the process if errors were present.
- * @param {{fileName: string, lineNumber: number, statement: string}[]} errors
- */
-function printErrors(errors) {
- if (errors.length > 0) {
-
- console.error('Error: You are using one or more blocked statements:\n');
-
- errors.forEach(entry => {
-
- // Stringify the statement to represent line-endings or other unescaped characters.
- let statement = JSON.stringify(entry.statement);
-
- console.error(` ${entry.fileName}@${entry.lineNumber}, Statement: ${statement}.\n`);
- });
-
- // Exit the process with an error exit code to notify the CI.
- process.exit(1);
- }
-}
-
-/**
- * Resolves all files, which should run against the forbidden identifiers check.
- * @return {Promise.>} Files to be checked.
- */
-function findTestFiles() {
- if (process.env['TRAVIS_PULL_REQUEST']) {
- return findChangedFiles();
- }
-
- let files = sourceFolders.map(folder => {
- return glob(`${folder}/**/*`);
- }).reduce((files, fileSet) => files.concat(fileSet), []);
-
- return Promise.resolve(files);
-}
-
-/**
- * List all the files that have been changed or added in the last commit range.
- * @returns {Promise.>} Resolves with a list of files that are added or changed.
- */
-function findChangedFiles() {
- let commitRange = process.env['TRAVIS_COMMIT_RANGE'];
-
- return exec(`git diff --name-status ${commitRange} ${sourceFolders.join(' ')}`)
- .then(rawDiff => {
- return rawDiff
- .split('\n')
- .filter(line => {
- // Status: C## => Copied (##% confident)
- // R## => Renamed (##% confident)
- // D => Deleted
- // M => Modified
- // A => Added
- return line.match(/([CR][0-9]*|[AM])\s+/);
- })
- .map(line => line.split(/\s+/, 2)[1]);
- });
-}
-
-/**
- * Executes a process command and wraps it inside of a promise.
- * @returns {Promise.}
- */
-function exec(cmd) {
- return new Promise(function(resolve, reject) {
- child_process.exec(cmd, function(err, stdout /*, stderr */) {
- if (err) {
- reject(err);
- } else {
- resolve(stdout);
- }
- });
- });
-}
diff --git a/scripts/ci/sources/mode.sh b/scripts/ci/sources/mode.sh
index 7d31a010ceae..ca22c8d90b0f 100644
--- a/scripts/ci/sources/mode.sh
+++ b/scripts/ci/sources/mode.sh
@@ -9,6 +9,10 @@ is_lint() {
[[ "$MODE" = lint ]]
}
-is_extract_metadata() {
- [[ "$MODE" = extract_metadata ]]
+is_aot() {
+ [[ "$MODE" = aot ]]
}
+
+is_payload() {
+ [[ "$MODE" = payload ]]
+}
\ No newline at end of file
diff --git a/scripts/release/copy-docs.sh b/scripts/release/copy-docs.sh
new file mode 100755
index 000000000000..a18c5acaddcc
--- /dev/null
+++ b/scripts/release/copy-docs.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Copy docs to material docs site
+
+# Run this script after `gulp docs`
+# Need to specify destination folder
+# Use OVERVIEW.html when possible. If there's no OVERVIEW file exists, use README.html
+
+usage='Usage: copy-docs.sh $destinationFolder'
+if [ $# -ne 1 ]; then
+ echo "Missing destination folder. $usage"
+ exit
+fi
+
+originFolder=./dist/docs/
+destFolder=$1
+
+if [ ! -w $destFolder ]; then
+ echo "Invalid destination folder. $usage"
+ exit
+fi
+
+for file in $originFolder*
+do
+ name=${file#$originFolder}
+ overviewFile=$originFolder$name/$name.html
+ readmeFile=$originFolder$name/README.html
+ destFile=$destFolder/$name.html
+ if [ -f $overviewFile ]; then
+ cp $overviewFile $destFile
+ echo "Copied $overviewFile to $destFile"
+ elif [ -f $readmeFile ]; then
+ cp $readmeFile $destFile
+ echo "Copied $readmeFile to $destFile"
+ fi
+done
diff --git a/scripts/release/publish-build-artifacts.sh b/scripts/release/publish-build-artifacts.sh
index 4e7dc3886044..1fb1f9d96d88 100755
--- a/scripts/release/publish-build-artifacts.sh
+++ b/scripts/release/publish-build-artifacts.sh
@@ -42,7 +42,7 @@ git config user.name "$commitAuthorName"
git config user.email "$commitAuthorEmail"
git config credential.helper "store --file=.git/credentials"
-echo "https://${MATERIAL2_BUILDS_TOKEN}:@github.com" > .git/credentials
+echo "https://${MATERIAL2_DOCS_CONTENT_TOKEN}:@github.com" > .git/credentials
git add -A
git commit -m "$commitMessage"
diff --git a/scripts/release/publish-docs-content.sh b/scripts/release/publish-docs-content.sh
new file mode 100755
index 000000000000..591569941afd
--- /dev/null
+++ b/scripts/release/publish-docs-content.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+
+# Publish material2 docs assets to the material2-docs-content repo
+# material.angular.io will pull from this assets repo to get the latest docs
+
+cd "$(dirname $0)/../../"
+
+docsPath="./dist/docs"
+repoPath="/tmp/material2-docs-content"
+repoUrl="https://github.com/angular/material2-docs-content"
+examplesSource="./dist/docs/examples"
+
+# If the docs directory is not present, generate docs
+if [ ! -d $docsPath ]; then
+ $(npm bin)/gulp docs
+fi
+
+# Get git meta info for commit
+commitSha="$(git rev-parse --short HEAD)"
+commitAuthorName="$(git --no-pager show -s --format='%an' HEAD)"
+commitAuthorEmail="$(git --no-pager show -s --format='%ae' HEAD)"
+commitMessage="$(git log --oneline -n 1)"
+
+# create directory and clone test repo
+rm -rf $repoPath
+mkdir -p $repoPath
+git clone $repoUrl $repoPath
+
+# Clean out repo directory and copy contents of dist/docs into it
+rm -rf $repoPath/*
+mkdir $repoPath/overview
+mkdir $repoPath/guides
+mkdir $repoPath/api
+mkdir $repoPath/examples
+
+# Move api files over to $repoPath/api
+cp -r $docsPath/api/* $repoPath/api
+
+# Flatten the markdown docs structure and move it into $repoPath/overview
+overviewFiles=$docsPath/markdown/
+for filename in $overviewFiles*
+do
+ if [ -d $filename ]; then
+ for _ in $filename/*
+ do
+ markdownFile=${filename#$overviewFiles}.html
+ # Filename should be same as folder name with .html extension
+ if [ -e $filename/$markdownFile ]; then
+ cp -r $filename/$markdownFile $repoPath/overview/
+ fi
+ done
+ fi
+done
+
+# Move guide files over to $repoPath/guides
+for filename in $overviewFiles*
+do
+ if [ -f $filename ]; then
+ cp -r $filename $repoPath/guides
+ fi
+done
+
+# Move highlighted examples into $repoPath
+cp -r $examplesSource/* $repoPath/examples
+
+# Copies assets over to the docs-content repository.
+cp LICENSE $repoPath/
+
+# Push content to repo
+cd $repoPath
+git config user.name "$commitAuthorName"
+git config user.email "$commitAuthorEmail"
+git config credential.helper "store --file=.git/credentials"
+
+echo "https://${MATERIAL2_BUILDS_TOKEN}:@github.com" > .git/credentials
+
+git add -A
+git commit -m "$commitMessage"
+git tag "$commitSha"
+git push origin master --tags
diff --git a/scripts/saucelabs/start-tunnel.sh b/scripts/saucelabs/start-tunnel.sh
index ec8f1b550d03..4110fe34aa91 100755
--- a/scripts/saucelabs/start-tunnel.sh
+++ b/scripts/saucelabs/start-tunnel.sh
@@ -2,58 +2,43 @@
set -e -o pipefail
-# Setup and start Sauce Connect for your TravisCI build
-# This script requires your .travis.yml to include the following two private env variables:
-# SAUCE_USERNAME
-# SAUCE_ACCESS_KEY
-# Follow the steps at https://saucelabs.com/opensource/travis to set that up.
-#
-# Curl and run this script as part of your .travis.yml before_script section:
-# before_script:
-# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
-
-CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
-CONNECT_DOWNLOAD="sc-latest-linux.tar.gz"
-
-CONNECT_LOG="$LOGS_DIR/sauce-connect"
-CONNECT_STDOUT="$LOGS_DIR/sauce-connect.stdout"
-CONNECT_STDERR="$LOGS_DIR/sauce-connect.stderr"
-
-# Get the appropriate URL for downloading Sauce Connect
-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.4.2-osx.zip"
-else
- # Otherwise, default to Linux for Travis-CI
- CONNECT_URL="https://saucelabs.com/downloads/sc-4.4.2-linux.tar.gz"
-fi
-mkdir -p $CONNECT_DIR
-cd $CONNECT_DIR
-curl $CONNECT_URL -o $CONNECT_DOWNLOAD 2> /dev/null 1> /dev/null
-mkdir sauce-connect
-tar --extract --file=$CONNECT_DOWNLOAD --strip-components=1 --directory=sauce-connect > /dev/null
-rm $CONNECT_DOWNLOAD
+TUNNEL_FILE="sc-4.4.3-linux.tar.gz"
+TUNNEL_URL="https://saucelabs.com/downloads/$TUNNEL_FILE"
+TUNNEL_DIR="/tmp/saucelabs-connect"
+TUNNEL_LOG="$LOGS_DIR/sauce-connect"
SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
+# Cleanup and create the folder structure for the tunnel connector.
+rm -rf $TUNNEL_DIR $BROWSER_PROVIDER_READY_FILE
+mkdir -p $TUNNEL_DIR
+
+cd $TUNNEL_DIR
+
+# Download the saucelabs connect binaries.
+curl $TUNNEL_URL -o $TUNNEL_FILE 2> /dev/null 1> /dev/null
+
+# Extract the saucelabs connect binaries from the tarball.
+mkdir -p sauce-connect
+tar --extract --file=$TUNNEL_FILE --strip-components=1 --directory=sauce-connect > /dev/null
+
+# Cleanup the download directory.
+rm $TUNNEL_FILE
+
ARGS=""
# Set tunnel-id only on Travis, to make local testing easier.
-if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then
- ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_NUMBER"
+if [ ! -z "$TRAVIS_JOB_ID" ]; then
+ ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_ID"
fi
if [ ! -z "$BROWSER_PROVIDER_READY_FILE" ]; then
ARGS="$ARGS --readyfile $BROWSER_PROVIDER_READY_FILE"
fi
-
echo "Starting Sauce Connect in the background, logging into:"
-echo " $CONNECT_LOG"
-echo " $CONNECT_STDOUT"
-echo " $CONNECT_STDERR"
+echo " $TUNNEL_LOG"
echo " ---"
echo " $ARGS"
-sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS \
- --logfile $CONNECT_LOG 2> $CONNECT_STDERR 1> $CONNECT_STDOUT &
+
+sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS --logfile $TUNNEL_LOG &
\ No newline at end of file
diff --git a/src/demo-app/autocomplete/autocomplete-demo.html b/src/demo-app/autocomplete/autocomplete-demo.html
index 0745c4ac4ea0..ba732cbc781e 100644
--- a/src/demo-app/autocomplete/autocomplete-demo.html
+++ b/src/demo-app/autocomplete/autocomplete-demo.html
@@ -1,3 +1,56 @@
+Space above cards:
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue.
+ Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus.
+ In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec,
+ feugiat ultricies mi. Aliquam erat volutpat. Nam placerat, tortor in ultrices porttitor,
+ orci enim rutrum enim, vel tempor sapien arcu a tellus. Vivamus convallis sodales ante varius
+ gravida. Curabitur a purus vel augue ultrices ultricies id a nisl. Nullam malesuada consequat
+ diam, a facilisis tortor volutpat et. Sed urna dolor, aliquet vitae posuere vulputate, euismod
+ ac lorem. Sed felis risus, pulvinar at interdum quis, vehicula sed odio. Phasellus in enim
+ venenatis, iaculis tortor eu, bibendum ante. Donec ac tellus dictum neque volutpat blandit.
+ Praesent efficitur faucibus risus, ac auctor purus porttitor vitae. Phasellus ornare dui nec
+ orci posuere, nec luctus mauris semper.
+
+
+ Morbi viverra, ante vel aliquet tincidunt, leo dolor pharetra quam, at semper massa orci nec
+ magna. Donec posuere nec sapien sed laoreet. Etiam cursus nunc in condimentum facilisis.
+ Etiam in tempor tortor. Vivamus faucibus egestas enim, at convallis diam pulvinar vel.
+ Cras ac orci eget nisi maximus cursus. Nunc urna libero, viverra sit amet nisl at, hendrerit
+ tempor turpis. Maecenas facilisis convallis mi vel tempor. Nullam vitae nunc leo. Cras sed
+ nisl consectetur, rhoncus sapien sit amet, tempus sapien.
+
+
+ Integer turpis erat, porttitor vitae mi faucibus, laoreet interdum tellus. Curabitur posuere
+ molestie dictum. Morbi eget congue risus, quis rhoncus quam. Suspendisse vitae hendrerit erat,
+ at posuere mi. Cras eu fermentum nunc. Sed id ante eu orci commodo volutpat non ac est.
+ Praesent ligula diam, congue eu enim scelerisque, finibus commodo lectus.
+
+
+
+
+
+
+
+
+ Delete Tab
+
+
+
+
+
+
+
Tab Group Demo - Dynamic Height
+
+
+
+ {{tab.label}}
+
{{tab.content}}
@@ -77,101 +134,56 @@
Tab Group Demo - Dynamic Tabs
-
-
-
- Delete Tab
-
-
-
-
-
-
Tab Group Demo - Dynamic Height
-
-
-
- {{tab.label}}
- {{tab.content}}
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue.
- Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus.
- In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec,
- feugiat ultricies mi. Aliquam erat volutpat. Nam placerat, tortor in ultrices porttitor,
- orci enim rutrum enim, vel tempor sapien arcu a tellus. Vivamus convallis sodales ante varius
- gravida. Curabitur a purus vel augue ultrices ultricies id a nisl. Nullam malesuada consequat
- diam, a facilisis tortor volutpat et. Sed urna dolor, aliquet vitae posuere vulputate, euismod
- ac lorem. Sed felis risus, pulvinar at interdum quis, vehicula sed odio. Phasellus in enim
- venenatis, iaculis tortor eu, bibendum ante. Donec ac tellus dictum neque volutpat blandit.
- Praesent efficitur faucibus risus, ac auctor purus porttitor vitae. Phasellus ornare dui nec
- orci posuere, nec luctus mauris semper.
-
-
- Morbi viverra, ante vel aliquet tincidunt, leo dolor pharetra quam, at semper massa orci nec
- magna. Donec posuere nec sapien sed laoreet. Etiam cursus nunc in condimentum facilisis.
- Etiam in tempor tortor. Vivamus faucibus egestas enim, at convallis diam pulvinar vel.
- Cras ac orci eget nisi maximus cursus. Nunc urna libero, viverra sit amet nisl at, hendrerit
- tempor turpis. Maecenas facilisis convallis mi vel tempor. Nullam vitae nunc leo. Cras sed
- nisl consectetur, rhoncus sapien sit amet, tempus sapien.
-
-
- Integer turpis erat, porttitor vitae mi faucibus, laoreet interdum tellus. Curabitur posuere
- molestie dictum. Morbi eget congue risus, quis rhoncus quam. Suspendisse vitae hendrerit erat,
- at posuere mi. Cras eu fermentum nunc. Sed id ante eu orci commodo volutpat non ac est.
- Praesent ligula diam, congue eu enim scelerisque, finibus commodo lectus.
+
+
+
-
-
-
-
-
Tab Group Demo - Fixed Height
-
+
{{tab.label}}
- {{tab.content}}
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue.
- Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus.
- In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec,
- feugiat ultricies mi. Aliquam erat volutpat. Nam placerat, tortor in ultrices porttitor,
- orci enim rutrum enim, vel tempor sapien arcu a tellus. Vivamus convallis sodales ante varius
- gravida. Curabitur a purus vel augue ultrices ultricies id a nisl. Nullam malesuada consequat
- diam, a facilisis tortor volutpat et. Sed urna dolor, aliquet vitae posuere vulputate, euismod
- ac lorem. Sed felis risus, pulvinar at interdum quis, vehicula sed odio. Phasellus in enim
- venenatis, iaculis tortor eu, bibendum ante. Donec ac tellus dictum neque volutpat blandit.
- Praesent efficitur faucibus risus, ac auctor purus porttitor vitae. Phasellus ornare dui nec
- orci posuere, nec luctus mauris semper.
+
+ {{tab.content}}
- Morbi viverra, ante vel aliquet tincidunt, leo dolor pharetra quam, at semper massa orci nec
- magna. Donec posuere nec sapien sed laoreet. Etiam cursus nunc in condimentum facilisis.
- Etiam in tempor tortor. Vivamus faucibus egestas enim, at convallis diam pulvinar vel.
- Cras ac orci eget nisi maximus cursus. Nunc urna libero, viverra sit amet nisl at, hendrerit
- tempor turpis. Maecenas facilisis convallis mi vel tempor. Nullam vitae nunc leo. Cras sed
- nisl consectetur, rhoncus sapien sit amet, tempus sapien.
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue.
+ Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus.
+ In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec,
+ feugiat ultricies mi. Aliquam erat volutpat. Nam placerat, tortor in ultrices porttitor,
+ orci enim rutrum enim, vel tempor sapien arcu a tellus. Vivamus convallis sodales ante varius
+ gravida. Curabitur a purus vel augue ultrices ultricies id a nisl. Nullam malesuada consequat
+ diam, a facilisis tortor volutpat et. Sed urna dolor, aliquet vitae posuere vulputate, euismod
+ ac lorem. Sed felis risus, pulvinar at interdum quis, vehicula sed odio. Phasellus in enim
+ venenatis, iaculis tortor eu, bibendum ante. Donec ac tellus dictum neque volutpat blandit.
+ Praesent efficitur faucibus risus, ac auctor purus porttitor vitae. Phasellus ornare dui nec
+ orci posuere, nec luctus mauris semper.
+
+
+ Morbi viverra, ante vel aliquet tincidunt, leo dolor pharetra quam, at semper massa orci nec
+ magna. Donec posuere nec sapien sed laoreet. Etiam cursus nunc in condimentum facilisis.
+ Etiam in tempor tortor. Vivamus faucibus egestas enim, at convallis diam pulvinar vel.
+ Cras ac orci eget nisi maximus cursus. Nunc urna libero, viverra sit amet nisl at, hendrerit
+ tempor turpis. Maecenas facilisis convallis mi vel tempor. Nullam vitae nunc leo. Cras sed
+ nisl consectetur, rhoncus sapien sit amet, tempus sapien.
+
+
+ Integer turpis erat, porttitor vitae mi faucibus, laoreet interdum tellus. Curabitur posuere
+ molestie dictum. Morbi eget congue risus, quis rhoncus quam. Suspendisse vitae hendrerit erat,
+ at posuere mi. Cras eu fermentum nunc. Sed id ante eu orci commodo volutpat non ac est.
+ Praesent ligula diam, congue eu enim scelerisque, finibus commodo lectus.
+
- Integer turpis erat, porttitor vitae mi faucibus, laoreet interdum tellus. Curabitur posuere
- molestie dictum. Morbi eget congue risus, quis rhoncus quam. Suspendisse vitae hendrerit erat,
- at posuere mi. Cras eu fermentum nunc. Sed id ante eu orci commodo volutpat non ac est.
- Praesent ligula diam, congue eu enim scelerisque, finibus commodo lectus.
+
+
+
+ md-raised-button
+ color="primary"
+ [mdTooltip]="message"
+ [mdTooltipPosition]="position"
+ [mdTooltipShowDelay]="showDelay"
+ [mdTooltipHideDelay]="hideDelay">
Mouse over to see the tooltip
-
+
Scroll down while tooltip is open to see it hide automatically
+ The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from Japan.
+ A small, agile dog that copes very well with mountainous terrain, the Shiba Inu was originally
+ bred for hunting.
+
+
+
+ LIKE
+ SHARE
+
+
diff --git a/src/examples/card-fancy/card-fancy-example.ts b/src/examples/card-fancy/card-fancy-example.ts
new file mode 100644
index 000000000000..8e19840d7cd4
--- /dev/null
+++ b/src/examples/card-fancy/card-fancy-example.ts
@@ -0,0 +1,9 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'card-fancy-example',
+ templateUrl: './card-fancy-example.html',
+ styleUrls: ['./card-fancy-example.css'],
+})
+export class CardFancyExample {}
diff --git a/src/examples/card-overview/card-overview-example.css b/src/examples/card-overview/card-overview-example.css
new file mode 100644
index 000000000000..7432308753e6
--- /dev/null
+++ b/src/examples/card-overview/card-overview-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/src/examples/card-overview/card-overview-example.html b/src/examples/card-overview/card-overview-example.html
new file mode 100644
index 000000000000..5e0c2b6dfe13
--- /dev/null
+++ b/src/examples/card-overview/card-overview-example.html
@@ -0,0 +1 @@
+Simple card
diff --git a/src/examples/card-overview/card-overview-example.ts b/src/examples/card-overview/card-overview-example.ts
new file mode 100644
index 000000000000..55fc9a690d54
--- /dev/null
+++ b/src/examples/card-overview/card-overview-example.ts
@@ -0,0 +1,8 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'card-overview-example',
+ templateUrl: './card-overview-example.html',
+})
+export class CardOverviewExample {}
diff --git a/src/examples/checkbox-configurable/checkbox-configurable-example.css b/src/examples/checkbox-configurable/checkbox-configurable-example.css
new file mode 100644
index 000000000000..558293fbb5b8
--- /dev/null
+++ b/src/examples/checkbox-configurable/checkbox-configurable-example.css
@@ -0,0 +1,14 @@
+.example-h2 {
+ margin: 10px;
+}
+
+.example-section {
+ display: flex;
+ align-content: center;
+ align-items: center;
+ height: 60px;
+}
+
+.example-margin {
+ margin: 0 10px;
+}
diff --git a/src/examples/checkbox-configurable/checkbox-configurable-example.html b/src/examples/checkbox-configurable/checkbox-configurable-example.html
new file mode 100644
index 000000000000..5876c05c6c46
--- /dev/null
+++ b/src/examples/checkbox-configurable/checkbox-configurable-example.html
@@ -0,0 +1,40 @@
+
+
+
+ Lorem ipsum dolor sit amet, pede a libero aenean phasellus, lectus metus sint ut risus,
+ fusce vel in pellentesque. Nisl rutrum etiam morbi consectetuer tempor magna, aenean nullam
+ nunc id, neque vivamus interdum sociis nulla scelerisque sem, dolor id wisi turpis magna
+ aliquam magna. Risus accumsan hac eget etiam donec sed, senectus erat mattis quam, tempor
+ vel urna occaecat cras, metus urna augue nec at. Et morbi amet dui praesent, nec eu at,
+ ligula ipsum dui sollicitudin, quis nisl massa viverra ligula, mauris fermentum orci arcu
+ enim fringilla. Arcu erat nulla in aenean lacinia ullamcorper, urna ante nam et sagittis,
+ tristique vehicula nibh ipsum vivamus, proin proin. Porta commodo nibh quis libero amet.
+ Taciti dui, sapien consectetuer.
+
+
+
+ add
+
+
+ Lorem ipsum dolor sit amet, pede a libero aenean phasellus, lectus metus sint ut risus, fusce
+ vel in pellentesque. Nisl rutrum etiam morbi consectetuer tempor magna, aenean nullam nunc id,
+ neque vivamus interdum sociis nulla scelerisque sem, dolor id wisi turpis magna aliquam magna.
+ Risus accumsan hac eget etiam donec sed, senectus erat mattis quam, tempor vel urna occaecat
+ cras, metus urna augue nec at. Et morbi amet dui praesent, nec eu at, ligula ipsum dui
+ sollicitudin, quis nisl massa viverra ligula, mauris fermentum orci arcu enim fringilla. Arcu
+ erat nulla in aenean lacinia ullamcorper, urna ante nam et sagittis, tristique vehicula nibh
+ ipsum vivamus, proin proin. Porta commodo nibh quis libero amet. Taciti dui, sapien
+ consectetuer.
+
+
+
+
+
+
diff --git a/src/examples/slider-configurable/slider-configurable-example.ts b/src/examples/slider-configurable/slider-configurable-example.ts
new file mode 100644
index 000000000000..933a9dee7311
--- /dev/null
+++ b/src/examples/slider-configurable/slider-configurable-example.ts
@@ -0,0 +1,29 @@
+import {Component, ViewEncapsulation} from '@angular/core';
+
+
+@Component({
+ selector: 'slider-configurable-example',
+ templateUrl: './slider-configurable-example.html',
+ styleUrls: ['./slider-configurable-example.css'],
+ encapsulation: ViewEncapsulation.None,
+})
+export class SliderConfigurableExample {
+ autoTicks = false;
+ disabled = false;
+ invert = false;
+ max = 100;
+ min = 0;
+ showTicks = false;
+ step = 1;
+ thumbLabel = false;
+ value = 0;
+ vertical = false;
+
+ get tickInterval(): number | 'auto' {
+ return this.showTicks ? (this.autoTicks ? 'auto' : this._tickInterval) : null;
+ }
+ set tickInterval(v) {
+ this._tickInterval = Number(v);
+ }
+ private _tickInterval = 1;
+}
diff --git a/src/examples/slider-overview/slider-overview-example.css b/src/examples/slider-overview/slider-overview-example.css
new file mode 100644
index 000000000000..8dfe08ccc21d
--- /dev/null
+++ b/src/examples/slider-overview/slider-overview-example.css
@@ -0,0 +1,4 @@
+/** No CSS for this example */
+md-slider {
+ width: 300px;
+}
diff --git a/src/examples/slider-overview/slider-overview-example.html b/src/examples/slider-overview/slider-overview-example.html
new file mode 100644
index 000000000000..9a92c8f867dd
--- /dev/null
+++ b/src/examples/slider-overview/slider-overview-example.html
@@ -0,0 +1 @@
+
diff --git a/src/examples/slider-overview/slider-overview-example.ts b/src/examples/slider-overview/slider-overview-example.ts
new file mode 100644
index 000000000000..1f020fd662ff
--- /dev/null
+++ b/src/examples/slider-overview/slider-overview-example.ts
@@ -0,0 +1,9 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'slider-overview-example',
+ templateUrl: './slider-overview-example.html',
+ styleUrls: ['./slider-overview-example.css'],
+})
+export class SliderOverviewExample {}
diff --git a/src/examples/snack-bar-component/snack-bar-component-example-snack.css b/src/examples/snack-bar-component/snack-bar-component-example-snack.css
new file mode 100644
index 000000000000..fa7dc6749acf
--- /dev/null
+++ b/src/examples/snack-bar-component/snack-bar-component-example-snack.css
@@ -0,0 +1,3 @@
+.example-pizza-party {
+ color: hotpink;
+}
diff --git a/src/examples/snack-bar-component/snack-bar-component-example-snack.html b/src/examples/snack-bar-component/snack-bar-component-example-snack.html
new file mode 100644
index 000000000000..d43b91e9a961
--- /dev/null
+++ b/src/examples/snack-bar-component/snack-bar-component-example-snack.html
@@ -0,0 +1,3 @@
+
+ 🍕🍕🍕🍕🍕 Pizza party!!! 🍕🍕🍕🍕🍕
+
diff --git a/src/examples/snack-bar-component/snack-bar-component-example.html b/src/examples/snack-bar-component/snack-bar-component-example.html
new file mode 100644
index 000000000000..69fe01bc3dcb
--- /dev/null
+++ b/src/examples/snack-bar-component/snack-bar-component-example.html
@@ -0,0 +1,3 @@
+
+ Pizza party
+
diff --git a/src/examples/snack-bar-component/snack-bar-component-example.ts b/src/examples/snack-bar-component/snack-bar-component-example.ts
new file mode 100644
index 000000000000..03ef19e8a70d
--- /dev/null
+++ b/src/examples/snack-bar-component/snack-bar-component-example.ts
@@ -0,0 +1,25 @@
+import {Component} from '@angular/core';
+import {MdSnackBar} from '@angular/material';
+
+
+@Component({
+ selector: 'snack-bar-component-example',
+ templateUrl: './snack-bar-component-example.html',
+})
+export class SnackBarComponentExample {
+ constructor(public snackBar: MdSnackBar) {}
+
+ openSnackBar() {
+ this.snackBar.openFromComponent(PizzaPartyComponent, {
+ duration: 500,
+ });
+ }
+}
+
+
+@Component({
+ selector: 'snack-bar-component-example-snack',
+ templateUrl: './snack-bar-component-example-snack.html',
+ styleUrls: ['./snack-bar-component-example-snack.css'],
+})
+export class PizzaPartyComponent {}
diff --git a/src/examples/snack-bar-overview/snack-bar-overview-example.css b/src/examples/snack-bar-overview/snack-bar-overview-example.css
new file mode 100644
index 000000000000..7432308753e6
--- /dev/null
+++ b/src/examples/snack-bar-overview/snack-bar-overview-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/src/examples/snack-bar-overview/snack-bar-overview-example.html b/src/examples/snack-bar-overview/snack-bar-overview-example.html
new file mode 100644
index 000000000000..91cb38c8b317
--- /dev/null
+++ b/src/examples/snack-bar-overview/snack-bar-overview-example.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+Show snack-bar
diff --git a/src/examples/snack-bar-overview/snack-bar-overview-example.ts b/src/examples/snack-bar-overview/snack-bar-overview-example.ts
new file mode 100644
index 000000000000..312de83ea671
--- /dev/null
+++ b/src/examples/snack-bar-overview/snack-bar-overview-example.ts
@@ -0,0 +1,17 @@
+import {Component} from '@angular/core';
+import {MdSnackBar} from '@angular/material';
+
+
+@Component({
+ selector: 'snack-bar-overview-example',
+ templateUrl: './snack-bar-overview-example.html',
+})
+export class SnackBarOverviewExample {
+ constructor(public snackBar: MdSnackBar) {}
+
+ openSnackBar(message: string, action: string) {
+ this.snackBar.open(message, action, {
+ duration: 2000,
+ });
+ }
+}
diff --git a/src/examples/tabs-overview/tabs-overview-example.css b/src/examples/tabs-overview/tabs-overview-example.css
new file mode 100644
index 000000000000..7432308753e6
--- /dev/null
+++ b/src/examples/tabs-overview/tabs-overview-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/src/examples/tabs-overview/tabs-overview-example.html b/src/examples/tabs-overview/tabs-overview-example.html
new file mode 100644
index 000000000000..173ece5dc477
--- /dev/null
+++ b/src/examples/tabs-overview/tabs-overview-example.html
@@ -0,0 +1,4 @@
+
+ Content 1
+ Content 2
+
diff --git a/src/examples/tabs-overview/tabs-overview-example.ts b/src/examples/tabs-overview/tabs-overview-example.ts
new file mode 100644
index 000000000000..4f222c112621
--- /dev/null
+++ b/src/examples/tabs-overview/tabs-overview-example.ts
@@ -0,0 +1,8 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'tabs-overview-example',
+ templateUrl: './tabs-overview-example.html',
+})
+export class TabsOverviewExample {}
diff --git a/src/examples/tabs-template-label/tabs-template-label-example.css b/src/examples/tabs-template-label/tabs-template-label-example.css
new file mode 100644
index 000000000000..7432308753e6
--- /dev/null
+++ b/src/examples/tabs-template-label/tabs-template-label-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/src/examples/tabs-template-label/tabs-template-label-example.html b/src/examples/tabs-template-label/tabs-template-label-example.html
new file mode 100644
index 000000000000..bde67b8e9138
--- /dev/null
+++ b/src/examples/tabs-template-label/tabs-template-label-example.html
@@ -0,0 +1 @@
+More examples coming soon!
diff --git a/src/examples/tabs-template-label/tabs-template-label-example.ts b/src/examples/tabs-template-label/tabs-template-label-example.ts
new file mode 100644
index 000000000000..7015b1f74182
--- /dev/null
+++ b/src/examples/tabs-template-label/tabs-template-label-example.ts
@@ -0,0 +1,8 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'tabs-template-label-example',
+ templateUrl: './tabs-template-label-example.html',
+})
+export class TabsTemplateLabelExample {}
diff --git a/src/examples/toolbar-multirow/toolbar-multirow-example.css b/src/examples/toolbar-multirow/toolbar-multirow-example.css
new file mode 100644
index 000000000000..d7c40156ba97
--- /dev/null
+++ b/src/examples/toolbar-multirow/toolbar-multirow-example.css
@@ -0,0 +1,7 @@
+.example-icon {
+ padding: 0 14px;
+}
+
+.example-spacer {
+ flex: 1 1 auto;
+}
diff --git a/src/examples/toolbar-multirow/toolbar-multirow-example.html b/src/examples/toolbar-multirow/toolbar-multirow-example.html
new file mode 100644
index 000000000000..9b178a21249f
--- /dev/null
+++ b/src/examples/toolbar-multirow/toolbar-multirow-example.html
@@ -0,0 +1,16 @@
+
+ Custom Toolbar
+
+
+ Second Line
+
+ verified_user
+
+
+
+ Third Line
+
+ favorite
+ delete
+
+
diff --git a/src/examples/toolbar-multirow/toolbar-multirow-example.ts b/src/examples/toolbar-multirow/toolbar-multirow-example.ts
new file mode 100644
index 000000000000..132b98174f67
--- /dev/null
+++ b/src/examples/toolbar-multirow/toolbar-multirow-example.ts
@@ -0,0 +1,9 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'toolbar-multirow-example',
+ templateUrl: './toolbar-multirow-example.html',
+ styleUrls: ['./toolbar-multirow-example.css'],
+})
+export class ToolbarMultirowExample {}
diff --git a/src/examples/toolbar-overview/toolbar-overview-example.css b/src/examples/toolbar-overview/toolbar-overview-example.css
new file mode 100644
index 000000000000..7432308753e6
--- /dev/null
+++ b/src/examples/toolbar-overview/toolbar-overview-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/src/examples/toolbar-overview/toolbar-overview-example.html b/src/examples/toolbar-overview/toolbar-overview-example.html
new file mode 100644
index 000000000000..bf8cc3998630
--- /dev/null
+++ b/src/examples/toolbar-overview/toolbar-overview-example.html
@@ -0,0 +1 @@
+My App
diff --git a/src/examples/toolbar-overview/toolbar-overview-example.ts b/src/examples/toolbar-overview/toolbar-overview-example.ts
new file mode 100644
index 000000000000..6919aca4f3fc
--- /dev/null
+++ b/src/examples/toolbar-overview/toolbar-overview-example.ts
@@ -0,0 +1,8 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'toolbar-overview-example',
+ templateUrl: './toolbar-overview-example.html',
+})
+export class ToolbarOverviewExample {}
diff --git a/src/examples/tooltip-overview/tooltip-overview-example.css b/src/examples/tooltip-overview/tooltip-overview-example.css
new file mode 100644
index 000000000000..7432308753e6
--- /dev/null
+++ b/src/examples/tooltip-overview/tooltip-overview-example.css
@@ -0,0 +1 @@
+/** No CSS for this example */
diff --git a/src/examples/tooltip-overview/tooltip-overview-example.html b/src/examples/tooltip-overview/tooltip-overview-example.html
new file mode 100644
index 000000000000..8319a8545846
--- /dev/null
+++ b/src/examples/tooltip-overview/tooltip-overview-example.html
@@ -0,0 +1 @@
+I have a tooltip
diff --git a/src/examples/tooltip-overview/tooltip-overview-example.ts b/src/examples/tooltip-overview/tooltip-overview-example.ts
new file mode 100644
index 000000000000..cf9eefc94557
--- /dev/null
+++ b/src/examples/tooltip-overview/tooltip-overview-example.ts
@@ -0,0 +1,8 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'tooltip-overview-example',
+ templateUrl: './tooltip-overview-example.html',
+})
+export class TooltipOverviewExample {}
diff --git a/src/examples/tooltip-position/tooltip-position-example.css b/src/examples/tooltip-position/tooltip-position-example.css
new file mode 100644
index 000000000000..04ec59dd1fc7
--- /dev/null
+++ b/src/examples/tooltip-position/tooltip-position-example.css
@@ -0,0 +1,9 @@
+.example-tooltip-host {
+ display: inline-flex;
+ align-items: center;
+ margin: 50px;
+}
+
+.example-select {
+ margin: 0 10px;
+}
diff --git a/src/examples/tooltip-position/tooltip-position-example.html b/src/examples/tooltip-position/tooltip-position-example.html
new file mode 100644
index 000000000000..156a5bf68492
--- /dev/null
+++ b/src/examples/tooltip-position/tooltip-position-example.html
@@ -0,0 +1,11 @@
+
+ Show tooltip
+
+ Before
+ After
+ Above
+ Below
+ Left
+ Right
+
+
diff --git a/src/examples/tooltip-position/tooltip-position-example.ts b/src/examples/tooltip-position/tooltip-position-example.ts
new file mode 100644
index 000000000000..0b580c722bfc
--- /dev/null
+++ b/src/examples/tooltip-position/tooltip-position-example.ts
@@ -0,0 +1,11 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'tooltip-position-example',
+ templateUrl: './tooltip-position-example.html',
+ styleUrls: ['./tooltip-position-example.css'],
+})
+export class TooltipPositionExample {
+ position = 'before';
+}
diff --git a/src/lib/autocomplete/README.md b/src/lib/autocomplete/README.md
index 1bc0814e9eec..73bddeb68ee6 100644
--- a/src/lib/autocomplete/README.md
+++ b/src/lib/autocomplete/README.md
@@ -1,5 +1 @@
-
-## Not yet implemented!
-
-The autocomplete is not yet implemented. This is only a scaffold to make
-subsequent PRs easier to read. Please do not try to use yet :)
\ No newline at end of file
+See documentation on [material.angular.io](https://material.angular.io/).
\ No newline at end of file
diff --git a/src/lib/autocomplete/_autocomplete-theme.scss b/src/lib/autocomplete/_autocomplete-theme.scss
index b77fff253e0c..7cce6dfe1c56 100644
--- a/src/lib/autocomplete/_autocomplete-theme.scss
+++ b/src/lib/autocomplete/_autocomplete-theme.scss
@@ -1,5 +1,19 @@
@import '../core/theming/theming';
-@mixin md-autocomplete-theme($theme) {
+@mixin mat-autocomplete-theme($theme) {
+ $foreground: map-get($theme, foreground);
+ $background: map-get($theme, background);
+
+ .mat-autocomplete-panel {
+ background: mat-color($background, card);
+ color: mat-color($foreground, text);
+
+ .mat-option {
+ &.mat-selected:not(.mat-active) {
+ background: mat-color($background, card);
+ color: mat-color($foreground, text);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/lib/autocomplete/autocomplete-trigger.ts b/src/lib/autocomplete/autocomplete-trigger.ts
new file mode 100644
index 000000000000..6d3c550022fc
--- /dev/null
+++ b/src/lib/autocomplete/autocomplete-trigger.ts
@@ -0,0 +1,371 @@
+import {
+ Directive,
+ ElementRef,
+ forwardRef,
+ Host,
+ Input,
+ NgZone,
+ Optional,
+ OnDestroy,
+ ViewContainerRef,
+} from '@angular/core';
+import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
+import {Overlay, OverlayRef, OverlayState, TemplatePortal} from '../core';
+import {MdAutocomplete} from './autocomplete';
+import {PositionStrategy} from '../core/overlay/position/position-strategy';
+import {ConnectedPositionStrategy} from '../core/overlay/position/connected-position-strategy';
+import {Observable} from 'rxjs/Observable';
+import {MdOptionSelectionChange, MdOption} from '../core/option/option';
+import {ENTER, UP_ARROW, DOWN_ARROW} from '../core/keyboard/keycodes';
+import {Dir} from '../core/rtl/dir';
+import {Subscription} from 'rxjs/Subscription';
+import {Subject} from 'rxjs/Subject';
+import 'rxjs/add/observable/merge';
+import 'rxjs/add/operator/startWith';
+import 'rxjs/add/operator/switchMap';
+import {MdInputContainer} from '../input/input-container';
+
+/**
+ * The following style constants are necessary to save here in order
+ * to properly calculate the scrollTop of the panel. Because we are not
+ * actually focusing the active item, scroll must be handled manually.
+ */
+
+/** The height of each autocomplete option. */
+export const AUTOCOMPLETE_OPTION_HEIGHT = 48;
+
+/** The total height of the autocomplete panel. */
+export const AUTOCOMPLETE_PANEL_HEIGHT = 256;
+
+/**
+ * Provider that allows the autocomplete to register as a ControlValueAccessor.
+ * @docs-private
+ */
+export const MD_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => MdAutocompleteTrigger),
+ multi: true
+};
+
+@Directive({
+ selector: 'input[mdAutocomplete], input[matAutocomplete]',
+ host: {
+ 'role': 'combobox',
+ 'autocomplete': 'off',
+ 'aria-autocomplete': 'list',
+ 'aria-multiline': 'false',
+ '[attr.aria-activedescendant]': 'activeOption?.id',
+ '[attr.aria-expanded]': 'panelOpen.toString()',
+ '[attr.aria-owns]': 'autocomplete?.id',
+ '(focus)': 'openPanel()',
+ '(blur)': '_handleBlur($event.relatedTarget?.tagName)',
+ '(input)': '_handleInput($event)',
+ '(keydown)': '_handleKeydown($event)',
+ },
+ providers: [MD_AUTOCOMPLETE_VALUE_ACCESSOR]
+})
+export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
+ private _overlayRef: OverlayRef;
+ private _portal: TemplatePortal;
+ private _panelOpen: boolean = false;
+
+ /** The subscription to positioning changes in the autocomplete panel. */
+ private _panelPositionSubscription: Subscription;
+
+ private _positionStrategy: ConnectedPositionStrategy;
+
+ /** Stream of blur events that should close the panel. */
+ private _blurStream = new Subject();
+
+ /** Whether or not the placeholder state is being overridden. */
+ private _manuallyFloatingPlaceholder = false;
+
+ /** View -> model callback called when value changes */
+ _onChange = (value: any) => {};
+
+ /** View -> model callback called when autocomplete has been touched */
+ _onTouched = () => {};
+
+ /* The autocomplete panel to be attached to this trigger. */
+ @Input('mdAutocomplete') autocomplete: MdAutocomplete;
+
+ /** Property with mat- prefix for no-conflict mode. */
+ @Input('matAutocomplete')
+ get _matAutocomplete(): MdAutocomplete {
+ return this.autocomplete;
+ }
+
+ set _matAutocomplete(autocomplete: MdAutocomplete) {
+ this.autocomplete = autocomplete;
+ }
+
+ constructor(private _element: ElementRef, private _overlay: Overlay,
+ private _viewContainerRef: ViewContainerRef,
+ @Optional() private _dir: Dir, private _zone: NgZone,
+ @Optional() @Host() private _inputContainer: MdInputContainer) {}
+
+ ngOnDestroy() {
+ if (this._panelPositionSubscription) {
+ this._panelPositionSubscription.unsubscribe();
+ }
+
+ this._destroyPanel();
+ }
+
+ /* Whether or not the autocomplete panel is open. */
+ get panelOpen(): boolean {
+ return this._panelOpen && this.autocomplete.showPanel;
+ }
+
+ /** Opens the autocomplete suggestion panel. */
+ openPanel(): void {
+ if (!this._overlayRef) {
+ this._createOverlay();
+ } else {
+ /** Update the panel width, in case the host width has changed */
+ this._overlayRef.getState().width = this._getHostWidth();
+ }
+
+ if (!this._overlayRef.hasAttached()) {
+ this._overlayRef.attach(this._portal);
+ this._subscribeToClosingActions();
+ }
+
+ this._panelOpen = true;
+ this._floatPlaceholder();
+ }
+
+ /** Closes the autocomplete suggestion panel. */
+ closePanel(): void {
+ if (this._overlayRef && this._overlayRef.hasAttached()) {
+ this._overlayRef.detach();
+ }
+
+ this._panelOpen = false;
+ this._resetPlaceholder();
+ }
+
+ /**
+ * A stream of actions that should close the autocomplete panel, including
+ * when an option is selected, on blur, and when TAB is pressed.
+ */
+ get panelClosingActions(): Observable {
+ return Observable.merge(
+ this.optionSelections,
+ this._blurStream.asObservable(),
+ this.autocomplete._keyManager.tabOut
+ );
+ }
+
+ /** Stream of autocomplete option selections. */
+ get optionSelections(): Observable {
+ return Observable.merge(...this.autocomplete.options.map(option => option.onSelectionChange));
+ }
+
+ /** The currently active option, coerced to MdOption type. */
+ get activeOption(): MdOption {
+ if (this.autocomplete._keyManager) {
+ return this.autocomplete._keyManager.activeItem as MdOption;
+ }
+ }
+
+ /**
+ * Sets the autocomplete's value. Part of the ControlValueAccessor interface
+ * required to integrate with Angular's core forms API.
+ *
+ * @param value New value to be written to the model.
+ */
+ writeValue(value: any): void {
+ Promise.resolve(null).then(() => this._setTriggerValue(value));
+ }
+
+ /**
+ * Saves a callback function to be invoked when the autocomplete's value
+ * changes from user input. Part of the ControlValueAccessor interface
+ * required to integrate with Angular's core forms API.
+ *
+ * @param fn Callback to be triggered when the value changes.
+ */
+ registerOnChange(fn: (value: any) => {}): void {
+ this._onChange = fn;
+ }
+
+ /**
+ * Saves a callback function to be invoked when the autocomplete is blurred
+ * by the user. Part of the ControlValueAccessor interface required
+ * to integrate with Angular's core forms API.
+ *
+ * @param fn Callback to be triggered when the component has been touched.
+ */
+ registerOnTouched(fn: () => {}) {
+ this._onTouched = fn;
+ }
+
+ _handleKeydown(event: KeyboardEvent): void {
+ if (this.activeOption && event.keyCode === ENTER) {
+ this.activeOption._selectViaInteraction();
+ } else {
+ this.autocomplete._keyManager.onKeydown(event);
+ if (event.keyCode === UP_ARROW || event.keyCode === DOWN_ARROW) {
+ this.openPanel();
+ Promise.resolve().then(() => this._scrollToOption());
+ }
+ }
+ }
+
+ _handleInput(event: KeyboardEvent): void {
+ // We need to ensure that the input is focused, because IE will fire the `input`
+ // event on focus/blur/load if the input has a placeholder. See:
+ // https://connect.microsoft.com/IE/feedback/details/885747/
+ if (document.activeElement === event.target) {
+ this._onChange((event.target as HTMLInputElement).value);
+ this.openPanel();
+ }
+ }
+
+ _handleBlur(newlyFocusedTag: string): void {
+ this._onTouched();
+
+ // Only emit blur event if the new focus is *not* on an option.
+ if (newlyFocusedTag !== 'MD-OPTION') {
+ this._blurStream.next(null);
+ }
+ }
+
+ /**
+ * In "auto" mode, the placeholder will animate down as soon as focus is lost.
+ * This causes the value to jump when selecting an option with the mouse.
+ * This method manually floats the placeholder until the panel can be closed.
+ */
+ private _floatPlaceholder(): void {
+ if (this._inputContainer && this._inputContainer.floatPlaceholder === 'auto') {
+ this._inputContainer.floatPlaceholder = 'always';
+ this._manuallyFloatingPlaceholder = true;
+ }
+ }
+
+ /** If the placeholder has been manually elevated, return it to its normal state. */
+ private _resetPlaceholder(): void {
+ if (this._manuallyFloatingPlaceholder) {
+ this._inputContainer.floatPlaceholder = 'auto';
+ this._manuallyFloatingPlaceholder = false;
+ }
+ }
+
+ /**
+ * Given that we are not actually focusing active options, we must manually adjust scroll
+ * to reveal options below the fold. First, we find the offset of the option from the top
+ * of the panel. The new scrollTop will be that offset - the panel height + the option
+ * height, so the active option will be just visible at the bottom of the panel.
+ */
+ private _scrollToOption(): void {
+ const optionOffset =
+ this.autocomplete._keyManager.activeItemIndex * AUTOCOMPLETE_OPTION_HEIGHT;
+ const newScrollTop =
+ Math.max(0, optionOffset - AUTOCOMPLETE_PANEL_HEIGHT + AUTOCOMPLETE_OPTION_HEIGHT);
+ this.autocomplete._setScrollTop(newScrollTop);
+ }
+
+ /**
+ * This method listens to a stream of panel closing actions and resets the
+ * stream every time the option list changes.
+ */
+ private _subscribeToClosingActions(): void {
+ // When the zone is stable initially, and when the option list changes...
+ Observable.merge(this._zone.onStable.first(), this.autocomplete.options.changes)
+ // create a new stream of panelClosingActions, replacing any previous streams
+ // that were created, and flatten it so our stream only emits closing events...
+ .switchMap(() => {
+ this._resetPanel();
+ return this.panelClosingActions;
+ })
+ // when the first closing event occurs...
+ .first()
+ // set the value, close the panel, and complete.
+ .subscribe(event => this._setValueAndClose(event));
+ }
+
+ /** Destroys the autocomplete suggestion panel. */
+ private _destroyPanel(): void {
+ if (this._overlayRef) {
+ this.closePanel();
+ this._overlayRef.dispose();
+ this._overlayRef = null;
+ }
+ }
+
+ private _setTriggerValue(value: any): void {
+ const toDisplay = this.autocomplete.displayWith ? this.autocomplete.displayWith(value) : value;
+ this._element.nativeElement.value = toDisplay || '';
+ }
+
+ /**
+ * This method closes the panel, and if a value is specified, also sets the associated
+ * control to that value. It will also mark the control as dirty if this interaction
+ * stemmed from the user.
+ */
+ private _setValueAndClose(event: MdOptionSelectionChange | null): void {
+ if (event) {
+ this._setTriggerValue(event.source.value);
+ this._onChange(event.source.value);
+ }
+
+ this.closePanel();
+ }
+
+ private _createOverlay(): void {
+ this._portal = new TemplatePortal(this.autocomplete.template, this._viewContainerRef);
+ this._overlayRef = this._overlay.create(this._getOverlayConfig());
+ }
+
+ private _getOverlayConfig(): OverlayState {
+ const overlayState = new OverlayState();
+ overlayState.positionStrategy = this._getOverlayPosition();
+ overlayState.width = this._getHostWidth();
+ overlayState.direction = this._dir ? this._dir.value : 'ltr';
+ return overlayState;
+ }
+
+ private _getOverlayPosition(): PositionStrategy {
+ this._positionStrategy = this._overlay.position().connectedTo(
+ this._element,
+ {originX: 'start', originY: 'bottom'}, {overlayX: 'start', overlayY: 'top'})
+ .withFallbackPosition(
+ {originX: 'start', originY: 'top'}, {overlayX: 'start', overlayY: 'bottom'}
+ );
+ this._subscribeToPositionChanges(this._positionStrategy);
+ return this._positionStrategy;
+ }
+
+ /**
+ * This method subscribes to position changes in the autocomplete panel, so the panel's
+ * y-offset can be adjusted to match the new position.
+ */
+ private _subscribeToPositionChanges(strategy: ConnectedPositionStrategy) {
+ this._panelPositionSubscription = strategy.onPositionChange.subscribe(change => {
+ this.autocomplete.positionY = change.connectionPair.originY === 'top' ? 'above' : 'below';
+ });
+ }
+
+ /** Returns the width of the input element, so the panel width can match it. */
+ private _getHostWidth(): number {
+ return this._element.nativeElement.getBoundingClientRect().width;
+ }
+
+ /** Reset active item to null so arrow events will activate the correct options.*/
+ private _resetActiveItem(): void {
+ this.autocomplete._keyManager.setActiveItem(null);
+ }
+
+ /**
+ * Resets the active item and re-calculates alignment of the panel in case its size
+ * has changed due to fewer or greater number of options.
+ */
+ private _resetPanel() {
+ this._resetActiveItem();
+ this._positionStrategy.recalculateLastPosition();
+ this.autocomplete._setVisibility();
+ }
+
+}
+
diff --git a/src/lib/autocomplete/autocomplete.html b/src/lib/autocomplete/autocomplete.html
index f0d1cbc032a0..cd94ceeb7340 100644
--- a/src/lib/autocomplete/autocomplete.html
+++ b/src/lib/autocomplete/autocomplete.html
@@ -1 +1,5 @@
-I'm an autocomplete!
\ No newline at end of file
+
+