UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

322 lines (321 loc) 10.7 kB
const p = (n) => { const t = Number.parseInt(n.slice(1, 3), 16) / 255, e = Number.parseInt(n.slice(3, 5), 16) / 255, r = Number.parseInt(n.slice(5, 7), 16) / 255, c = Math.max(t, e, r), o = Math.min(t, e, r); let i = 0, f = 0; const a = (c + o) / 2; if (c === o) i = f = 0; else { const s = c - o; switch (f = a > 0.5 ? s / (2 - c - o) : s / (c + o), c) { case t: i = (e - r) / s + (e < r ? 6 : 0); break; case e: i = (r - t) / s + 2; break; case r: i = (t - e) / s + 4; break; } i /= 6; } return [Math.round(i * 360), Math.round(f * 100), Math.round(a * 100)]; }, d = (n, t, e) => { n /= 360, t /= 100, e /= 100; const r = (a, s, l) => (l < 0 && (l += 1), l > 1 && (l -= 1), l < 1 / 6 ? a + (s - a) * 6 * l : l < 1 / 2 ? s : l < 2 / 3 ? a + (s - a) * (2 / 3 - l) * 6 : a); let c, o, i; if (t === 0) c = o = i = e; else { const a = e < 0.5 ? e * (1 + t) : e + t - e * t, s = 2 * e - a; c = r(s, a, n + 0.3333333333333333), o = r(s, a, n), i = r(s, a, n - 0.3333333333333333); } const f = (a) => { const s = Math.round(a * 255).toString(16); return s.length === 1 ? "0" + s : s; }; return `#${f(c)}${f(o)}${f(i)}`; }, $ = (n, t) => { const [e, r, c] = p(n), o = Math.max(0, Math.min(100, c + t)); return d(e, r, o); }, k = (n, t) => { const [e, r, c] = p(n), o = Math.max(0, Math.min(100, r + t)); return d(e, o, c); }, w = (n, t) => { const [e, r, c] = p(n), o = (e + t + 360) % 360; return d(o, r, c); }, y = (n, t) => { const e = (f) => { const a = Number.parseInt(f.slice(1, 3), 16) / 255, s = Number.parseInt(f.slice(3, 5), 16) / 255, l = Number.parseInt(f.slice(5, 7), 16) / 255, g = (u) => u <= 0.03928 ? u / 12.92 : Math.pow((u + 0.055) / 1.055, 2.4); return 0.2126 * g(a) + 0.7152 * g(s) + 0.0722 * g(l); }, r = e(n), c = e(t), o = Math.max(r, c), i = Math.min(r, c); return (o + 0.05) / (i + 0.05); }, b = (n, t, e = "AA") => { const r = y(n, t); return e === "AA" ? r >= 4.5 : r >= 7; }, m = (n, t, e = "AA") => { const r = n, [c, o, i] = p(r); for (let s = 0; s <= 50; s += 5) { const l = Math.min(100, i + s), g = d(c, o, l); if (b(g, t, e)) return g; const u = Math.max(0, i - s), M = d(c, o, u); if (b(M, t, e)) return M; } const f = "#ffffff", a = "#000000"; return b(f, t, e) ? f : b(a, t, e) ? a : n; }, h = (n) => { const [t, e, r] = p(n); return { 50: d(t, Math.max(10, e - 40), Math.min(95, r + 40)), 100: d(t, Math.max(20, e - 30), Math.min(90, r + 35)), 200: d(t, Math.max(30, e - 20), Math.min(85, r + 25)), 300: d(t, Math.max(40, e - 10), Math.min(75, r + 15)), 400: d(t, e, Math.min(65, r + 5)), 500: n, 600: d(t, Math.min(100, e + 10), Math.max(35, r - 5)), 700: d(t, Math.min(100, e + 15), Math.max(25, r - 15)), 800: d(t, Math.min(100, e + 20), Math.max(15, r - 25)), 900: d(t, Math.min(100, e + 25), Math.max(10, r - 35)), 950: d(t, Math.min(100, e + 30), Math.max(5, r - 45)), DEFAULT: n, foreground: m(n, "#ffffff") }; }, F = (n, t = "light") => ({ success: t === "light" ? "#22c55e" : "#16a34a", warning: t === "light" ? "#f59e0b" : "#d97706", danger: t === "light" ? "#ef4444" : "#dc2626", info: t === "light" ? "#3b82f6" : "#2563eb" }), v = () => typeof window > "u" ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light", x = (n) => { if (typeof window > "u") return () => { }; const t = window.matchMedia("(prefers-color-scheme: dark)"), e = (r) => { n(r.matches ? "dark" : "light"); }; return t.addEventListener("change", e), () => { t.removeEventListener("change", e); }; }, A = (n) => n === "system" ? v() : n, E = (n) => { const t = {}; return Object.entries(n.colors).forEach(([e, r]) => { t[`--frank-${e.replace(/([A-Z])/g, "-$1").toLowerCase()}`] = r; }), Object.entries(n.spacing).forEach(([e, r]) => { t[`--frank-spacing-${e}`] = r; }), Object.entries(n.borderRadius).forEach(([e, r]) => { t[`--frank-radius-${e}`] = r; }), Object.entries(n.shadows).forEach(([e, r]) => { t[`--frank-shadow-${e}`] = r; }), Object.entries(n.typography.fontSize).forEach(([e, [r, c]]) => { t[`--frank-text-${e}`] = r, t[`--frank-text-${e}-line-height`] = c.lineHeight, c.letterSpacing && (t[`--frank-text-${e}-letter-spacing`] = c.letterSpacing); }), Object.entries(n.typography.fontWeight).forEach(([e, r]) => { t[`--frank-font-${e}`] = r; }), n.cssVariables && Object.entries(n.cssVariables).forEach(([e, r]) => { t[e.startsWith("--") ? e : `--${e}`] = r; }), t; }, T = (n, t) => { const e = t || document.documentElement; Object.entries(n).forEach(([r, c]) => { e.style.setProperty(r, c); }); }, j = (n, t) => { const e = t || document.documentElement; n.forEach((r) => { e.style.removeProperty(r); }); }, C = (n) => { const { primaryColor: t, secondaryColor: e, mode: r, colorHarmony: c } = n, o = h(t), i = h(e || w(t, 30)), a = h(r === "light" ? "#6b7280" : "#9ca3af"), s = F(t, r), l = { background: r === "light" ? "#ffffff" : "#0f172a", foreground: r === "light" ? "#0f172a" : "#f8fafc", content1: r === "light" ? "#ffffff" : "#18181b", content2: r === "light" ? "#f4f4f5" : "#27272a", content3: r === "light" ? "#e4e4e7" : "#3f3f46", content4: r === "light" ? "#d4d4d8" : "#52525b", primary: o, primaryForeground: m("#ffffff", o[500]), secondary: i, secondaryForeground: m("#ffffff", i[500]), accent: o[600], accentForeground: m("#ffffff", o[600]), muted: a[100], mutedForeground: a[600], border: r === "light" ? a[200] : a[800], divider: r === "light" ? a[100] : a[800], input: r === "light" ? "#ffffff" : "#27272a", inputForeground: r === "light" ? "#0f172a" : "#f8fafc", focus: o[500], focusVisible: o[500], overlay: r === "light" ? "rgba(0, 0, 0, 0.5)" : "rgba(0, 0, 0, 0.8)", success: s.success, successForeground: m("#ffffff", s.success), warning: s.warning, warningForeground: m("#ffffff", s.warning), danger: s.danger, dangerForeground: m("#ffffff", s.danger), info: s.info, infoForeground: m("#ffffff", s.info), selection: o[100], selectionForeground: o[900], disabled: a[300], disabledForeground: a[500], card: "", cardForeground: "", popover: "", popoverForeground: "", ring: "", destructive: "", destructiveForeground: "" }, g = { primary: o, secondary: i, neutral: a, success: h(s.success), warning: h(s.warning), danger: h(s.danger), info: h(s.info) }; return { name: `Generated ${r} theme`, mode: r, colors: l, palette: g }; }, L = (n) => { const t = [], e = [], r = {}; if (!n.colors) return t.push("Theme must have colors defined"), { valid: !1, errors: t, warnings: e, accessibility: { contrastRatios: r, wcagLevel: "fail" } }; const c = ["background", "foreground", "primary", "primaryForeground"]; for (const a of c) a in n.colors || t.push(`Missing required color: ${a}`); const o = (a, s) => { const l = n.colors[a], g = n.colors[s]; if (l && g) { const u = y(typeof l == "string" ? l : l.DEFAULT, typeof g == "string" ? g : g.DEFAULT); r[`${a}/${s}`] = u, u < 4.5 && e.push(`Low contrast ratio for ${a} on ${s}: ${u.toFixed(2)}`); } }; o("foreground", "background"), o("primaryForeground", "primary"), o("secondaryForeground", "secondary"), o("successForeground", "success"), o("warningForeground", "warning"), o("dangerForeground", "danger"), o("infoForeground", "info"); const i = Math.min(...Object.values(r)); let f; return i >= 7 ? f = "AAA" : i >= 4.5 ? f = "AA" : i >= 3 ? f = "A" : f = "fail", { valid: t.length === 0, errors: t, warnings: e, accessibility: { contrastRatios: r, wcagLevel: f } }; }, V = (n, t) => { const e = { ...n }; return t.colors && (e.colors = { ...e.colors, ...t.colors }), t.typography && (e.typography = { ...e.typography, ...t.typography }), t.spacing && (e.spacing = { ...e.spacing, ...t.spacing }), t.components && (e.components = { ...e.components, ...t.components }), t.cssVariables && (e.cssVariables = { ...e.cssVariables, ...t.cssVariables }), t.custom && (e.custom = { ...e.custom, ...t.custom }), e; }, S = (n, t, e, r = "default") => { const c = n.components[t]; if (!c) return; const o = c[e]; if (!(!o || typeof o != "object")) return o; }, I = (n, t, e, r = "default", c = "md") => { const o = S(n, t, e, r); if (!o) return ""; let i = o.base || ""; const f = o.colors?.[r]; f && (i += ` ${f.background || ""} ${f.foreground || ""} ${f.border || ""}`); const a = o.sizes?.[c]; return a && (i += ` ${a}`), i.trim(); }, O = (n, t) => { if (!(typeof window > "u")) try { localStorage.setItem("frank-auth-theme", n), localStorage.setItem("frank-auth-theme-mode", t); } catch { } }, H = () => { if (typeof window > "u") return {}; try { const n = localStorage.getItem("frank-auth-theme"), t = localStorage.getItem("frank-auth-theme-mode"); return { theme: n || void 0, mode: t || void 0 }; } catch { return {}; } }, N = { // Color utilities hexToHsl: p, hslToHex: d, adjustBrightness: $, adjustSaturation: k, adjustHue: w, getContrastRatio: y, isValidContrast: b, findAccessibleColor: m, // Palette generation generateColorPalette: h, generateSemanticColors: F, // Theme mode getSystemTheme: v, watchSystemTheme: x, resolveThemeMode: A, // CSS variables generateCSSVariables: E, applyCSSVariables: T, removeCSSVariables: j, // Theme generation generateTheme: C, validateTheme: L, mergeThemes: V, // Component utilities getComponentVariant: S, getComponentStyles: I, // Storage saveThemeToStorage: O, loadThemeFromStorage: H }; export { N as ThemeUtils, $ as adjustBrightness, w as adjustHue, k as adjustSaturation, T as applyCSSVariables, m as findAccessibleColor, E as generateCSSVariables, h as generateColorPalette, F as generateSemanticColors, C as generateTheme, I as getComponentStyles, S as getComponentVariant, y as getContrastRatio, v as getSystemTheme, p as hexToHsl, d as hslToHex, b as isValidContrast, H as loadThemeFromStorage, V as mergeThemes, j as removeCSSVariables, A as resolveThemeMode, O as saveThemeToStorage, L as validateTheme, x as watchSystemTheme }; //# sourceMappingURL=theme.js.map