UNPKG

minsky-kit

Version:
199 lines (161 loc) 5.79 kB
// imports import Component from "./Component"; import Ticker from "../managers/Ticker"; import { getInstances } from "../core/Core"; import { strToCssClass } from "../utils/css"; import { generateAccordionElement as factory1, removeAccordionElement as factory2, } from "../factories/AccordionFactory"; // static const // class definition export default class Accordion extends Component { // constructor constructor(args = {}, objectName = 'Accordion') { // call super super(args, objectName); // set properties this._name = args.name || 'accordion'; this.$titleWrapper = this.$el.querySelector(`.${this._name}__title-wrapper`); this.$trigger = this.$el.querySelector(`.${this._name}__trigger`); this.$arrow = this.$el.querySelector(`.${this._name}__arrow`); this.$contentWrapper = this.$el.querySelector(`.${this._name}__content-wrapper`); this.$content = this.$el.querySelector(`.${this._name}__content`); this.hash = `#${this.$el.getAttribute('id')}`; this.isOpen = args.isOpen ? args.isOpen : false; this.group = args.group || null; this.closedHeight = args.closedHeight || 0; this.preventDefault = args.preventDefault || false; // add group to el as data if (this.group) { this.$el.dataset.accordionGroup = this.group; } // toggle animation for init to remove transition on creation setNoAnimation.call(this); // check for hash in URL if (window.location.hash && window.location.hash === this.hash && !this.isOpen) this.isOpen = true; // set start state this.toggle(this.isOpen, true); // add listeners this.$titleWrapper.addEventListener('click', this.blm.add('onTitleClick', onTitleClick)); } // methods open(hard = false, dynamic = false) { // check noAnimation if (hard) setNoAnimation.call(this); // loop over instances and close them if groups match if (this.group) { const instances = getInstances(); for (const instance of instances[this.objectName]) { if (instance.isOpen && instance.group === this.group) instance.close(); } } // open this.$el.classList.add(strToCssClass(this._name, null, 'open')); this.$el.classList.remove(strToCssClass(this._name, null, 'closed')); // update state this.isOpen = true; // updateSize before opening if (dynamic) { window.requestAnimationFrame(() => { window.requestAnimationFrame(() => { this.refresh(); }); }) } else { this.refresh(); } // update accesibility this.$trigger.setAttribute('aria-expanded', true); // dispatch event this.dispatch('open'); } close(hard = false) { // check noAnimation if (hard) setNoAnimation.call(this); // open this.$el.classList.add(strToCssClass(this._name, null, 'closed')); this.$el.classList.remove(strToCssClass(this._name, null, 'open')); // update state this.isOpen = false; // updateSize before opening this.refresh(); // update accesibility this.$trigger.setAttribute('aria-expanded', false); // dispatch event this.dispatch('close'); } toggle(forceState = null, hard = false) { // check forced state const isOpen = typeof forceState === 'boolean' ? !!forceState : !this.isOpen; // toggle if (!isOpen) { this.close(hard); } else { this.open(hard); } // !isOpen ? this.close(hard) : this.open(hard); } refresh() { const height = this.isOpen ? this.$content.offsetHeight : this.closedHeight; this.$contentWrapper.style.height = height + (parseFloat(height).toString().length === height.toString().length ? 'px' : ''); // dispatch event this.dispatch('refresh'); } destroy() { this.$contentWrapper.style.height = null; this.$el.classList.remove(strToCssClass(this._name, null, 'open'), strToCssClass(this._name, null, 'closed'), this._name); this.$titleWrapper.removeEventListener('click', this.blm.remove('onTitleClick', onTitleClick)); super.destroy(); } // getters & setters get title() { return this.$titleWrapper.querySelector(`.${this._name}__title`).innerText; } set title(value) { if (value !== this.title) { this.$titleWrapper.querySelector(`.${this._name}__title`).innerText = value; } } get transition() { return this.$el.classList.contains(strToCssClass(this._name, 'noAnimation')); } set transition(value) { if (this.transition !== value) { if (!value) { this.$el.classList.add(strToCssClass(this._name, 'noAnimation')); this.$contentWrapper.style.transition = 'none'; this.$arrow.style.transition = 'none'; } else { this.$el.classList.remove(strToCssClass(this._name, 'noAnimation')); this.$contentWrapper.style.transition = null; this.$arrow.style.transition = null; } } } } // event listeners function onTitleClick(e) { this.dispatch('titleClick', { originalEvent: e, }); if (!e.defaultPrevented) { this.toggle(); } if (this.preventDefault) e.preventDefault(); } function setNoAnimation() { this.transition = false; Ticker.quick(50, () => { this.transition = true; }); } // deprecated methods export function generateAccordionElement(args) { this.log('warn', "Deprecation warning: 'generateAccordionElement' in Accortdion is deprecated, use 'generateAccordionElement()` from /factories/AccordionFactory.js instead."); return factory1(args); } export function removeAccordionElement(args) { this.log('warn', "Deprecation warning: 'removeAccordionElement' in Accortdion is deprecated, use 'removeAccordionElement()` from /factories/AccordionFactory.js instead."); return factory2(args); }