33 lines (28 loc) · 1017 B
 1import { $$ } from "./dom.js";
 2
 3const isInteractive = (target) => target.closest("a, button, input, textarea, select");
 4
 5/**
 6 * Make [data-card-link] elements clickable/keyboard-activatable as a whole,
 7 * while leaving inner interactive elements working. Internal links go through
 8 * the injected navigate(); external links open in a new tab.
 9 */
10export const initCards = (signal, navigate) => {
11  $$("[data-card-link]").forEach((card) => {
12    const href = card.dataset.cardLink;
13    if (!href) return;
14    const external = card.dataset.cardExternal === "true";
15
16    const go = () => {
17      if (external) window.open(href, "_blank", "noopener,noreferrer");
18      else navigate(href);
19    };
20
21    card.addEventListener("click", (e) => {
22      if (!isInteractive(e.target)) go();
23    }, { signal });
24
25    card.addEventListener("keydown", (e) => {
26      if (isInteractive(e.target)) return;
27      if (e.key === "Enter" || e.key === " ") {
28        e.preventDefault();
29        go();
30      }
31    }, { signal });
32  });
33};