Mercurial
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/design_system/src/components/link.js Wed Aug 05 05:25:40 2026 -0700 @@ -0,0 +1,53 @@ +/** + * 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); +}