axentix
Version:
Axentix is a framework mixing fully customizable components & utility-first classes, leaving the design choice to the developer.
118 lines (117 loc) • 5.52 kB
JavaScript
const A = {
components: [],
plugins: [],
prefix: "ax",
mode: ""
}, d = (e) => `--${A.prefix}-${e}`, R = (e) => e.checkValidity() || e.validationMessage, w = (e, t) => {
const s = document.createElement("div");
s.axGenerated = !0, e.appendChild(s), s.classList.add("form-helper-invalid"), s.innerHTML = t;
}, S = (e) => {
const t = e.querySelector(".form-helper-invalid");
t && t.axGenerated && t.remove();
}, p = (e) => {
e.classList.remove("form-valid", "form-invalid", "form-no-helper"), S(e);
}, L = (e, t) => {
const s = e.getAttribute("data-form-validate");
let r = !1;
if (s) {
const a = s.toLowerCase().split(",");
if (r = a.includes("auto"), a.includes("lazy") && t === "input") return;
}
const n = R(e), o = e.closest(".form-field, .form-file");
return p(o), n !== !0 ? (r && typeof n == "string" ? w(o, n) : o.querySelector(".form-helper-invalid") || o.classList.add("form-no-helper"), o.classList.add("form-invalid"), !1) : (o.classList.add("form-valid"), o.querySelector(".form-helper-valid") || o.classList.add("form-no-helper"), !0);
}, C = (e) => {
e.querySelectorAll("[data-form-validate]").forEach((s) => p(s.closest(".form-field, .form-file")));
}, q = (e) => [...e.querySelectorAll("[data-form-validate]")].map((s) => L(s, "change")).every((s) => s);
let m = !0;
const c = (e) => {
e.forEach(g);
}, y = (e) => {
if (m) {
m = !1;
return;
}
setTimeout(() => {
c(e);
}, 10);
}, g = (e) => {
const t = e.closest(".form-field"), s = t.querySelector(".form-custom-select"), r = t.classList.contains("active"), n = ["date", "month", "week", "time"];
let o = s && e.tagName === "DIV" && e.innerText.length > 0;
s || (o = e.value.length > 0 || e.tagName !== "SELECT" && e.placeholder.length > 0 || e.tagName === "SELECT" || n.some((i) => e.matches(`[type="${i}"]`)));
const a = document.activeElement === e, l = e.hasAttribute("disabled") || e.hasAttribute("readonly");
e.firstInit ? (h(e, r, o, a, t, s), e.firstInit = !1, e.isInit = !0) : l || h(e, r, o, a, t, s);
}, h = (e, t, s, r, n, o) => {
const a = e.type === "textarea", l = n.querySelector("label:not(.form-check)");
!t && (s || r) ? n.classList.add("active") : t && !(s || r) && n.classList.remove("active"), a ? l && (l.style.backgroundColor = I(l)) : M(e, n, o, l), r && !a ? n.classList.add("is-focused") : o || n.classList.remove("is-focused"), r && a ? n.classList.add("is-textarea-focused") : n.classList.remove("is-textarea-focused");
}, M = (e, t, s, r) => {
const n = e.clientWidth, o = e.offsetLeft, a = e.clientHeight + (s ? s.offsetTop : e.offsetTop) + "px", l = e.closest(".form-material").classList.contains("form-material-bordered");
t.style.setProperty(d("form-material-position"), a);
let i = o, f = "left", x = n + "px", u = 0;
t.classList.contains("form-rtl") && (f = "right", i = t.clientWidth - n - o), t.style.setProperty(d(`form-material-${f}-offset`), i + "px"), i != 0 && (u = o), t.style.setProperty(d("form-material-width"), x), r && (r.style.left = u + "px", l && (r.style.backgroundColor = I(r)));
}, v = (e) => {
const t = window.getComputedStyle(e).backgroundColor;
if (t && !["transparent", "rgba(0, 0, 0, 0)"].includes(t)) return t;
}, I = (e) => {
e.style.backgroundColor = "";
let t = e;
for (; t.parentElement; ) {
const r = v(t);
if (r) return r;
t = t.parentElement;
}
const s = v(document.documentElement);
return s || "white";
}, b = (e, t) => {
e.hasAttribute("data-form-validate") && L(e, t.type);
}, T = (e, t) => {
e.forEach((s) => {
s === t.target && g(s);
});
}, k = (e, t) => {
t.target.tagName === "FORM" && t.target.classList.contains("form-material") && y(e);
}, V = (e) => {
e.forEach((o) => {
o.firstInit = !0, o.validateRef = b.bind(null, o), o.addEventListener("input", o.validateRef), o.addEventListener("change", o.validateRef);
}), c(e);
const t = T.bind(null, e);
document.addEventListener("focus", t, !0), document.addEventListener("blur", t, !0);
const s = y.bind(null, e);
window.addEventListener("pageshow", s);
const r = k.bind(null, e);
document.addEventListener("reset", r);
const n = c.bind(null, e);
window.addEventListener("resize", n);
}, D = (e, t) => {
const s = e.files;
s.length > 1 ? t.innerHTML = Array.from(s).map((r) => r.name).join(", ") : s[0] && (t.innerHTML = s[0].name);
}, $ = (e) => {
if (e.isInit) return;
e.isInit = !0;
const t = e.querySelector('input[type="file"]'), s = e.querySelector(".form-file-path");
t.handleRef = D.bind(null, t, s), t.validateRef = b.bind(null, t), t.addEventListener("change", t.handleRef), t.addEventListener("input", t.validateRef), t.addEventListener("change", t.validateRef);
}, B = () => {
const e = Array.from(document.querySelectorAll(".form-file"));
try {
e.forEach($);
} catch (t) {
console.error("[Axentix] Form file error", t);
}
}, E = (e = document.querySelectorAll(
".form-material .form-field:not(.form-default) .form-control:not(.form-custom-select)"
)) => {
const { setupInputs: t, detectInputs: s } = Array.from(e).reduce(
(r, n) => (n.isInit ? r.detectInputs.push(n) : r.setupInputs.push(n), r),
{ setupInputs: [], detectInputs: [] }
);
B();
try {
t.length > 0 && V(t), s.length > 0 && c(s);
} catch (r) {
console.error("[Axentix] Material forms error", r);
}
};
document.addEventListener("DOMContentLoaded", () => E());
const H = { updateInputs: E, validate: q, resetValidation: C };
export {
H as Forms
};