view design_system/src/components/alert.js @ 268:f7b1188d5fb1

support repo rules Copilot bundle path Match both +_repo_rules2+ and +http_archive+ Copilot CLI repository layouts during deployment and production startup. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 13:02:41 -0700
parents 2b6e732087ff
children
line wrap: on
line source

/**
 * Presents a semantic status message with optional dismissal.
 *
 * @extends {HTMLElement}
 */
export class ZenAlert extends HTMLElement {
  static get observedAttributes() {
    return ["dismissible", "tone"];
  }

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

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

  attributeChangedCallback() {
    this.sync();
  }

  unbindDismissControl() {
    if (this._dismissControl && this._dismissHandler) {
      this._dismissControl.removeEventListener(
        "click",
        this._dismissHandler,
      );
    }
    this._dismissControl = null;
    this._dismissHandler = null;
  }

  sync() {
    this.setAttribute(
      "role",
      this.getAttribute("tone") === "danger" ? "alert" : "status",
    );

    let dismiss = this.querySelector(":scope > [data-zen-dismiss]");
    if (!this.hasAttribute("dismissible")) {
      this.unbindDismissControl();
      if (dismiss?.dataset.zenGenerated === "true") dismiss.remove();
      return;
    }

    if (!dismiss) {
      dismiss = document.createElement("button");
      dismiss.type = "button";
      dismiss.dataset.zenDismiss = "";
      dismiss.dataset.zenGenerated = "true";
      dismiss.setAttribute("aria-label", "Dismiss message");
      const icon = document.createElement("zen-icon");
      icon.setAttribute("name", "close");
      dismiss.append(icon);
      this.append(dismiss);
    }
    if (dismiss === this._dismissControl) return;

    this.unbindDismissControl();
    this._dismissControl = dismiss;
    this._dismissHandler = () => {
      this.dispatchEvent(new CustomEvent("zen-dismiss", {
        bubbles: true,
        composed: true,
      }));
      this.remove();
    };
    dismiss.addEventListener("click", this._dismissHandler);
  }
}

if (!customElements.get("zen-alert")) {
  customElements.define("zen-alert", ZenAlert);
}