UNPKG

@ussebastian/kitdigital

Version:

Kit Digital de la Universidad San Sebastián

151 lines (128 loc) 4.84 kB
export class Collapsable { constructor(element, key) { this.key = key; this.element = element; this.triggerElement = null; this.contentElement = null; this.collapsableId = null; this.contentElementHeight = null; this.groupId = null; this.animationDuration = 250; this.isOpen = false; this.element = element; this.triggerElement = this.element; } // get the list of the group of collapsables setKeyboardNavigation() { if (this.groupId) { const currentGroup = window.USSKitDigital.componentsSharedState.Collapsable.groups[this.groupId]; // make the focus go to the previous collapsable, if its the first one go to the last this.element.addEventListener('keydown', (e) => { if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') { e.preventDefault(); const index = currentGroup.indexOf(this); if (index > 0) { currentGroup[index - 1].triggerElement.focus(); } else { currentGroup[currentGroup.length - 1].triggerElement.focus(); } } if (e.key === 'ArrowDown' || e.key === 'ArrowRight') { e.preventDefault(); const index = currentGroup.indexOf(this); if (index < currentGroup.length - 1) { currentGroup[index + 1].triggerElement.focus(); } else { currentGroup[0].triggerElement.focus(); } } if (e.key === 'Home' || e.keyCode === 36) { e.preventDefault(); currentGroup[0].triggerElement.focus(); } if (e.key === 'End' || e.keyCode === 35) { e.preventDefault(); currentGroup[currentGroup.length - 1].triggerElement.focus(); } }); } } closeGroup() { if ( window.USSKitDigital?.componentsSharedState?.Collapsable?.groups[this.groupId] === undefined ) { window.USSKitDigital.componentsSharedState = { Collapsable: { groups: { [this.groupId]: [], }, }, }; } window.USSKitDigital.componentsSharedState.Collapsable.groups[this.groupId].push(this); } closeAllGroupCollapsables() { window.USSKitDigital.componentsSharedState.Collapsable.groups[this.groupId].forEach( (collapsable) => { if (collapsable !== this) { collapsable.close(); } }, ); } mount() { this.collapsableId = this.triggerElement.dataset.ussCollapsableTriggerFor; this.animationDuration = this.triggerElement.dataset.ussCollapsableAnimationDuration || 250; this.groupId = this.triggerElement.dataset.ussCollapsableCloseGroup; if (this.groupId) this.closeGroup(); this.contentElement = document.querySelector( `[data-uss-collapsable-id="${this.collapsableId}"]`, ); this.contentElement.setAttribute('id', this.element.id || this.collapsableId); this.contentElement.style.setProperty('--animation-duration', `${this.animationDuration}ms`); if (!this.contentElement) { throw new Error('Collapsable: Content element not found.'); } // Initial state this.contentElementHeight = this.contentElement.offsetHeight; this.contentElement.style.setProperty( '--uss-collapsable-height', `${this.contentElementHeight}px`, ); this.contentElement.dataset.ussCollapsableOpen = 'false'; this.contentElement.setAttribute('aria-labelledby', `trigger-of-${this.collapsableId}`); this.triggerElement.setAttribute('aria-expanded', 'false'); this.triggerElement.setAttribute('aria-controls', this.element.id || this.collapsableId); this.triggerElement.setAttribute('id', `trigger-of-${this.collapsableId}`); this.toggleTabIndexes(); this.triggerElement.addEventListener('click', () => this.toggleOpenState()); this.setKeyboardNavigation(); } toggleOpenState() { this.contentElement.dataset.ussCollapsableOpen = String(!this.isOpen); this.triggerElement.setAttribute('aria-expanded', !this.isOpen); if (!this.isOpen) { if (this.groupId) this.closeAllGroupCollapsables(); setTimeout(() => { if (this.isOpen) this.contentElement.style.overflow = 'visible'; }, this.animationDuration); } else { this.contentElement.style.overflow = 'hidden'; } this.isOpen = !this.isOpen; this.toggleTabIndexes(); } close() { this.contentElement.dataset.ussCollapsableOpen = 'false'; this.triggerElement.setAttribute('aria-expanded', 'false'); this.contentElement.style.overflow = 'hidden'; this.isOpen = false; this.toggleTabIndexes(); } toggleTabIndexes() { this.contentElement.querySelectorAll('a, button, input, select, textarea').forEach((el) => { el.setAttribute('tabindex', this.isOpen ? '0' : '-1'); }); } }