1/** 2 * Drawer Component - ES Module 3 * 4 * Usage: 5 * 1. Include this script in your page 6 * 2. Add data attributes to your HTML: 7 * - data-drawer-id="unique-id" on the drawer element 8 * - data-drawer-trigger="unique-id" on any element that should open the drawer 9 * - data-drawer-close="unique-id" on any element inside the drawer that should close it 10 * 3. Use data-drawer-anchor to specify the drawer position (left, right, top, bottom) 11 */ 12 13import { openDialog } from "./dialog.js"; 14 15const drawerState = {}; 16let closeButtonHandlers = new Map(); 17let triggerHandlers = new Map(); 18let backdropClickHandler = null; 19let keyupHandler = null; 20 21function initializeDrawer(drawer) { 22 const id = drawer.dataset.drawerId; 23 if (!id) return; 24 25 drawerState[id] = { 26 isOpen: false, 27 element: drawer, 28 }; 29 30 const closeButtons = drawer.querySelectorAll(`[data-drawer-close="${id}"]`); 31 closeButtons.forEach((btn) => { 32 const handler = () => closeDrawer(id); 33 btn.addEventListener("click", handler); 34 closeButtonHandlers.set(btn, handler); 35 }); 36} 37 38function initializeDrawerTriggers() { 39 const triggers = document.querySelectorAll("[data-drawer-trigger]"); 40 triggers.forEach((trigger) => { 41 const id = trigger.dataset.drawerTrigger; 42 const handler = (e) => { 43 e.preventDefault(); 44 openDrawer(id); 45 }; 46 trigger.addEventListener("click", handler); 47 triggerHandlers.set(trigger, handler); 48 }); 49} 50 51function setupGlobalEventListeners() { 52 backdropClickHandler = () => { 53 Object.keys(drawerState).forEach((id) => { 54 if (drawerState[id].isOpen) { 55 closeDrawer(id); 56 } 57 }); 58 }; 59 document.addEventListener("backdrop:clicked", backdropClickHandler); 60 61 keyupHandler = (e) => { 62 if (e.key === "Escape") { 63 Object.keys(drawerState).forEach((id) => { 64 if (drawerState[id].isOpen) { 65 closeDrawer(id); 66 } 67 }); 68 } 69 }; 70 document.addEventListener("keyup", keyupHandler); 71} 72 73export function openDrawer(id) { 74 let state = drawerState[id]; 75 if (!state) { 76 const drawer = document.querySelector(`[data-drawer-id="${id}"]`); 77 if (!drawer) { 78 return; 79 } 80 initializeDrawer(drawer); 81 state = drawerState[id]; 82 } 83 if (!state) return; 84 85 state.isOpen = true; 86 state.element.classList.add("open"); 87 88 // Use showModal for <dialog> elements 89 if (state.element.tagName === "DIALOG" && !state.element.open) { 90 //state.element.showModal(); 91 openDialog({ contentId: state.element.getAttribute("data-drawer-id") }); 92 } 93 94 const openBackdropEvent = new CustomEvent("backdrop:open"); 95 document.dispatchEvent(openBackdropEvent); 96} 97 98export function closeDrawer(id) { 99 const state = drawerState[id]; 100 if (!state) return; 101 102 state.isOpen = false; 103 state.element.classList.remove("open"); 104 105 // Close <dialog> elements properly 106 if (state.element.tagName === "DIALOG" && state.element.open) { 107 state.element.close(); 108 } 109 110 const closeBackdropEvent = new CustomEvent("backdrop:close"); 111 document.dispatchEvent(closeBackdropEvent); 112} 113 114export function destroyDrawer() { 115 closeButtonHandlers.forEach((handler, btn) => { 116 btn.removeEventListener("click", handler); 117 }); 118 closeButtonHandlers.clear(); 119 120 triggerHandlers.forEach((handler, trigger) => { 121 trigger.removeEventListener("click", handler); 122 }); 123 triggerHandlers.clear(); 124 125 if (backdropClickHandler) { 126 document.removeEventListener("backdrop:clicked", backdropClickHandler); 127 backdropClickHandler = null; 128 } 129 if (keyupHandler) { 130 document.removeEventListener("keyup", keyupHandler); 131 keyupHandler = null; 132 } 133} 134 135export function initDrawer() { 136 const drawers = document.querySelectorAll("[data-drawer-id]"); 137 drawers.forEach(initializeDrawer); 138 initializeDrawerTriggers(); 139 setupGlobalEventListeners(); 140} 141initDrawer();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.