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-media-query/iron-media-query.html">
12 <link rel=
"import" href=
"../iron-selector/iron-selector.html">
15 `paper-drawer-panel` contains a drawer panel and a main panel. The drawer
16 and the main panel are side-by-side with drawer on the left. When the browser
17 window size is smaller than the `responsiveWidth`, `paper-drawer-panel`
18 changes to narrow layout. In narrow layout, the drawer will be stacked on top
19 of the main panel. The drawer will slide in/out to hide/reveal the main
22 Use the attribute `drawer` to indicate that the element is the drawer panel and
23 `main` to indicate that the element is the main panel.
28 <div drawer> Drawer panel... </div>
29 <div main> Main panel... </div>
32 The drawer and the main panels are not scrollable. You can set CSS overflow
33 property on the elements to make them scrollable or use `paper-header-panel`.
38 <paper-header-panel drawer>
39 <paper-toolbar></paper-toolbar>
40 <div> Drawer content... </div>
42 <paper-header-panel main>
43 <paper-toolbar></paper-toolbar>
44 <div> Main content... </div>
48 An element that should toggle the drawer will automatically do so if it's
49 given the `paper-drawer-toggle` attribute. Also this element will automatically
50 be hidden in wide layout.
55 <paper-header-panel drawer>
57 <div>Application</div>
59 <div> Drawer content... </div>
61 <paper-header-panel main>
63 <paper-icon-button icon="menu" paper-drawer-toggle></paper-icon-button>
66 <div> Main content... </div>
70 To position the drawer to the right, add `right-drawer` attribute.
72 <paper-drawer-panel right-drawer>
73 <div drawer> Drawer panel... </div>
74 <div main> Main panel... </div>
77 Styling `paper-drawer-panel`
79 To change the main container:
82 --paper-drawer-panel-main-container: {
83 background-color: gray;
87 To change the drawer container when it's in the left side:
90 --paper-drawer-panel-left-drawer-container: {
91 background-color: white;
95 To change the drawer container when it's in the right side:
98 --paper-drawer-panel-right-drawer-container: {
99 background-color: white;
103 @group Paper elements
104 @element paper-drawer-panel
105 @demo demo/index.html
109 <dom-module id=
"paper-drawer-panel">
110 <link rel=
"import" type=
"css" href=
"paper-drawer-panel.css">
115 on-query-matches-changed=
"_onQueryMatchesChanged"
116 query=
"[[_computeMediaQuery(forceNarrow, responsiveWidth)]]">
120 attr-for-selected=
"id"
121 class$=
"[[_computeIronSelectorClass(narrow, transition, dragging, rightDrawer, peeking)]]"
123 selected=
"[[selected]]">
125 <div id=
"main" style$=
"[[_computeMainStyle(narrow, rightDrawer, drawerWidth)]]">
126 <content select=
"[main]"></content>
127 <div id=
"scrim" on-tap=
"closeDrawer"></div>
130 <div id=
"drawer" style$=
"[[_computeDrawerStyle(drawerWidth)]]">
131 <content select=
"[drawer]"></content>
145 // this would be the only `paper-drawer-panel` in
146 // the whole app that can be in `dragging` state
147 var sharedPanel
= null;
149 function classNames(obj
) {
151 for (var key
in obj
) {
152 if (obj
.hasOwnProperty(key
) && obj
[key
]) {
157 return classes
.join(' ');
162 is
: 'paper-drawer-panel',
165 * Fired when the narrow layout changes.
167 * @event paper-responsive-change {{narrow: boolean}} detail -
168 * narrow: true if the panel is in narrow layout.
172 * Fired when the a panel is selected.
174 * Listening for this event is an alternative to observing changes in the `selected` attribute.
175 * This event is fired both when a panel is selected.
177 * @event iron-select {{item: Object}} detail -
178 * item: The panel that the event refers to.
182 * Fired when a panel is deselected.
184 * Listening for this event is an alternative to observing changes in the `selected` attribute.
185 * This event is fired both when a panel is deselected.
187 * @event iron-deselect {{item: Object}} detail -
188 * item: The panel that the event refers to.
193 * The panel to be selected when `paper-drawer-panel` changes to narrow
202 * If true, swipe from the edge is disable.
210 * If true, swipe to open/close the drawer is disabled.
218 * Whether the user is dragging the drawer interactively.
228 * Width of the drawer panel.
236 * How many pixels on the side of the screen are sensitive to edge
239 edgeSwipeSensitivity
: {
245 * If true, ignore `responsiveWidth` setting and force the narrow layout.
253 * Whether the browser has support for the transform CSS property.
258 return 'transform' in this.style
;
263 * Whether the browser has support for the will-change CSS property.
268 return 'willChange' in this.style
;
273 * Returns true if the panel is in narrow layout. This is useful if you
274 * need to show/hide elements based on the layout.
277 reflectToAttribute
: true,
285 * Whether the drawer is peeking out from the edge.
295 * Max-width when the panel changes to narrow layout.
303 * If true, position the drawer to the right.
311 * The panel that is being selected. `drawer` for the drawer panel and
312 * `main` for the main panel.
315 reflectToAttribute
: true,
322 * The attribute on elements that should toggle the drawer on tap, also elements will
323 * automatically be hidden in wide layout.
325 drawerToggleAttribute
: {
327 value
: 'paper-drawer-toggle'
331 * Whether the transition is enabled.
343 down
: '_downHandler',
348 '_forceNarrowChanged(forceNarrow, defaultSelected)'
352 * Toggles the panel open and closed.
354 * @method togglePanel
356 togglePanel: function() {
357 if (this._isMainSelected()) {
369 openDrawer: function() {
370 this.selected
= 'drawer';
376 * @method closeDrawer
378 closeDrawer: function() {
379 this.selected
= 'main';
383 // Avoid transition at the beginning e.g. page loads and enable
384 // transitions only after the element is rendered and ready.
385 this.transition
= true;
388 _computeIronSelectorClass: function(narrow
, transition
, dragging
, rightDrawer
, peeking
) {
391 'narrow-layout': narrow
,
392 'right-drawer': rightDrawer
,
393 'left-drawer': !rightDrawer
,
394 transition
: transition
,
399 _computeDrawerStyle: function(drawerWidth
) {
400 return 'width:' + drawerWidth
+ ';';
403 _computeMainStyle: function(narrow
, rightDrawer
, drawerWidth
) {
406 style
+= 'left:' + ((narrow
|| rightDrawer
) ? '0' : drawerWidth
) + ';';
409 style
+= 'right:' + (narrow
? '' : drawerWidth
) + ';';
415 _computeMediaQuery: function(forceNarrow
, responsiveWidth
) {
416 return forceNarrow
? '' : '(max-width: ' + responsiveWidth
+ ')';
419 _computeSwipeOverlayHidden: function(narrow
, disableEdgeSwipe
) {
420 return !narrow
|| disableEdgeSwipe
;
423 _onTrack: function(event
) {
424 if (sharedPanel
&& this !== sharedPanel
) {
427 switch (event
.detail
.state
) {
429 this._trackStart(event
);
435 this._trackEnd(event
);
441 _responsiveChange: function(narrow
) {
442 this._setNarrow(narrow
);
445 this.selected
= this.defaultSelected
;
448 this.setScrollDirection(this._swipeAllowed() ? 'y' : 'all');
449 this.fire('paper-responsive-change', {narrow
: this.narrow
});
452 _onQueryMatchesChanged: function(event
) {
453 this._responsiveChange(event
.detail
.value
);
456 _forceNarrowChanged: function() {
457 // set the narrow mode only if we reached the `responsiveWidth`
458 this._responsiveChange(this.forceNarrow
|| this.$.mq
.queryMatches
);
461 _swipeAllowed: function() {
462 return this.narrow
&& !this.disableSwipe
;
465 _isMainSelected: function() {
466 return this.selected
=== 'main';
469 _startEdgePeek: function() {
470 this.width
= this.$.drawer
.offsetWidth
;
471 this._moveDrawer(this._translateXForDeltaX(this.rightDrawer
?
472 -this.edgeSwipeSensitivity
: this.edgeSwipeSensitivity
));
473 this._setPeeking(true);
476 _stopEdgePeek: function() {
478 this._setPeeking(false);
479 this._moveDrawer(null);
483 _downHandler: function(event
) {
484 if (!this.dragging
&& this._isMainSelected() && this._isEdgeTouch(event
) && !sharedPanel
) {
485 this._startEdgePeek();
487 event
.preventDefault();
493 _upHandler: function() {
494 this._stopEdgePeek();
499 _onTap: function(event
) {
500 var targetElement
= Polymer
.dom(event
).localTarget
;
501 var isTargetToggleElement
= targetElement
&&
502 this.drawerToggleAttribute
&&
503 targetElement
.hasAttribute(this.drawerToggleAttribute
);
505 if (isTargetToggleElement
) {
510 _isEdgeTouch: function(event
) {
511 var x
= event
.detail
.x
;
513 return !this.disableEdgeSwipe
&& this._swipeAllowed() &&
515 x
>= this.offsetWidth
- this.edgeSwipeSensitivity
:
516 x
<= this.edgeSwipeSensitivity
);
519 _trackStart: function(event
) {
520 if (this._swipeAllowed()) {
522 this._setDragging(true);
524 if (this._isMainSelected()) {
525 this._setDragging(this.peeking
|| this._isEdgeTouch(event
));
529 this.width
= this.$.drawer
.offsetWidth
;
530 this.transition
= false;
535 _translateXForDeltaX: function(deltaX
) {
536 var isMain
= this._isMainSelected();
538 if (this.rightDrawer
) {
539 return Math
.max(0, isMain
? this.width
+ deltaX
: deltaX
);
541 return Math
.min(0, isMain
? deltaX
- this.width
: deltaX
);
545 _trackX: function(event
) {
547 var dx
= event
.detail
.dx
;
550 if (Math
.abs(dx
) <= this.edgeSwipeSensitivity
) {
551 // Ignore trackx until we move past the edge peek.
554 this._setPeeking(false);
557 this._moveDrawer(this._translateXForDeltaX(dx
));
561 _trackEnd: function(event
) {
563 var xDirection
= event
.detail
.dx
> 0;
565 this._setDragging(false);
566 this.transition
= true;
568 this._moveDrawer(null);
570 if (this.rightDrawer
) {
571 this[xDirection
? 'closeDrawer' : 'openDrawer']();
573 this[xDirection
? 'openDrawer' : 'closeDrawer']();
578 _transformForTranslateX: function(translateX
) {
579 if (translateX
=== null) {
583 return this.hasWillChange
? 'translateX(' + translateX
+ 'px)' :
584 'translate3d(' + translateX
+ 'px, 0, 0)';
587 _moveDrawer: function(translateX
) {
588 this.transform(this._transformForTranslateX(translateX
), this.$.drawer
);