| <!-- |
| @license |
| Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |
| This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
| The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
| Code distributed by Google as part of the polymer project is also |
| subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
| --> |
| |
| <link rel="import" href="../polymer/polymer.html"> |
| <link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html"> |
| |
| <!-- |
| `iron-collapse` creates a collapsible block of content. By default, the content |
| will be collapsed. Use `opened` or `toggle()` to show/hide the content. |
| |
| <button on-click="toggle">toggle collapse</button> |
| |
| <iron-collapse id="collapse"> |
| <div>Content goes here...</div> |
| </iron-collapse> |
| |
| ... |
| |
| toggle: function() { |
| this.$.collapse.toggle(); |
| } |
| |
| `iron-collapse` adjusts the max-height/max-width of the collapsible element to show/hide |
| the content. So avoid putting padding/margin/border on the collapsible directly, |
| and instead put a div inside and style that. |
| |
| <style> |
| .collapse-content { |
| padding: 15px; |
| border: 1px solid #dedede; |
| } |
| </style> |
| |
| <iron-collapse> |
| <div class="collapse-content"> |
| <div>Content goes here...</div> |
| </div> |
| </iron-collapse> |
| |
| ### Styling |
| |
| The following custom properties and mixins are available for styling: |
| |
| Custom property | Description | Default |
| ----------------|-------------|---------- |
| `--iron-collapse-transition-duration` | Animation transition duration | `300ms` |
| |
| @group Iron Elements |
| @hero hero.svg |
| @demo demo/index.html |
| @element iron-collapse |
| --> |
| |
| <dom-module id="iron-collapse"> |
| |
| <template> |
| |
| <style> |
| :host { |
| display: block; |
| transition-duration: var(--iron-collapse-transition-duration, 300ms); |
| /* Safari 10 needs this property prefixed to correctly apply the custom property */ |
| -webkit-transition-duration: var(--iron-collapse-transition-duration, 300ms); |
| overflow: visible; |
| } |
| |
| :host(.iron-collapse-closed) { |
| display: none; |
| } |
| |
| :host(:not(.iron-collapse-opened)) { |
| overflow: hidden; |
| } |
| </style> |
| |
| <slot></slot> |
| |
| </template> |
| |
| </dom-module> |
| |
| <script> |
| Polymer({ |
| |
| is: 'iron-collapse', |
| |
| behaviors: [Polymer.IronResizableBehavior], |
| |
| properties: { |
| |
| /** |
| * If true, the orientation is horizontal; otherwise is vertical. |
| * |
| * @attribute horizontal |
| */ |
| horizontal: {type: Boolean, value: false, observer: '_horizontalChanged'}, |
| |
| /** |
| * Set opened to true to show the collapse element and to false to hide it. |
| * |
| * @attribute opened |
| */ |
| opened: |
| {type: Boolean, value: false, notify: true, observer: '_openedChanged'}, |
| |
| /** |
| * When true, the element is transitioning its opened state. When false, |
| * the element has finished opening/closing. |
| * |
| * @attribute transitioning |
| */ |
| transitioning: {type: Boolean, notify: true, readOnly: true}, |
| |
| /** |
| * Set noAnimation to true to disable animations. |
| * |
| * @attribute noAnimation |
| */ |
| noAnimation: {type: Boolean}, |
| |
| /** |
| * Stores the desired size of the collapse body. |
| * @private |
| */ |
| _desiredSize: {type: String, value: ''} |
| }, |
| |
| get dimension() { |
| return this.horizontal ? 'width' : 'height'; |
| }, |
| |
| /** |
| * `maxWidth` or `maxHeight`. |
| * @private |
| */ |
| get _dimensionMax() { |
| return this.horizontal ? 'maxWidth' : 'maxHeight'; |
| }, |
| |
| /** |
| * `max-width` or `max-height`. |
| * @private |
| */ |
| get _dimensionMaxCss() { |
| return this.horizontal ? 'max-width' : 'max-height'; |
| }, |
| |
| hostAttributes: { |
| role: 'group', |
| 'aria-hidden': 'true', |
| }, |
| |
| listeners: {transitionend: '_onTransitionEnd'}, |
| |
| /** |
| * Toggle the opened state. |
| * |
| * @method toggle |
| */ |
| toggle: function() { |
| this.opened = !this.opened; |
| }, |
| |
| show: function() { |
| this.opened = true; |
| }, |
| |
| hide: function() { |
| this.opened = false; |
| }, |
| |
| /** |
| * Updates the size of the element. |
| * @param {string} size The new value for `maxWidth`/`maxHeight` as css property value, usually `auto` or `0px`. |
| * @param {boolean=} animated if `true` updates the size with an animation, otherwise without. |
| */ |
| updateSize: function(size, animated) { |
| // Consider 'auto' as '', to take full size. |
| size = size === 'auto' ? '' : size; |
| |
| var willAnimate = animated && !this.noAnimation && this.isAttached && |
| this._desiredSize !== size; |
| |
| this._desiredSize = size; |
| |
| this._updateTransition(false); |
| // If we can animate, must do some prep work. |
| if (willAnimate) { |
| // Animation will start at the current size. |
| var startSize = this._calcSize(); |
| // For `auto` we must calculate what is the final size for the animation. |
| // After the transition is done, _transitionEnd will set the size back to |
| // `auto`. |
| if (size === '') { |
| this.style[this._dimensionMax] = ''; |
| size = this._calcSize(); |
| } |
| // Go to startSize without animation. |
| this.style[this._dimensionMax] = startSize; |
| // Force layout to ensure transition will go. Set scrollTop to itself |
| // so that compilers won't remove it. |
| this.scrollTop = this.scrollTop; |
| // Enable animation. |
| this._updateTransition(true); |
| // If final size is the same as startSize it will not animate. |
| willAnimate = (size !== startSize); |
| } |
| // Set the final size. |
| this.style[this._dimensionMax] = size; |
| // If it won't animate, call transitionEnd to set correct classes. |
| if (!willAnimate) { |
| this._transitionEnd(); |
| } |
| }, |
| |
| /** |
| * enableTransition() is deprecated, but left over so it doesn't break |
| * existing code. Please use `noAnimation` property instead. |
| * |
| * @method enableTransition |
| * @deprecated since version 1.0.4 |
| */ |
| enableTransition: function(enabled) { |
| Polymer.Base._warn( |
| '`enableTransition()` is deprecated, use `noAnimation` instead.'); |
| this.noAnimation = !enabled; |
| }, |
| |
| _updateTransition: function(enabled) { |
| this.style.transitionDuration = (enabled && !this.noAnimation) ? '' : '0s'; |
| }, |
| |
| _horizontalChanged: function() { |
| this.style.transitionProperty = this._dimensionMaxCss; |
| var otherDimension = |
| this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxWidth'; |
| this.style[otherDimension] = ''; |
| this.updateSize(this.opened ? 'auto' : '0px', false); |
| }, |
| |
| _openedChanged: function() { |
| this.setAttribute('aria-hidden', !this.opened); |
| |
| this._setTransitioning(true); |
| this.toggleClass('iron-collapse-closed', false); |
| this.toggleClass('iron-collapse-opened', false); |
| this.updateSize(this.opened ? 'auto' : '0px', true); |
| |
| // Focus the current collapse. |
| if (this.opened) { |
| this.focus(); |
| } |
| }, |
| |
| _transitionEnd: function() { |
| this.style[this._dimensionMax] = this._desiredSize; |
| this.toggleClass('iron-collapse-closed', !this.opened); |
| this.toggleClass('iron-collapse-opened', this.opened); |
| this._updateTransition(false); |
| this.notifyResize(); |
| this._setTransitioning(false); |
| }, |
| |
| _onTransitionEnd: function(event) { |
| if (Polymer.dom(event).rootTarget === this) { |
| this._transitionEnd(); |
| } |
| }, |
| |
| _calcSize: function() { |
| return this.getBoundingClientRect()[this.dimension] + 'px'; |
| } |
| |
| }); |
| </script> |