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;
}
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', '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', this.variant].join(' ');
const titleAsId = this.accordiontitle.toLowerCase().replace(/\W/g, '-');
const accordionItemHref = '#' + titleAsId + '--title';
return (
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
<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"
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={classContentAttributes}
id={`${titleAsId}--content`}
role="region"
aria-hidden="true"
style={{display: 'none'}}
>
<hy-box pt="0" pb="0" pl="0.75" pr="0.75">
<div class="hy-accordion__content--inner-wrapper">
<slot></slot>
</div>
</hy-box>
</div>