Skip to content
Snippets Groups Projects
accordion-item.tsx 8.77 KiB
Newer Older
  • Learn to ignore specific revisions
  • import {Component, Listen, Prop, State, Element, h} from '@stencil/core';
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    @Component({
      tag: 'hy-accordion-item',
      styleUrl: 'accordion-item.scss',
      shadow: false
    })
    export class AccordionItem {
    
    Tuukka Turu's avatar
    Tuukka Turu committed
      @Element() el: HTMLElement;
    
    Tuukka Turu's avatar
    Tuukka Turu committed
      @Prop() accordiontitle?: string;
    
    Tuukka Turu's avatar
    Tuukka Turu committed
      @State() ready: boolean = false;
    
    
      @Listen('window:hashchange')
      onHashChange() {
        let anchor = window.location.hash;
    
        if (anchor.length > 0) {
          //console.log(anchor);
          //console.log('Please Open the Panel');
    
          let target = document.querySelectorAll(`${anchor}`)[0];
          let targetParent = target.closest('.hy-accordion__item');
          let targetContent = targetParent.querySelectorAll('.hy-accordion__content')[0];
          this.expandSection1(targetContent);
        }
      }
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
      componentDidLoad() {
        this.ready = true;
      }
    
      componentDidRender() {
        let anchor = window.location.hash;
    
        if (anchor.length > 0) {
          console.log(anchor);
          console.log('Please Open the Panel');
    
          let target = document.querySelectorAll(`${anchor}`)[0];
          let targetParent = target.closest('.hy-accordion__item');
          let targetContent = targetParent.querySelectorAll('.hy-accordion__content')[0];
          this.expandSection1(targetContent);
        }
      }
    
      collapseSection1(element) {
        element.style.height = 0 + 'px';
        element.setAttribute('data-collapsed', 'true');
        setTimeout(() => {
          element.style.display = 'none';
        }, 250);
      }
    
      expandSection1(element) {
        element.style.display = 'block';
        element.style.height = element.scrollHeight + 'px';
        element.setAttribute('data-collapsed', 'false');
      }
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
      render() {
    
    Tuukka Turu's avatar
    Tuukka Turu committed
        const containerId = this.el.parentElement.id;
    
    Tuukka Turu's avatar
    Tuukka Turu committed
        function collapseSection(element) {
          element.style.height = 0 + 'px';
          element.setAttribute('data-collapsed', 'true');
    
    Tuukka Turu's avatar
    Tuukka Turu committed
          setTimeout(() => {
            element.style.display = 'none';
          }, 250);
    
    Tuukka Turu's avatar
    Tuukka Turu committed
        }
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
        function expandSection(element) {
    
    Tuukka Turu's avatar
    Tuukka Turu committed
          element.style.display = 'block';
          element.style.height = element.scrollHeight + 'px';
    
    Tuukka Turu's avatar
    Tuukka Turu committed
          element.setAttribute('data-collapsed', 'false');
        }
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
        if (this.ready && containerId.length > 0) {
          document.querySelectorAll(`#${containerId}`).forEach(function (accordion) {
    
    Tuukka Turu's avatar
    Tuukka Turu committed
            const allowMultiple = accordion.hasAttribute('data-allow-multiple');
    
    Tuukka Turu's avatar
    Tuukka Turu committed
            const allowToggle = allowMultiple ? allowMultiple : accordion.hasAttribute('data-allow-toggle');
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
            const triggers = Array.prototype.slice.call(accordion.querySelectorAll('.hy-accordion__button'));
    
            accordion.addEventListener('click', function (event) {
              let target = event.target as HTMLTextAreaElement;
    
    Tuukka Turu's avatar
    Tuukka Turu committed
              const targetElement = target.tagName.toLowerCase();
              const possibleTags = [targetElement].some((r) => ['svg', 'path', 'button'].indexOf(r) >= 0);
    
    Tuukka Turu's avatar
    Tuukka Turu committed
              if (target && possibleTags) {
                if (targetElement !== 'button') {
                  target = target.closest('.hy-accordion__button');
                }
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                let targetParent = target.closest('.hy-accordion__item');
                let targetContent = targetParent.querySelectorAll('.hy-accordion__content')[0];
                const isExpanded = target.getAttribute('aria-expanded') == 'true';
                const active = accordion.querySelector('[aria-expanded="true"]');
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                if (!allowMultiple && active && active !== target) {
                  active.setAttribute('aria-expanded', 'false');
                  collapseSection(targetContent);
                  if (targetParent.classList.contains('hy-accordion__item__is-open')) {
                    targetParent.classList.remove('hy-accordion__item__is-open');
                  }
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                  accordion.querySelector(`#${active.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'true');
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                  if (!allowToggle) {
                    active.removeAttribute('aria-disabled');
                  }
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                if (!isExpanded) {
                  expandSection(targetContent);
                  target.setAttribute('aria-expanded', 'true');
                  targetParent.classList.add('hy-accordion__item__is-open');
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                  accordion.querySelector(`#${target.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'false');
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                  if (!allowToggle) {
                    target.setAttribute('aria-disabled', 'true');
                  }
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                } else if (allowToggle && isExpanded) {
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                  target.setAttribute('aria-expanded', 'false');
                  collapseSection(targetContent);
                  if (targetParent.classList.contains('hy-accordion__item__is-open')) {
                    targetParent.classList.remove('hy-accordion__item__is-open');
                  }
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                  accordion.querySelector(`#${target.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'true');
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                event.preventDefault();
    
                event.stopImmediatePropagation();
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
            if (accordion) {
              accordion.addEventListener('keydown', function (event: KeyboardEvent) {
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                const target = event.target as HTMLButtonElement;
                const key = event.which.toString();
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                // 33 = Page Up, 34 = Page Down
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                const ctrlModifier = event.ctrlKey && key.match(/33|34/);
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                if (target.classList.contains('hy-accordion__button')) {
                  // Up/ Down arrow and Control + Page Up/ Page Down keyboard operations
                  // 38 = Up, 40 = Down
                  if (key.match(/38|40/) || ctrlModifier) {
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                    const index = triggers.indexOf(target);
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                    const direction = key.match(/34|40/) ? 1 : -1;
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                    const length = triggers.length;
                    const newIndex = (index + length + direction) % length;
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                    triggers[newIndex].focus();
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                    event.preventDefault();
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                  } else if (key.match(/35|36/)) {
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                    // 35 = End, 36 = Home keyboard operations
                    switch (key) {
                      // Go to first accordion
                      case '36':
                        triggers[0].focus();
                        break;
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                      // Go to last accordion
    
    Tuukka Turu's avatar
    Tuukka Turu committed
                      case '35':
                        triggers[triggers.length - 1].focus();
                        break;
                    }
                    event.preventDefault();
                  }
                }
              });
    
    Tuukka Turu's avatar
    Tuukka Turu committed
    
    
    Tuukka Turu's avatar
    Tuukka Turu committed
              accordion.querySelectorAll('.hy-accordion__button').forEach(function (trigger) {
                trigger.addEventListener('focus', function () {
                  trigger.classList.add('focus');
                });
                trigger.addEventListener('blur', function () {
                  trigger.classList.remove('focus');
                });
              });
    
    Tuukka Turu's avatar
    Tuukka Turu committed
        const classAttributes = ['hy-accordion__item'];
        const titleAsId = this.accordiontitle.toLowerCase().replace(/\W/g, '-');
    
        const accordionItemHref = '#' + titleAsId + '--title';
    
        return (
          <div class={classAttributes.join(' ')}>
            <div class="hy-accordion--heading">
              <a href={accordionItemHref} class="hy-accordion__link">
                <button
                  aria-expanded="false"
                  aria-controls={`${titleAsId}--content`}
                  class="hy-accordion__button"
                  id={`${titleAsId}--title`}
                >
                  <span class="hy-accordion--heading__icon">
                    <hy-icon icon={'hy-icon-caret-down'} size={20} />
                  </span>
                  {this.accordiontitle}
                </button>
              </a>
            </div>
            <div
              aria-labelledBy={`${titleAsId}--title`}
              class="hy-accordion__content"
              id={`${titleAsId}--content`}
              role="region"
              aria-hidden="true"
              style={{display: 'none'}}
            >
              <hy-box pt="1.5" pb="3" pl="2" pr="2">
                <div class="hy-accordion__content--inner-wrapper">
                  <slot></slot>
                </div>
              </hy-box>
            </div>
          </div>
        );
    
        /*
    
    Tuukka Turu's avatar
    Tuukka Turu committed
        return (
    
    Tuukka Turu's avatar
    Tuukka Turu committed
          <div class={classAttributes.join(' ')}>
    
    Tuukka Turu's avatar
    Tuukka Turu committed
            <div class="hy-accordion--heading">
    
                <button
                  aria-expanded="false"
                  aria-controls={`${titleAsId}--content`}
                  class="hy-accordion__button"
                  id={`${titleAsId}--title`}
                >
                  <span class="hy-accordion--heading__icon">
                    <hy-icon icon={'hy-icon-caret-down'} size={20} />
                  </span>
                  {this.accordiontitle}
                </button>
    
    Tuukka Turu's avatar
    Tuukka Turu committed
            </div>
    
    Tuukka Turu's avatar
    Tuukka Turu committed
            <div
              aria-labelledBy={`${titleAsId}--title`}
              class="hy-accordion__content"
              id={`${titleAsId}--content`}
              role="region"
    
    Tuukka Turu's avatar
    Tuukka Turu committed
              aria-hidden="true"
              style={{display: 'none'}}
    
    Tuukka Turu's avatar
    Tuukka Turu committed
              <hy-box pt="1.5" pb="3" pl="2" pr="2">
                <div class="hy-accordion__content--inner-wrapper">
                  <slot></slot>
                </div>
              </hy-box>
    
    Tuukka Turu's avatar
    Tuukka Turu committed
            </div>
          </div>
        );