2 Copyright (c) 2014 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
11 `core-drawer-panel` contains a drawer panel and a main panel. The drawer
12 and the main panel are side-by-side with drawer on the left. When the browser
13 window size is smaller than the `responsiveWidth`, `core-drawer-panel`
14 changes to narrow layout. In narrow layout, the drawer will be stacked on top
15 of the main panel. The drawer will slide in/out to hide/reveal the main
18 Use the attribute `drawer` to indicate that the element is the drawer panel and
19 `main` to indicate that the element is the main panel.
24 <div drawer> Drawer panel... </div>
25 <div main> Main panel... </div>
28 The drawer and the main panels are not scrollable. You can set CSS overflow
29 property on the elements to make them scrollable or use `core-header-panel`.
34 <core-header-panel drawer>
35 <core-toolbar></core-toolbar>
36 <div> Drawer content... </div>
38 <core-header-panel main>
39 <core-toolbar></core-toolbar>
40 <div> Main content... </div>
44 An element that should toggle the drawer will automatically do so if it's
45 given the `core-drawer-toggle` attribute. Also this element will automatically
46 be hidden in wide layout.
51 <core-header-panel drawer>
53 <div>Application</div>
55 <div> Drawer content... </div>
57 <core-header-panel main>
59 <core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
62 <div> Main content... </div>
66 To position the drawer to the right, add `rightDrawer` attribute.
68 <core-drawer-panel rightDrawer>
69 <div drawer> Drawer panel... </div>
70 <div main> Main panel... </div>
73 @group Polymer Core Elements
74 @element core-drawer-panel
78 <link rel=
"import" href=
"../core-media-query/core-media-query.html">
79 <link rel=
"import" href=
"../core-selector/core-selector.html">
81 <polymer-element name=
"core-drawer-panel" touch-action=
"auto">
84 <link rel=
"stylesheet" href=
"core-drawer-panel.css">
86 <core-media-query query=
"max-width: {{forceNarrow ? '' : responsiveWidth}}" queryMatches=
"{{queryMatches}}"></core-media-query>
88 <core-selector class=
"{{ {'narrow-layout' : narrow, transition : transition, dragging : dragging, 'right-drawer': rightDrawer} | tokenList }}" valueattr=
"id" selected=
"{{selected}}">
90 <div id=
"main" _style=
"left: {{ narrow || rightDrawer ? '0' : drawerWidth }}; right: {{ rightDrawer ? (narrow ? '' : drawerWidth) : '' }};">
91 <content select=
"[main]"></content>
92 <div id=
"scrim" on-tap=
"{{togglePanel}}"></div>
95 <div id=
"drawer" _style=
"width: {{ drawerWidth }}">
96 <content select=
"[drawer]"></content>
104 Polymer('core-drawer-panel', {
107 * Fired when the narrow layout changes.
109 * @event core-responsive-change
110 * @param {Object} detail
111 * @param {boolean} detail.narrow true if the panel is in narrow layout.
115 * Fired when the selected panel changes.
117 * Listening for this event is an alternative to observing changes in the `selected` attribute.
118 * This event is fired both when a panel is selected and deselected.
119 * The `isSelected` detail property contains the selection state.
122 * @param {Object} detail
123 * @param {boolean} detail.isSelected true for selection and false for deselection
124 * @param {Object} detail.item the panel that the event refers to
130 * Width of the drawer panel.
132 * @attribute drawerWidth
136 drawerWidth
: '256px',
139 * Max-width when the panel changes to narrow layout.
141 * @attribute responsiveWidth
145 responsiveWidth
: '640px',
148 * The panel that is being selected. `drawer` for the drawer panel and
149 * `main` for the main panel.
151 * @attribute selected
155 selected
: {value
: null, reflect
: true},
158 * The panel to be selected when `core-drawer-panel` changes to narrow
161 * @attribute defaultSelected
165 defaultSelected
: 'main',
168 * Returns true if the panel is in narrow layout. This is useful if you
169 * need to show/hide elements based on the layout.
175 narrow
: {value
: false, reflect
: true},
178 * If true, position the drawer to the right.
180 * @attribute rightDrawer
187 * If true, swipe to open/close the drawer is disabled.
189 * @attribute disableSwipe
196 * If true, ignore `responsiveWidth` setting and force the narrow layout.
198 * @attribute forceNarrow
206 trackstart
: 'trackStart',
208 trackend
: 'trackEnd',
214 // Whether the transition is enabled.
217 // How many pixels on the side of the screen are sensitive to edge swipes and peek.
218 edgeSwipeSensitivity
: 15,
220 // Whether the drawer is peeking out from the edge.
223 // Whether the user is dragging the drawer interactively.
226 // Whether the browser has support for the transform CSS property.
229 // Whether the browser has support for the will-change CSS property.
232 // The attribute on elements that should toggle the drawer on tap, also
233 // elements will automatically be hidden in wide layout.
234 toggleAttribute
: 'core-drawer-toggle',
236 created: function() {
237 this.hasTransform
= 'transform' in this.style
;
238 this.hasWillChange
= 'willChange' in this.style
;
241 domReady: function() {
242 // to avoid transition at the beginning e.g. page loads
243 // NOTE: domReady is already raf delayed and delaying another frame
244 // ensures a layout has occurred.
245 this.async(function() {
246 this.transition
= true;
251 * Toggles the panel open and closed.
253 * @method togglePanel
255 togglePanel: function() {
256 this.selected
= this.isMainSelected() ? 'drawer' : 'main';
264 openDrawer: function() {
265 this.selected
= 'drawer';
271 * @method closeDrawer
273 closeDrawer: function() {
274 this.selected
= 'main';
277 queryMatchesChanged: function() {
278 this.narrow
= this.queryMatches
|| this.forceNarrow
;
280 this.selected
= this.defaultSelected
;
282 this.setAttribute('touch-action', this.swipeAllowed() ? 'pan-y' : '');
283 this.fire('core-responsive-change', {narrow
: this.narrow
});
286 forceNarrowChanged: function() {
287 this.queryMatchesChanged();
290 swipeAllowed: function() {
291 return this.narrow
&& !this.disableSwipe
;
294 isMainSelected: function() {
295 return this.selected
=== 'main';
298 startEdgePeek: function() {
299 this.width
= this.$.drawer
.offsetWidth
;
300 this.moveDrawer(this.translateXForDeltaX(this.rightDrawer
?
301 -this.edgeSwipeSensitivity
: this.edgeSwipeSensitivity
));
305 stopEdgePeak: function() {
307 this.peeking
= false;
308 this.moveDrawer(null);
312 downHandler: function(e
) {
313 if (!this.dragging
&& this.isMainSelected() && this.isEdgeTouch(e
)) {
314 this.startEdgePeek();
318 upHandler: function(e
) {
322 tapHandler: function(e
) {
323 if (e
.target
&& this.toggleAttribute
&&
324 e
.target
.hasAttribute(this.toggleAttribute
)) {
329 isEdgeTouch: function(e
) {
330 return this.swipeAllowed() && (this.rightDrawer
?
331 e
.pageX
>= this.offsetWidth
- this.edgeSwipeSensitivity
:
332 e
.pageX
<= this.edgeSwipeSensitivity
);
335 trackStart : function(e
) {
336 if (this.swipeAllowed()) {
337 this.dragging
= true;
339 if (this.isMainSelected()) {
340 this.dragging
= this.peeking
|| this.isEdgeTouch(e
);
344 this.width
= this.$.drawer
.offsetWidth
;
345 this.transition
= false;
351 translateXForDeltaX: function(deltaX
) {
352 var isMain
= this.isMainSelected();
353 if (this.rightDrawer
) {
354 return Math
.max(0, isMain
? this.width
+ deltaX
: deltaX
);
356 return Math
.min(0, isMain
? deltaX
- this.width
: deltaX
);
360 trackx : function(e
) {
363 if (Math
.abs(e
.dx
) <= this.edgeSwipeSensitivity
) {
364 return; // Ignore trackx until we move past the edge peek.
366 this.peeking
= false;
368 this.moveDrawer(this.translateXForDeltaX(e
.dx
));
372 trackEnd : function(e
) {
374 this.dragging
= false;
375 this.transition
= true;
376 this.moveDrawer(null);
378 if (this.rightDrawer
) {
379 this.selected
= e
.xDirection
> 0 ? 'main' : 'drawer';
381 this.selected
= e
.xDirection
> 0 ? 'drawer' : 'main';
386 transformForTranslateX: function(translateX
) {
387 if (translateX
=== null) {
390 return this.hasWillChange
? 'translateX(' + translateX
+ 'px)' :
391 'translate3d(' + translateX
+ 'px, 0, 0)';
394 moveDrawer: function(translateX
) {
395 var s
= this.$.drawer
.style
;
397 if (this.hasTransform
) {
398 s
.transform
= this.transformForTranslateX(translateX
);
400 s
.webkitTransform
= this.transformForTranslateX(translateX
);