From 3d64bb099301a65ee73e0ad3f5e66c4bb6ea5d65 Mon Sep 17 00:00:00 2001 From: bat Date: Mon, 3 Apr 2023 08:29:09 +0000 Subject: [PATCH] Dropdown with --- dropdown.js | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 dropdown.js diff --git a/dropdown.js b/dropdown.js new file mode 100644 index 0000000..1f5b8ad --- /dev/null +++ b/dropdown.js @@ -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() + } + }) + } +} \ No newline at end of file