/* ============================================================= * @whynot/design — atoms.js * ------------------------------------------------------------ * , , , , * , , * * Shadow-DOM components. Each adopts the shared component * stylesheet so utility classes inside the shadow root work. * Token CSS variables cascade through shadow boundaries * because they're inherited properties. * ============================================================= */ import { LitElement, html, nothing } from "lit"; import { getSharedSheet } from "./_styles.js"; import { ICON_PATHS } from "./icons.js"; class WnBase extends LitElement { static styles = []; connectedCallback() { super.connectedCallback(); // Adopt the shared sheet on first connect, after super() has built the shadow root. const root = this.shadowRoot; if (root && !root.adoptedStyleSheets.includes(getSharedSheet())) { root.adoptedStyleSheets = [...root.adoptedStyleSheets, getSharedSheet()]; } } } /* ---------- ---------- */ export class WnButton extends WnBase { static properties = { variant: { type: String, reflect: true }, size: { type: String, reflect: true }, icon: { type: String }, iconEnd: { type: String, attribute: "icon-end" }, type: { type: String }, disabled: { type: Boolean, reflect: true }, href: { type: String }, }; constructor() { super(); this.variant = "secondary"; this.size = "md"; this.type = "button"; this.disabled = false; } render() { const cls = [ "wn-btn", this.variant && this.variant !== "secondary" ? `wn-btn--${this.variant}` : "", this.size === "sm" ? "wn-btn--sm" : this.size === "lg" ? "wn-btn--lg" : "", ].filter(Boolean).join(" "); const iconStart = this.icon ? html`` : nothing; const iconEnd = this.iconEnd ? html`` : nothing; if (this.href) { return html`${iconStart}${iconEnd}`; } return html``; } } /* ---------- ---------- */ export class WnTag extends WnBase { static properties = { active: { type: Boolean, reflect: true }, draft: { type: Boolean, reflect: true }, }; render() { const cls = ["wn-tag", this.active ? "wn-tag--active" : "", this.draft ? "wn-tag--draft" : "", ].filter(Boolean).join(" "); return html``; } } /* ---------- ---------- */ export class WnEyebrow extends WnBase { static properties = { strong: { type: Boolean, reflect: true } }; render() { const cls = "wn-eyebrow" + (this.strong ? " wn-eyebrow--strong" : ""); return html``; } } /* ---------- ---------- */ export class WnStamp extends WnBase { render() { return html``; } } /* ---------- ---------- */ export class WnStageDot extends WnBase { static properties = { level: { type: String, reflect: true }, label: { type: String }, }; constructor() { super(); this.level = "S2"; } render() { const lvl = String(this.level || "S2").toLowerCase(); const cls = `wn-dot wn-stage-dot wn-stage-dot--${lvl}`; return html` ${this.label || this.level} `; } } /* ---------- ---------- */ export class WnPhaseDot extends WnBase { static properties = { state: { type: String, reflect: true }, num: { type: String, reflect: true }, }; constructor() { super(); this.state = "todo"; this.num = ""; } render() { const cls = `wn-phase-dot wn-phase-dot--${this.state}`; const glyph = this.state === "done" ? "✓" : this.num; return html` ${glyph} `; } } /* ---------- ---------- */ export class WnIcon extends WnBase { static properties = { name: { type: String, reflect: true }, size: { type: String, reflect: true }, }; constructor() { super(); this.size = "md"; } render() { const path = ICON_PATHS[this.name]; const cls = `wn-icon wn-icon--${this.size || "md"}`; if (!path) { return html``; } return html``; } } export function defineAtoms() { if (!customElements.get("wn-button")) customElements.define("wn-button", WnButton); if (!customElements.get("wn-tag")) customElements.define("wn-tag", WnTag); if (!customElements.get("wn-eyebrow")) customElements.define("wn-eyebrow", WnEyebrow); if (!customElements.get("wn-stamp")) customElements.define("wn-stamp", WnStamp); if (!customElements.get("wn-stage-dot")) customElements.define("wn-stage-dot", WnStageDot); if (!customElements.get("wn-phase-dot")) customElements.define("wn-phase-dot", WnPhaseDot); if (!customElements.get("wn-icon")) customElements.define("wn-icon", WnIcon); } export { WnBase };