@tenoxui/moxie
Version:
Very lightweight utility-first CSS engine for style generation
386 lines (385 loc) • 13.6 kB
JavaScript
function R(h) {
return h.replace(/^(\d)/, "\\3$1 ").replace(/([#{}.:;?%&,@+*~'"!^$[\]()=>|/])/g, "\\$1");
}
function P(h) {
if (/^(webkit|moz|ms|o)[A-Z]/.test(h)) {
const e = h.match(/^(webkit|moz|ms|o)/);
if (e) {
const s = e[0];
return `-${s}${h.slice(s.length).replace(/[A-Z]/g, (t) => `-${t.toLowerCase()}`)}`;
}
}
return h.replace(/[A-Z]/g, (e) => `-${e.toLowerCase()}`);
}
function b(h, e, s, t, l, n) {
return `${h ? `${h}:` : ""}${e}${s ? "-" : ""}${s}${t}${l ? `/${l}${n}` : ""}`;
}
function V(h) {
return h.replace(/[.*+?^${}()|[\]\\/\\-]/g, "\\$&");
}
function S(h) {
if (!h) return [];
const e = /* @__PURE__ */ new Set();
return Object.entries(h).forEach(([s, t]) => {
t && typeof t == "object" && Object.keys(t).forEach((l) => {
e.add(l);
});
}), Array.from(e);
}
function Z({
safelist: h = [],
property: e = {},
classes: s = {}
} = {}) {
const t = s, l = Object.keys(e);
if (!t)
return [...l, ...h].sort((c, o) => o.length - c.length);
const a = [...S(t)];
return [...l, ...a, ...h].sort((c, o) => o.length - c.length);
}
function z({
inputPrefixChars: h = [],
safelist: e = [],
property: s = {},
classes: t = {}
} = {}) {
let l = Z({ safelist: e, property: s, classes: t }).map(
V
);
l.length > 0 && (l = l.join("|") + "|");
const n = "\\[[^\\]]+\\]", a = "\\([^()]*(?:\\([^()]*\\)[^()]*)*\\)", c = "\\{[^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\}", o = `[${["a-zA-Z0-9_\\-", ...h].join("")}]`, r = (
// Simple prefix (hover, md, focus, etc.)
o + "+|" + // value-like prefix (nth-(4), max-[445px], etc.)
o + "+(?:-(?:" + n + "|" + a + "|" + c + "))|" + // added support for custom secondValue for prefix
o + "+(?:-(?:" + n + "|" + a + "|" + c + "))?(?:\\/[a-zA-Z0-9_\\-]+)|" + // Direct bracket, parenthesis, or brace content
n + "|" + a + "|" + c
), d = `(${l}\\[[^\\]]+\\])`, i = "(?:-)", $ = "(-?(?:\\d+(?:\\.\\d+)?)|(?:[a-zA-Z0-9_]+(?:-[a-zA-Z0-9_]+)*(?:-[a-zA-Z0-9_]+)*)|(?:#[0-9a-fA-F]+)|" + // Hex colors
n + "|" + // Bracket content
c + "|" + // Curly brace content
a + "|(?:\\$[^\\s\\/]+))", A = "([a-zA-Z%]*)", f = "(?:\\/(-?(?:\\d+(?:\\.\\d+)?)|(?:[a-zA-Z0-9_]+(?:-[a-zA-Z0-9_]+)*(?:-[a-zA-Z0-9_]+)*)|(?:#[0-9a-fA-F]+)|" + n + "|" + c + "|" + a + "|(?:\\$[^\\s\\/]+))([a-zA-Z%]*))?";
return {
prefix: r,
type: d,
separator: i,
value: $,
unit: A,
secondValuePattern: f,
all: "^(?:(" + r + "):)?" + d + i + $ + A + f + "$"
};
}
class _ {
constructor({ property: e = {}, values: s = {}, classes: t = {}, prefixChars: l = [] } = {}) {
this.property = e, this.values = s, this.classes = t, this.prefixChars = l.map(V);
}
regexp(e) {
return z({
safelist: e,
property: this.property,
classes: this.classes,
inputPrefixChars: this.prefixChars
});
}
parse(e, s) {
const t = this.regexp(s), l = e.match(new RegExp(t.all));
if (l) {
const [, a, c, o, r, d, i] = l;
return [a, c, o, r || "", d, i];
}
const n = e.match(
new RegExp(`^(?:(${t.prefix}):)?${t.type}$`)
);
return n ? [n[1], n[2], "", "", void 0, void 0] : null;
}
// unique value parser
processValue(e, s, t) {
if (!e) return "";
const l = (n) => n.replace(/\{([^}]+)\}/g, (a, c) => {
const o = this.values, r = o !== null ? typeof o[t] == "object" ? o[t][c] : o[c] : void 0;
return typeof r == "string" ? r : a;
});
if (typeof this.values == "object" && this.values !== null && (this.values[t] && typeof this.values[t] == "object" && this.values[t][e] || this.values[e]))
return typeof this.values[t] == "object" && this.values[t] !== null ? this.values[t][e] : this.values[e];
if (e.startsWith("$"))
return `var(--${e.slice(1)})`;
if (e.startsWith("[") && e.endsWith("]") || e.startsWith("(") && e.endsWith(")")) {
const n = e.slice(1, -1).replace(/\\\_/g, "m0x13c55").replace(/\_/g, " ").replace(/m0x13c55/g, "_");
return n.includes("{") ? l(n) : n.startsWith("--") ? `var(${n})` : n;
}
return e + (s || "");
}
processShorthand(e = "", s = "", t = "", l, n = "", a = "", c = "", o) {
const r = this.property[e];
if (typeof r == "object" && !Array.isArray(r) && !("property" in r))
return null;
const d = /^(?:\(|\[)([^:]+):(.+)(?:\)|\])$/;
let i = null, $ = s || "";
const A = $.match(d);
if (A && (i = A[1].trim(), $ = A[2].trim()), (typeof r == "string" && !r.includes(":") || Array.isArray(r)) && (!s || s.includes(i + ":") || n))
return null;
let f;
s.includes(i + ":") ? f = s.startsWith("(") ? `(${$})` : `[${$}]` : f = s;
const y = this.processValue(f, t, e), g = this.processValue(n, a, e);
if (e.startsWith("[") && e.endsWith("]")) {
if (!s || n) return null;
const u = e.slice(1, -1).split(",").map(
(C) => C.trim().startsWith("--") ? String(C.trim()) : P(String(C.trim()))
);
return {
className: b(l, e, s, t),
cssRules: u.length === 1 ? u[0] : u,
value: y,
prefix: l
};
}
if (r) {
if (typeof r == "object" && "property" in r) {
const C = r.group && this.values[r.group][y] ? this.values[r.group][y] : t ? s : y, p = (
// handle `properties.property` function
typeof r.property == "function" ? r.property({
value: s.startsWith("[") ? y : C,
unit: s.startsWith("[") ? "" : t,
secondValue: s.startsWith("[") ? "" : a ? n : g,
secondUnit: s.startsWith("[") ? "" : a,
key: i,
raw: o
}) : (
// defaulting to string property
// e.g. { property: { p: { property: 'padding', value: '{0} {1}' } }
// the `p` is the type or the shorthand for `padding` property -
// and has support for second value
r.property
)
);
if (p && typeof p == "object" && !Array.isArray(p) && "cssRules" in p) {
const {
className: W,
cssRules: j = null,
value: v = null,
prefix: w
} = p;
return {
className: W || c,
cssRules: j,
value: v,
prefix: w || l,
isCustom: !!W
};
}
const m = r.value || "{0}";
let x;
if (typeof m == "function")
x = m({
value: C,
unit: t,
secondValue: a ? n : g,
secondUnit: a,
key: i,
raw: o
});
else if (typeof m == "string") {
const W = r.group || e, j = this.processValue(f, t, W);
this.values[W] && typeof this.values[W] == "object" && this.values[W][f] ? x = this.values[W][f] : m.includes("{") ? x = this.parseValuePattern(
W,
m,
j,
"",
g,
""
) : typeof m == "string" && !m.includes("{") ? x = m : x = y;
} else if (Array.isArray(m)) {
if (!m.includes(s + t) || n) return null;
x = s + t;
} else x = null;
return (typeof r.property == "string" || Array.isArray(r.property)) && typeof m == "string" && (s.includes(i + ":") || !m.includes("{1") && n) || // check if the property is string or array of properties
// but the value is null
(typeof r.property == "string" || Array.isArray(r.property)) && m === null || // check if the type is a direct rules but has `value` defined
typeof r.property == "string" && r.property.includes(":") && s || (typeof r.property == "string" || Array.isArray(r.property)) && typeof r.value == "string" && !r.value.includes("{") && s ? null : {
className: b(l, e, s, t, n, a),
cssRules: (
// if not property, or when `properties.property` as function return null
p ? Array.isArray(p) ? p : (
// is direct CSS rules
typeof p == "string" && (p.includes(":") || p.includes("value:")) && p.includes("value:") ? p.slice(6) : (
// basic string property
P(String(p))
)
) : null
),
value: m === null || p === null || p.includes(":") || p.includes("value:") ? null : s.startsWith("[") ? y : x,
prefix: l
};
}
const u = (
// handle `properties` as function
// e.g. m: ({ value, unit }) => `margin: ${value}${unit || 'px'}`
// m-4 => margin: 4px
// m-4rem => margin: 4rem
typeof r == "function" ? r({
value: s.startsWith("[") ? y : t ? s : y,
unit: s.startsWith("[") ? "" : t,
secondValue: s.startsWith("[") ? "" : a ? n : g,
secondUnit: s.startsWith("[") ? "" : a,
key: i,
raw: o
}) : (
// e.g. { property: { bg: 'background' } }
// the `bg` is the type or the shorthand for `background` property
r
)
);
if (u && typeof u == "object" && !Array.isArray(u) && "cssRules" in u) {
const {
className: C,
cssRules: p = null,
value: m = null,
prefix: x
} = u;
return {
className: C || c,
cssRules: p,
value: m,
prefix: x || l,
isCustom: !!C
};
}
return {
className: b(l, e, s, t, n, a),
cssRules: u ? Array.isArray(u) ? u : typeof u == "string" && (u.includes(":") || u.startsWith("value:")) && u.startsWith("value:") ? u.slice(6) : P(String(u)) : null,
value: typeof u == "string" && u.includes(":") ? null : y,
prefix: l
};
}
return null;
}
parseValuePattern(e, s, t, l, n, a) {
if (!s.includes("{0}") && !s.includes("{1") && !s.includes("||"))
return s;
const [c, o] = s.split("||").map((i) => i.trim()), r = this.processValue(t, l, e), d = this.processValue(n, a, e);
if (s.includes("{0}") && s.includes("{1") || s.includes("{1")) {
let i = c;
if (t && (i = i.replace(/\{0\}/g, r)), s.includes("{1")) {
s.includes("{1}") && (n ? i = n.startsWith("[") ? d : i.replace(/\{1\}/g, d) : i = o || c);
const $ = /\{1([^}]*)\}/g;
let A;
for (; (A = $.exec(i)) !== null; ) {
const f = A[0], y = A[1].trim();
let g = d;
!g && y.includes("|") ? g = y.split("|")[1].trim() : g || (g = ""), i = t.startsWith("[") ? r : i.replace(f, g);
}
}
return t ? i : o || c;
} else
return t ? t.startsWith("[") ? r : c.replace(/\{0\}/g, r) : o || c;
}
getParentClass(e) {
return Object.keys(this.classes).filter(
(s) => Object.prototype.hasOwnProperty.call(
this.classes[s],
e
)
);
}
processCustomClass(e, s = "", t = "", l = "", n = "", a = "") {
if (!e) return null;
const c = this.getParentClass(e), o = s && e.endsWith(`-${s}${t}`);
if (c.length > 0) {
const r = c.map((d) => {
const i = this.classes[d];
if (!i || s && !o && i[e] && !i[e].includes("{0}") && !i[e].includes("|"))
return null;
const $ = this.parseValuePattern(
e,
i[e] || "",
s,
t,
n,
a
);
return `${P(String(d))}: ${$}`;
}).filter(Boolean).join("; ");
return {
className: o ? e : b(l, e, s, t, n, a),
cssRules: r,
value: null,
prefix: l
};
}
return null;
}
process(e) {
try {
const s = Array.isArray(e) ? e : e.split(/\s+/), t = [];
for (const l of s)
try {
if (!l) continue;
const n = this.parse(l);
if (!n) continue;
const [a, c, o, r, d, i] = n;
if (!c) continue;
const $ = [...n, b(a, c, o, r, d, i)], A = this.getParentClass(`${c}-${o}`).length > 0 ? `${c}-${o}` : c;
try {
const f = this.processCustomClass(
A,
o,
r,
a,
d,
i
);
if (f) {
const { className: y, cssRules: g, prefix: u } = f;
if (!g || g === "null") continue;
t.push({
className: R(y),
cssRules: g,
value: null,
prefix: u,
raw: $
});
continue;
}
} catch (f) {
console.warn(`Error processing custom class "${l}":`, f);
}
try {
const f = this.processShorthand(
c,
o,
r,
a,
d,
i,
l,
$
);
if (f) {
const { className: y, cssRules: g, value: u, prefix: C, isCustom: p } = f;
if (!g || g === "null") continue;
t.push({
className: p ? y : R(y),
cssRules: g,
value: u,
prefix: C,
raw: $
});
}
} catch (f) {
console.warn(`Error processing shorthand "${l}":`, f);
}
} catch (n) {
console.warn(`Failed to process class \`${l}\`:`, n);
}
return t;
} catch (s) {
return console.error("Critical error in process method:", s), [];
}
}
}
export {
_ as TenoxUI,
b as constructRaw,
_ as default,
R as escapeCSSSelector,
z as regexp,
P as toKebabCase
};