preline
Version:
Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.
207 lines (163 loc) • 5.14 kB
text/typescript
/*
* HSCollapse
* @version: 2.5.0
* @author: Preline Labs Ltd.
* @license: Licensed under MIT and Preline UI Fair Use License (https://preline.co/docs/license.html)
* Copyright 2024 Preline Labs Ltd.
*/
import { dispatch, afterTransition } from '../../utils';
import { ICollapse } from '../collapse/interfaces';
import HSBasePlugin from '../base-plugin';
import { ICollectionItem } from '../../interfaces';
class HSCollapse extends HSBasePlugin<{}> implements ICollapse {
private readonly contentId: string | null;
public content: HTMLElement | null;
private animationInProcess: boolean;
constructor(el: HTMLElement, options?: {}, events?: {}) {
super(el, options, events);
this.contentId = this.el.dataset.hsCollapse;
this.content = document.querySelector(this.contentId);
this.animationInProcess = false;
if (this.content) this.init();
}
private init() {
this.createCollection(window.$hsCollapseCollection, this);
if (this?.el?.ariaExpanded) {
if (this.el.classList.contains('open')) this.el.ariaExpanded = 'true';
else this.el.ariaExpanded = 'false';
}
this.el.addEventListener('click', () => {
if (this.content.classList.contains('open')) {
this.hide();
} else {
this.show();
}
});
}
private hideAllMegaMenuItems() {
this.content
.querySelectorAll('.hs-mega-menu-content.block')
.forEach((el) => {
el.classList.remove('block');
el.classList.add('hidden');
});
}
// Public methods
public show() {
if (this.animationInProcess || this.el.classList.contains('open'))
return false;
this.animationInProcess = true;
this.el.classList.add('open');
if (this?.el?.ariaExpanded) this.el.ariaExpanded = 'true';
this.content.classList.add('open');
this.content.classList.remove('hidden');
this.content.style.height = '0';
setTimeout(() => {
this.content.style.height = `${this.content.scrollHeight}px`;
this.fireEvent('beforeOpen', this.el);
dispatch('beforeOpen.hs.collapse', this.el, this.el);
});
afterTransition(this.content, () => {
this.content.style.height = '';
this.fireEvent('open', this.el);
dispatch('open.hs.collapse', this.el, this.el);
this.animationInProcess = false;
});
}
public hide() {
if (this.animationInProcess || !this.el.classList.contains('open'))
return false;
this.animationInProcess = true;
this.el.classList.remove('open');
if (this?.el?.ariaExpanded) this.el.ariaExpanded = 'false';
this.content.style.height = `${this.content.scrollHeight}px`;
setTimeout(() => {
this.content.style.height = '0';
});
this.content.classList.remove('open');
afterTransition(this.content, () => {
this.content.classList.add('hidden');
this.content.style.height = '';
this.fireEvent('hide', this.el);
dispatch('hide.hs.collapse', this.el, this.el);
this.animationInProcess = false;
});
if (this.content.querySelectorAll('.hs-mega-menu-content.block').length) {
this.hideAllMegaMenuItems();
}
}
// Static methods
static getInstance(target: HTMLElement, isInstance = false) {
const elInCollection = window.$hsCollapseCollection.find(
(el) =>
el.element.el ===
(typeof target === 'string' ? document.querySelector(target) : target),
);
return elInCollection
? isInstance
? elInCollection
: elInCollection.element.el
: null;
}
static autoInit() {
if (!window.$hsCollapseCollection) window.$hsCollapseCollection = [];
document
.querySelectorAll('.hs-collapse-toggle:not(.--prevent-on-load-init)')
.forEach((el: HTMLElement) => {
if (
!window.$hsCollapseCollection.find(
(elC) => (elC?.element?.el as HTMLElement) === el,
)
)
new HSCollapse(el);
});
}
static show(target: HTMLElement) {
const elInCollection = window.$hsCollapseCollection.find(
(el) =>
el.element.el ===
(typeof target === 'string' ? document.querySelector(target) : target),
);
if (
elInCollection &&
elInCollection.element.content.classList.contains('hidden')
)
elInCollection.element.show();
}
static hide(target: HTMLElement) {
const elInCollection = window.$hsCollapseCollection.find(
(el) =>
el.element.el ===
(typeof target === 'string' ? document.querySelector(target) : target),
);
if (
elInCollection &&
!elInCollection.element.content.classList.contains('hidden')
)
elInCollection.element.hide();
}
// Backward compatibility
static on(evt: string, target: HTMLElement, cb: Function) {
const elInCollection = window.$hsCollapseCollection.find(
(el) =>
el.element.el ===
(typeof target === 'string' ? document.querySelector(target) : target),
);
if (elInCollection) elInCollection.element.events[evt] = cb;
}
}
declare global {
interface Window {
HSCollapse: Function;
$hsCollapseCollection: ICollectionItem<HSCollapse>[];
}
}
window.addEventListener('load', () => {
HSCollapse.autoInit();
// Uncomment for debug
// console.log('Collapse collection:', window.$hsCollapseCollection);
});
if (typeof window !== 'undefined') {
window.HSCollapse = HSCollapse;
}
export default HSCollapse;