view design_system/src/components/link.js @ 258:60a876c4587a

[ui] Add semantic primitive ownership Build a layered Zenbu token and sizing system, make authored controls use native-underneath primitives, migrate mrjunejune without imposing visual surfaces, and document/enforce HTML ownership in the catalog and wiki. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Wed, 05 Aug 2026 05:25:40 -0700
parents
children
line wrap: on
line source

/**
 * Adds an optional reusable effect to one direct native link.
 *
 * @extends {HTMLElement}
 */
export class ZenLink extends HTMLElement {
  static get observedAttributes() {
    return ["effect"];
  }

  connectedCallback() {
    this._observer ||= new MutationObserver(() => this.sync());
    this._observer.observe(this, { childList: true });
    this.sync();
  }

  disconnectedCallback() {
    this._observer?.disconnect();
    this.removeGeneratedDecoration();
  }

  attributeChangedCallback() {
    if (this.isConnected) this.sync();
  }

  removeGeneratedDecoration() {
    this.querySelector(
      ':scope > a > zen-icon[data-zen-link-decoration][data-zen-generated="true"]',
    )?.remove();
  }

  sync() {
    const link = this.querySelector(":scope > a");
    if (!link || this.getAttribute("effect") !== "paw") {
      this.removeGeneratedDecoration();
      return;
    }
    let decoration = link.querySelector(
      ":scope > zen-icon[data-zen-link-decoration]",
    );
    if (!decoration) {
      decoration = document.createElement("zen-icon");
      decoration.dataset.zenLinkDecoration = "";
      decoration.dataset.zenGenerated = "true";
      decoration.setAttribute("name", "paw");
      link.prepend(decoration);
    }
  }
}

if (!customElements.get("zen-link")) {
  customElements.define("zen-link", ZenLink);
}