Newer
Older
import {Component, Listen, Prop, State, Element, h} from '@stencil/core';
@Component({
tag: 'hy-accordion-item',
styleUrl: 'accordion-item.scss',
shadow: false
})
export class AccordionItem {
componentDidLoad() {
this.ready = true;
}
componentDidRender() {
if (window.location.hash) {
this.expandPanelByAnchor(window.location.hash);
}
}
if (window.location.hash) {
this.expandPanelByAnchor(window.location.hash);
}
}
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
@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 key = event.which.toString();
// 33 = Page Up, 34 = Page Down
const ctrlModifier = event.ctrlKey && key.match(/33|34/);
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) {
const index = triggers.indexOf(target);
const direction = key.match(/34|40/) ? 1 : -1;
const length = triggers.length;
const newIndex = (index + length + direction) % length;
triggers[newIndex].focus();
event.preventDefault();
} else if (key.match(/35|36/)) {
// 35 = End, 36 = Home keyboard operations
switch (key) {
// Go to first accordion
case '36':
triggers[0].focus();
break;
// Go to last accordion
case '35':
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'];
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" tabindex="-1">
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
<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>
);