ranui
Version:
A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.
105 lines (104 loc) • 6.12 kB
JavaScript
import { a as i, n as o, o as h, r as l, t as c } from "./utils-D1iZnChu.js";
import { c as d } from "./mocks-CMGoftIc.js";
import { t as u } from "./events-C59wGdni.js";
import { i as m, n as b } from "./factory-ZNhcQ4tf.js";
import { a as v, n as p } from "./ssr-DSGwPtEd.js";
import { i as g, n as w } from "./theme-kOWZbKCq.js";
var f = ".remove-wap-active-focus{outline:0;-webkit-tap-highlight-color:transparent}.remove-wap-active-focus:active,.remove-wap-active-focus:focus{outline:0;-webkit-tap-highlight-color:transparent}:host{display:var(--ran-theme-switch-display, inline-flex);box-sizing:border-box}.ran-theme-switch{display:inline-flex;align-items:center;gap:var(--ran-theme-switch-gap, 2px);padding:var(--ran-theme-switch-padding, 2px);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, 28px);height:var(--ran-theme-switch-button-size, 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-color, var(--ran-color-text-secondary, #4d4d4d));cursor:pointer;padding:0}.ran-theme-switch button:hover{color:var(--ran-theme-switch-hover-color, var(--ran-color-text, #171717))}.ran-theme-switch button[aria-pressed=true]{background:var(--ran-theme-switch-active-background, var(--ran-color-bg-hover, #ebebeb));color:var(--ran-theme-switch-active-color, var(--ran-color-text, #171717))}.ran-theme-switch button:focus-visible{outline:var(--ran-theme-switch-focus-outline, 2px solid var(--ran-color-primary, #006bff));outline-offset:2px}.ran-theme-switch svg{width:var(--ran-theme-switch-icon-size, 16px);height:var(--ran-theme-switch-icon-size, 16px)}", a = [
"system",
"light",
"dark"
], y = {
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>'
}, s = "ran-theme-switch-sync", _ = class extends p {
static get observedAttributes() {
return [
"label-system",
"label-light",
"label-dark",
"sheet"
];
}
_events = new u();
_shadowDom;
_group;
constructor() {
super(), this._shadowDom = o(this, f), this._group = c(this._shadowDom, ".ran-theme-switch", () => {
const t = a.map((e) => {
const r = b().attr("type", "button").data("choice", e).attr("part", `button ${e}`).aria("pressed", "false").build();
return d || (r.innerHTML = y[e]), r;
});
return m().class("ran-theme-switch").attr("part", "switch").role("group").children(t).build();
});
}
get sheet() {
return l(this, "sheet");
}
set sheet(t) {
i(this, "sheet", t);
}
get value() {
return w() || "system";
}
set value(t) {
a.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._group.querySelectorAll("button")) t.setAttribute("aria-label", this._label(t.dataset.choice));
}
_reflect() {
const t = this.value;
for (const e of this._group.querySelectorAll("button")) e.setAttribute("aria-pressed", e.dataset.choice === t ? "true" : "false");
}
_select(t) {
g(t), this._reflect(), this._syncMeta(t), document.dispatchEvent(new CustomEvent(s)), 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 && a.includes(e) && this._select(e);
};
_handleSync = () => this._reflect();
handlerExternalCss = () => {
h(this, this._shadowDom, "sheet", null, this.sheet);
};
connectedCallback() {
this.handlerExternalCss(), this._syncLabels(), this._reflect(), this._events.on(this._group, "click", this._handleClick), document.addEventListener(s, this._handleSync), typeof window < "u" && window.addEventListener("storage", this._handleSync);
}
disconnectedCallback() {
this._events.abort(), document.removeEventListener(s, 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());
}
};
v("r-theme-switch", _);
export {
_ as t
};