1"use strict"; 2// src/ts/toggle.ts 3// Toggle genérico por data-attributes, com ARIA e eventos customizados. 4// Atributos aceitos no botão: 5// - data-toggle-target: "#id" | "id" | ".classe" | seletor CSS. 6// - data-toggle-mode: "class" | "display" (default: "class") 7// - data-toggle-class: string (default: "hidden") usado apenas no modo "class" 8// - data-toggle-focus: (presença = tenta focar algo dentro do alvo ao abrir) 9(function () { 10 function resolveTarget(selectorOrId) { 11 if (!selectorOrId) 12 return null; 13 const s = selectorOrId.trim(); 14 if (!s) 15 return null; 16 if (s.startsWith("#") || s.startsWith(".") || s.includes("[") || s.includes(" ")) { 17 return document.querySelector(s); 18 } 19 return document.getElementById(s); 20 } 21 function setAriaExpanded(btn, expanded, target) { 22 btn.setAttribute("aria-expanded", String(expanded)); 23 if (target === null || target === void 0 ? void 0 : target.id) 24 btn.setAttribute("aria-controls", target.id); 25 } 26 function setAriaHidden(target, hidden) { 27 target.setAttribute("aria-hidden", String(hidden)); 28 } 29 function toggleByClass(target, cls) { 30 target.classList.toggle(cls); 31 const isHidden = target.classList.contains(cls); 32 setAriaHidden(target, isHidden); 33 return !isHidden; 34 } 35 function toggleByDisplay(target) { 36 const current = getComputedStyle(target).display; 37 const willShow = current === "none"; 38 target.style.display = willShow ? "block" : "none"; 39 setAriaHidden(target, !willShow); 40 return willShow; 41 } 42 function focusFirstFocusable(el) { 43 const selector = [ 44 "button", 45 "[href]", 46 "input", 47 "select", 48 "textarea", 49 "[tabindex]:not([tabindex='-1'])" 50 ].join(", "); 51 const focusable = el.querySelector(selector); 52 if (focusable) 53 focusable.focus(); 54 } 55 function getOptionsFromButton(btn) { 56 const targetSelector = btn.getAttribute("data-toggle-target"); 57 if (!targetSelector) 58 return null; 59 const mode = btn.getAttribute("data-toggle-mode") || "class"; 60 const toggleClass = btn.getAttribute("data-toggle-class") || "hidden"; 61 const focusOnOpen = btn.hasAttribute("data-toggle-focus"); 62 return { targetSelector, mode, toggleClass, focusOnOpen }; 63 } 64 function handleToggleClick(ev, root = document) { 65 const target = ev.target; 66 if (!target) 67 return false; 68 const btn = target.closest("[data-toggle-target]"); 69 if (!btn) 70 return false; 71 const opts = getOptionsFromButton(btn); 72 if (!opts) 73 return false; 74 const targetEl = resolveTarget(opts.targetSelector); 75 if (!targetEl) 76 return false; 77 let expanded; 78 if (opts.mode === "display") { 79 expanded = toggleByDisplay(targetEl); 80 } 81 else { 82 expanded = toggleByClass(targetEl, opts.toggleClass || "hidden"); 83 } 84 setAriaExpanded(btn, expanded, targetEl); 85 if (expanded && opts.focusOnOpen) { 86 requestAnimationFrame(() => focusFirstFocusable(targetEl)); 87 } 88 btn.dispatchEvent(new CustomEvent("toggle:changed", { 89 bubbles: true, 90 detail: { expanded, target: targetEl, button: btn, mode: opts.mode } 91 })); 92 return true; 93 } 94 function initToggleButtons(root = document) { 95 root.addEventListener("click", (ev) => { 96 handleToggleClick(ev, root); 97 }); 98 } 99 // Auto-inicializa 100 if (typeof window !== "undefined" && typeof document !== "undefined") { 101 if (document.readyState === "loading") { 102 document.addEventListener("DOMContentLoaded", () => initToggleButtons(document)); 103 } 104 else { 105 initToggleButtons(document); 106 } 107 // Expõe globalmente para uso manual se necessário 108 window.PortalToggle = { initToggleButtons }; 109 } 110})();
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.