You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
menu/dropdown.js

106 lines
2.5 KiB
JavaScript

export class Dropdown extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'})
this.dialogEl = document.createElement('dialog')
this.dialogEl.addEventListener('click', e => {
const rect = this.dialogEl.getBoundingClientRect()
const clickedInDialog = (
rect.top <= e.clientY &&
e.clientY <= rect.top + rect.height &&
rect.left <= e.clientX &&
e.clientX <= rect.left + rect.width
)
const isDialog = e.target === this.dialogEl
if (isDialog && !clickedInDialog) {
this.close()
}
})
this.shadowRoot.appendChild(this.dialogEl)
}
connectedCallback() {
const style = document.createElement('style')
style.textContent = `
dialog {
min-width: 200px;
border: 1px solid rgba(0, 0, 0, 0.3);
border-radius: 6px;
box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
}
dialog {
background: #222;
color: #ddd;
padding: 3px;
margin-top: var(--anchor-bottom);
margin-right: calc(
100% - var(--anchor-right)
);
margin-left: auto;
margin-bottom: auto;
position: static;
}
dialog[open] {
display: flex;
flex-direction: column;
}
dialog::backdrop {
opacity: 0;
top: 0;
left: 0;
margin: 0;
padding: 0;
height: var(--window-height);
height: var(--window-width);
}
button {
background: #222;
font-size: 16px;
border: none;
color: inherit;
padding: 8px 10px;
text-align: left;
}
`
this.shadowRoot.append(style)
}
open(anchor) {
const rect = anchor.getBoundingClientRect()
const style = this.shadowRoot.host.style
style.setProperty(
'--anchor-right', `${rect.right}px`
)
style.setProperty(
'--anchor-bottom',
`${window.scrollY + rect.bottom - 3}px`
)
style.setProperty(
'--window-height', `${window.height}px`
)
style.setProperty(
'--window-width', `${window.width}px`
)
this.dialogEl.showModal()
}
close() {
this.dialogEl.close()
}
clear() {
this.dialogEl.replaceChildren()
}
add(text, handler = undefined) {
const btn = document.createElement('button')
btn.innerText = text
this.dialogEl.appendChild(btn)
btn.addEventListener('click', () => {
this.close()
if (handler !== undefined) {
handler()
}
})
}
}