Skip to content
Snippets Groups Projects
accordion-item.tsx 8.78 KiB
Newer Older
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('hashchange', {target: 'window'})
  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>
    );