ranui
Version:
A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.
719 lines (718 loc) • 18.2 kB
JavaScript
import { escapeHtml as p } from "ranuts/utils";
var f = typeof document > "u", g = 0, H = 1, w = 2, h = null, l = null, v = 0, y = /* @__PURE__ */ new Set(), A = !1;
function I(t, e) {
const r = e?.equals ?? Object.is, s = {
value: t,
observers: /* @__PURE__ */ new Set()
};
return [() => (B(s), s.value), (o) => {
const a = typeof o == "function" ? o(s.value) : o;
if (!r(s.value, a)) {
s.value = a;
for (const c of s.observers) M(c, w);
v === 0 && R();
}
}];
}
function T(t, e) {
const r = _(t, !1, e?.equals);
return k(r), () => (r.disposed || ($(r), B(r)), r.value);
}
function L(t) {
const e = _(t, !0);
return k(e), j(e), () => z(e);
}
function ct(t) {
v++;
try {
t();
} finally {
v--, v === 0 && R();
}
}
function ht(t) {
const e = h;
h = null;
try {
return t();
} finally {
h = e;
}
}
function N(t) {
const e = {
owned: [],
cleanups: [],
owner: l
}, r = l, s = h;
l = e, h = null;
try {
return t(() => V(e));
} finally {
l = r, h = s;
}
}
function x(t) {
l && l.cleanups.push(t);
}
function ft() {
return l;
}
function dt(t, e) {
const r = l, s = h;
l = t, h = null;
try {
return e();
} finally {
l = r, h = s;
}
}
function _(t, e, r) {
return {
fn: t,
sources: /* @__PURE__ */ new Set(),
isEffect: e,
running: !1,
disposed: !1,
state: w,
observers: /* @__PURE__ */ new Set(),
value: void 0,
equals: r ?? Object.is,
owned: [],
cleanups: [],
owner: l
};
}
function k(t) {
l && l.owned.push(t);
}
function B(t) {
h && (h.sources.add(t), t.observers.add(h));
}
function M(t, e) {
if (t.disposed || t.state >= e) return;
const r = t.state === g;
if (t.state = e, t.isEffect) y.add(t);
else if (r) for (const s of t.observers) M(s, H);
}
function R() {
if (!(v > 0 || A)) {
A = !0;
try {
for (; y.size > 0; ) {
const t = [...y];
y.clear();
for (const e of t) e.disposed || $(e);
}
} finally {
A = !1;
}
}
}
function $(t) {
if (!(t.disposed || t.state === g)) {
if (t.state === H)
for (const e of t.sources) "fn" in e && $(e);
t.state === w && j(t), t.state = g;
}
}
function j(t) {
if (t.running) throw new Error("ranui reactivity: cyclic dependency detected (a computation triggered itself).");
q(t);
const e = h, r = l;
h = t, l = t, t.running = !0, t.state = g;
try {
const s = t.fn();
if (t.isEffect)
typeof s == "function" && t.cleanups.push(s);
else {
const i = t.value;
if (t.value = s, t.observers.size > 0 && !t.equals(i, s)) for (const n of t.observers) M(n, w);
}
} finally {
t.running = !1, h = e, l = r;
}
}
function q(t) {
for (const e of t.owned) z(e);
t.owned.length = 0;
for (const e of t.cleanups) e();
t.cleanups.length = 0;
for (const e of t.sources) e.observers.delete(t);
t.sources.clear();
}
function z(t) {
t.disposed || (t.disposed = !0, q(t), t.observers.clear());
}
function V(t) {
for (const e of t.owned) z(e);
t.owned.length = 0;
for (const e of t.cleanups) e();
t.cleanups.length = 0;
}
function O(t) {
return p(t);
}
var K = (t) => typeof t == "string" ? !1 : "tagName" in t && "childrenList" in t, U = ".#[";
function Y(t) {
const e = [];
let r = 0;
const s = /^[a-zA-Z][\w-]*/.exec(t);
for (s !== null && (e.push(s[0]), r = s[0].length); r < t.length; ) {
const i = t[r];
if (i === "[") {
const o = t.indexOf("]", r + 1);
if (o === -1) return null;
e.push(t.slice(r, o + 1)), r = o + 1;
continue;
}
if (i !== "." && i !== "#") return null;
let n = r + 1;
for (; n < t.length && !U.includes(t[n]); ) n += 1;
if (n === r + 1) return null;
e.push(t.slice(r, n)), r = n;
}
return e.length > 0 ? e : null;
}
var Z = (t, e) => {
const r = e;
if (r.startsWith(".")) return t.classList.contains(r.slice(1));
if (r.startsWith("#")) return t.getAttribute("id") === r.slice(1);
if (r.startsWith("[") && r.endsWith("]")) {
const [s, i] = r.slice(1, -1).trim().split("="), n = (s || "").trim();
if (!n) return !1;
if (i == null) return t.hasAttribute(n);
const o = i.trim().replace(/^['"]|['"]$/g, "");
return t.getAttribute(n) === o;
}
return t.tagName === r.toLowerCase();
}, Q = (t, e) => {
const r = e.trim();
if (!r) return !1;
const s = Y(r);
return s === null ? !1 : s.every((i) => Z(t, i));
}, C = (t, e, r) => {
for (const s of t)
K(s) && (Q(s, e) && r.push(s), C(s.childrenList, e, r));
}, E = class {
childrenList = [];
appendChild(t) {
return this.childrenList.push(t), t;
}
serialize() {
return this.childrenList.map((t) => typeof t == "string" ? p(t) : t.serialize()).join("");
}
querySelector(t) {
const e = this.querySelectorAll(t);
return e.length > 0 ? e[0] : null;
}
querySelectorAll(t) {
const e = [];
return C(this.childrenList, t, e), e;
}
}, X = class {
tagName;
attributes = /* @__PURE__ */ new Map();
inlineStyles = /* @__PURE__ */ new Map();
childrenList = [];
shadowRoot = null;
textContent = null;
content;
eventListeners = /* @__PURE__ */ new Map();
style = {
setProperty: (t, e) => {
const r = t.startsWith("--") ? t : t.replace(/([A-Z])/g, "-$1").toLowerCase();
this.inlineStyles.set(r, e);
},
removeProperty: (t) => this.inlineStyles.delete(t)
};
classList = {
add: (...t) => {
const e = this.attributes.get("class") || "", r = /* @__PURE__ */ new Set([...e.split(" ").filter(Boolean), ...t]);
this.attributes.set("class", Array.from(r).join(" "));
},
remove: (...t) => {
const e = (this.attributes.get("class") || "").split(" ").filter((r) => !t.includes(r));
this.attributes.set("class", e.join(" "));
},
toggle: (t) => {
this.classList.contains(t) ? this.classList.remove(t) : this.classList.add(t);
},
contains: (t) => (this.attributes.get("class") || "").split(" ").includes(t)
};
_innerHTML = "";
get innerHTML() {
return this._innerHTML;
}
set innerHTML(t) {
this._innerHTML = t, this.tagName === "template" && this.content && (this.content.childrenList = [t]);
}
constructor(t = "div") {
this.tagName = t.toLowerCase(), this.tagName === "template" && (this.content = new E());
}
get hidden() {
return this.hasAttribute("hidden");
}
set hidden(t) {
t ? this.setAttribute("hidden", "") : this.removeAttribute("hidden");
}
setAttribute(t, e) {
this.attributes.set(t, e);
}
getAttribute(t) {
return this.attributes.get(t) || null;
}
removeAttribute(t) {
this.attributes.delete(t);
}
hasAttribute(t) {
return this.attributes.has(t);
}
appendChild(t) {
return this.childrenList.push(t), t;
}
attachShadow(t) {
return this.shadowRoot = new J(this, t), this.shadowRoot;
}
querySelector(t) {
const e = this.querySelectorAll(t);
return e.length > 0 ? e[0] : null;
}
querySelectorAll(t) {
const e = [];
return C(this.childrenList, t, e), e;
}
addEventListener(t, e) {
const r = this.eventListeners.get(t) || /* @__PURE__ */ new Set();
r.add(e), this.eventListeners.set(t, r);
}
removeEventListener(t, e) {
const r = this.eventListeners.get(t);
r && (r.delete(e), r.size === 0 && this.eventListeners.delete(t));
}
dispatchEvent(t) {
const e = this.eventListeners.get(t.type);
if (!e || e.size === 0) return !0;
for (const r of e) typeof r == "function" ? r.call(this, t) : r.handleEvent(t);
return !t.defaultPrevented;
}
serialize(t) {
typeof this._preSerialize == "function" && this._preSerialize();
const e = t || this._ssrTag || this.tagName, r = Array.from(this.attributes.entries()).map(([o, a]) => ` ${o}="${O(a)}"`).join(""), s = Array.from(this.inlineStyles.entries()).map(([o, a]) => `${o}:${a}`).join(";"), i = s ? ` style="${O(s)}"` : "";
let n = "";
return this.shadowRoot && (n += this.shadowRoot.serialize()), this.textContent !== null ? n += p(this.textContent) : this._innerHTML ? n += this._innerHTML : n += this.childrenList.map((o) => typeof o == "string" ? p(o) : (o instanceof E, o.serialize())).join(""), [
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"link",
"meta",
"param",
"source",
"track",
"wbr"
].includes(e) && !n ? `<${e}${r}${i} />` : `<${e}${r}${i}>${n}</${e}>`;
}
}, J = class {
host;
options;
childrenList = [];
adoptedStyleSheets = [];
constructor(t, e) {
this.host = t, this.options = e;
}
appendChild(t) {
return this.childrenList.push(t), t;
}
querySelector(t) {
const e = this.querySelectorAll(t);
return e.length > 0 ? e[0] : null;
}
querySelectorAll(t) {
const e = [];
return C(this.childrenList, t, e), e;
}
serialize() {
return `<template shadowrootmode="${this.options.mode}"${this.options.delegatesFocus ? " shadowrootdelegatesfocus" : ""}>${this.adoptedStyleSheets.map((t) => `<style>${p(t)}</style>`).join("")}${this.childrenList.map((t) => typeof t == "string" ? p(t) : (t instanceof E, t.serialize())).join("")}</template>`;
}
}, pt = () => ({ current: null }), D = (t) => t.reduce((e, r) => Array.isArray(r) ? e.concat(D(r)) : e.concat(r), []), m = (t) => t == null ? null : t instanceof G ? t.build() : typeof t == "string" ? f ? t : document.createTextNode(t) : t, tt = (t, e) => {
if (f) {
S(t, [e()]);
return;
}
const r = document.createComment(""), s = document.createComment("");
t.appendChild(r), t.appendChild(s);
let i = null;
const n = () => {
i?.(), i = null;
let o = r.nextSibling;
for (; o && o !== s; ) {
const a = o.nextSibling;
o.parentNode?.removeChild(o), o = a;
}
};
L(() => {
const o = e();
n();
const a = document.createDocumentFragment();
i = N((c) => (S(a, [o]), c)), s.parentNode?.insertBefore(a, s);
}), x(() => i?.());
}, F = "__ranFor";
function vt(t) {
return {
...t,
[F]: !0
};
}
var et = (t) => typeof t == "object" && t !== null && t[F] === !0;
function mt(t) {
const e = T(() => !!t.when()), r = () => t.when();
return () => e() ? t.children(r) : t.fallback?.() ?? null;
}
function bt(t) {
return t;
}
function yt(t) {
const e = t.children, r = T(() => e.findIndex((s) => !!s.when()));
return () => {
const s = r();
if (s < 0) return t.fallback?.() ?? null;
const i = e[s];
return i.children(() => i.when());
};
}
var rt = (t, e, r) => {
const [s, i] = I(e);
let n = null;
const o = N((a) => {
const c = m(r(t, s));
return n = typeof c == "string" ? document.createTextNode(c) : c, a;
});
return {
node: n,
index: i,
dispose: o
};
}, P = (t, e) => {
const r = t.parentNode;
if (!r) return;
let s = t;
for (const i of e)
s.nextSibling !== i && r.insertBefore(i, s.nextSibling), s = i;
}, st = (t, e) => {
if (f) {
(e.each() ?? []).forEach((i, n) => {
const o = m(e.render(i, () => n));
o != null && t.appendChild(o);
});
return;
}
const r = document.createComment("");
t.appendChild(r);
let s = /* @__PURE__ */ new Map();
x(() => {
for (const i of s.values()) i.dispose();
s.clear();
}), L(() => {
const i = e.each() ?? [], n = /* @__PURE__ */ new Map(), o = [];
i.forEach((a, c) => {
const b = e.key(a, c);
if (n.has(b)) return;
let d = s.get(b);
d ? (s.delete(b), d.index(c)) : d = rt(a, c, e.render), n.set(b, d), d.node && o.push(d.node);
});
for (const a of s.values())
a.node?.parentNode?.removeChild(a.node), a.dispose();
P(r, o), s = n;
});
}, W = "__ranIndex";
function gt(t) {
return {
...t,
[W]: !0
};
}
var nt = (t) => typeof t == "object" && t !== null && t[W] === !0, it = (t, e, r) => {
const [s, i] = I(t);
let n = null;
const o = N((a) => {
const c = m(r(s, e));
return n = typeof c == "string" ? document.createTextNode(c) : c, a;
});
return {
node: n,
setItem: i,
dispose: o
};
}, ot = (t, e) => {
if (f) {
(e.each() ?? []).forEach((i, n) => {
const o = m(e.render(() => i, n));
o != null && t.appendChild(o);
});
return;
}
const r = document.createComment("");
t.appendChild(r);
let s = [];
x(() => {
for (const i of s) i.dispose();
s = [];
}), L(() => {
const i = e.each() ?? [];
for (let n = 0; n < i.length; n++) n < s.length ? s[n].setItem(i[n]) : s.push(it(i[n], n, e.render));
for (let n = s.length - 1; n >= i.length; n--) {
const { node: o } = s[n];
o?.parentNode?.removeChild(o), s[n].dispose(), s.pop();
}
P(r, s.map((n) => n.node).filter((n) => n != null));
});
}, S = (t, e) => {
D(e).forEach((r) => {
if (et(r)) {
st(t, r);
return;
}
if (nt(r)) {
ot(t, r);
return;
}
if (typeof r == "function") {
tt(t, r);
return;
}
const s = m(r);
s != null && t.appendChild(s);
});
};
var at = /* @__PURE__ */ new Set([
"svg",
"circle",
"clipPath",
"defs",
"desc",
"ellipse",
"feBlend",
"feColorMatrix",
"feComposite",
"feDropShadow",
"feFlood",
"feGaussianBlur",
"feMerge",
"feMergeNode",
"feOffset",
"filter",
"foreignObject",
"g",
"image",
"line",
"linearGradient",
"marker",
"mask",
"path",
"pattern",
"polygon",
"polyline",
"radialGradient",
"rect",
"stop",
"switch",
"symbol",
"text",
"textPath",
"tspan",
"use"
]), G = class {
el;
constructor(t, e) {
const r = e ?? (at.has(t) ? "http://www.w3.org/2000/svg" : void 0);
this.el = f ? new X(t) : r ? document.createElementNS(r, t) : document.createElement(t);
}
id(t) {
return this.el.setAttribute("id", t), this;
}
bind(t, e) {
typeof t == "function" ? L(() => e(t())) : e(t);
}
class(t) {
return this.bind(t, (e) => {
f ? this.el.attributes.set("class", e) : this.el.className = e;
}), this;
}
addClass(...t) {
return t.forEach((e) => this.el.classList.add(e)), this;
}
removeClass(...t) {
return t.forEach((e) => this.el.classList.remove(e)), this;
}
attr(t, e) {
return this.bind(e, (r) => this.el.setAttribute(t, r)), this;
}
attrs(t) {
return Object.entries(t).forEach(([e, r]) => {
r != null && this.el.setAttribute(e, String(r));
}), this;
}
boolAttr(t, e, r = "") {
return this.bind(e, (s) => {
s ? this.el.setAttribute(t, r) : this.el.removeAttribute(t);
}), this;
}
part(t) {
return this.attr("part", t);
}
data(t, e) {
return this.attr(`data-${t}`, e);
}
style(t, e) {
return typeof t == "string" ? this.bind(e ?? "", (r) => this.el.style.setProperty(t, r)) : Object.entries(t).forEach(([r, s]) => this.el.style.setProperty(r, s)), this;
}
cssVar(t, e) {
const r = t.startsWith("--") ? t : `--${t}`;
return this.style(r, e);
}
aria(t, e) {
return this.attr(`aria-${t}`, e);
}
role(t) {
return this.attr("role", t);
}
tabIndex(t) {
return this.attr("tabindex", String(t));
}
label(t) {
return this.aria("label", t);
}
labelledBy(t) {
return this.aria("labelledby", t);
}
describedBy(t) {
return this.aria("describedby", t);
}
ariaHidden(t = !0) {
return this.aria("hidden", String(t));
}
on(t, e, r) {
return this.el.addEventListener(t, e, r), this;
}
listen(t, e, r, s) {
return t.on(this.el, e, r, s), this;
}
delegate(t, e, r, s, i) {
return t.delegate(this.el, e, r, s, i), this;
}
children(...t) {
return S(this.el, t), this;
}
replaceChildren(...t) {
if (f) {
const e = this.el;
e.childrenList = [];
} else this.el.replaceChildren();
return this.children(...t);
}
text(t) {
return this.bind(t, (e) => {
this.el.textContent = e;
}), this;
}
ref(t) {
return t.current = this.el, this;
}
shadow(t = { mode: "closed" }) {
const e = this.el.attachShadow(t);
return new lt(this.el, e, t);
}
build() {
return this.el;
}
serialize() {
if (f) return this.el.serialize();
const t = document.createElement("div");
return t.appendChild(this.el.cloneNode(!0)), t.innerHTML;
}
}, lt = class {
root;
hostEl;
options;
constructor(t, e, r) {
this.hostEl = t, this.root = e, this.options = r;
}
children(...t) {
return S(this.root, t), this;
}
adoptSheet(...t) {
return this.root.adoptedStyleSheets = [...this.root.adoptedStyleSheets, ...t], this;
}
css(t) {
if (f)
return this.root.adoptedStyleSheets.push(t), this;
if (typeof CSSStyleSheet < "u") try {
const r = new CSSStyleSheet();
return r.replaceSync(t), this.root.adoptedStyleSheets = [...this.root.adoptedStyleSheets, r], this;
} catch {
}
const e = document.createElement("style");
return e.textContent = t, this.root.appendChild(e), this;
}
done() {
return {
host: this.hostEl,
shadow: this.root
};
}
serialize() {
return f ? this.root.serialize() : this.root.innerHTML;
}
}, u = (t) => new G(t), St = () => u("div"), wt = () => u("span"), Lt = () => u("slot"), Ct = () => u("button"), At = () => u("input"), Et = () => u("style"), Nt = () => u("label"), xt = () => u("ul"), Mt = () => u("li"), $t = () => u("section"), zt = () => u("article"), Ot = () => u("nav"), Ht = () => u("header"), It = () => u("footer"), Tt = () => u("main"), _t = (t = "open", e = !1) => {
const r = u("template");
return r.attr("shadowrootmode", t), e && r.attr("shadowrootdelegatesfocus", ""), r;
};
export {
Q as A,
I as B,
mt as C,
X as D,
E,
L as F,
f as H,
N as I,
ft as L,
O as M,
ct as N,
J as O,
T as P,
x as R,
lt as S,
pt as T,
ht as V,
u as _,
It as a,
gt as b,
Nt as c,
Ot as d,
$t as f,
xt as g,
Et as h,
St as i,
p as j,
C as k,
Mt as l,
wt as m,
Ct as n,
Ht as o,
Lt as p,
_t as r,
At as s,
zt as t,
Tt as u,
G as v,
yt as w,
bt as x,
vt as y,
dt as z
};