ranui
Version:
A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.
103 lines (102 loc) • 6.09 kB
JavaScript
import { H as i, i as o, n as h } from "./factory-WDxu11V0.js";
import { t as l } from "./events-Cqz3ramM.js";
import "./builder-EH76YCFS.js";
import { i as c, n as d, o as u, t as b } from "./utils-U-9uH7EX.js";
import { a as m, n as v } from "./ssr-BzykYefm.js";
import { i as p, n as g } from "./theme-DKH_E9Cp.js";
var w = ":host{display:var(--ran-theme-switch-display, inline-flex);box-sizing:border-box}:host([hidden]){display:none}.ran-theme-switch{display:inline-flex;align-items:center;gap:var(--ran-theme-switch-gap, var(--ran-space-1, 4px));padding:var(--ran-theme-switch-padding, var(--ran-space-1, 4px));border-width:var(--ran-skin-border-width, 1px);border-style:var(--ran-skin-border-style, solid);border-color:var(--ran-theme-switch-border-color, var(--ran-color-border, #eaeaea));border-radius:var(--ran-theme-switch-radius, var(--ran-radius-full, 9999px));background:var(--ran-theme-switch-background, transparent);box-sizing:border-box}.ran-theme-switch button{width:var(--ran-theme-switch-button-size, var(--ran-size-5, 28px));height:var(--ran-theme-switch-button-size, var(--ran-size-5, 28px));display:grid;place-items:center;border:none;border-radius:var(--ran-theme-switch-radius, var(--ran-radius-full, 9999px));background:transparent;color:var(--ran-theme-switch-button-color, var(--ran-color-text-secondary, #4d4d4d));cursor:pointer;padding:0}.ran-theme-switch button:hover{color:var(--ran-theme-switch-button-hover-color, var(--ran-color-text, #171717))}.ran-theme-switch button[aria-pressed=true]{background:var(--ran-theme-switch-button-active-background, var(--ran-color-bg-hover, #ebebeb));color:var(--ran-theme-switch-button-active-color, var(--ran-color-text, #171717))}.ran-theme-switch button:focus-visible{outline:var(--ran-theme-switch-button-focus-outline, 2px solid var(--ran-color-primary, #006bff));outline-offset:var(--ran-theme-switch-button-focus-outline-offset, 2px)}.ran-theme-switch svg{width:var(--ran-theme-switch-icon-size, var(--ran-size-1, 16px));height:var(--ran-theme-switch-icon-size, var(--ran-size-1, 16px))}", s = [
"system",
"light",
"dark"
], f = {
system: '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="1.5" y="2.5" width="13" height="9" rx="1.5" fill="none" stroke="currentColor" stroke-width="1.5"/><path d="M5.5 14h5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
light: '<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="3" fill="none" stroke="currentColor" stroke-width="1.5"/><path d="M8 1v1.8M8 13.2V15M15 8h-1.8M2.8 8H1m11.4-4.4-1.3 1.3M4.9 11.1l-1.3 1.3m9.8 0-1.3-1.3M4.9 4.9 3.6 3.6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
dark: '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M13.5 9.5A6 6 0 0 1 6.5 2.5a6 6 0 1 0 7 7z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>'
}, a = "ran-theme-switch-sync", _ = class extends v {
static get observedAttributes() {
return [
"label-system",
"label-light",
"label-dark",
"sheet"
];
}
_events = new l();
_shadowDom;
_group;
_buttons;
constructor() {
super(), this._shadowDom = b(this, w), this._buttons = s.map((t) => {
const e = h().attr("type", "button").data("choice", t).attr("part", `button ${t}`).aria("pressed", "false").build();
return i || (e.innerHTML = f[t]), e;
}), this._group = o().class("ran-theme-switch").attr("part", "switch").role("group").children(this._buttons).build(), this._shadowDom.appendChild(this._group);
}
get sheet() {
return d(this, "sheet");
}
set sheet(t) {
c(this, "sheet", t);
}
get value() {
return g() || "system";
}
set value(t) {
s.includes(t) && this._select(t);
}
_label(t) {
const e = {
system: "System theme",
light: "Light theme",
dark: "Dark theme"
}[t];
return this.getAttribute(`label-${t}`) || e;
}
_syncLabels() {
this._group.setAttribute("aria-label", this.getAttribute("label") || "Theme");
for (const t of this._buttons) t.setAttribute("aria-label", this._label(t.dataset.choice));
}
_reflect() {
const t = this.value;
for (const e of this._buttons) e.setAttribute("aria-pressed", e.dataset.choice === t ? "true" : "false");
}
_select(t) {
p(t), this._reflect(), this._syncMeta(t), document.dispatchEvent(new CustomEvent(a)), this.dispatchEvent(new CustomEvent("change", {
detail: { theme: t },
bubbles: !0,
composed: !0
}));
}
_syncMeta(t) {
if (typeof requestAnimationFrame > "u") return;
const e = document.querySelectorAll('meta[name="theme-color"]');
e.length && requestAnimationFrame(() => {
for (const r of e)
if (r.dataset.ranOriginalContent === void 0 && (r.dataset.ranOriginalContent = r.getAttribute("content") || ""), t === "system") r.setAttribute("content", r.dataset.ranOriginalContent);
else {
const n = getComputedStyle(document.documentElement).getPropertyValue("--ran-color-bg").trim() || getComputedStyle(document.body).backgroundColor;
r.setAttribute("content", n);
}
});
}
_handleClick = (t) => {
const e = t.target.closest?.("button")?.dataset.choice;
e && s.includes(e) && this._select(e);
};
_handleSync = () => this._reflect();
handlerExternalCss = () => {
u(this, this._shadowDom, "sheet", null, this.sheet);
};
connectedCallback() {
this.handlerExternalCss(), this._syncLabels(), this._reflect(), this._events.on(this._group, "click", this._handleClick), document.addEventListener(a, this._handleSync), typeof window < "u" && window.addEventListener("storage", this._handleSync);
}
disconnectedCallback() {
this._events.abort(), document.removeEventListener(a, this._handleSync), typeof window < "u" && window.removeEventListener("storage", this._handleSync);
}
attributeChangedCallback(t, e, r) {
e !== r && (t === "sheet" && this.handlerExternalCss(), t.startsWith("label") && this._syncLabels());
}
};
m("r-theme-switch", _);
export {
_ as t
};