UNPKG

nexora

Version:

A lightweight, production-ready JavaScript library for building user interfaces, supporting JSX.

388 lines (387 loc) 11.6 kB
var A = Object.defineProperty; var I = (e, t, n) => t in e ? A(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n; var y = (e, t, n) => I(e, typeof t != "symbol" ? t + "" : t, n); function L(e, t) { if (e === t) return !0; if (typeof e != "object" || e === null || typeof t != "object" || t === null) return !1; const n = Object.keys(e), r = Object.keys(t); if (n.length !== r.length) return !1; for (const s of n) if (!t.hasOwnProperty(s) || e[s] !== t[s]) return !1; return !0; } function p(e) { return e ? e._dom ? e._dom : e._rendered ? p(e._rendered) : null : null; } function K(e) { let t = null; return (n) => !n && !t ? e(n) : !t || !L(t, n) ? (t = { ...n }, e(n)) : null; } const C = /* @__PURE__ */ new Map(), E = /* @__PURE__ */ new WeakMap(), T = /* @__PURE__ */ new WeakMap(); function B(e) { var o; const t = h.currentComponentFn; if (!t) throw new Error("onInit must be called within a component"); C.has(t) || (C.set(t, []), E.set(t, /* @__PURE__ */ new Map())), (o = C.get(t)) == null || o.push(e); const n = E.get(t); if (!n.has(e)) { const [i, c] = h.createState(null); n.set(e, [i, c]), e().then((l) => { c(l), h.triggerUpdate(t); }); } const [r, s] = n.get(e); return [r(), s]; } function v(e) { const t = C.get(e); return t && (h.currentComponentFn = e, t.forEach((n) => { const r = Promise.resolve(n()).then((s) => (s !== void 0 && E.set(e, s), s)); T.set(e, r); })), E.get(e); } function S(e, t, n = null) { var c; const r = e.type, s = e.props; v(r); const o = (c = s.children) == null ? void 0 : c[0], i = m(o, t, n); return e._rendered = o, e._dom = i, i; } function R(e, t, n) { Object.keys(t).forEach((r) => { if (r !== "children" && !(r in n)) if (r.startsWith("on")) { const s = r.toLowerCase().substring(2); e.removeEventListener(s, t[r]); } else e[r] = ""; }), Object.keys(n).forEach((r) => { if (r !== "children" && t[r] !== n[r]) if (r.startsWith("on")) { const s = r.toLowerCase().substring(2); t[r] && e.removeEventListener(s, t[r]), e.addEventListener(s, n[r]); } else e[r] = n[r]; }); } function m(e, t, n = null) { var s; if (Array.isArray(e)) { const o = document.createDocumentFragment(); return e.forEach((i) => m(i, o, null)), t.appendChild(o), o.firstChild; } if (e.type === "reactive-wrapper") { const o = (s = e.props.children) == null ? void 0 : s[0]; if (!o) throw new Error("Reactive wrapper must have a child"); e.props._componentFn && (o.props = o.props || {}, o.props._componentFn = e.props._componentFn); const i = m(o, t, n); return e._dom = i, i; } if (typeof e.type == "function") return S(e, t, n); const r = e.type === "TEXT_ELEMENT" ? document.createTextNode(e.props.nodeValue) : document.createElement(e.type); return r._vnode = e, e._dom = r, r instanceof HTMLElement && R(r, {}, e.props), r instanceof HTMLElement && e.props.children && e.props.children.forEach((o) => { o && m(o, r); }), n ? t.insertBefore(r, n) : t.appendChild(r), r; } function g(e, t, n) { var s, o, i, c, l; if (Array.isArray(t) && Array.isArray(n)) { const u = Math.max(t.length, n.length); for (let a = 0; a < u; a++) if (a < t.length && a < n.length) g(e, t[a], n[a]); else if (a >= t.length) m(n[a], e); else { const f = p(t[a]); (s = f == null ? void 0 : f.parentNode) == null || s.removeChild(f); } return; } if (Array.isArray(t) || Array.isArray(n)) { const u = Array.isArray(t) ? p(t[0]) : p(t); if (u) { const a = u.parentNode; a && (Array.isArray(t) ? t.forEach((f) => { const d = p(f); d && a.removeChild(d); }) : a.removeChild(u), m(n, e)); } return; } if (t.type === "reactive-wrapper" && n.type === "reactive-wrapper") { const u = (o = t.props.children) == null ? void 0 : o[0], a = (i = n.props.children) == null ? void 0 : i[0]; if (!u || !a) return; if (t.props._renderKey !== n.props._renderKey) { const f = p(t), d = m(a, e); f && ((c = f.parentNode) == null || c.replaceChild(d, f)), n._dom = d; return; } g(e, u, a), n._dom = t._dom; return; } if (t.type !== n.type) { const u = p(t), a = m(n, e); u && ((l = u.parentNode) == null || l.replaceChild(a, u)); return; } if (n.type === "TEXT_ELEMENT") { const u = p(t); u && t.props.nodeValue !== n.props.nodeValue && (u.nodeValue = n.props.nodeValue), n._dom = u; return; } const r = p(t); r && (R(r, t.props, n.props), n._dom = r, b(r, t.props.children || [], n.props.children || [])); } function b(e, t, n) { const r = Math.max(t.length, n.length); for (let s = 0; s < r; s++) { const o = t[s], i = n[s]; if (!i && o) { const c = p(o); c && e.removeChild(c); } else !o && i ? m(i, e) : o && i && g(e, o, i); } } function w(e, t) { const n = t._vnode; n ? (g(t, n, e), n.props = {}, n.ref = null) : m(e, t), t._vnode = e; } class k { constructor() { y(this, "stateIndexes", /* @__PURE__ */ new WeakMap()); y(this, "currentComponentFn", null); y(this, "rootElement", null); y(this, "states", /* @__PURE__ */ new WeakMap()); } /** * Creates a state for the given component. * @param initialValue - The initial value of the state. * @returns A tuple containing the getter and setter for the state. */ createState(t) { if (this.rootElement ?? (this.rootElement = document.getElementById("app")), !this.currentComponentFn) throw new Error("createState must be called within a component"); const n = this.currentComponentFn; this.stateIndexes.has(n) || this.stateIndexes.set(n, 0); const r = this.stateIndexes.get(n); this.stateIndexes.set(n, r + 1), this.states.has(n) || this.states.set(n, /* @__PURE__ */ new Map()); const s = this.states.get(n); return s.has(r) || s.set(r, t), [() => { const c = this.states.get(n); return c == null ? void 0 : c.get(r); }, (c) => { const l = this.states.get(n); if (!l) return; const u = l.get(r), a = typeof c == "function" ? c(u) : c; Object.is(u, a) || (l.set(r, a), queueMicrotask(() => { const f = this.render(n); if (this.rootElement) { const d = this.findElementByComponent(this.rootElement, n); d && d._vnode && w(f, d); } })); }]; } /** * Checks if the given component function has state. * @param componentFn - The component function to check. * @returns True if the component function has state, false otherwise. */ hasState(t) { return this.states.has(t); } /** * Triggers an update for the given component function. * @param componentFn - The component function to trigger an update for. */ triggerUpdate(t) { queueMicrotask(() => { const n = this.render(t); if (this.rootElement) { const r = this.findElementByComponent(this.rootElement, t); r && r._vnode && w(n, r); } }); } /** * Finds the element by the given component function. * @param root - The root element to search within. * @param componentFn - The component function to search for. * @returns The element that matches the component function. */ findElementByComponent(t, n) { var s, o; if (((o = (s = t._vnode) == null ? void 0 : s.props) == null ? void 0 : o._componentFn) === n) return t; const r = (i) => { var c, l; for (const u of Array.from(i.children)) { if (((l = (c = u._vnode) == null ? void 0 : c.props) == null ? void 0 : l._componentFn) === n) return u; const a = r(u); if (a) return a; } return null; }; return r(t); } /** * Renders the given component function. * @param ComponentFn - The component function to render. * @returns The VNode of the component. */ render(t, n) { const r = this.currentComponentFn; this.currentComponentFn = t; try { this.stateIndexes.set(t, 0); const s = t(n || {}), o = Date.now(); return s && typeof s == "object" && Object.keys(s).forEach((i) => { i.startsWith("_temp") && delete s[i]; }), { type: "reactive-wrapper", props: { children: [s], _componentFn: t, _renderKey: o }, key: null, ref: null }; } finally { this.currentComponentFn = r; } } } const h = new k(); function F(e) { return h.createState(e); } function _(e, t, ...n) { if (typeof e == "function") { const o = h.currentComponentFn; h.currentComponentFn = e; try { h.stateIndexes.set(e, 0); const i = e({ ...t, children: n }); return t && Object.keys(t).forEach((c) => { c.startsWith("_temp") && delete t[c]; }), h.hasState(e) ? { type: "reactive-wrapper", props: { children: [i], _componentFn: e, _renderKey: Date.now() }, key: null, ref: null } : { type: e, props: { ...t, children: [i], _componentFn: e }, key: null, ref: null }; } finally { h.currentComponentFn = o; } } const r = t ? { ...t } : {}; r.style && typeof r.style == "object" && (r.style = Object.entries(r.style).reduce((o, [i, c]) => { const l = i.replace(/([A-Z])/g, "-$1").toLowerCase(); return o ? `${o};${l}:${c}` : `${l}:${c}`; }, "")); const s = n.map( (o) => typeof o == "object" ? o : { type: "TEXT_ELEMENT", props: { nodeValue: o } } ); return { type: e, props: { ...r, children: s } }; } let x = { getRouterContext: () => ({ currentPath: window.location.pathname, params: {} }), setRouterContext: () => { } }; function O({ value: e, children: t }) { return x = e, t; } function M() { if (!x) throw new Error("useRouter must be used within a Router"); return x; } function D(e) { window.history.pushState({}, "", e), M().setRouterContext((n) => ({ ...n, currentPath: e })); } function j({ to: e, children: t, className: n }) { return /* @__PURE__ */ _("a", { href: e, onClick: (s) => { s.preventDefault(), D(e); }, className: n }, t); } function U({ path: e, component: t }) { const { getRouterContext: n } = M(), { currentPath: r } = n(); return W(e, r) ? /* @__PURE__ */ _(t, null) : null; } function W(e, t) { const n = e.replace(/:[^\s/]+/g, "([^/]+)").replace(/\*/g, ".*"); return new RegExp(`^${n}$`).test(t); } function q({ children: e }) { console.log("Router"); const [t, n] = F({ currentPath: window.location.pathname, params: {} }), r = () => { n((s) => ({ ...s, currentPath: window.location.pathname })); }; return typeof window < "u" && window.addEventListener("popstate", r), /* @__PURE__ */ _(O, { value: { getRouterContext: t, setRouterContext: n } }, /* @__PURE__ */ _("div", null, e)); } export { j as Link, _ as Nexora, U as Route, q as Router, O as RouterProvider, F as createState, b as diffChildren, v as executeInitCallbacks, p as findDom, K as freeze, m as mount, S as mountComponent, D as navigate, B as onInit, g as patch, h as reactive, w as render, L as shallowEqual, R as updateProps, M as useRouter };