import { onHtmxLoad, onReady } from "./utils"; export const dedupeByID = (items: T[], idForItem: (item: T) => string | undefined): T[] => { const seen = new Set(); return items.filter((item) => { const id = idForItem(item); if (!id) { return true; } if (seen.has(id)) { return false; } seen.add(id); return true; }); }; export const dedupeWithin = (root: ParentNode): void => { const elements = root.querySelectorAll(":scope > [data-id]"); const uniqueElements = new Set(dedupeByID(Array.from(elements), (item) => item.dataset.id)); elements.forEach((item) => { if (!uniqueElements.has(item)) { item.remove(); } }); }; export const dedupe = (root: ParentNode = document): void => { const containers = new Set(); const elements = root.querySelectorAll("[data-id]"); elements.forEach((item) => { if (item.parentElement) { containers.add(item.parentElement); } }); containers.forEach((container) => { dedupeWithin(container); }); }; const dedupeSwapTarget = (target: EventTarget | null): void => { if (!(target instanceof HTMLElement)) { return; } if (target.matches("[data-id]")) { const parent = target.parentElement; if (parent) { dedupeWithin(parent); } return; } const containers = new Set(); const elements = target.querySelectorAll("[data-id]"); elements.forEach((item) => { if (item.parentElement) { containers.add(item.parentElement); } }); containers.forEach((container) => { dedupeWithin(container); }); }; onReady(() => dedupe()); window.addEventListener("load", () => dedupe()); onHtmxLoad((root) => dedupeSwapTarget(root));