2 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
3 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
5 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
6 Code distributed by Google as part of the polymer project is also
7 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
10 <link rel=
"import" href=
"../polymer/polymer.html">
11 <link rel=
"import" href=
"../iron-flex-layout/iron-flex-layout.html">
14 `paper-header-panel` contains a header section and a content panel section.
16 __Important:__ The `paper-header-panel` will not display if its parent does not have a height.
18 Using layout classes, you can make the `paper-header-panel` fill the screen
20 <body class="fullbleed layout vertical">
21 <paper-header-panel class="flex">
23 <div>Hello World!</div>
28 Special support is provided for scrolling modes when one uses a paper-toolbar or equivalent for the
34 <paper-toolbar>Header</paper-toolbar>
35 <div>Content goes here...</div>
38 If you want to use other than `paper-toolbar` for the header, add `paper-header` class to that
44 <div class="paper-header">Header</div>
45 <div>Content goes here...</div>
48 To have the content fit to the main area, use the `fit` class.
51 <div class="paper-header">standard</div>
52 <div class="fit">content fits 100% below the header</div>
57 Controls header and scrolling behavior. Options are `standard`, `seamed`, `waterfall`, `waterfall-tall`, `scroll` and
58 `cover`. Default is `standard`.
61 ----------------|-------------
62 `standard` | The header is a step above the panel. The header will consume the panel at the point of entry, preventing it from passing through to the opposite side.
63 `seamed` | The header is presented as seamed with the panel.
64 `waterfall` | Similar to standard mode, but header is initially presented as seamed with panel, but then separates to form the step.
65 `waterfall-tall` | The header is initially taller (`tall` class is added to the header). As the user scrolls, the header separates (forming an edge) while condensing (`tall` class is removed from the header).
66 `scroll` | The header keeps its seam with the panel, and is pushed off screen.
67 `cover` | The panel covers the whole `paper-header-panel` including the header. This allows user to style the panel in such a way that the panel is partially covering the header.
71 <paper-header-panel mode="waterfall">
72 <div class="paper-header">standard</div>
73 <div class="content fit">content fits 100% below the header</div>
79 To change the shadow that shows up underneath the header:
82 --paper-header-panel-shadow: {
85 box-shadow: inset 0px 5px 6px -3px rgba(0, 0, 0, 0.4);
89 To change the panel container in different modes:
92 --paper-header-panel-standard-container: {
93 border: 1px solid gray;
96 --paper-header-panel-cover-container: {
97 border: 1px solid gray;
100 --paper-header-panel-waterfall-container: {
101 border: 1px solid gray;
104 --paper-header-panel-waterfall-tall-container: {
105 border: 1px solid gray;
109 @group Paper Elements
110 @element paper-header-panel
111 @demo demo/index.html
115 <dom-module id=
"paper-header-panel">
120 @apply(--layout-vertical);
126 /* Create a stack context, we will need it for the shadow*/
132 * Default paper header panel shadow
134 --paper-header-panel-shadow: {
137 box-shadow: inset
0px
5px
6px -
3px rgba(
0,
0,
0,
0.4);
142 @apply(--layout-flex);
147 -webkit-overflow-scrolling: touch;
148 flex-basis:
0.0001px;
154 :host([mode=scroll]) #mainContainer {
155 @apply(--paper-header-panel-scroll-container);
159 :host([mode=scroll]) {
162 -webkit-overflow-scrolling: touch;
168 :host([mode=cover]) #mainContainer {
169 @apply(--paper-header-panel-cover-container);
180 :host([mode=standard]) #mainContainer {
181 @apply(--paper-header-panel-standard-container);
187 :host([mode=waterfall]) #mainContainer {
188 @apply(--paper-header-panel-waterfall-container);
192 * mode: waterfall-tall
194 :host([mode=waterfall-tall]) #mainContainer {
195 @apply(--paper-header-panel-waterfall-tall-container);
198 :host ::content paper-toolbar,
199 :host ::content .paper-header {
201 overflow: visible !important;
204 :host ::content paper-toolbar:after,
205 :host ::content .paper-header:after {
206 @apply(--paper-header-panel-shadow);
208 -webkit-transition: opacity
0.5s, -webkit-transform
0.5s;
209 transition: opacity
0.5s, transform
0.5s;
220 -webkit-transform: scale3d(
1,
0,
1);
221 -webkit-transform-origin:
0%
0%;
223 transform: scale3d(
1,
0,
1);
224 transform-origin:
0%
0%;
227 :host ::content paper-toolbar.has-shadow:after,
228 :host ::content .paper-header.has-shadow:after {
230 -webkit-transform: scale3d(
1,
1,
1);
231 transform: scale3d(
1,
1,
1);
236 <content id=
"headerContent" select=
"paper-toolbar, .paper-header"></content>
237 <div id=
"mainContainer" class$=
"[[_computeMainContainerClass(mode)]]">
238 <content id=
"mainContent" select=
"*"></content>
250 var SHADOW_WHEN_SCROLLING
= 1;
251 var SHADOW_ALWAYS
= 2;
261 standard
: SHADOW_ALWAYS
,
262 waterfall
: SHADOW_WHEN_SCROLLING
,
263 'waterfall-tall': SHADOW_WHEN_SCROLLING
267 'waterfall-tall': true
273 is
: 'paper-header-panel',
276 * Fired when the content has been scrolled. `event.detail.target` returns
277 * the scrollable element which you can use to access scroll info such as
280 * <paper-header-panel on-content-scroll="{{scrollHandler}}">
282 * </paper-header-panel>
285 * scrollHandler: function(event) {
286 * var scroller = event.detail.target;
287 * console.log(scroller.scrollTop);
290 * @event content-scroll
296 * Controls header and scrolling behavior. Options are
297 * `standard`, `seamed`, `waterfall`, `waterfall-tall`, `scroll` and
298 * `cover`. Default is `standard`.
300 * `standard`: The header is a step above the panel. The header will consume the
301 * panel at the point of entry, preventing it from passing through to the
304 * `seamed`: The header is presented as seamed with the panel.
306 * `waterfall`: Similar to standard mode, but header is initially presented as
307 * seamed with panel, but then separates to form the step.
309 * `waterfall-tall`: The header is initially taller (`tall` class is added to
310 * the header). As the user scrolls, the header separates (forming an edge)
311 * while condensing (`tall` class is removed from the header).
313 * `scroll`: The header keeps its seam with the panel, and is pushed off screen.
315 * `cover`: The panel covers the whole `paper-header-panel` including the
316 * header. This allows user to style the panel in such a way that the panel is
317 * partially covering the header.
319 * <paper-header-panel mode="cover">
320 * <paper-toolbar class="tall">
321 * <core-icon-button icon="menu"></core-icon-button>
323 * <div class="content"></div>
324 * </paper-header-panel>
329 observer
: '_modeChanged',
330 reflectToAttribute
: true
334 * If true, the drop-shadow is always shown no matter what mode is set to.
342 * The class used in waterfall-tall mode. Change this if the header
343 * accepts a different class for toggling height, e.g. "medium-tall"
351 * If true, the scroller is at the top
361 '_computeDropShadowHidden(atTop, mode, shadow)'
365 this.scrollHandler
= this._scroll
.bind(this);
368 // Run `scroll` logic once to initialze class names, etc.
369 this._keepScrollingState();
372 detached: function() {
373 this._removeListener();
377 * Returns the header element
383 return Polymer
.dom(this.$.headerContent
).getDistributedNodes()[0];
387 * Returns the scrollable element.
393 return this._getScrollerForMode(this.mode
);
397 * Returns true if the scroller has a visible shadow.
399 * @property visibleShadow
402 get visibleShadow() {
403 return this.header
.classList
.contains('has-shadow');
406 _computeDropShadowHidden: function(atTop
, mode
, shadow
) {
408 var shadowMode
= MODE_CONFIGS
.shadowMode
[mode
];
411 this.toggleClass('has-shadow', true, this.header
);
413 } else if (shadowMode
=== SHADOW_ALWAYS
) {
414 this.toggleClass('has-shadow', true, this.header
);
416 } else if (shadowMode
=== SHADOW_WHEN_SCROLLING
&& !atTop
) {
417 this.toggleClass('has-shadow', true, this.header
);
420 this.toggleClass('has-shadow', false, this.header
);
425 _computeMainContainerClass: function(mode
) {
426 // TODO: It will be useful to have a utility for classes
427 // e.g. Polymer.Utils.classes({ foo: true });
431 classes
['flex'] = mode
!== 'cover';
433 return Object
.keys(classes
).filter(
434 function(className
) {
435 return classes
[className
];
439 _addListener: function() {
440 this.scroller
.addEventListener('scroll', this.scrollHandler
, false);
443 _removeListener: function() {
444 this.scroller
.removeEventListener('scroll', this.scrollHandler
);
447 _modeChanged: function(newMode
, oldMode
) {
448 var configs
= MODE_CONFIGS
;
449 var header
= this.header
;
450 var animateDuration
= 200;
453 // in tallMode it may add tallClass to the header; so do the cleanup
454 // when mode is changed from tallMode to not tallMode
455 if (configs
.tallMode
[oldMode
] && !configs
.tallMode
[newMode
]) {
456 header
.classList
.remove(this.tallClass
);
457 this.async(function() {
458 header
.classList
.remove('animate');
461 header
.classList
.toggle('animate', configs
.tallMode
[newMode
]);
464 this._keepScrollingState();
467 _keepScrollingState: function () {
468 var main
= this.scroller
;
469 var header
= this.header
;
471 this._setAtTop(main
.scrollTop
=== 0);
473 if (header
&& MODE_CONFIGS
.tallMode
[this.mode
]) {
474 this.toggleClass(this.tallClass
, this.atTop
||
475 header
.classList
.contains(this.tallClass
) &&
476 main
.scrollHeight
< this.offsetHeight
, header
);
480 _scroll: function(e
) {
481 this._keepScrollingState();
482 this.fire('content-scroll', {target
: this.scroller
}, {bubbles
: false});
485 _getScrollerForMode: function(mode
) {
486 return MODE_CONFIGS
.outerScroll
[mode
] ?
487 this : this.$.mainContainer
;