class UIDropdown extends HTMLElement {
isOpen: boolean = false
contentEl: HTMLElement | null = null
isClosing: boolean = false
constructor() {
super()
this.toggle = this.toggle.bind(this)
this.handleClickOutside = this.handleClickOutside.bind(this)
}
connectedCallback(): void {
const trigger = this.querySelector('[data-trigger]')
this.contentEl = this.querySelector('[data-content]')
if (trigger) {
trigger.addEventListener('click', this.toggle)
}
document.addEventListener('click', this.handleClickOutside)
}
disconnectedCallback(): void {
const trigger = this.querySelector('[data-trigger]')
if (trigger) {
trigger.removeEventListener('click', this.toggle)
}
document.removeEventListener('click', this.handleClickOutside)
}
toggle(): void {
if (this.isClosing) {
return
}
this.isOpen = !this.isOpen
if (this.contentEl) {
if (this.isOpen) {
this.contentEl.classList.remove('hidden')
} else {
this.contentEl.classList.add('hidden')
}
}
}
close(): void {
if (this.isClosing) {
return
}
this.isClosing = true
this.isOpen = false
if (this.contentEl) {
this.contentEl.classList.add('hidden')
}
setTimeout(() => {
this.isClosing = false
}, 100)
}
handleClickOutside(event: MouseEvent): void {
if (!this.contains(event.target as Node)) {
this.close()
}
}
}
customElements.define('ui-dropdown', UIDropdown)