ExamplesPlaygroundReference Source

coral-spectrum/coral-component-sidenav/src/scripts/SideNavLevel.js

  1. /**
  2. * Copyright 2019 Adobe. All rights reserved.
  3. * This file is licensed to you under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License. You may obtain a copy
  5. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. *
  7. * Unless required by applicable law or agreed to in writing, software distributed under
  8. * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
  9. * OF ANY KIND, either express or implied. See the License for the specific language
  10. * governing permissions and limitations under the License.
  11. */
  12.  
  13. import {commons} from '../../../coral-utils';
  14. import {BaseComponent} from '../../../coral-base-component';
  15. import {Decorator} from '../../../coral-decorator';
  16.  
  17. const CLASSNAME = '_coral-SideNav';
  18.  
  19. /**
  20. @class Coral.SideNav.Level
  21. @classdesc A SideNav Level component
  22. @htmltag coral-sidenav-level
  23. @extends {HTMLElement}
  24. @extends {BaseComponent}
  25. */
  26. const SideNavLevel = Decorator(class extends BaseComponent(HTMLElement) {
  27. /** @ignore */
  28. static get observedAttributes() {
  29. return super.observedAttributes.concat(['_expanded']);
  30. }
  31.  
  32. /** @ignore */
  33. attributeChangedCallback(name, oldValue, value) {
  34. if (name === '_expanded') {
  35. const isExpanded = value === 'on';
  36.  
  37. if (oldValue !== value) {
  38. this.classList.toggle('is-expanded', isExpanded);
  39.  
  40. // Do animation in next frame to avoid a forced reflow
  41. window.requestAnimationFrame(() => {
  42. // Don't animate on initialization
  43. if (this._animate) {
  44. // Remove height as we want the level to naturally grow if content is added later
  45. commons.transitionEnd(this, () => {
  46. if (isExpanded) {
  47. this.style.height = '';
  48. } else {
  49. this.hidden = true;
  50. }
  51. });
  52.  
  53. // Force height to enable transition
  54. if (!isExpanded) {
  55. this.style.height = `${this.scrollHeight}px`;
  56. } else {
  57. this.hidden = false;
  58. }
  59.  
  60. // We read the offset height to force a reflow, this is needed to start the transition between absolute values
  61. // https://blog.alexmaccaw.com/css-transitions under Redrawing
  62. // eslint-disable-next-line no-unused-vars
  63. const offsetHeight = this.offsetHeight;
  64.  
  65. this.style.height = isExpanded ? `${this.scrollHeight}px` : 0;
  66. } else {
  67. // Make sure it's animated next time
  68. this._animate = true;
  69.  
  70. // Hide it on initialization if closed
  71. if (!isExpanded) {
  72. this.style.height = 0;
  73. this.hidden = true;
  74. }
  75. }
  76. });
  77. }
  78. } else {
  79. super.attributeChangedCallback(name, oldValue, value);
  80. }
  81. }
  82.  
  83. /** @ignore */
  84. render() {
  85. super.render();
  86.  
  87. this.classList.add(CLASSNAME);
  88.  
  89. // a11y
  90. this.setAttribute('role', 'region');
  91. }
  92. });
  93.  
  94. export default SideNavLevel;