Files
linkding/bookmarks/frontend/components/dropdown.js
2026-01-01 01:08:54 +01:00

73 lines
1.7 KiB
JavaScript

import { HeadlessElement } from "../utils/element.js";
class Dropdown extends HeadlessElement {
constructor() {
super();
this.opened = false;
this.onClick = this.onClick.bind(this);
this.onOutsideClick = this.onOutsideClick.bind(this);
this.onEscape = this.onEscape.bind(this);
this.onFocusOut = this.onFocusOut.bind(this);
}
init() {
// Prevent opening the dropdown automatically on focus, so that it only
// opens on click when JS is enabled
this.style.setProperty("--dropdown-focus-display", "none");
this.addEventListener("keydown", this.onEscape);
this.addEventListener("focusout", this.onFocusOut);
this.toggle = this.querySelector(".dropdown-toggle");
this.toggle.setAttribute("aria-expanded", "false");
this.toggle.addEventListener("click", this.onClick);
}
disconnectedCallback() {
this.close();
}
open() {
this.opened = true;
this.classList.add("active");
this.toggle.setAttribute("aria-expanded", "true");
document.addEventListener("click", this.onOutsideClick);
}
close() {
this.opened = false;
this.classList.remove("active");
this.toggle?.setAttribute("aria-expanded", "false");
document.removeEventListener("click", this.onOutsideClick);
}
onClick() {
if (this.opened) {
this.close();
} else {
this.open();
}
}
onOutsideClick(event) {
if (!this.contains(event.target)) {
this.close();
}
}
onEscape(event) {
if (event.key === "Escape" && this.opened) {
event.preventDefault();
this.close();
this.toggle.focus();
}
}
onFocusOut(event) {
if (!this.contains(event.relatedTarget)) {
this.close();
}
}
}
customElements.define("ld-dropdown", Dropdown);