Newer
Older
import {Component, Listen, Prop, State, Element, h} from '@stencil/core';
import {AccordionVariants} from '../../utils/utils';
let keys = {
enter: 'Enter', //13
tab: 'Tab', //9
pageUp: 'PageUp', //33
pageDown: 'PageDown', //34
arrowUp: 'ArrowUp', // 38
arrowDown: 'ArrowDown', //40
home: 'Home', //36
end: 'End', //35
};
@Component({
tag: 'hy-accordion-item',
styleUrl: 'accordion-item.scss',
Ekaterina Kondareva
committed
shadow: false,
@Prop() variant: AccordionVariants = AccordionVariants.default;
componentDidLoad() {
this.ready = true;
let hyMainDiv = this.el.closest('.hy-main');
if (hyMainDiv) {
if (!hyMainDiv.classList.contains('with-sidebar')) {
this.headerstyle = 'large';
}
}
}
componentDidRender() {
if (window.location.hash) {
this.expandPanelByAnchor(window.location.hash);
}
}
if (window.location.hash) {
this.expandPanelByAnchor(window.location.hash);
}
}
@Listen('keydown')
handleKeyDown(event: KeyboardEvent) {
const containerId = this.el.parentElement.id;
let accordion = document.querySelectorAll(`#${containerId}`)[0];
const triggers = Array.prototype.slice.call(accordion.querySelectorAll('.hy-accordion__button'));
let target = event.target as HTMLButtonElement;
const ctrlModifier = event.ctrlKey && [keys.pageDown, keys.pageUp].includes(key); //key.match(/33|34/);
if (target.classList.contains('hy-accordion__button')) {
// Up/ Down arrow and Control + Page Up/ Page Down keyboard operations
if ([keys.arrowDown, keys.arrowUp].includes(key) || ctrlModifier) {
const index = triggers.indexOf(target);
const direction = [keys.arrowDown, keys.pageDown].includes(key) ? 1 : -1;
const length = triggers.length;
const newIndex = (index + length + direction) % length;
triggers[newIndex].focus();
event.preventDefault();
} else if ([keys.home, keys.end].includes(key)) {
switch (key) {
// Go to first accordion
triggers[0].focus();
break;
// Go to last accordion
triggers[triggers.length - 1].focus();
break;
}
event.preventDefault();
}
}
}
@Listen('click')
handleClick(event) {
const containerId = this.el.parentElement.id;
let target = event.target as HTMLTextAreaElement;
const targetElement = target.tagName.toLowerCase();
const possibleTags = [targetElement].some((r) => ['svg', 'span', 'path', 'button', 'a'].indexOf(r) >= 0);
let accordion = document.querySelectorAll(`#${containerId}`)[0];
const allowMultiple = accordion.hasAttribute('data-allow-multiple');
const allowToggle = allowMultiple ? allowMultiple : accordion.hasAttribute('data-allow-toggle');
if (target && possibleTags) {
if (targetElement !== 'button') {
target = target.closest('.hy-accordion__button');
}
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"]');
if (!allowMultiple && active && active !== target) {
active.setAttribute('aria-expanded', 'false');
this.collapseSection(targetContent);
if (targetParent.classList.contains('hy-accordion__item__is-open')) {
targetParent.classList.remove('hy-accordion__item__is-open');
}
accordion.querySelector(`#${active.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'true');
if (!allowToggle) {
active.removeAttribute('aria-disabled');
}
}
if (!isExpanded) {
this.expandSection(targetContent);
target.setAttribute('aria-expanded', 'true');
targetParent.classList.add('hy-accordion__item__is-open');
accordion.querySelector(`#${target.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'false');
if (!allowToggle) {
target.setAttribute('aria-disabled', 'true');
}
} else if (allowToggle && isExpanded) {
target.setAttribute('aria-expanded', 'false');
this.collapseSection(targetContent);
if (targetParent.classList.contains('hy-accordion__item__is-open')) {
targetParent.classList.remove('hy-accordion__item__is-open');
}
accordion.querySelector(`#${target.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'true');
}
event.preventDefault();
event.stopImmediatePropagation();
}
}
expandPanelByAnchor(anchor) {
if (anchor.length > 0) {
anchor = anchor.substr(1);
let target = document.querySelectorAll(`[id=${anchor}]`)[0];
if (target && target.classList.contains('hy-accordion__button')) {
let targetParent = target.closest('.hy-accordion__item');
let targetContent = targetParent.querySelectorAll('.hy-accordion__content')[0];
this.expandSection(targetContent);
target.setAttribute('aria-expanded', 'true');
targetParent.classList.add('hy-accordion__item__is-open');
const containerId = targetParent.parentElement.parentElement.id;
if (containerId.length > 0) {
let accordion = document.querySelectorAll(`#${containerId}`)[0];
accordion.querySelector(`#${target.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'false');
}
collapseSection(element) {
element.style.height = 0 + 'px';
element.setAttribute('data-collapsed', 'true');
setTimeout(() => {
element.style.display = 'none';
}, 250);
}
expandSection(element) {
element.style.display = 'block';
element.style.height = element.scrollHeight + 'px';
element.setAttribute('data-collapsed', 'false');
}
if (this.ready && containerId.length > 0) {
document.querySelectorAll(`#${containerId}`).forEach(function (accordion) {
if (accordion) {
accordion.querySelectorAll('.hy-accordion__button').forEach(function (trigger) {
trigger.addEventListener('focus', function () {
trigger.classList.add('focus');
});
trigger.addEventListener('blur', function () {
trigger.classList.remove('focus');
});
});
const classAttributes = ['hy-accordion__item', this.variant].join(' ');
const classInnerWrapper = ['hy-accordion__item--container', this.variant].join(' ');
const classHeadingAttributes = ['hy-accordion--heading', this.variant].join(' ');
const classContentAttributes = [
'hy-accordion__content',
`hy-accordion__content--${this.variant}`,
this.variant,
].join(' ');
const classContentInnerWrapper = [
'hy-accordion__content--inner-wrapper',
`hy-accordion__content--inner-wrapper--${this.headerstyle}`,
`hy-accordion__content--inner-wrapper--${this.variant}`,
].join(' ');
const titleAsId = this.accordiontitle.toLowerCase().replace(/\W/g, '-');
const accordionItemHref = '#' + titleAsId + '--title';
return (
<div class={classAttributes}>
<div class={classInnerWrapper}>
<div class={classHeadingAttributes}>
<a href={accordionItemHref} class="hy-accordion__link" tabindex="-1">
<button
aria-expanded="false"
aria-controls={`${titleAsId}--content`}
class={`hy-accordion__button hy-accordion__button--${this.headerstyle}`}
id={`${titleAsId}--title`}
>
<span class="hy-accordion--heading__icon">
</button>
</a>
</div>
<div
aria-labelledBy={`${titleAsId}--title`}
class={classContentAttributes}
id={`${titleAsId}--content`}
role="region"
aria-hidden="true"
style={{display: 'none'}}
>
<div class={classContentInnerWrapper}>
<slot></slot>
</div>