import XNode from "@web-atoms/core/dist/core/XNode"; import "./styles/expander.global.css"; export interface IExpander { icon?: string | string[]; isExpanded: boolean; "event-expanded"?: (e: CustomEvent) => any; "event-collapsed"?: (e: CustomEvent) => any; [key: string]: any; } document.body.addEventListener("click", (e: MouseEvent) => { if (e.defaultPrevented) { return; } let start = e.target as HTMLElement; while (start) { if (/icon|caret|header/.test(start.getAttribute("data-element"))) { break; } start = start.parentElement; } start = start?.parentElement; if (!start) { return; } const isExpander = start?.getAttribute("data-is-expander"); if (!/^(menu|expander)$/i.test(isExpander)) { return; } const ds = start.dataset; if (/menu/i.test(isExpander)) { e.preventDefault(); e.stopImmediatePropagation(); } if (ds.isExpanded === "false") { start.dispatchEvent(new CustomEvent("expanded", { bubbles: true, cancelable: true })); } else { start.dispatchEvent(new CustomEvent("collapsed", { bubbles: true, cancelable: true })); } }, { capture: true }); document.body.addEventListener("expanded", (ce) => { if (ce.defaultPrevented) { return; } const target = ce.target as HTMLElement; target.dataset.isExpanded = "true"; }); document.body.addEventListener("collapsed", (ce) => { if (ce.defaultPrevented) { return; } const target = ce.target as HTMLElement; target.dataset.isExpanded = "false"; }); export default function Expander( { icon, isExpanded, ... a }: IExpander, header: XNode, detail: XNode) { if (!detail) { throw new Error("Expander must contain two children, one header and one detail") } const ha = header.attributes ??= {}; const da = detail.attributes ??= {}; ha["data-element"] = "header"; da["data-element"] = "detail"; const iconElement = !icon ? [] : ( Array.isArray(icon) ? icon : [icon] ).map((i) => ); return
{ ... iconElement } { header } { } { detail }
; } export function ExpanderMenu({ icon, isExpanded, ... a }: IExpander, header: XNode, ... details: XNode[]) { if (details.length === 0) { throw new Error("Expander must contain two children, one header and one detail") } const ha = header.attributes ??= {}; ha["data-element"] = "header"; let i = 2; details = details.filter((x: any) => x !== false); for (const iterator of details) { const ia = (iterator.attributes ??= {}); ia["data-element"] = "detail"; ia["style-grid-row-start"] = (i++).toString(); } const iconElement = !icon ? [] : ( Array.isArray(icon) ? icon : [icon] ).map((i) => ); return
{ ... iconElement } { header } { } { ... details }
; }