1 changed files with 105 additions and 0 deletions
@ -0,0 +1,105 @@ |
|||
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: 120%; |
|||
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}px` |
|||
) |
|||
style.setProperty( |
|||
'--window-height', `${window.height}px` |
|||
) |
|||
style.setProperty( |
|||
'--window-width', `${window.width}px` |
|||
) |
|||
this.dialogEl.showModal() |
|||
this.dialogEl.classList.add('opened') |
|||
} |
|||
|
|||
close() { |
|||
this.dialogEl.close() |
|||
} |
|||
|
|||
add(text, handler = undefined) { |
|||
const btn = document.createElement('button') |
|||
btn.innerText = text |
|||
this.dialogEl.appendChild(btn) |
|||
btn.addEventListener('click', () => { |
|||
this.dispatchEvent(new CustomEvent( |
|||
'close-menu', {bubbles: true} |
|||
)) |
|||
if (handler !== undefined) { |
|||
handler() |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
Loading…
Reference in new issue