Нема описа
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

accordion.js 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. class AccordionItem extends HTMLElement {
  2. static get observedAttributes() {
  3. return ['title'];
  4. }
  5. #title = '';
  6. #collapsed = true;
  7. constructor() {
  8. super();
  9. this.attachShadow({ mode: 'open' });
  10. }
  11. connectedCallback() {
  12. this.update();
  13. this.shadowRoot.addEventListener('click', this.toggle.bind(this));
  14. }
  15. attributeChangedCallback(name, oldValue, newValue) {
  16. if (name === 'title') {
  17. this.#title = newValue;
  18. }
  19. this.update();
  20. }
  21. toggle() {
  22. this.#collapsed = !this.#collapsed;
  23. this.update();
  24. // Dispatch a custom event to notify the parent AccordionElement
  25. const event = new CustomEvent('accordion-item-toggle', {
  26. bubbles: true,
  27. detail: {
  28. collapsed: this.#collapsed,
  29. item: this,
  30. },
  31. });
  32. this.dispatchEvent(event);
  33. }
  34. update() {
  35. this.shadowRoot.innerHTML = `
  36. <style>
  37. .accordion-item {
  38. }
  39. .accordion-title {
  40. display: flex;
  41. justify-content: space-between;
  42. align-items: center;
  43. cursor: pointer;
  44. padding: 0.5rem;
  45. background-color: white;
  46. }
  47. .accordion-title:hover {
  48. background-color: white;
  49. }
  50. .accordion-title::after {
  51. content: '${this.#collapsed ? '+' : '−'}';
  52. font-size: 1rem;
  53. font-weight: bold;
  54. color: #777;
  55. margin-left: 0.5rem;
  56. }
  57. .accordion-content {
  58. padding: 0.5rem;
  59. display: ${this.#collapsed ? 'none' : 'block'};
  60. }
  61. </style>
  62. <div class="accordion-item">
  63. <div class="accordion-title">${this.#title}</div>
  64. <div class="accordion-content">
  65. <slot></slot>
  66. </div>
  67. </div>
  68. `;
  69. }
  70. }
  71. class AccordionElement extends HTMLElement {
  72. #activeItem = null;
  73. constructor() {
  74. super();
  75. this.attachShadow({ mode: 'open' });
  76. this.shadowRoot.innerHTML = '<slot></slot>';
  77. this.addEventListener('accordion-item-toggle', this.handleItemToggle.bind(this));
  78. }
  79. handleItemToggle(event) {
  80. const { collapsed, item } = event.detail;
  81. // If the active item is different from the toggled item, collapse the active item
  82. if (this.#activeItem && this.#activeItem !== item && !collapsed) {
  83. this.#activeItem.toggle();
  84. }
  85. // Update the active item
  86. if (!collapsed) {
  87. this.#activeItem = item;
  88. } else if (this.#activeItem === item) {
  89. this.#activeItem = null;
  90. }
  91. }
  92. }
  93. customElements.define('accordion-item', AccordionItem);
  94. customElements.define('accordion-element', AccordionElement);