| OLD | NEW |
| 1 <!-- | 1 <!-- |
| 2 @license | 2 @license |
| 3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | 3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |
| 4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | 4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
| 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
| 7 Code distributed by Google as part of the polymer project is also | 7 Code distributed by Google as part of the polymer project is also |
| 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
| 9 --> | 9 --> |
| 10 | 10 |
| 11 <link rel="import" href="../polymer/polymer.html"> | 11 <link rel="import" href="../polymer/polymer.html"> |
| 12 <link rel="import" href="../paper-styles/default-theme.html"> | 12 <link rel="import" href="../paper-styles/default-theme.html"> |
| 13 <link rel="import" href="../paper-input/paper-input.html"> | 13 <link rel="import" href="../paper-input/paper-input.html"> |
| 14 <link rel="import" href="../paper-menu-button/paper-menu-button.html"> | 14 <link rel="import" href="../paper-menu-button/paper-menu-button.html"> |
| 15 <link rel="import" href="../paper-ripple/paper-ripple.html"> | 15 <link rel="import" href="../paper-ripple/paper-ripple.html"> |
| 16 <link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html
"> | 16 <link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html
"> |
| 17 <link rel="import" href="../iron-behaviors/iron-control-state.html"> | 17 <link rel="import" href="../iron-behaviors/iron-control-state.html"> |
| 18 <link rel="import" href="../iron-behaviors/iron-button-state.html"> | 18 <link rel="import" href="../iron-behaviors/iron-button-state.html"> |
| 19 <link rel="import" href="../iron-icons/iron-icons.html"> | 19 <link rel="import" href="../iron-icons/iron-icons.html"> |
| 20 <link rel="import" href="../iron-icon/iron-icon.html"> | 20 <link rel="import" href="../iron-icon/iron-icon.html"> |
| 21 <link rel="import" href="../iron-selector/iron-selectable.html"> | 21 <link rel="import" href="../iron-selector/iron-selectable.html"> |
| 22 <link rel="import" href="../iron-form-element-behavior/iron-form-element-behavio
r.html"> |
| 23 <link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.
html"> |
| 22 | 24 |
| 23 <!-- | 25 <!-- |
| 26 Material design: [Dropdown menus](https://www.google.com/design/spec/components/
buttons.html#buttons-dropdown-buttons) |
| 27 |
| 24 `paper-dropdown-menu` is similar to a native browser select element. | 28 `paper-dropdown-menu` is similar to a native browser select element. |
| 25 `paper-dropdown-menu` works with selectable content. The currently selected | 29 `paper-dropdown-menu` works with selectable content. The currently selected |
| 26 item is displayed in the control. If no item is selected, the `label` is | 30 item is displayed in the control. If no item is selected, the `label` is |
| 27 displayed instead. | 31 displayed instead. |
| 28 | 32 |
| 29 The child element with the class `dropdown-content` will be used as the dropdown | 33 The child element with the class `dropdown-content` will be used as the dropdown |
| 30 menu. It could be a `paper-menu` or element that triggers `iron-select` when | 34 menu. It could be a `paper-menu` or element that triggers `iron-select` when |
| 31 selecting its children. | 35 selecting its children. |
| 32 | 36 |
| 33 Example: | 37 Example: |
| 34 | 38 |
| 35 <paper-dropdown-menu label="Your favourite pastry"> | 39 <paper-dropdown-menu label="Your favourite pastry"> |
| 36 <paper-menu class="dropdown-content"> | 40 <paper-menu class="dropdown-content"> |
| 37 <paper-item>Croissant</paper-item> | 41 <paper-item>Croissant</paper-item> |
| 38 <paper-item>Donut</paper-item> | 42 <paper-item>Donut</paper-item> |
| 39 <paper-item>Financier</paper-item> | 43 <paper-item>Financier</paper-item> |
| 40 <paper-item>Madeleine</paper-item> | 44 <paper-item>Madeleine</paper-item> |
| 41 </paper-menu> | 45 </paper-menu> |
| 42 </paper-dropdown-menu> | 46 </paper-dropdown-menu> |
| 43 | 47 |
| 44 This example renders a dropdown menu with 4 options. | 48 This example renders a dropdown menu with 4 options. |
| 45 | 49 |
| 50 Similarly to using `iron-select`, `iron-deselect` events will cause the |
| 51 current selection of the `paper-dropdown-menu` to be cleared. |
| 52 |
| 46 ### Styling | 53 ### Styling |
| 47 | 54 |
| 48 The following custom properties and mixins are also available for styling: | 55 The following custom properties and mixins are also available for styling: |
| 49 | 56 |
| 50 Custom property | Description | Default | 57 Custom property | Description | Default |
| 51 ----------------|-------------|---------- | 58 ----------------|-------------|---------- |
| 52 `--paper-dropdown-menu` | A mixin that is applied to the element host | `{}` | 59 `--paper-dropdown-menu` | A mixin that is applied to the element host | `{}` |
| 53 `--paper-dropdown-menu-disabled` | A mixin that is applied to the element host w
hen disabled | `{}` | 60 `--paper-dropdown-menu-disabled` | A mixin that is applied to the element host w
hen disabled | `{}` |
| 54 `--paper-dropdown-menu-ripple` | A mixin that is applied to the internal ripple
| `{}` | 61 `--paper-dropdown-menu-ripple` | A mixin that is applied to the internal ripple
| `{}` |
| 55 `--paper-dropdown-menu-button` | A mixin that is applied to the internal menu bu
tton | `{}` | 62 `--paper-dropdown-menu-button` | A mixin that is applied to the internal menu bu
tton | `{}` |
| (...skipping 11 matching lines...) Expand all Loading... |
| 67 --> | 74 --> |
| 68 | 75 |
| 69 <dom-module id="paper-dropdown-menu"> | 76 <dom-module id="paper-dropdown-menu"> |
| 70 <style> | 77 <style> |
| 71 :host { | 78 :host { |
| 72 display: inline-block; | 79 display: inline-block; |
| 73 position: relative; | 80 position: relative; |
| 74 text-align: left; | 81 text-align: left; |
| 75 cursor: pointer; | 82 cursor: pointer; |
| 76 | 83 |
| 84 /* NOTE(cdata): Both values are needed, since some phones require the |
| 85 * value to be `transparent`. |
| 86 */ |
| 87 -webkit-tap-highlight-color: rgba(0,0,0,0); |
| 88 -webkit-tap-highlight-color: transparent; |
| 89 |
| 77 --paper-input-container-input: { | 90 --paper-input-container-input: { |
| 78 overflow: hidden; | 91 overflow: hidden; |
| 79 white-space: nowrap; | 92 white-space: nowrap; |
| 80 text-overflow: ellipsis; | 93 text-overflow: ellipsis; |
| 81 max-width: 100%; | 94 max-width: 100%; |
| 82 box-sizing: border-box; | 95 box-sizing: border-box; |
| 83 cursor: pointer; | 96 cursor: pointer; |
| 84 }; | 97 }; |
| 85 | 98 |
| 86 @apply(--paper-dropdown-menu); | 99 @apply(--paper-dropdown-menu); |
| 87 } | 100 } |
| 88 | 101 |
| 89 :host([disabled]) { | 102 :host([disabled]) { |
| 90 @apply(--paper-dropdown-menu-disabled); | 103 @apply(--paper-dropdown-menu-disabled); |
| 91 } | 104 } |
| 92 | 105 |
| 93 :host([noink]) paper-ripple { | 106 :host([noink]) paper-ripple { |
| 94 display: none; | 107 display: none; |
| 95 } | 108 } |
| 96 | 109 |
| 97 :host([no-label-float]) paper-ripple { | 110 :host([no-label-float]) paper-ripple { |
| 98 top: 8px; | 111 top: 8px; |
| 99 } | 112 } |
| 100 | 113 |
| 101 paper-ripple { | 114 paper-ripple { |
| 102 top: 20px; | 115 top: 12px; |
| 103 left: 8px; | 116 left: 0px; |
| 104 bottom: 16px; | 117 bottom: 8px; |
| 105 right: 8px; | 118 right: 0px; |
| 106 | 119 |
| 107 @apply(--paper-dropdown-menu-ripple); | 120 @apply(--paper-dropdown-menu-ripple); |
| 108 } | 121 } |
| 109 | 122 |
| 110 paper-menu-button { | 123 paper-menu-button { |
| 124 display: block; |
| 125 padding: 0; |
| 111 @apply(--paper-dropdown-menu-button); | 126 @apply(--paper-dropdown-menu-button); |
| 112 } | 127 } |
| 113 | 128 |
| 114 paper-input { | 129 paper-input { |
| 115 @apply(--paper-dropdown-menu-input); | 130 @apply(--paper-dropdown-menu-input); |
| 116 } | 131 } |
| 117 | 132 |
| 118 iron-icon { | 133 iron-icon { |
| 119 color: var(--disabled-text-color); | 134 color: var(--disabled-text-color); |
| 120 | 135 |
| 121 @apply(--paper-dropdown-menu-icon); | 136 @apply(--paper-dropdown-menu-icon); |
| 122 } | 137 } |
| 123 | 138 |
| 124 </style> | 139 </style> |
| 125 <template> | 140 <template> |
| 126 <paper-menu-button | 141 <paper-menu-button |
| 127 id="menuButton" | 142 id="menuButton" |
| 128 vertical-align="top" | 143 vertical-align="top" |
| 129 horizontal-align="right" | 144 horizontal-align="right" |
| 130 vertical-offset="[[_computeMenuVerticalOffset(noLabelFloat)]]" | 145 vertical-offset="[[_computeMenuVerticalOffset(noLabelFloat)]]" |
| 131 disabled="[[disabled]]" | 146 disabled="[[disabled]]" |
| 132 no-animations="[[noAnimations]]" | 147 no-animations="[[noAnimations]]" |
| 133 on-iron-select="_onIronSelect" | 148 on-iron-select="_onIronSelect" |
| 149 on-iron-deselect="_onIronDeselect" |
| 134 opened="{{opened}}"> | 150 opened="{{opened}}"> |
| 135 <div class="dropdown-trigger"> | 151 <div class="dropdown-trigger"> |
| 136 <paper-ripple></paper-ripple> | 152 <paper-ripple></paper-ripple> |
| 137 <paper-input | 153 <paper-input |
| 154 invalid="[[invalid]]" |
| 138 readonly | 155 readonly |
| 139 disabled="[[disabled]]" | 156 disabled="[[disabled]]" |
| 140 value="[[selectedItemLabel]]" | 157 value="[[selectedItemLabel]]" |
| 141 placeholder="[[placeholder]]" | 158 placeholder="[[placeholder]]" |
| 142 always-float-label="[[alwaysFloatLabel]]" | 159 always-float-label="[[alwaysFloatLabel]]" |
| 143 no-label-float="[[noLabelFloat]]" | 160 no-label-float="[[noLabelFloat]]" |
| 144 label="[[label]]"> | 161 label="[[label]]"> |
| 145 <iron-icon icon="arrow-drop-down" suffix></iron-icon> | 162 <iron-icon icon="arrow-drop-down" suffix></iron-icon> |
| 146 </paper-input> | 163 </paper-input> |
| 147 </div> | 164 </div> |
| (...skipping 15 matching lines...) Expand all Loading... |
| 163 */ | 180 */ |
| 164 | 181 |
| 165 /** | 182 /** |
| 166 * Fired when the dropdown closes. | 183 * Fired when the dropdown closes. |
| 167 * | 184 * |
| 168 * @event paper-dropdown-close | 185 * @event paper-dropdown-close |
| 169 */ | 186 */ |
| 170 | 187 |
| 171 behaviors: [ | 188 behaviors: [ |
| 172 Polymer.IronControlState, | 189 Polymer.IronControlState, |
| 173 Polymer.IronButtonState | 190 Polymer.IronButtonState, |
| 191 Polymer.IronFormElementBehavior, |
| 192 Polymer.IronValidatableBehavior |
| 174 ], | 193 ], |
| 175 | 194 |
| 176 properties: { | 195 properties: { |
| 177 /** | 196 /** |
| 178 * The derived "label" of the currently selected item. This value | 197 * The derived "label" of the currently selected item. This value |
| 179 * is the `label` property on the selected item if set, or else the | 198 * is the `label` property on the selected item if set, or else the |
| 180 * trimmed text content of the selected item. | 199 * trimmed text content of the selected item. |
| 181 */ | 200 */ |
| 182 selectedItemLabel: { | 201 selectedItemLabel: { |
| 183 type: String, | 202 type: String, |
| 184 notify: true, | 203 notify: true, |
| 185 computed: '_computeSelectedItemLabel(selectedItem)' | 204 readOnly: true |
| 186 }, | 205 }, |
| 187 | 206 |
| 188 /** | 207 /** |
| 189 * The last selected item. An item is selected if the dropdown menu has | 208 * The last selected item. An item is selected if the dropdown menu has |
| 190 * a child with class `dropdown-content`, and that child triggers an | 209 * a child with class `dropdown-content`, and that child triggers an |
| 191 * `iron-select` event with the selected `item` in the `detail`. | 210 * `iron-select` event with the selected `item` in the `detail`. |
| 211 * |
| 212 * @type {?Object} |
| 192 */ | 213 */ |
| 193 selectedItem: { | 214 selectedItem: { |
| 194 type: Object, | 215 type: Object, |
| 195 notify: true, | 216 notify: true, |
| 196 readOnly: true | 217 readOnly: true |
| 197 }, | 218 }, |
| 198 | 219 |
| 199 /** | 220 /** |
| 221 * The value for this element that will be used when submitting in |
| 222 * a form. It is read only, and will always have the same value |
| 223 * as `selectedItemLabel`. |
| 224 */ |
| 225 value: { |
| 226 type: String, |
| 227 notify: true, |
| 228 readOnly: true |
| 229 }, |
| 230 |
| 231 /** |
| 200 * The label for the dropdown. | 232 * The label for the dropdown. |
| 201 */ | 233 */ |
| 202 label: { | 234 label: { |
| 203 type: String | 235 type: String |
| 204 }, | 236 }, |
| 205 | 237 |
| 206 /** | 238 /** |
| 207 * The placeholder for the dropdown. | 239 * The placeholder for the dropdown. |
| 208 */ | 240 */ |
| 209 placeholder: { | 241 placeholder: { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 keyBindings: { | 287 keyBindings: { |
| 256 'up down': 'open', | 288 'up down': 'open', |
| 257 'esc': 'close' | 289 'esc': 'close' |
| 258 }, | 290 }, |
| 259 | 291 |
| 260 hostAttributes: { | 292 hostAttributes: { |
| 261 role: 'group', | 293 role: 'group', |
| 262 'aria-haspopup': 'true' | 294 'aria-haspopup': 'true' |
| 263 }, | 295 }, |
| 264 | 296 |
| 297 observers: [ |
| 298 '_selectedItemChanged(selectedItem)' |
| 299 ], |
| 300 |
| 265 attached: function() { | 301 attached: function() { |
| 266 // NOTE(cdata): Due to timing, a preselected value in a `IronSelectable` | 302 // NOTE(cdata): Due to timing, a preselected value in a `IronSelectable` |
| 267 // child will cause an `iron-select` event to fire while the element is | 303 // child will cause an `iron-select` event to fire while the element is |
| 268 // still in a `DocumentFragment`. This has the effect of causing | 304 // still in a `DocumentFragment`. This has the effect of causing |
| 269 // handlers not to fire. So, we double check this value on attached: | 305 // handlers not to fire. So, we double check this value on attached: |
| 270 var contentElement = this.contentElement; | 306 var contentElement = this.contentElement; |
| 271 if (contentElement && contentElement.selectedItem) { | 307 if (contentElement && contentElement.selectedItem) { |
| 272 this._setSelectedItem(contentElement.selectedItem); | 308 this._setSelectedItem(contentElement.selectedItem); |
| 273 } | 309 } |
| 274 }, | 310 }, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 297 /** | 333 /** |
| 298 * A handler that is called when `iron-select` is fired. | 334 * A handler that is called when `iron-select` is fired. |
| 299 * | 335 * |
| 300 * @param {CustomEvent} event An `iron-select` event. | 336 * @param {CustomEvent} event An `iron-select` event. |
| 301 */ | 337 */ |
| 302 _onIronSelect: function(event) { | 338 _onIronSelect: function(event) { |
| 303 this._setSelectedItem(event.detail.item); | 339 this._setSelectedItem(event.detail.item); |
| 304 }, | 340 }, |
| 305 | 341 |
| 306 /** | 342 /** |
| 343 * A handler that is called when `iron-deselect` is fired. |
| 344 * |
| 345 * @param {CustomEvent} event An `iron-deselect` event. |
| 346 */ |
| 347 _onIronDeselect: function(event) { |
| 348 this._setSelectedItem(null); |
| 349 }, |
| 350 |
| 351 /** |
| 307 * A handler that is called when the dropdown is tapped. | 352 * A handler that is called when the dropdown is tapped. |
| 308 * | 353 * |
| 309 * @param {CustomEvent} event A tap event. | 354 * @param {CustomEvent} event A tap event. |
| 310 */ | 355 */ |
| 311 _onTap: function(event) { | 356 _onTap: function(event) { |
| 312 if (Polymer.Gestures.findOriginalTarget(event) === this) { | 357 if (Polymer.Gestures.findOriginalTarget(event) === this) { |
| 313 this.open(); | 358 this.open(); |
| 314 } | 359 } |
| 315 }, | 360 }, |
| 316 | 361 |
| 317 /** | 362 /** |
| 318 * Compute the label for the dropdown given a selected item. | 363 * Compute the label for the dropdown given a selected item. |
| 319 * | 364 * |
| 320 * @param {Element} selectedItem A selected Element item, with an | 365 * @param {Element} selectedItem A selected Element item, with an |
| 321 * optional `label` property. | 366 * optional `label` property. |
| 322 */ | 367 */ |
| 323 _computeSelectedItemLabel: function(selectedItem) { | 368 _selectedItemChanged: function(selectedItem) { |
| 369 var value = ''; |
| 324 if (!selectedItem) { | 370 if (!selectedItem) { |
| 325 return ''; | 371 value = ''; |
| 372 } else { |
| 373 value = selectedItem.label || selectedItem.textContent.trim(); |
| 326 } | 374 } |
| 327 | 375 |
| 328 return selectedItem.label || selectedItem.textContent.trim(); | 376 this._setValue(value); |
| 377 this._setSelectedItemLabel(value); |
| 329 }, | 378 }, |
| 330 | 379 |
| 331 /** | 380 /** |
| 332 * Compute the vertical offset of the menu based on the value of | 381 * Compute the vertical offset of the menu based on the value of |
| 333 * `noLabelFloat`. | 382 * `noLabelFloat`. |
| 334 * | 383 * |
| 335 * @param {boolean} noLabelFloat True if the label should not float | 384 * @param {boolean} noLabelFloat True if the label should not float |
| 336 * above the input, otherwise false. | 385 * above the input, otherwise false. |
| 337 */ | 386 */ |
| 338 _computeMenuVerticalOffset: function(noLabelFloat) { | 387 _computeMenuVerticalOffset: function(noLabelFloat) { |
| 339 // NOTE(cdata): These numbers are somewhat magical because they are | 388 // NOTE(cdata): These numbers are somewhat magical because they are |
| 340 // derived from the metrics of elements internal to `paper-input`'s | 389 // derived from the metrics of elements internal to `paper-input`'s |
| 341 // template. The metrics will change depending on whether or not the | 390 // template. The metrics will change depending on whether or not the |
| 342 // input has a floating label. | 391 // input has a floating label. |
| 343 return noLabelFloat ? -4 : 16; | 392 return noLabelFloat ? -4 : 8; |
| 393 }, |
| 394 |
| 395 /** |
| 396 * Returns false if the element is required and does not have a selection, |
| 397 * and true otherwise. |
| 398 * @return {Boolean} true if `required` is false, or if `required` is true |
| 399 * and the element has a valid selection. |
| 400 */ |
| 401 _getValidity: function() { |
| 402 return this.disabled || !this.required || (this.required && this.value); |
| 344 } | 403 } |
| 345 }); | 404 }); |
| 346 })(); | 405 })(); |
| 347 </script> | 406 </script> |
| 348 | |
| OLD | NEW |